Back to index

php5  5.3.10
safe_mode.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                        |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: safe_mode.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 
00026 #if HAVE_UNISTD_H
00027 #include <unistd.h>
00028 #endif
00029 #include <sys/stat.h>
00030 #include "ext/standard/pageinfo.h"
00031 #include "safe_mode.h"
00032 #include "SAPI.h"
00033 #include "php_globals.h"
00034 
00035 /*
00036  * php_checkuid
00037  *
00038  * This function has six modes:
00039  * 
00040  * 0 - return invalid (0) if file does not exist
00041  * 1 - return valid (1)  if file does not exist
00042  * 2 - if file does not exist, check directory
00043  * 3 - only check directory (needed for mkdir)
00044  * 4 - check mode and param
00045  * 5 - only check file
00046  */
00047 
00048 PHPAPI int php_checkuid_ex(const char *filename, const char *fopen_mode, int mode, int flags)
00049 {
00050        struct stat sb;
00051        int ret, nofile=0;
00052        long uid=0L, gid=0L, duid=0L, dgid=0L;
00053        char path[MAXPATHLEN];
00054        char *s, filenamecopy[MAXPATHLEN];
00055        TSRMLS_FETCH();
00056 
00057        path[0] = '\0';
00058 
00059        if (!filename) {
00060               return 0; /* path must be provided */
00061        }
00062 
00063        if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) {
00064               return 0;
00065        }
00066        filename=(char *)&filenamecopy;
00067 
00068        if (fopen_mode) {
00069               if (fopen_mode[0] == 'r') {
00070                      mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
00071               } else {
00072                      mode = CHECKUID_CHECK_FILE_AND_DIR;
00073               }
00074        }
00075               
00076        /* First we see if the file is owned by the same user...
00077         * If that fails, passthrough and check directory...
00078         */
00079        if (mode != CHECKUID_ALLOW_ONLY_DIR) {
00080 #if HAVE_BROKEN_GETCWD
00081               char ftest[MAXPATHLEN];
00082 
00083               strcpy(ftest, filename);
00084               if (VCWD_GETCWD(ftest, sizeof(ftest)) == NULL) {
00085                      strcpy(path, filename);
00086               } else
00087 #endif
00088               expand_filepath(filename, path TSRMLS_CC);
00089 
00090               ret = VCWD_STAT(path, &sb);
00091               if (ret < 0) {
00092                      if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) {
00093                             if ((flags & CHECKUID_NO_ERRORS) == 0) {
00094                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
00095                             }
00096                             return 0;
00097                      } else if (mode == CHECKUID_ALLOW_FILE_NOT_EXISTS) {
00098                             if ((flags & CHECKUID_NO_ERRORS) == 0) {
00099                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
00100                             }
00101                             return 1;
00102                      } 
00103                      nofile = 1;
00104               } else {
00105                      uid = sb.st_uid;
00106                      gid = sb.st_gid;
00107                      if (uid == php_getuid()) {
00108                             return 1;
00109                      } else if (PG(safe_mode_gid) && gid == php_getgid()) {
00110                             return 1;
00111                      }
00112               }
00113 
00114               /* Trim off filename */
00115               if ((s = strrchr(path, DEFAULT_SLASH))) {
00116                      if (*(s + 1) == '\0' && s != path) { /* make sure that the / is not the last character */
00117                             *s = '\0';
00118                             s = strrchr(path, DEFAULT_SLASH);
00119                      }
00120                      if (s) {
00121                             if (s == path) {
00122                                    path[1] = '\0';
00123                             } else {
00124                                    *s = '\0';
00125                             }
00126                      }
00127               }
00128        } else { /* CHECKUID_ALLOW_ONLY_DIR */
00129               s = strrchr(filename, DEFAULT_SLASH);
00130 
00131               if (s == filename) {
00132                      /* root dir */
00133                      path[0] = DEFAULT_SLASH;
00134                      path[1] = '\0';
00135               } else if (s && *(s + 1) != '\0') { /* make sure that the / is not the last character */
00136                      *s = '\0';
00137                      VCWD_REALPATH(filename, path);
00138                      *s = DEFAULT_SLASH;
00139               } else {
00140                      /* Under Solaris, getcwd() can fail if there are no
00141                       * read permissions on a component of the path, even
00142                       * though it has the required x permissions */
00143                      path[0] = '.';
00144                      path[1] = '\0';
00145                      VCWD_GETCWD(path, sizeof(path));
00146               }
00147        } /* end CHECKUID_ALLOW_ONLY_DIR */
00148        
00149        if (mode != CHECKUID_ALLOW_ONLY_FILE) {
00150               /* check directory */
00151               ret = VCWD_STAT(path, &sb);
00152               if (ret < 0) {
00153                      if ((flags & CHECKUID_NO_ERRORS) == 0) {
00154                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
00155                      }
00156                      return 0;
00157               }
00158               duid = sb.st_uid;
00159               dgid = sb.st_gid;
00160               if (duid == php_getuid()) {
00161                      return 1;
00162               } else if (PG(safe_mode_gid) && dgid == php_getgid()) {
00163                      return 1;
00164               } else {
00165                      if (SG(rfc1867_uploaded_files)) {
00166                             if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
00167                                    return 1;
00168                             }
00169                      }
00170               }
00171        }
00172 
00173        if (mode == CHECKUID_ALLOW_ONLY_DIR) {
00174               uid = duid;
00175               gid = dgid;
00176               if (s) {
00177                      *s = 0;
00178               }
00179        }
00180        
00181        if (nofile) {
00182               uid = duid;
00183               gid = dgid;
00184               filename = path;
00185        }
00186 
00187        if ((flags & CHECKUID_NO_ERRORS) == 0) {
00188               if (PG(safe_mode_gid)) {
00189                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect.  The script whose uid/gid is %ld/%ld is not allowed to access %s owned by uid/gid %ld/%ld", php_getuid(), php_getgid(), filename, uid, gid);
00190               } else {
00191                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect.  The script whose uid is %ld is not allowed to access %s owned by uid %ld", php_getuid(), filename, uid);
00192               }                    
00193        }
00194 
00195        return 0;
00196 }
00197 
00198 PHPAPI int php_checkuid(const char *filename, const char *fopen_mode, int mode)
00199 {
00200 #ifdef NETWARE
00201 /* NetWare don't have uid*/
00202        return 1;
00203 #else
00204        return php_checkuid_ex(filename, fopen_mode, mode, 0);
00205 #endif
00206 }
00207 
00208 PHPAPI char *php_get_current_user(void)
00209 {
00210        struct stat *pstat;
00211        TSRMLS_FETCH();
00212 
00213        if (SG(request_info).current_user) {
00214               return SG(request_info).current_user;
00215        }
00216 
00217        /* FIXME: I need to have this somehow handled if
00218        USE_SAPI is defined, because cgi will also be
00219        interfaced in USE_SAPI */
00220 
00221        pstat = sapi_get_stat(TSRMLS_C);
00222 
00223        if (!pstat) {
00224               return "";
00225        } else {
00226 #ifdef PHP_WIN32
00227               char name[256];
00228               DWORD len = sizeof(name)-1;
00229 
00230               if (!GetUserName(name, &len)) {
00231                      return "";
00232               }
00233               name[len] = '\0';
00234               SG(request_info).current_user_length = len;
00235               SG(request_info).current_user = estrndup(name, len);
00236               return SG(request_info).current_user;            
00237 #else
00238               struct passwd *pwd;
00239 #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
00240               struct passwd _pw;
00241               struct passwd *retpwptr = NULL;
00242               int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
00243               char *pwbuf;
00244 
00245               if (pwbuflen < 1) {
00246                      return "";
00247               }
00248               pwbuf = emalloc(pwbuflen);
00249               if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
00250                      efree(pwbuf);
00251                      return "";
00252               }
00253               pwd = &_pw;
00254 #else
00255               if ((pwd=getpwuid(pstat->st_uid))==NULL) {
00256                      return "";
00257               }
00258 #endif
00259               SG(request_info).current_user_length = strlen(pwd->pw_name);
00260               SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
00261 #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
00262               efree(pwbuf);
00263 #endif
00264               return SG(request_info).current_user;            
00265 #endif
00266        }      
00267 }      
00268 
00269 /*
00270  * Local variables:
00271  * tab-width: 4
00272  * c-basic-offset: 4
00273  * End:
00274  * vim600: sw=4 ts=4 fdm=marker
00275  * vim<600: sw=4 ts=4
00276  */