1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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$ */
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
php_checkuid_ex(const char * filename,const char * fopen_mode,int mode,int flags)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
php_checkuid(const char * filename,const char * fopen_mode,int mode)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
php_get_current_user(void)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 */
277