}
convert_to_string_ex(arg);
- if (PG(safe_mode) && !php_checkuid((*arg)->value.str.val, NULL, CHECKUID_ALLOW_ONLY_DIR)) {
+ if (PG(safe_mode) && !php_checkuid((*arg)->value.str.val, NULL, CHECKUID_ALLOW_ONLY_FILE)) {
RETURN_FALSE;
}
ret = VCWD_CHDIR((*arg)->value.str.val);
PHPAPI FILE *php_fopen_with_path(char *filename, char *mode, char *path, char **opened_path)
{
char *pathbuf, *ptr, *end;
+ char *exec_fname;
char trypath[MAXPATHLEN];
+ char trydir[MAXPATHLEN];
+ char safe_mode_include_dir[MAXPATHLEN];
struct stat sb;
FILE *fp;
+ int path_length;
int filename_length;
+ int safe_mode_include_dir_length;
+ int exec_fname_length;
PLS_FETCH();
+ ELS_FETCH();
if (opened_path) {
*opened_path = NULL;
}
+
+ if(!filename) {
+ return NULL;
+ }
filename_length = strlen(filename);
-
- /* Absolute & relative path open */
- if ((*filename == '.') || (IS_ABSOLUTE_PATH(filename, filename_length))) {
+
+ /* Relative path open */
+ if (*filename == '.') {
+ if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
+ return NULL;
+ }
+ return php_fopen_and_set_opened_path(filename, mode, opened_path);
+ }
+
+ /*
+ * files in safe_mode_include_dir (or subdir) are excluded from
+ * safe mode GID/UID checks
+ */
+ *safe_mode_include_dir = 0;
+ safe_mode_include_dir_length = 0;
+ if(PG(safe_mode_include_dir) && VCWD_REALPATH(PG(safe_mode_include_dir), safe_mode_include_dir)) {
+ safe_mode_include_dir_length = strlen(safe_mode_include_dir);
+ }
+
+ /* Absolute path open */
+ if (IS_ABSOLUTE_PATH(filename, filename_length)) {
+ /* Check to see if file is in safe_mode_include_dir (or subdir) */
+ if (PG(safe_mode) && *safe_mode_include_dir && VCWD_REALPATH(filename, trypath)) {
+#ifdef PHP_WIN32
+ if (strncasecmp(safe_mode_include_dir, trypath, safe_mode_include_dir_length) == 0)
+#else
+ if (strncmp(safe_mode_include_dir, trypath, safe_mode_include_dir_length) == 0)
+#endif
+ {
+ /* absolute path matches safe_mode_include_dir */
+ fp = php_fopen_and_set_opened_path(trypath, mode, opened_path);
+ if (fp) {
+ return fp;
+ }
+ }
+ }
if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
return NULL;
}
}
return php_fopen_and_set_opened_path(filename, mode, opened_path);
}
- pathbuf = estrdup(path);
+
+ /* check in provided path */
+ /* append the calling scripts' current working directory
+ * as a fall back case
+ */
+ exec_fname = zend_get_executed_filename(ELS_C);
+ exec_fname_length = strlen(exec_fname);
+ path_length = strlen(path);
+
+ while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])) {
+ }
+ if (exec_fname && exec_fname[0] == '[') {
+ /* [no active file] */
+ exec_fname_length = 0;
+ }
+
+ pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1);
+ memcpy(pathbuf, path, path_length);
+#ifdef PHP_WIN32
+ pathbuf[path_length] = ';';
+#else
+ pathbuf[path_length] = ':';
+#endif
+ memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length);
+ pathbuf[path_length + exec_fname_length +1] = '\0';
ptr = pathbuf;
end++;
}
snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename);
+ /* Check to see trypath is in safe_mode_include_dir (or subdir) */
+ if (PG(safe_mode) && *safe_mode_include_dir && VCWD_REALPATH(trypath, trydir)) {
+#ifdef PHP_WIN32
+ if (strncasecmp(safe_mode_include_dir, trydir, safe_mode_include_dir_length) == 0)
+#else
+ if (strncmp(safe_mode_include_dir, trydir, safe_mode_include_dir_length) == 0)
+#endif
+ {
+ /* trypath is in safe_mode_include_dir */
+ fp = php_fopen_and_set_opened_path(trydir, mode, opened_path);
+ if (fp) {
+ efree(pathbuf);
+ return fp;
+ }
+ }
+ }
if (PG(safe_mode)) {
if (VCWD_STAT(trypath, &sb) == 0 && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) {
efree(pathbuf);
return fp;
}
ptr = end;
- }
+ } /* end provided path */
efree(pathbuf);
-
- {
- char *exec_fname;
- int exec_fname_len;
- ELS_FETCH();
-
- exec_fname = zend_get_executed_filename(ELS_C);
- exec_fname_len = strlen(exec_fname);
-
- pathbuf = (char *) emalloc(exec_fname_len+filename_length+1+1); /* Over allocate to save time */
- memcpy(pathbuf, exec_fname, exec_fname_len+1);
-
- while ((--exec_fname_len >= 0) && !IS_SLASH(pathbuf[exec_fname_len])) {
- }
- pathbuf[exec_fname_len] = DEFAULT_SLASH;
- memcpy(&pathbuf[exec_fname_len+1], filename, filename_length+1);
-
- if (PG(safe_mode)) {
- if (VCWD_STAT(pathbuf, &sb) == 0 && (!php_checkuid(pathbuf, mode, CHECKUID_CHECK_MODE_PARAM))) {
- efree(pathbuf);
- return NULL;
- }
- }
- fp = php_fopen_and_set_opened_path(pathbuf, mode, opened_path);
- efree(pathbuf);
- return fp;
- }
- return NULL; /* Not really needed anymore */
+ return NULL;
}
/* }}} */
STD_PHP_INI_BOOLEAN("register_argc_argv", "1", PHP_INI_ALL, OnUpdateBool, register_argc_argv, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("register_globals", "1", PHP_INI_ALL, OnUpdateBool, register_globals, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("safe_mode_include_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, safe_mode_include_dir, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("safe_mode_gid", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode_gid, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("short_open_tag",DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals)
STD_PHP_INI_BOOLEAN("sql.safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, sql_safe_mode, php_core_globals, core_globals)
zend_bool implicit_flush;
zend_bool safe_mode;
+ char *safe_mode_include_dir;
zend_bool safe_mode_gid;
zend_bool sql_safe_mode;
zend_bool enable_dl;
struct stat sb;
int ret;
long uid=0L, gid=0L, duid=0L, dgid=0L;
+ char path[MAXPATHLEN];
char *s;
PLS_FETCH();
return 1;
}
+ /* First we see if the file is owned by the same user...
+ * If that fails, passthrough and check directory...
+ */
if (mode != CHECKUID_ALLOW_ONLY_DIR) {
- ret = VCWD_STAT(filename, &sb);
+ VCWD_REALPATH(filename, path);
+ ret = VCWD_STAT(path, &sb);
if (ret < 0) {
if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) {
php_error(E_WARNING, "Unable to access %s", filename);
}
} else {
uid = sb.st_uid;
+ gid = sb.st_gid;
if (uid == php_getuid()) {
return 1;
+ } else if (PG(safe_mode_gid) && gid == php_getgid()) {
+ return 1;
}
}
- }
- s = strrchr(filename,'/');
- /* This loop gets rid of trailing slashes which could otherwise be
- * used to confuse the function.
- */
- while(s && *(s+1)=='\0' && s>filename) {
- *s='\0';
- s = strrchr(filename,'/');
- }
+ /* Trim off filename */
+ if (s = strrchr(path,DEFAULT_SLASH)) {
+ *s = '\0';
+ }
+ } else { /* CHECKUID_ALLOW_ONLY_DIR */
+ s = strrchr(filename,DEFAULT_SLASH);
- if (s) {
- *s='\0';
- ret = VCWD_STAT(filename, &sb);
- *s='/';
+ if (s) {
+ *s = '\0';
+ VCWD_REALPATH(filename, path);
+ *s = DEFAULT_SLASH;
+ } else {
+ VCWD_GETCWD(path, MAXPATHLEN);
+ }
+ } /* end CHECKUID_ALLOW_ONLY_DIR */
+
+ if (mode != CHECKUID_ALLOW_ONLY_FILE) {
+ /* check directory */
+ ret = VCWD_STAT(path, &sb);
if (ret < 0) {
php_error(E_WARNING, "Unable to access %s", filename);
return 0;
}
duid = sb.st_uid;
- } else {
- char cwd[MAXPATHLEN];
- if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
- php_error(E_WARNING, "Unable to access current working directory");
- return 0;
- }
- ret = VCWD_STAT(cwd, &sb);
- if (ret < 0) {
- php_error(E_WARNING, "Unable to access %s", cwd);
- return 0;
- }
- duid = sb.st_uid;
- }
- if (duid == (uid=php_getuid())) {
- return 1;
- } else if (PG(safe_mode_gid) && dgid == (gid=php_getgid())) {
- return 1;
- } else {
- SLS_FETCH();
+ dgid = sb.st_gid;
+ if (duid == php_getuid()) {
+ return 1;
+ } else if (PG(safe_mode_gid) && dgid == php_getgid()) {
+ return 1;
+ } else {
+ SLS_FETCH();
- if (SG(rfc1867_uploaded_files)) {
- if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
- return 1;
+ if (SG(rfc1867_uploaded_files)) {
+ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
+ return 1;
+ }
}
}
+ }
- if (PG(safe_mode_gid)) {
- php_error(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", uid, gid, filename, duid, dgid);
- } else {
- php_error(E_WARNING, "SAFE MODE Restriction in effect. The script whose uid is %ld is not allowed to access %s owned by uid %ld", uid, filename, duid);
- }
- return 0;
+ if (mode == CHECKUID_ALLOW_ONLY_DIR) {
+ uid = duid;
+ gid = dgid;
+ if (s) {
+ *s = 0;
+ }
}
+ if (PG(safe_mode_gid)) {
+ php_error(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);
+ } else {
+ php_error(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);
+ }
+ return 0;
}
#define CHECKUID_CHECK_FILE_AND_DIR 2
#define CHECKUID_ALLOW_ONLY_DIR 3
#define CHECKUID_CHECK_MODE_PARAM 4
+#define CHECKUID_ALLOW_ONLY_FILE 5
extern PHPAPI int php_checkuid(const char *filename, char *fopen_mode, int mode);
extern PHPAPI char *php_get_current_user(void);
; then turn on safe_mode_gid.
safe_mode_gid = Off
+; When safe_mode is on, UID/GID checks are bypassed when
+; including files from this directory and its subdirectories.
+; (directory must also be in include_path or full path must
+; be used when including)
+safe_mode_include_dir =
+
; When safe_mode is on, only executables located in the safe_mode_exec_dir
; will be allowed to be executed via the exec family of functions.
safe_mode_exec_dir =
safe_mode_gid = Off ; By default, Safe Mode does a UID compare
; check when opening files. If you want to
; relax this to a GID compare, then turn on
- ; safe_mode_gid.
+ ; safe_mode_gid. (safe_mode must be On)
+safe_mode_include_dir = ; When safe_mode is on, UID/GID checks are
+ ; bypassed when including files from this
+ ; directory and its subdirectories. (directory
+ ; must also be in include_path or full path
+ ; must be used when including)
safe_mode_exec_dir =
safe_mode_allowed_env_vars = PHP_ ; Setting certain environment variables
; may be a potential security breach.
; Local Variables:
; tab-width: 4
-; End:
\ No newline at end of file
+; End:
safe_mode_gid = Off ; By default, Safe Mode does a UID compare
; check when opening files. If you want to
; relax this to a GID compare, then turn on
- ; safe_mode_gid.
+ ; safe_mode_gid. (safe_mode must be On)
+safe_mode_include_dir = ; When safe_mode is on, UID/GID checks are
+ ; bypassed when including files from this
+ ; directory and its subdirectories. (directory
+ ; must also be in include_path or full path
+ ; must be used when including)
safe_mode_exec_dir =
safe_mode_allowed_env_vars = PHP_ ; Setting certain environment variables
; may be a potential security breach.
; Local Variables:
; tab-width: 4
-; End:
\ No newline at end of file
+; End: