Passenger: Utils.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List

# Utils.h

    00001 /*
    00002  *  Phusion Passenger - http://www.modrails.com/
    00003  *  Copyright (c) 2010 Phusion
    00004  *
    00005  *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
    00006  *
    00007  *  Permission is hereby granted, free of charge, to any person obtaining a copy
    00008  *  of this software and associated documentation files (the "Software"), to deal
    00009  *  in the Software without restriction, including without limitation the rights
    00010  *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    00011  *  copies of the Software, and to permit persons to whom the Software is
    00012  *  furnished to do so, subject to the following conditions:
    00013  *
    00014  *  The above copyright notice and this permission notice shall be included in
    00015  *  all copies or substantial portions of the Software.
    00016  *
    00017  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    00018  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    00019  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    00020  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    00021  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    00022  *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    00023  *  THE SOFTWARE.
    00024  */
    00025 #ifndef _PASSENGER_UTILS_H_
    00026 #define _PASSENGER_UTILS_H_
    00027
    00028 #include <boost/shared_ptr.hpp>
    00029 #include <sys/types.h>
    00030 #include <sys/stat.h>
    00031 #include <string>
    00032 #include <vector>
    00033 #include <utility>
    00034 #include <sstream>
    00035 #include <cstdio>
    00036 #include <climits>
    00037 #include <cstdlib>
    00038 #include <cstring>
    00039 #include <errno.h>
    00040 #include <unistd.h>
    00041 #include "StaticString.h"
    00042 #include "Exceptions.h"
    00043
    00044 namespace Passenger {
    00045
    00046 using namespace std;
    00047 using namespace boost;
    00048
    00049 static const uid_t USER_NOT_GIVEN = (uid_t) -1;
    00050 static const gid_t GROUP_NOT_GIVEN = (gid_t) -1;
    00051
    00052 typedef struct CachedFileStat CachedFileStat;
    00053 class ResourceLocator;
    00054
    00055 /** Enumeration which indicates what kind of file a file is. */
    00056 typedef enum {
    00057         /** The file doesn't exist. */
    00058         FT_NONEXISTANT,
    00059         /** A regular file or a symlink to a regular file. */
    00060         FT_REGULAR,
    00061         /** A directory. */
    00062         FT_DIRECTORY,
    00063         /** Something else, e.g. a pipe or a socket. */
    00064         FT_OTHER
    00065 } FileType;
    00066
    00067 /**
    00068  * Convenience shortcut for creating a <tt>shared_ptr</tt>.
    00069  * Instead of:
    00070  * @code
    00071  *    shared_ptr<Foo> foo;
    00072  *    ...
    00073  *    foo = shared_ptr<Foo>(new Foo());
    00074  * @endcode
    00075  * one can write:
    00076  * @code
    00077  *    shared_ptr<Foo> foo;
    00078  *    ...
    00079  *    foo = ptr(new Foo());
    00080  * @endcode
    00081  *
    00082  * @param pointer The item to put in the shared_ptr object.
    00083  * @ingroup Support
    00084  */
    00085 template<typename T> shared_ptr<T>
    00086 ptr(T *pointer) {
    00087         return shared_ptr<T>(pointer);
    00088 }
    00089
    00090 /**
    00091  * Used internally by toString(). Do not use directly.
    00092  *
    00093  * @internal
    00094  */
    00095 template<typename T>
    00096 struct AnythingToString {
    00097         string operator()(T something) {
    00098                 stringstream s;
    00099                 s << something;
    00100                 return s.str();
    00101         }
    00102 };
    00103
    00104 /**
    00105  * Used internally by toString(). Do not use directly.
    00106  * @internal
    00107  */
    00108 template<>
    00109 struct AnythingToString< vector<string> > {
    00110         string operator()(const vector<string> &v) {
    00111                 string result = "[";
    00112                 vector<string>::const_iterator it;
    00113                 unsigned int i;
    00114                 for (it = v.begin(), i = 0; it != v.end(); it++, i++) {
    00115                         result.append("'");
    00116                         result.append(*it);
    00117                         if (i == v.size() - 1) {
    00118                                 result.append("'");
    00119                         } else {
    00120                                 result.append("', ");
    00121                         }
    00122                 }
    00123                 result.append("]");
    00124                 return result;
    00125         }
    00126 };
    00127
    00128 /**
    00129  * Used internally by toString(). Do not use directly.
    00130  * @internal
    00131  */
    00132 template<>
    00133 struct AnythingToString< vector<StaticString> > {
    00134         string operator()(const vector<StaticString> &v) {
    00135                 string result = "[";
    00136                 vector<StaticString>::const_iterator it;
    00137                 unsigned int i;
    00138                 for (it = v.begin(), i = 0; it != v.end(); it++, i++) {
    00139                         result.append("'");
    00140                         result.append(it->data(), it->size());
    00141                         if (i == v.size() - 1) {
    00142                                 result.append("'");
    00143                         } else {
    00144                                 result.append("', ");
    00145                         }
    00146                 }
    00147                 result.append("]");
    00148                 return result;
    00149         }
    00150 };
    00151
    00152 /**
    00153  * Convert anything to a string.
    00154  *
    00155  * @param something The thing to convert.
    00156  * @ingroup Support
    00157  */
    00158 template<typename T> string
    00159 toString(T something) {
    00160         return AnythingToString<T>()(something);
    00161 }
    00162
    00163 /**
    00164  * Converts the given string to an integer.
    00165  * @ingroup Support
    00166  */
    00167 int atoi(const string &s);
    00168
    00169 /**
    00170  * Converts the given string to a long integer.
    00171  * @ingroup Support
    00172  */
    00173 long atol(const string &s);
    00174
    00175 /** Round <em>number</em> up to the nearest multiple of <em>multiple</em>. */
    00176 template<typename IntType> IntType
    00177 roundUp(IntType number, IntType multiple) {
    00178         return (number + multiple - 1) / multiple * multiple;
    00179 }
    00180
    00181 /**
    00182  * Split the given string using the given separator.
    00183  *
    00184  * @param str The string to split.
    00185  * @param sep The separator to use.
    00186  * @param output The vector to write the output to.
    00187  * @ingroup Support
    00188  */
    00189 void split(const string &str, char sep, vector<string> &output);
    00190
    00191 /**
    00192  * Check whether the specified file exists.
    00193  *
    00194  * @param filename The filename to check.
    00195  * @param cstat A CachedFileStat object, if you want to use cached statting.
    00196  * @param throttleRate A throttle rate for cstat. Only applicable if cstat is not NULL.
    00197  * @return Whether the file exists.
    00198  * @throws FileSystemException Unable to check because of a filesystem error.
    00199  * @throws TimeRetrievalException
    00200  * @throws boost::thread_interrupted
    00201  * @ingroup Support
    00202  */
    00203 bool fileExists(const StaticString &filename, CachedFileStat *cstat = 0,
    00204                 unsigned int throttleRate = 0);
    00205
    00206 /**
    00207  * Check whether 'filename' exists and what kind of file it is.
    00208  *
    00209  * @param filename The filename to check.
    00210  * @param mstat A CachedFileStat object, if you want to use cached statting.
    00211  * @param throttleRate A throttle rate for cstat. Only applicable if cstat is not NULL.
    00212  * @return The file type.
    00213  * @throws FileSystemException Unable to check because of a filesystem error.
    00214  * @throws TimeRetrievalException
    00215  * @throws boost::thread_interrupted
    00216  * @ingroup Support
    00217  */
    00218 FileType getFileType(const StaticString &filename, CachedFileStat *cstat = 0,
    00219                      unsigned int throttleRate = 0);
    00220
    00221 /**
    00222  * Create the given file with the given contents, permissions and ownership.
    00223  * This function does not leave behind junk files: if the ownership cannot be set
    00224  * or if not all data can be written then then the file will be deleted.
    00225  *
    00226  * @param filename The file to create.
    00227  * @param contents The contents to write to the file.
    00228  * @param permissions The desired file permissions.
    00229  * @param owner The desired file owner. Specify USER_NOT_GIVEN if you want to use the current
    00230  *              process's owner as the file owner.
    00231  * @param group The desired file group. Specify GROUP_NOT_GIVEN if you want to use the current
    00232  *              process's group as the file group.
    00233  * @param overwrite Whether to overwrite the file if it exists. If set to false
    00234  *                  and the file exists then nothing will happen.
    00235  * @throws FileSystemException Something went wrong.
    00236  * @ingroup Support
    00237  */
    00238 void createFile(const string &filename, const StaticString &contents,
    00239                 mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
    00240                 uid_t owner = USER_NOT_GIVEN, gid_t group = GROUP_NOT_GIVEN,
    00241                 bool overwrite = true);
    00242
    00243 /**
    00244  * Returns a canonical version of the specified path. All symbolic links
    00245  * and relative path elements are resolved.
    00246  *
    00247  * @throws FileSystemException Something went wrong.
    00248  * @ingroup Support
    00249  */
    00250 string canonicalizePath(const string &path);
    00251
    00252 /**
    00253  * If <em>path</em> refers to a symlink, then this function resolves the
    00254  * symlink for 1 level. That is, if the symlink points to another symlink,
    00255  * then the other symlink will not be resolved. The resolved path is returned.
    00256  *
    00257  * If the symlink doesn't point to an absolute path, then this function will
    00258  * prepend <em>path</em>'s directory to the result.
    00259  *
    00260  * If <em>path</em> doesn't refer to a symlink then this method will return
    00261  * <em>path</em>.
    00262  *
    00263  * @throws FileSystemException Something went wrong.
    00264  * @ingroup Support
    00265  */
    00266 string resolveSymlink(const string &path);
    00267
    00268 /**
    00269  * Given a path, extracts its directory name.
    00270  *
    00271  * @ingroup Support
    00272  */
    00273 string extractDirName(const StaticString &path);
    00274
    00275 /**
    00276  * Given a path, extracts its base name.
    00277  *
    00278  * @ingroup Support
    00279  */
    00280 string extractBaseName(const StaticString &path);
    00281
    00282 /**
    00283  * Escape the given raw string into an XML value.
    00284  *
    00285  * @throws std::bad_alloc Something went wrong.
    00286  * @ingroup Support
    00287  */
    00288 string escapeForXml(const string &input);
    00289
    00290 /**
    00291  * Sets a socket in non-blocking mode.
    00292  *
    00293  * @throws SystemException Something went wrong.
    00294  * @ingroup Support
    00295  */
    00296 void setNonBlocking(int fd);
    00297
    00298 /**
    00299  * Returns the username of the user that the current process is running as.
    00300  * If the user has no associated username, then "UID xxxx" is returned,
    00301  * where xxxx is the current UID.
    00302  */
    00303 string getProcessUsername();
    00304
    00305 /**
    00306  * Converts a mode string into a mode_t value.
    00307  *
    00308  * At this time only the symbolic mode strings are supported, e.g. something like looks
    00309  * this: "u=rwx,g=w,o=rx". The grammar is as follows:
    00310  * @code
    00311  *   mode   ::= (clause ("," clause)*)?
    00312  *   clause ::= who "=" permission*
    00313  *   who    ::= "u" | "g" | "o"
    00314  *   permission ::= "r" | "w" | "x" | "s"
    00315  * @endcode
    00316  *
    00317  * Notes:
    00318  * - The mode value starts with 0. So if you specify "u=rwx", then the group and world
    00319  *   permissions will be empty (set to 0).
    00320  * - The "s" permission is only allowed for who == "u" or who == "g".
    00321  * - The return value does not depend on the umask.
    00322  *
    00323  * @throws InvalidModeStringException The mode string cannot be parsed.
    00324  */
    00325 mode_t parseModeString(const StaticString &mode);
    00326
    00327 /**
    00328  * Return the path name for the directory in which the system stores general
    00329  * temporary files. This is usually "/tmp", but might be something else depending
    00330  * on some environment variables.
    00331  *
    00332  * @ensure result != NULL
    00333  * @ingroup Support
    00334  */
    00335 const char *getSystemTempDir();
    00336
    00337 /* Create a temporary directory for storing Phusion Passenger instance-specific
    00338  * temp files, such as temporarily buffered uploads, sockets for backend
    00339  * processes, etc.
    00340  * The directory that will be created is the one returned by
    00341  * <tt>getPassengerTempDir(false, parentDir)</tt>. This call stores the path to
    00342  * this temp directory in an internal variable, so that subsequent calls to
    00343  * getPassengerTempDir() will return the same path.
    00344  *
    00345  * The created temp directory will have several subdirectories:
    00346  * - webserver_private - for storing the web server's buffered uploads.
    00347  * - info - for storing files that allow external tools to query information
    00348  *          about a running Phusion Passenger instance.
    00349  * - backends - for storing Unix sockets created by backend processes.
    00350  * - master - for storing files such as the Passenger HelperServer socket.
    00351  *
    00352  * If a (sub)directory already exists, then it will not result in an error.
    00353  *
    00354  * The <em>userSwitching</em> and <em>lowestUser</em> arguments passed to
    00355  * this method are used for determining the optimal permissions for the
    00356  * (sub)directories. The permissions will be set as tightly as possible based
    00357  * on the values. The <em>workerUid</em> and <em>workerGid</em> arguments
    00358  * will be used for determining the owner of certain subdirectories.
    00359  *
    00360  * @note You should only call this method inside the web server's master
    00361  *       process. In case of Apache, this is the Apache control process,
    00362  *       the one that tends to run as root. This is because this function
    00363  *       will set directory permissions and owners/groups, which may require
    00364  *       root privileges.
    00365  *
    00366  * @param parentDir The directory under which the Phusion Passenger-specific
    00367  *                  temp directory should be created. This argument may be the
    00368  *                  empty string, in which case getSystemTempDir() will be used
    00369  *                  as the parent directory.
    00370  * @param userSwitching Whether user switching is turned on.
    00371  * @param lowestUser The user that the spawn manager and the pool server will
    00372  *                   run as, if user switching is turned off.
    00373  * @param workerUid The UID that the web server's worker processes are running
    00374  *                  as. On Apache, this is the UID that's associated with the
    00375  *                  'User' directive.
    00376  * @param workerGid The GID that the web server's worker processes are running
    00377  *                  as. On Apache, this is the GID that's associated with the
    00378  *                  'Group' directive.
    00379  * @throws IOException Something went wrong.
    00380  * @throws SystemException Something went wrong.
    00381  * @throws FileSystemException Something went wrong.
    00382  */
    00383 /* void createPassengerTempDir(const string &parentDir, bool userSwitching,
    00384                             const string &lowestUser,
    00385                             uid_t workerUid, gid_t workerGid); */
    00386
    00387 /**
    00388  * Create the directory at the given path, creating intermediate directories
    00389  * if necessary. The created directories' permissions are exactly as specified
    00390  * by the 'mode' parameter (i.e. the umask will be ignored). You can specify
    00391  * this directory's owner and group through the 'owner' and 'group' parameters.
    00392  * A value of USER_NOT_GIVEN for 'owner' and/or GROUP_NOT_GIVEN 'group' means
    00393  * that the owner/group should not be changed.
    00394  *
    00395  * If 'path' already exists, then nothing will happen.
    00396  *
    00397  * @param mode A mode string, as supported by parseModeString().
    00398  * @throws FileSystemException Something went wrong.
    00399  * @throws InvalidModeStringException The mode string cannot be parsed.
    00400  */
    00401 void makeDirTree(const string &path, const StaticString &mode = "u=rwx,g=,o=",
    00402         uid_t owner = USER_NOT_GIVEN, gid_t group = GROUP_NOT_GIVEN);
    00403
    00404 /**
    00405  * Remove an entire directory tree recursively. If the directory doesn't exist then this
    00406  * function does nothing.
    00407  *
    00408  * @throws FileSystemException Something went wrong.
    00409  */
    00410 void removeDirTree(const string &path);
    00411
    00412 /**
    00413  * Check whether the specified directory is a valid Ruby on Rails
    00414  * application root directory.
    00415  *
    00416  * @param cstat A CachedFileStat object, if you want to use cached statting.
    00417  * @param throttleRate A throttle rate for cstat. Only applicable if cstat is not NULL.
    00418  * @throws FileSystemException Unable to check because of a system error.
    00419  * @throws TimeRetrievalException
    00420  * @throws boost::thread_interrupted
    00421  * @ingroup Support
    00422  */
    00423 bool verifyRailsDir(const string &dir, CachedFileStat *cstat = 0,
    00424                     unsigned int throttleRate = 0);
    00425
    00426 /**
    00427  * Check whether the specified directory is a valid Rack application
    00428  * root directory.
    00429  *
    00430  * @param cstat A CachedFileStat object, if you want to use cached statting.
    00431  * @param throttleRate A throttle rate for cstat. Only applicable if cstat is not NULL.
    00432  * @throws FileSystemException Unable to check because of a filesystem error.
    00433  * @throws TimeRetrievalException
    00434  * @throws boost::thread_interrupted
    00435  * @ingroup Support
    00436  */
    00437 bool verifyRackDir(const string &dir, CachedFileStat *cstat = 0,
    00438                    unsigned int throttleRate = 0);
    00439
    00440 /**
    00441  * Check whether the specified directory is a valid WSGI application
    00442  * root directory.
    00443  *
    00444  * @param cstat A CachedFileStat object, if you want to use cached statting.
    00445  * @param throttleRate A throttle rate for cstat. Only applicable if cstat is not NULL.
    00446  * @throws FileSystemException Unable to check because of a filesystem error.
    00447  * @throws TimeRetrievalException
    00448  * @throws boost::thread_interrupted
    00449  * @ingroup Support
    00450  */
    00451 bool verifyWSGIDir(const string &dir, CachedFileStat *cstat = 0,
    00452                    unsigned int throttleRate = 0);
    00453
    00454 void prestartWebApps(const ResourceLocator &locator, const string &serializedprestartURLs);
    00455
    00456 /**
    00457  * Returns the system's host name.
    00458  *
    00459  * @throws SystemException The host name cannot be retrieved.
    00460  */
    00461 string getHostName();
    00462
    00463 /**
    00464  * Given a prefix string, a middle string and a postfix string, try to build a string
    00465  * that looks like <tt>prefix + middle + postfix</tt>, with as many characters from
    00466  * <tt>midle</tt> preserved as possible.
    00467  *
    00468  * If <tt>prefix + middle + postfix</tt> does not fit in <tt>max</tt> characters,
    00469  * then <tt>middle</tt> will be truncated so that it fits. If <tt>max</tt> is too
    00470  * small to contain even 1 character from <tt>middle</tt>, then an ArgumentException
    00471  * will be thrown.
    00472  *
    00473  * @code
    00474  *   fillInMiddle(18, "server.", "1234", ".socket");    // "server.1234.socket"
    00475  *   fillInMiddle(16, "server.", "1234", ".socket");    // "server.12.socket"
    00476  *   fillInMiddle(14, "server.", "1234", ".socket");    // ArgumentException
    00477  * @endcode
    00478  *
    00479  * @returns The resulting string, with <tt>middle</tt> possibly truncated.
    00480  * @throws ArgumentException <tt>max</tt> is too small to contain even 1
    00481  *         character from <tt>middle</tt>.
    00482  * @post result.size() <= max
    00483  */
    00484 string fillInMiddle(unsigned int max, const string &prefix, const string &middle, const string &postfix = "");
    00485
    00486 /**
    00487  * Convert the given binary data to hexadecimal.
    00488  */
    00489 string toHex(const StaticString &data);
    00490
    00491 /**
    00492  * Convert the given binary data to hexadecimal. This form accepts an
    00493  * output buffer which must be at least data.size() * 2 bytes large.
    00494  */
    00495 void toHex(const StaticString &data, char *output);
    00496
    00497 /**
    00498  * Convert a signal number to its associated name.
    00499  */
    00500 string getSignalName(int sig);
    00501
    00502 /**
    00503  * Create a new Unix server socket which is bounded to <tt>filename</tt>.
    00504  *
    00505  * @param filename The filename to bind the socket to.
    00506  * @param backlogSize The size of the socket's backlog. Specify 0 to use the
    00507  *                    platform's maximum allowed backlog size.
    00508  * @param autoDelete Whether <tt>filename</tt> should be deleted, if it already exists.
    00509  * @return The file descriptor of the newly created Unix server socket.
    00510  * @throws RuntimeException Something went wrong.
    00511  * @throws SystemException Something went wrong while creating the Unix server socket.
    00512  * @throws boost::thread_interrupted A system call has been interrupted.
    00513  * @ingroup Support
    00514  */
    00515 int createUnixServer(const char *filename, unsigned int backlogSize = 0, bool autoDelete = true);
    00516
    00517 /**
    00518  * Connect to a Unix server socket at <tt>filename</tt>.
    00519  *
    00520  * @param filename The filename of the socket to connect to.
    00521  * @return The file descriptor of the connected client socket.
    00522  * @throws RuntimeException Something went wrong.
    00523  * @throws SystemException Something went wrong while connecting to the Unix server.
    00524  * @throws boost::thread_interrupted A system call has been interrupted.
    00525  * @ingroup Support
    00526  */
    00527 int connectToUnixServer(const char *filename);
    00528
    00529 /**
    00530  * Connect to a TCP server socket at the given host name and port.
    00531  *
    00532  * @param hostname The host name of the TCP server.
    00533  * @param port The port number of the TCP server.
    00534  * @return The file descriptor of the connected client socket.
    00535  * @throws IOException Something went wrong while connecting to the Unix server.
    00536  * @throws SystemException Something went wrong while connecting to the Unix server.
    00537  * @throws boost::thread_interrupted A system call has been interrupted.
    00538  * @ingroup Support
    00539  */
    00540 int connectToTcpServer(const char *hostname, unsigned int port);
    00541
    00542
    00543
    00544 /**
    00545  * Represents a buffered upload file.
    00546  *
    00547  * @ingroup Support
    00548  */
    00549 class BufferedUpload {
    00550 public:
    00551         /** The file handle. */
    00552         FILE *handle;
    00553
    00554         /**
    00555          * Create an empty upload bufer file, and open it for reading and writing.
    00556          *
    00557          * @throws SystemException Something went wrong.
    00558          */
    00559         BufferedUpload(const string &dir, const char *identifier = "temp") {
    00560                 char templ[PATH_MAX];
    00561                 int fd;
    00562
    00563                 snprintf(templ, sizeof(templ), "%s/%s.XXXXXX", dir.c_str(), identifier);
    00564                 templ[sizeof(templ) - 1] = '\0';
    00565                 fd = mkstemp(templ);
    00566                 if (fd == -1) {
    00567                         char message[1024];
    00568                         int e = errno;
    00569
    00570                         snprintf(message, sizeof(message), "Cannot create a temporary file '%s'", templ);
    00571                         message[sizeof(message) - 1] = '\0';
    00572                         throw SystemException(message, e);
    00573                 }
    00574
    00575                 /* We use a POSIX trick here: the file's permissions are set to "u=,g=,o="
    00576                  * and the file is deleted immediately from the filesystem, while we
    00577                  * keep its file handle open. The result is that no other processes
    00578                  * will be able to access this file's contents anymore, except us.
    00579                  * We now have an anonymous disk-backed buffer.
    00580                  */
    00581                 fchmod(fd, 0000);
    00582                 unlink(templ);
    00583
    00584                 handle = fdopen(fd, "w+");
    00585         }
    00586
    00587         ~BufferedUpload() {
    00588                 fclose(handle);
    00589         }
    00590 };
    00591
    00592 /**
    00593  * Fills the given memory space or string with zeroes when a MemoryZeroGuard object
    00594  * is destroyed. Useful for ensuring that buffers containing password data or
    00595  * other sensitive information is cleared when it goes out of scope.
    00596  */
    00597 class MemZeroGuard {
    00598 private:
    00599         void *data;
    00600         unsigned int size;
    00601         string *str;
    00602
    00603         static void securelyZeroMemory(volatile void *data, unsigned int size) {
    00604                 /* We do not use memset() here because the compiler may
    00605                  * optimize out memset() calls. Instead, the following
    00606                  * code is guaranteed to zero the memory.
    00607                  * http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html
    00608                  */
    00609                 volatile char *p = (volatile char *) data;
    00610                 while (size--) {
    00611                         *p++ = 0;
    00612                 }
    00613         }
    00614
    00615 public:
    00616         /**
    00617          * Creates a new MemZeroGuard object with a memory region to zero.
    00618          *
    00619          * @param data The data to zero after destruction.
    00620          * @param size The size of the data.
    00621          * @pre data != NULL
    00622          */
    00623         MemZeroGuard(void *data, unsigned int size) {
    00624                 this->data = data;
    00625                 this->size = size;
    00626                 this->str  = NULL;
    00627         }
    00628
    00629         /**
    00630          * Creates a new MemoryZeroGuard object with a string to zero.
    00631          *
    00632          * @param str The string to zero after destruction.
    00633          */
    00634         MemZeroGuard(string &str) {
    00635                 this->data = NULL;
    00636                 this->size = NULL;
    00637                 this->str  = &str;
    00638         }
    00639
    00640         /**
    00641          * Zero the data immediately. The data will still be zeroed after
    00642          * destruction of this object.
    00643          */
    00644         void zeroNow() {
    00645                 if (str == NULL) {
    00646                         securelyZeroMemory(data, size);
    00647                 } else {
    00648                         securelyZeroMemory((volatile void *) str->c_str(), str->size());
    00649                 }
    00650         }
    00651
    00652         ~MemZeroGuard() {
    00653                 zeroNow();
    00654         }
    00655 };
    00656
    00657 } // namespace Passenger
    00658
    00659 #endif /* _PASSENGER_UTILS_H_ */
    00660