Annotation of embedaddon/php/main/safe_mode.c, revision 1.1.1.1
1.1 misho 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 321634 2012-01-01 13:15:04Z felipe $ */
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>