Last week, we continued our discussion of PHP standalone scripts with child processes and more. This week, we conclude our discussion and bring together what you've learned. The third of three parts, this article is excerpted from chapter five of the book Advanced PHP Programming, written by George Schlossnagle (Sams; ISBN: 0672325616).
A classic security precaution when writing Unix daemons is having them drop all unneeded privileges. Like being able to access files outside where they need to be, possessing unneeded privileges is a recipe for trouble. In the event that the code (or PHP itself) has an exploitable flaw, you can minimize damage by ensuring that a daemon is running as a user with minimal rights to alter files on the system.
One way to approach this is to simply execute the daemon as the unprivileged user. This is usually inadequate if the program needs to initially open resources (logfiles, data files, sockets, and so on) that the unprivileged user does not have rights to.
If you are running as the root user, you can drop your privileges by using the posix_setuid() and posiz_setgid() functions. Here is an example that changes the running program's privileges to those of the user nobody:
As with chroot(), any privileged resources that were open prior to dropping privileges remain open, but new ones cannot be created.
Guaranteeing Exclusivity
You often want to require that only one instance of a script can be running at any given time. For daemonizing scripts, this is especially important because running in the background makes it easy to accidentally invoke instances multiple times.
The standard technique for guaranteeing exclusivity is to have scripts lock a specific file (often a lockfile, used exclusively for that purpose) by using flock(). If the lock fails, the script should exit with an error. Here's an example:
$fp = fopen("/tmp/.lockfile", "a");
if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
fputs(STDERR, "Failed to acquire lock\n");
exit;
}
/* lock successful safe to perform work */
Locking mechanisms are discussed in greater depth in Chapter 10, "Data Component Caching."