1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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 272374 2008-12-31 11:17:49Z sebastian $ */
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 22 : {
50 : struct stat sb;
51 22 : int ret, nofile=0;
52 22 : long uid=0L, gid=0L, duid=0L, dgid=0L;
53 : char path[MAXPATHLEN];
54 : char *s, filenamecopy[MAXPATHLEN];
55 : TSRMLS_FETCH();
56 :
57 22 : path[0] = '\0';
58 :
59 22 : if (!filename) {
60 0 : return 0; /* path must be provided */
61 : }
62 :
63 22 : if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) {
64 0 : return 0;
65 : }
66 22 : filename=(char *)&filenamecopy;
67 :
68 22 : if (fopen_mode) {
69 2 : if (fopen_mode[0] == 'r') {
70 0 : mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
71 : } else {
72 2 : 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 22 : 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 20 : expand_filepath(filename, path TSRMLS_CC);
89 :
90 20 : ret = VCWD_STAT(path, &sb);
91 20 : if (ret < 0) {
92 5 : if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) {
93 0 : if ((flags & CHECKUID_NO_ERRORS) == 0) {
94 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
95 : }
96 0 : return 0;
97 5 : } else if (mode == CHECKUID_ALLOW_FILE_NOT_EXISTS) {
98 0 : if ((flags & CHECKUID_NO_ERRORS) == 0) {
99 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
100 : }
101 0 : return 1;
102 : }
103 5 : nofile = 1;
104 : } else {
105 15 : uid = sb.st_uid;
106 15 : gid = sb.st_gid;
107 15 : if (uid == php_getuid()) {
108 14 : return 1;
109 1 : } else if (PG(safe_mode_gid) && gid == php_getgid()) {
110 0 : return 1;
111 : }
112 : }
113 :
114 : /* Trim off filename */
115 6 : if ((s = strrchr(path, DEFAULT_SLASH))) {
116 6 : if (*(s + 1) == '\0' && s != path) { /* make sure that the / is not the last character */
117 0 : *s = '\0';
118 0 : s = strrchr(path, DEFAULT_SLASH);
119 : }
120 6 : if (s) {
121 6 : if (s == path) {
122 1 : path[1] = '\0';
123 : } else {
124 5 : *s = '\0';
125 : }
126 : }
127 : }
128 : } else { /* CHECKUID_ALLOW_ONLY_DIR */
129 2 : s = strrchr(filename, DEFAULT_SLASH);
130 :
131 2 : if (s == filename) {
132 : /* root dir */
133 0 : path[0] = DEFAULT_SLASH;
134 0 : path[1] = '\0';
135 4 : } else if (s && *(s + 1) != '\0') { /* make sure that the / is not the last character */
136 2 : *s = '\0';
137 2 : VCWD_REALPATH(filename, path);
138 2 : *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 0 : path[0] = '.';
144 0 : path[1] = '\0';
145 0 : VCWD_GETCWD(path, sizeof(path));
146 : }
147 : } /* end CHECKUID_ALLOW_ONLY_DIR */
148 :
149 8 : if (mode != CHECKUID_ALLOW_ONLY_FILE) {
150 : /* check directory */
151 8 : ret = VCWD_STAT(path, &sb);
152 8 : if (ret < 0) {
153 0 : if ((flags & CHECKUID_NO_ERRORS) == 0) {
154 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
155 : }
156 0 : return 0;
157 : }
158 8 : duid = sb.st_uid;
159 8 : dgid = sb.st_gid;
160 8 : if (duid == php_getuid()) {
161 6 : return 1;
162 2 : } else if (PG(safe_mode_gid) && dgid == php_getgid()) {
163 0 : return 1;
164 : } else {
165 2 : if (SG(rfc1867_uploaded_files)) {
166 0 : if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
167 0 : return 1;
168 : }
169 : }
170 : }
171 : }
172 :
173 2 : if (mode == CHECKUID_ALLOW_ONLY_DIR) {
174 1 : uid = duid;
175 1 : gid = dgid;
176 1 : if (s) {
177 1 : *s = 0;
178 : }
179 : }
180 :
181 2 : if (nofile) {
182 0 : uid = duid;
183 0 : gid = dgid;
184 0 : filename = path;
185 : }
186 :
187 2 : if ((flags & CHECKUID_NO_ERRORS) == 0) {
188 1 : if (PG(safe_mode_gid)) {
189 0 : 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 1 : 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 2 : return 0;
196 : }
197 :
198 : PHPAPI int php_checkuid(const char *filename, const char *fopen_mode, int mode)
199 10 : {
200 : #ifdef NETWARE
201 : /* NetWare don't have uid*/
202 : return 1;
203 : #else
204 10 : return php_checkuid_ex(filename, fopen_mode, mode, 0);
205 : #endif
206 : }
207 :
208 : PHPAPI char *php_get_current_user(void)
209 1 : {
210 : struct stat *pstat;
211 : TSRMLS_FETCH();
212 :
213 1 : if (SG(request_info).current_user) {
214 0 : 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 1 : pstat = sapi_get_stat(TSRMLS_C);
222 :
223 1 : if (!pstat) {
224 0 : 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 1 : if ((pwd=getpwuid(pstat->st_uid))==NULL) {
256 0 : return "";
257 : }
258 : #endif
259 1 : SG(request_info).current_user_length = strlen(pwd->pw_name);
260 1 : 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 1 : 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 : */
|