ext/apache2/Utils.h in passenger-2.1.2 vs ext/apache2/Utils.h in passenger-2.1.3

- old
+ new

@@ -217,62 +217,118 @@ * @ingroup Support */ string escapeForXml(const string &input); /** - * Return the path name for the directory in which temporary files are - * to be stored. + * Given a username that's supposed to be the "lowest user" in the user switching mechanism, + * checks whether this username exists. If so, this users's UID and GID will be stored into + * the arguments of the same names. If not, <em>uid</em> and <em>gid</em> will be set to + * the UID and GID of the "nobody" user. If that user doesn't exist either, then <em>uid</em> + * and <em>gid</em> will be set to -1. + */ +void determineLowestUserAndGroup(const string &user, uid_t &uid, gid_t &gid); + +/** + * Return the path name for the directory in which the system stores general + * temporary files. This is usually "/tmp", but might be something else depending + * on some environment variables. * * @ensure result != NULL * @ingroup Support */ -const char *getTempDir(); +const char *getSystemTempDir(); /** * Return the path name for the directory in which Phusion Passenger-specific * temporary files are to be stored. This directory is unique for this instance * of the web server in which Phusion Passenger is running. * - * The result will be cached into the PHUSION_PASSENGER_TMP environment variable, - * which will be used for future calls to this function. To bypass this cache, + * If the environment variable PASSENGER_INSTANCE_TEMP_DIR is set, then that value + * will be returned. If this environment variable is not set, then it will be set + * with the return value. + * + * To bypass the usage of the PASSENGER_INSTANCE_TEMP_DIR environment variable, * set 'bypassCache' to true. * + * @param bypassCache Whether PASSENGER_INSTANCE_TEMP_DIR should be bypassed. + * @param systemTempDir The directory under which the Phusion Passenger-specific + * temp directory should be located. If set to the empty string, + * then the return value of getSystemTempDir() will be used. * @ensure !result.empty() * @ingroup Support */ -string getPassengerTempDir(bool bypassCache = false); +string getPassengerTempDir(bool bypassCache = false, const string &systemTempDir = ""); -/* Create a temp folder for storing Phusion Passenger-specific temp files, - * such as temporarily buffered uploads, sockets for backend processes, etc. - * This call also sets the PHUSION_PASSENGER_TMP environment variable, which - * allows backend processes to find this temp folder. +/* Create a temp directory under <em>systemTempDir</em>, for storing Phusion + * Passenger-specific temp files, such as temporarily buffered uploads, + * sockets for backend processes, etc. This call also sets the + * PASSENGER_INSTANCE_TEMP_DIR environment variable, which allows subprocesses + * to find this temp directory. * - * Does nothing if this folder already exists. + * The created temp directory will have several subdirectories: + * - webserver_private - for storing the web server's buffered uploads. + * - info - for storing files that allow external tools to query information + * about a running Phusion Passenger instance. + * - backends - for storing Unix sockets created by backend processes. + * - var - for storing all other kinds of temp files that the backend processes + * create. * + * If a (sub)directory already exists, then it will not result in an error. + * + * The <em>userSwitching</em> and <em>lowestUser</em> arguments passed to + * this method are used for determining the optimal permissions for the + * (sub)directories. The permissions will be set as tightly as possible based + * on the values. The <em>workerUid</em> and <em>workerGid</em> arguments + * will be used for determining the owner of certain subdirectories. + * + * @note You should only call this method inside the web server's master + * process. In case of Apache, this is the Apache control process, + * the one that tends to run as root. This is because this function + * will set directory permissions and owners/groups, which may require + * root privileges. + * + * @param systemTempDir The directory under which the Phusion Passenger-specific + * temp directory should be created. You should normally + * specify the return value of getSystemTempDir(). + * @param userSwitching Whether user switching is turned on. + * @param lowestUser The user that the spawn manager and the pool server will + * run as, if user switching is turned off. + * @param workerUid The UID that the web server's worker processes are running + * as. On Apache, this is the UID that's associated with the + * 'User' directive. + * @param workerGid The GID that the web server's worker processes are running + * as. On Apache, this is the GID that's associated with the + * 'Group' directive. * @throws IOException Something went wrong. * @throws SystemException Something went wrong. + * @throws FileSystemException Something went wrong. */ -void createPassengerTempDir(); +void createPassengerTempDir(const string &systemTempDir, bool userSwitching, + const string &lowestUser, + uid_t workerUid, gid_t workerGid); /** * Create the directory at the given path, creating intermediate directories * if necessary. The created directories' permissions are as specified by the - * 'mode' parameter. + * 'mode' parameter. You can specify this directory's owner and group through + * the 'owner' and 'group' parameters. A value of -1 for 'owner' or 'group' + * means that the owner/group should not be changed. * * If 'path' already exists, then nothing will happen. * * @throws IOException Something went wrong. * @throws SystemException Something went wrong. + * @throws FileSystemException Something went wrong. */ -void makeDirTree(const char *path, const char *mode = "u=rwx,g=,o="); +void makeDirTree(const string &path, const char *mode = "u=rwx,g=,o=", uid_t owner = -1, gid_t group = -1); /** * Remove an entire directory tree recursively. * - * @throws SystemException Something went wrong. + * @throws FileSystemException Something went wrong. */ -void removeDirTree(const char *path); +void removeDirTree(const string &path); /** * Check whether the specified directory is a valid Ruby on Rails * application root directory. * @@ -307,56 +363,61 @@ */ bool verifyWSGIDir(const string &dir, CachedMultiFileStat *mstat = 0, unsigned int throttleRate = 0); /** - * Represents a temporary file. The associated file is automatically - * deleted upon object destruction. + * Represents a buffered upload file. * * @ingroup Support */ -class TempFile { +class BufferedUpload { public: - /** The filename. If this temp file is anonymous, then the filename is an empty string. */ - string filename; /** The file handle. */ FILE *handle; /** - * Create an empty, temporary file, and open it for reading and writing. + * Create an empty upload bufer file, and open it for reading and writing. * - * @param anonymous Set to true if this temp file should be unlinked - * immediately. Anonymous temp files are useful if one just wants - * a big not-in-memory buffer to work with. * @throws SystemException Something went wrong. */ - TempFile(const char *identifier = "temp", bool anonymous = true) { + BufferedUpload(const char *identifier = "temp") { char templ[PATH_MAX]; int fd; - snprintf(templ, sizeof(templ), "%s/%s.XXXXXX", getPassengerTempDir().c_str(), identifier); + snprintf(templ, sizeof(templ), "%s/%s.XXXXXX", getDir().c_str(), identifier); templ[sizeof(templ) - 1] = '\0'; fd = mkstemp(templ); if (fd == -1) { char message[1024]; + int e = errno; + snprintf(message, sizeof(message), "Cannot create a temporary file '%s'", templ); message[sizeof(message) - 1] = '\0'; - throw SystemException(message, errno); + throw SystemException(message, e); } - if (anonymous) { - fchmod(fd, 0000); - unlink(templ); - } else { - filename.assign(templ); - } + + /* We use a POSIX trick here: the file's permissions are set to "u=,g=,o=" + * and the file is deleted immediately from the filesystem, while we + * keep its file handle open. The result is that no other processes + * will be able to access this file's contents anymore, except us. + * We now have an anonymous disk-backed buffer. + */ + fchmod(fd, 0000); + unlink(templ); + handle = fdopen(fd, "w+"); } - ~TempFile() { + ~BufferedUpload() { fclose(handle); - if (!filename.empty()) { - unlink(filename.c_str()); - } + } + + /** + * Returns the directory in which upload buffer files are stored. + * This is a subdirectory of the directory returned by getPassengerTempDir(). + */ + static string getDir() { + return getPassengerTempDir() + "/webserver_private"; } }; } // namespace Passenger