Fix Linux Users Home Permissions with a Cron Job
As a security nut myself, and also a Linux admin, one of my biggest pet peeves is when I've taken the time and care to segment all the users on a server into separate home directories, and then some developer comes along, logs in as root, and changes the ownership of files. Other things can cause this, like Apache, PHP, Mutt, etc.. So I've always used a cron job that executes daily (and on demand) which automatically fixes all the permissions back to what they should be.
Linux Home Directories
Essentially, every website/client has a separate username and home directory, where their site files are located.
HUMANPERMS USERNAME:GROUPNAME DIRECTORY --------------------------------------------------------- drwx------ boxadmin:boxadmin /web/boxadmin/ drwx------ jkjklol:jkjklol /web/jkjklol/ drwx------ el33tbill:el33tbill /web/el33tbill/
/etc/passwd File
In the /etc/passwd
file is the list of all the users:
username:x:UID:GID:comment:homedirectory:shell
boxadmin:x:503:503::/web/boxadmin:/bin/bash jkjklol:x:511:511:jkjklol.com:/web/jkjklol:/usr/bin/rssh el33tbill:x:513:513:el33tbill.com:/web/el33tbill:/usr/bin/rssh
/etc/shells File
The /etc/shells
file contains a list of all the shells that a user can use to login with. So if the shell listed in /etc/passwd is not listed here, they cannot login interactively (ftp/shell). Side Note: I restrict website users to only rssh or scponly shells.
/bin/sh /bin/bash /sbin/nologin /usr/bin/rssh
Why Cron
This is the way to do it, well, this is how I've been doing it for about 10 years now. The below script is probably the 30th version, it works very well.
With cron I don't have to worry or constantly login to the system and run complex find commands, it also prevents my security protection tools from sending me alerts by fixing these ownership issues first.
In summary, I truly love me some cron.
Setup the Cron Script
Make sure you have the latest version of GNU find or you won't be able to use the find /web/el33tbill -mount \( ! -user el33tbill -o ! -group el33tbill \)
syntax.
$ find --version find (GNU findutils) 4.4.2
Then save the below script as /etc/cron.daily/fix_user_home_dir_owner_perms.cron
or something like that. I like to give cron scripts the .cron
suffix, even though they are just normal shell scripts.
Finally make sure to chown that file to be owned as root:root and also chmod it to 755
$ chown root:root /etc/cron.daily/fix_user_home_dir_owner_perms.cron $ chmod 755 /etc/cron.daily/fix_user_home_dir_owner_perms.cron
The Script
Copy paste from below or download the file.
As you can see, the chown command (which is the only command that modifies anything) is commented out below. So you can run this first to see what it will find, and then uncomment it to make it live.
The reason for the seemingly complex operation of first searching for all the files with improper ownership and saving to the FOUND variable is one of the benefits of this being my 30th version. Basically the way cron works is it will exectue this file, and if there is any output at all it will usually send that output to the MAILTO=
address in /etc/crontab
, meaning if there is no output, it was a total success and found no bad perms, if there is output, it will not only fix them, it will also let you know exactly what the files were before fixing them, in a detailed stat like output.
The other thing I am really proud of with this is the first for LINE
line. What that sed code does is it grabs the list of shells that are allowed for logins and uses that as a filter against /etc/passwd
which means it will only list users that have shells listed. This means things like apache, sendmail, exim, mysql, bin, and all the various other daemons and services that use shells like /bin/false
won't show up. The 3rd sed prevents any users with the /sbin/nologin
shell from being checked.
WARNING: There is only 1 danger with this script, so if you neglect this warning blame yourself. The only danger is that this will run on a system user like exim, apache, nobody, mysql, etc., which could happen easily if that user's shell is improper. This can sometimes happen (and be a security risk) if a package was installed incorrectly, or is just really outdated. To prevent any danger, run this script as it is below first and verify that the DEBUG: lines show it is only being run for valid users, and not for daemon users. Once you verify that, you can comment the DEBUG line, and uncomment the chown line, and then you won't have to worry about user home directory ownership ever again!
#!/bin/bash function fix_user_home_dir_owner_perms () { local LINE FOUND UN HD for LINE in $( sed -n "\@\(`sed -n '\#^/#p' /etc/shells | sed '\#nologin#d' | sed -e :a -e 'N;s/\n/\\\\|/g;ta'`\)@p" /etc/passwd | sed 's/^\([^:]*\):[^\/]*\(\/[^:]*\):\(.*\)$/UN=\1;HD=\2;/g' ); do # set to blank FOUND= UN= HD=; # eval the LINE read from /etc/passwd - UN=username;HD=/web/userhome; eval $LINE; echo "DEBUG: USERNAME:${UN} HOMEDIRECTORY: ${HD}" # search users home dir for anything they arent the user:group owner of, if any found print detailed info about it and save to the FOUND var FOUND=$( find $HD -mount \( ! -user $UN -o ! -group $UN \) -printf '%.5m %10M %#9u:%-9g %#5U:%-5G [%AD | %TD | %CD] [%Y] %p\n' 2>/dev/null ); # if results, echo USER - HOME followed by all the results saved in FOUND, then recursively chown home dir of user, showing changes [[ ${#FOUND} -gt 1 ]] && echo -e "\n\n --- ${UN}:${UN} - ${HD}\n${FOUND}" #&& chown --preserve-root -cR $UN:$UN $HD done } # this runs the function declared above fix_user_home_dir_owner_perms # exit with success or failure exit $?
Output
I ran this script manually (after turning off the DEBUG line and uncommenting the chown part) to create some output.
--- el33tbill:el33tbill - /web/el33tbill 00755 drwxr-xr-x root:nobody 502:500 [02/07/13 | 02/07/13 | 03/27/13] [d] /web/el33tbill/sites/el33tbill.com/tmp/s changed ownership of `/web/el33tbill/sites/el33tbill.com/tmp/s' to el33tbill:el33tbill
Bonus, Extend with Permissions
You can easily modify this script, as I have, to fix the actual permissions of the home directories as well.
My personal preference is to chmod all home directories to 700, which means no-one other than a super-user and the actual linux user who owns that home directory can view the files in it. The caveat to this approach is that in order for Apache to access the site files, I chmod the site directory /web/el33tbill/sites/el33tbill.com
to 755.
That means another user who is logged in to the machine via ssh, cannot do $ ls /web/el33tbill
or $ ls /web/el33tbill/sites
, but they could do $ ls /web/el33tbill/sites/el33tbill.com
.. It's a nice secure way to do it.
eval $LINE
line is:
... eval $LINE; chmod -c 700 $HD
If you do that you can't just hope that it will work and go off to play solitaire.. That's what a Windows user would do, hence the big joke about "el33tbill" (it's impossible for a Windows user aka bill gates to ever be considered an elite hacker, but a script kiddie el33t sure why not).
You need to verify that your web server still works, and also tail your apache error_log after restarting apache to double check.
« Getting the Mimetype of an Image with PHPView all MySQL Variables for Pasting into my.cnf »
Comments