Okay so this all started with our users not being able to share files on our webserver. We use SSH only for upload/download and interactive access (ie: no ftp). Through trial and error we found out that the default umask (under OSX Server) for sftp uploaded files are 0033 (ie: rwxr–r–) and directories are 0022 (ie: rwxr-xr-x). This creates a problem when one user uploads a file and another user downloads/modifies and tries to re-upload it — they simply can’t because the group permissions are wrong.
If we were using ftp (which we are not) there are some solutions on the net that allow you to modify the startup parameters for the ftp server so that the default umask for all files is 0013 — which would allow a group of people to share/overwrite each others files — but we are using ssh only.
So we came up with two other solutions — a shared upload account and/or a cron job that would modify the group permissions on the website directory to allow group sharing. We went with the second solution and that’s where I ran into so many problems that I decided to create this post. You see normally Unix users know that spaces (and strange characters) in filenames are a no-no. Well that’s not true for Windows and Mac users, they use spaces and other odd characters in their filenames/folders all the time.
I started writing — what I thought was — a simple “for loop” script to go through the website folder and change the group permissions. Of course on the first try things didn’t work nicely because of spaces, so I started compensating for that and came up with:for i in `find /Path/to/www -type d -print0 |xargs -0 -n 1`
This kinda worked, but the for loop would still split the lines when it hit spaces in filenames. I tried to mess around with it and gave up. After RTFMing a bit more I tried:for i in `find /Path/to/www -type d -exec echo \"{}\" \;`
The thinking behind this was that the exec would echo the filenames quoted and it should work….well it didn’t, the for loop still split the input lines at spaces.
Finally after a latenight RTFM session (and lots of cursing), I think I’ve found the ultimate file handling loop statement:find /Path/to/www -type d ! -perm -g=wx -print0 | while IFS= read -rd $'\0' filename
Okay so this version uses “while” rather than “for” but it works like a charm and chews through spaces and all other kinds of weird chars and creates a output stream that’s ready to be used by your choice of commands (chmod in my case).
After trimming and optimizing the script a bit, here is the final product:# The following find will search for
# all files under /Path/to/www, that
# are NOT symlinks, and do NOT have
# group write permission. The list is
# "\0" seperated and the while portion
# will loop around this character and
# ignore everything else in the path.
find /Path/to/www ! -type l ! -perm -g=w -print0 | while IFS= read -rd $'\0' filename
do
# We've found a directory with no group
# write permission, so fix it.
if [ -d "$filename" ]
then
chmod g+rwx "$filename"
# echo Directory changed
stat -l "$filename"
fi
# We've found a file with no group
# write permission, so fix it.
if [ -f "$filename" ]
then
chmod g+rw "$filename"
# echo File changed
stat -l "$filename"
fi
done
Hopefully you’ll find this code (or portions of it) useful for your own day-to-day hack-and-slash solutions to annoying problems. Let me know if you come up with an even better solution :-)
2 responses to “OSX Webmaster special: Shared webserver, bad umask settings, group permissions and filenames with spaces…”
Couldn’t you just chmod -R g+w /path/to/www
Or even better yet create a wrapper script for sftp
eg:
#!/bin/sh
umask 022
exec /path/to/sftp-server
Then change the sshd_config
Subsystem sftp /path/to/sftp-wrapper-script
Hi pyhimys,
If you didn’t care about execute permission…yes. I needed to make sure that I have g+wx on dirs, ONLY g+w on files and don’t touch symlinks, so I had to “find” them. The other thing is if you run chmod -R on a filesystem with 18000 files and about 1200 folders it takes a bit of time….add to that the fact that I like to run the script every couple of minutes.
I would have done the wrapper script if I was dealing with “standard” webserver only machine….but I don’t want to change the umask for everyone who sftps into the server. I realize a more detailed wrapper could potentially parse out the user and set the umask dynamically (maybe?)…..but that would have taken too much time….unless you know of a wrapper that does that already somewhere on the net?
Thanks for the comments….
Many