1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 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.62.2.1.2.8 2007/01/12 12:11:18 bjori 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 0 : {
50 : struct stat sb;
51 0 : int ret, nofile=0;
52 0 : long uid=0L, gid=0L, duid=0L, dgid=0L;
53 : char path[MAXPATHLEN];
54 : char *s, filenamecopy[MAXPATHLEN];
55 0 : php_stream_wrapper *wrapper = NULL;
56 : TSRMLS_FETCH();
57 :
58 0 : path[0] = '\0';
59 :
60 0 : if (!filename) {
61 0 : return 0; /* path must be provided */
62 : }
63 :
64 0 : if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) {
65 0 : return 0;
66 : }
67 0 : filename=(char *)&filenamecopy;
68 :
69 0 : if (fopen_mode) {
70 0 : if (fopen_mode[0] == 'r') {
71 0 : mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
72 : } else {
73 0 : mode = CHECKUID_CHECK_FILE_AND_DIR;
74 : }
75 : }
76 :
77 : /*
78 : * If given filepath is a URL, allow - safe mode stuff
79 : * related to URL's is checked in individual functions
80 : */
81 0 : wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC);
82 0 : if (wrapper != NULL)
83 0 : return 1;
84 :
85 : /* First we see if the file is owned by the same user...
86 : * If that fails, passthrough and check directory...
87 : */
88 0 : if (mode != CHECKUID_ALLOW_ONLY_DIR) {
89 0 : expand_filepath(filename, path TSRMLS_CC);
90 0 : ret = VCWD_STAT(path, &sb);
91 0 : if (ret < 0) {
92 0 : 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 0 : } 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 0 : nofile = 1;
104 : } else {
105 0 : uid = sb.st_uid;
106 0 : gid = sb.st_gid;
107 0 : if (uid == php_getuid()) {
108 0 : return 1;
109 0 : } else if (PG(safe_mode_gid) && gid == php_getgid()) {
110 0 : return 1;
111 : }
112 : }
113 :
114 : /* Trim off filename */
115 0 : if ((s = strrchr(path, DEFAULT_SLASH))) {
116 0 : if (s == path)
117 0 : path[1] = '\0';
118 : else
119 0 : *s = '\0';
120 : }
121 : } else { /* CHECKUID_ALLOW_ONLY_DIR */
122 0 : s = strrchr(filename, DEFAULT_SLASH);
123 :
124 0 : if (s == filename) {
125 : /* root dir */
126 0 : path[0] = DEFAULT_SLASH;
127 0 : path[1] = '\0';
128 0 : } else if (s) {
129 0 : *s = '\0';
130 0 : VCWD_REALPATH(filename, path);
131 0 : *s = DEFAULT_SLASH;
132 : } else {
133 : /* Under Solaris, getcwd() can fail if there are no
134 : * read permissions on a component of the path, even
135 : * though it has the required x permissions */
136 0 : path[0] = '.';
137 0 : path[1] = '\0';
138 0 : VCWD_GETCWD(path, sizeof(path));
139 : }
140 : } /* end CHECKUID_ALLOW_ONLY_DIR */
141 :
142 0 : if (mode != CHECKUID_ALLOW_ONLY_FILE) {
143 : /* check directory */
144 0 : ret = VCWD_STAT(path, &sb);
145 0 : if (ret < 0) {
146 0 : if ((flags & CHECKUID_NO_ERRORS) == 0) {
147 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
148 : }
149 0 : return 0;
150 : }
151 0 : duid = sb.st_uid;
152 0 : dgid = sb.st_gid;
153 0 : if (duid == php_getuid()) {
154 0 : return 1;
155 0 : } else if (PG(safe_mode_gid) && dgid == php_getgid()) {
156 0 : return 1;
157 : } else {
158 0 : if (SG(rfc1867_uploaded_files)) {
159 0 : if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
160 0 : return 1;
161 : }
162 : }
163 : }
164 : }
165 :
166 0 : if (mode == CHECKUID_ALLOW_ONLY_DIR) {
167 0 : uid = duid;
168 0 : gid = dgid;
169 0 : if (s) {
170 0 : *s = 0;
171 : }
172 : }
173 :
174 0 : if (nofile) {
175 0 : uid = duid;
176 0 : gid = dgid;
177 0 : filename = path;
178 : }
179 :
180 0 : if ((flags & CHECKUID_NO_ERRORS) == 0) {
181 0 : if (PG(safe_mode_gid)) {
182 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);
183 : } else {
184 0 : 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);
185 : }
186 : }
187 :
188 0 : return 0;
189 : }
190 :
191 0 : PHPAPI int php_checkuid(const char *filename, const char *fopen_mode, int mode) {
192 : #ifdef NETWARE
193 : /* NetWare don't have uid*/
194 : return 1;
195 : #else
196 0 : return php_checkuid_ex(filename, fopen_mode, mode, 0);
197 : #endif
198 : }
199 :
200 : PHPAPI char *php_get_current_user()
201 0 : {
202 : struct stat *pstat;
203 : TSRMLS_FETCH();
204 :
205 0 : if (SG(request_info).current_user) {
206 0 : return SG(request_info).current_user;
207 : }
208 :
209 : /* FIXME: I need to have this somehow handled if
210 : USE_SAPI is defined, because cgi will also be
211 : interfaced in USE_SAPI */
212 :
213 0 : pstat = sapi_get_stat(TSRMLS_C);
214 :
215 0 : if (!pstat) {
216 0 : return "";
217 : } else {
218 : #ifdef PHP_WIN32
219 : char name[256];
220 : DWORD len = sizeof(name)-1;
221 :
222 : if (!GetUserName(name, &len)) {
223 : return "";
224 : }
225 : name[len] = '\0';
226 : SG(request_info).current_user_length = len;
227 : SG(request_info).current_user = estrndup(name, len);
228 : return SG(request_info).current_user;
229 : #else
230 : struct passwd *pwd;
231 : #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
232 : struct passwd _pw;
233 : struct passwd *retpwptr = NULL;
234 : int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
235 : char *pwbuf;
236 :
237 : if (pwbuflen < 1) {
238 : return "";
239 : }
240 : pwbuf = emalloc(pwbuflen);
241 : if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
242 : efree(pwbuf);
243 : return "";
244 : }
245 : pwd = &_pw;
246 : #else
247 0 : if ((pwd=getpwuid(pstat->st_uid))==NULL) {
248 0 : return "";
249 : }
250 : #endif
251 0 : SG(request_info).current_user_length = strlen(pwd->pw_name);
252 0 : SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
253 : #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
254 : efree(pwbuf);
255 : #endif
256 0 : return SG(request_info).current_user;
257 : #endif
258 : }
259 : }
260 :
261 : /*
262 : * Local variables:
263 : * tab-width: 4
264 : * c-basic-offset: 4
265 : * End:
266 : * vim600: sw=4 ts=4 fdm=marker
267 : * vim<600: sw=4 ts=4
268 : */
|