File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / main / safe_mode.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:48:05 2012 UTC (12 years, 4 months ago) by misho
Branches: php, MAIN
CVS tags: v5_3_10, HEAD
php

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2012 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Author: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                        |
   16:    +----------------------------------------------------------------------+
   17:  */
   18: 
   19: /* $Id: safe_mode.c,v 1.1.1.1 2012/02/21 23:48:05 misho Exp $ */
   20: 
   21: #include "php.h"
   22: 
   23: #include <stdio.h>
   24: #include <stdlib.h>
   25: 
   26: #if HAVE_UNISTD_H
   27: #include <unistd.h>
   28: #endif
   29: #include <sys/stat.h>
   30: #include "ext/standard/pageinfo.h"
   31: #include "safe_mode.h"
   32: #include "SAPI.h"
   33: #include "php_globals.h"
   34: 
   35: /*
   36:  * php_checkuid
   37:  *
   38:  * This function has six modes:
   39:  * 
   40:  * 0 - return invalid (0) if file does not exist
   41:  * 1 - return valid (1)  if file does not exist
   42:  * 2 - if file does not exist, check directory
   43:  * 3 - only check directory (needed for mkdir)
   44:  * 4 - check mode and param
   45:  * 5 - only check file
   46:  */
   47: 
   48: PHPAPI int php_checkuid_ex(const char *filename, const char *fopen_mode, int mode, int flags)
   49: {
   50: 	struct stat sb;
   51: 	int ret, nofile=0;
   52: 	long uid=0L, gid=0L, duid=0L, dgid=0L;
   53: 	char path[MAXPATHLEN];
   54: 	char *s, filenamecopy[MAXPATHLEN];
   55: 	TSRMLS_FETCH();
   56: 
   57: 	path[0] = '\0';
   58: 
   59: 	if (!filename) {
   60: 		return 0; /* path must be provided */
   61: 	}
   62: 
   63: 	if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) {
   64: 		return 0;
   65: 	}
   66: 	filename=(char *)&filenamecopy;
   67: 
   68: 	if (fopen_mode) {
   69: 		if (fopen_mode[0] == 'r') {
   70: 			mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
   71: 		} else {
   72: 			mode = CHECKUID_CHECK_FILE_AND_DIR;
   73: 		}
   74: 	}
   75: 		
   76: 	/* First we see if the file is owned by the same user...
   77: 	 * If that fails, passthrough and check directory...
   78: 	 */
   79: 	if (mode != CHECKUID_ALLOW_ONLY_DIR) {
   80: #if HAVE_BROKEN_GETCWD
   81: 		char ftest[MAXPATHLEN];
   82: 
   83: 		strcpy(ftest, filename);
   84: 		if (VCWD_GETCWD(ftest, sizeof(ftest)) == NULL) {
   85: 			strcpy(path, filename);
   86: 		} else
   87: #endif
   88: 		expand_filepath(filename, path TSRMLS_CC);
   89: 
   90: 		ret = VCWD_STAT(path, &sb);
   91: 		if (ret < 0) {
   92: 			if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) {
   93: 				if ((flags & CHECKUID_NO_ERRORS) == 0) {
   94: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
   95: 				}
   96: 				return 0;
   97: 			} else if (mode == CHECKUID_ALLOW_FILE_NOT_EXISTS) {
   98: 				if ((flags & CHECKUID_NO_ERRORS) == 0) {
   99: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
  100: 				}
  101: 				return 1;
  102: 			} 
  103: 			nofile = 1;
  104: 		} else {
  105: 			uid = sb.st_uid;
  106: 			gid = sb.st_gid;
  107: 			if (uid == php_getuid()) {
  108: 				return 1;
  109:  			} else if (PG(safe_mode_gid) && gid == php_getgid()) {
  110:  				return 1;
  111: 			}
  112: 		}
  113: 
  114: 		/* Trim off filename */
  115: 		if ((s = strrchr(path, DEFAULT_SLASH))) {
  116: 			if (*(s + 1) == '\0' && s != path) { /* make sure that the / is not the last character */
  117: 				*s = '\0';
  118: 				s = strrchr(path, DEFAULT_SLASH);
  119: 			}
  120: 			if (s) {
  121: 				if (s == path) {
  122: 					path[1] = '\0';
  123: 				} else {
  124: 					*s = '\0';
  125: 				}
  126: 			}
  127: 		}
  128: 	} else { /* CHECKUID_ALLOW_ONLY_DIR */
  129: 		s = strrchr(filename, DEFAULT_SLASH);
  130: 
  131: 		if (s == filename) {
  132: 			/* root dir */
  133: 			path[0] = DEFAULT_SLASH;
  134: 			path[1] = '\0';
  135: 		} else if (s && *(s + 1) != '\0') { /* make sure that the / is not the last character */
  136: 			*s = '\0';
  137: 			VCWD_REALPATH(filename, path);
  138: 			*s = DEFAULT_SLASH;
  139: 		} else {
  140: 			/* Under Solaris, getcwd() can fail if there are no
  141: 			 * read permissions on a component of the path, even
  142: 			 * though it has the required x permissions */
  143: 			path[0] = '.';
  144: 			path[1] = '\0';
  145: 			VCWD_GETCWD(path, sizeof(path));
  146:  		}
  147: 	} /* end CHECKUID_ALLOW_ONLY_DIR */
  148: 	
  149: 	if (mode != CHECKUID_ALLOW_ONLY_FILE) {
  150: 		/* check directory */
  151: 		ret = VCWD_STAT(path, &sb);
  152: 		if (ret < 0) {
  153: 			if ((flags & CHECKUID_NO_ERRORS) == 0) {
  154: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
  155: 			}
  156: 			return 0;
  157: 		}
  158: 		duid = sb.st_uid;
  159: 		dgid = sb.st_gid;
  160: 		if (duid == php_getuid()) {
  161: 			return 1;
  162:  		} else if (PG(safe_mode_gid) && dgid == php_getgid()) {
  163:  			return 1;
  164: 		} else {
  165: 			if (SG(rfc1867_uploaded_files)) {
  166: 				if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
  167: 					return 1;
  168: 				}
  169: 			}
  170: 		}
  171: 	}
  172: 
  173: 	if (mode == CHECKUID_ALLOW_ONLY_DIR) {
  174: 		uid = duid;
  175: 		gid = dgid;
  176: 		if (s) {
  177: 			*s = 0;
  178: 		}
  179: 	}
  180: 	
  181: 	if (nofile) {
  182: 		uid = duid;
  183: 		gid = dgid;
  184: 		filename = path;
  185: 	}
  186: 
  187: 	if ((flags & CHECKUID_NO_ERRORS) == 0) {
  188: 		if (PG(safe_mode_gid)) {
  189: 			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);
  190: 		} else {
  191: 			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);
  192: 		}			
  193: 	}
  194: 
  195: 	return 0;
  196: }
  197: 
  198: PHPAPI int php_checkuid(const char *filename, const char *fopen_mode, int mode)
  199: {
  200: #ifdef NETWARE
  201: /* NetWare don't have uid*/
  202: 	return 1;
  203: #else
  204: 	return php_checkuid_ex(filename, fopen_mode, mode, 0);
  205: #endif
  206: }
  207: 
  208: PHPAPI char *php_get_current_user(void)
  209: {
  210: 	struct stat *pstat;
  211: 	TSRMLS_FETCH();
  212: 
  213: 	if (SG(request_info).current_user) {
  214: 		return SG(request_info).current_user;
  215: 	}
  216: 
  217: 	/* FIXME: I need to have this somehow handled if
  218: 	USE_SAPI is defined, because cgi will also be
  219: 	interfaced in USE_SAPI */
  220: 
  221: 	pstat = sapi_get_stat(TSRMLS_C);
  222: 
  223: 	if (!pstat) {
  224: 		return "";
  225: 	} else {
  226: #ifdef PHP_WIN32
  227: 		char name[256];
  228: 		DWORD len = sizeof(name)-1;
  229: 
  230: 		if (!GetUserName(name, &len)) {
  231: 			return "";
  232: 		}
  233: 		name[len] = '\0';
  234: 		SG(request_info).current_user_length = len;
  235: 		SG(request_info).current_user = estrndup(name, len);
  236: 		return SG(request_info).current_user;		
  237: #else
  238: 		struct passwd *pwd;
  239: #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
  240: 		struct passwd _pw;
  241: 		struct passwd *retpwptr = NULL;
  242: 		int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
  243: 		char *pwbuf;
  244: 
  245: 		if (pwbuflen < 1) {
  246: 			return "";
  247: 		}
  248: 		pwbuf = emalloc(pwbuflen);
  249: 		if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
  250: 			efree(pwbuf);
  251: 			return "";
  252: 		}
  253: 		pwd = &_pw;
  254: #else
  255: 		if ((pwd=getpwuid(pstat->st_uid))==NULL) {
  256: 			return "";
  257: 		}
  258: #endif
  259: 		SG(request_info).current_user_length = strlen(pwd->pw_name);
  260: 		SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
  261: #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
  262: 		efree(pwbuf);
  263: #endif
  264: 		return SG(request_info).current_user;		
  265: #endif
  266: 	}	
  267: }	
  268: 
  269: /*
  270:  * Local variables:
  271:  * tab-width: 4
  272:  * c-basic-offset: 4
  273:  * End:
  274:  * vim600: sw=4 ts=4 fdm=marker
  275:  * vim<600: sw=4 ts=4
  276:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>