note 37289 added to function.posix-setuid
| From: | rjmooney at syr dot edu | Date: | Sun, 09 Nov 2003 08:40:17 +0000 |
| Subject: | note 37289 added to function.posix-setuid | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-60154@lists.php.net to get a copy of this message | ||
For simple operations, you can easily create a privilege-separation mechanism to perform commands
that require elevated privileges.
For example, in creating a document repository, I had the need to provide access to certain
directory and file operations based on a user's login name. It's unrealistic and unsecure
to provide the web server access to all of the directories that the user may need to access, so I
created a setuid() script to perform the required operations for me.
An exerpt from the code demonstrates this:
<?
//
// main.php
//
// Perform a privileged stat()
function privsep_stat($path)
{
// Call the privilege separation program, ask for a stat of the specified path
$serialized_result = exec("/path/to/privsep.php stat " . $path, $oa,
$return_code);
if ($return_code != 0)
{
return false;
}
// Return the unserialized object
return unserialize($serialized_result);
}
// Get file statistics on a file we don't have access to as the web server user
$st = privsep_stat("/private_directory/private_file");
print_r($st);
?>
privsep.php looks like this:
#!/usr/local/bin/php
<?
//
// privsep.php
//
// Don't allow this script to be run from the web
if (isset($_SERVER['REQUEST_METHOD']))
{
print "<br>This program is not intended to be run directly from the WWW.\n";
return 1;
}
// TODO: add your argument validation here
// A stat was requested
if ($argv[1] == "stat")
{
// Reset the stat() cache
clearstatcache();
// Original user ID
$original_uid = posix_get_uid();
// Set our real user ID to root
$success = posix_setuid(0);
if (!$success)
{
print "Error: Cannot setuid().\n";
return 1;
}
// Store the file statistics
$st = stat($argv[2]);
// Drop the real UID back to the calling user ID
$success = posix_setuid($original_uid);
if (!$success)
{
print "Error: Cannot setuid().\n";
return 1;
}
// Drop the effective UID as well
$success = posix_seteuid($original_uid);
if (!$success)
{
print "Error: Cannot seteuid().\n";
return 1;
}
// Serialize the result and print it
$result = serialize($st);
print $result;
// Success!
return 0;
}
?>
Finally, privsep.php's permissions are configured like this:
# chown root:wheel privsep.php
# chmod 4755 privsep.php
And look like this:
-rwsr-xr-x 1 root wheel 1000 Nov 1 00:00 privsep.php
It's probably wise to keep privsep.php out of your document root to help mitigate any
successful attack.
This method can be extended for other functions. Use at your own risk.
----
Manual Page -- http://www.php.net/manual/en/function.posix-setuid.php
Edit -- http://master.php.net/manage/user-notes.php?action=edit+37289
Delete -- http://master.php.net/manage/user-notes.php?action=delete+37289&report=yes
Reject -- http://master.php.net/manage/user-notes.php?action=reject+37289&report=yes
Search -- http://master.php.net/manage/user-notes.php