Thursday, September 11, 2008

Sudoing in PHP to Reset Folder Permissions

At work today I engaged our academic file server (running Mac OS X.5.4) in an on-and-off all-day battle about folder permissions. The problems:

  1. One of our teachers kept getting locked out of his folders on the server when he modified or moved them from his PC client. Bummer. I needed an EASY way for him to reset his permissions himself, meaning:

  2. I needed to create a web-accessible script (in PHP) to make a UNIX call to reset his permissions on-demand (ie, whenever he visited the page, his permissions would be reset)


Here’s how I eventually won:

I created a file in the server’s web host root (for this particular server, just the default /Library/WebServer/Documents/) called teachername.php (where “teachername” is the teacher’s name... duh). Even though our website is hosted on a separate server, the server in question also has web services enabled, which will allow the teacher to simply visit
servername.domainname.net/teachername.php and the server will run the script.

Creating that script wasn’t as easy as I expected, though. After hours researching and trying to get PHP’s system() function to work, I decided to try exec() instead. The file contents look something like this:


<?php
$output = array();
$return = -5; // Some erroneous value
exec("sudo /bin/chmod -R 770 /Volumes/Share\ Point/teacherusername/",$output,$return);
echo "chmod output: ";
print_r($output);
echo '<br /><br />';
echo "sudo/chmod return value: " . $return . "<br /><br />";
echo "<strong>Permissions reset complete.</strong>";
?>


There's really only one line that's important, the rest is all debugging info:

exec("sudo /bin/chmod -R 770 /Volumes/Share\ Point/teacherusername/",$output,$return);

This tells PHP to spawn a new child process to execute the sudo command. I had to add apache’s _www user to the sudoers file on the server (in Terminal, use the command "sudo visudo", then edit using vi commands):

_www    ALL=NOPASSWD: /bin/chmod,/usr/bin/whoami

IMPORTANT SECURITY NOTE: the _www user ONLY has permissions to sudo the commands chmod and whoami (and do so without a password), it ISN'T allowed to sudo anything else. For more information about modifying the sudoers file, refer to http://linsec.ca/Using_Sudo_to_Limit_Access, as well as the limited documentation available in the file itself. (you can try it on your own Mac, just open terminal and type "sudo visudo").


The rest is basic POSIX permissions: change mode (chmod) -Recursively to -rwxrwx--- (770) on the teacher’s folder. The other PHP variables give the exec command a place to deposit both the return value from sudo (a 0 means successful execution), as well as any output that was generated by chmod (should be none).


Yes, I had fun with this puzzle. Hopefully someone else might stumble on this and find it useful, too...

No comments: