--- embedaddon/php/main/streams/plain_wrapper.c 2012/02/21 23:48:05 1.1.1.1 +++ embedaddon/php/main/streams/plain_wrapper.c 2014/06/15 20:04:01 1.1.1.4 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: plain_wrapper.c,v 1.1.1.1 2012/02/21 23:48:05 misho Exp $ */ +/* $Id: plain_wrapper.c,v 1.1.1.4 2014/06/15 20:04:01 misho Exp $ */ #include "php.h" #include "php_globals.h" @@ -48,6 +48,11 @@ #define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC TSRMLS_CC) #define php_stream_fopen_from_file_int_rel(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC TSRMLS_CC) +#if !defined(WINDOWS) && !defined(NETWARE) +extern int php_get_uid_by_name(const char *name, uid_t *uid TSRMLS_DC); +extern int php_get_gid_by_name(const char *name, gid_t *gid TSRMLS_DC); +#endif + /* parse standard "fopen" modes into open() flags */ PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags) { @@ -73,11 +78,7 @@ PHPAPI int php_stream_parse_fopen_modes(const char *mo /* unknown mode */ return FAILURE; } -#if defined(O_NONBLOCK) - if (strchr(mode, 'n')) { - flags |= O_NONBLOCK; - } -#endif + if (strchr(mode, '+')) { flags |= O_RDWR; } else if (flags) { @@ -86,6 +87,12 @@ PHPAPI int php_stream_parse_fopen_modes(const char *mo flags |= O_RDONLY; } +#if defined(O_NONBLOCK) + if (strchr(mode, 'n')) { + flags |= O_NONBLOCK; + } +#endif + #if defined(_O_TEXT) && defined(O_BINARY) if (strchr(mode, 't')) { flags |= _O_TEXT; @@ -108,7 +115,7 @@ typedef struct { unsigned is_pipe:1; /* don't try and seek */ unsigned cached_fstat:1; /* sb is valid */ unsigned _reserved:29; - + int lock_flag; /* stores the lock state */ char *temp_file_name; /* if non-null, this is the path to a temporary file that * is to be deleted when the stream is closed */ @@ -134,7 +141,7 @@ static int do_fstat(php_stdio_stream_data *d, int forc if (!d->cached_fstat || force) { int fd; int r; - + PHP_STDIOP_GET_FD(fd, d); r = fstat(fd, &d->sb); d->cached_fstat = r == 0; @@ -147,7 +154,7 @@ static int do_fstat(php_stdio_stream_data *d, int forc static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC) { php_stdio_stream_data *self; - + self = pemalloc_rel_orig(sizeof(*self), persistent_id); memset(self, 0, sizeof(*self)); self->file = NULL; @@ -156,14 +163,14 @@ static php_stream *_php_stream_fopen_from_fd_int(int f self->is_process_pipe = 0; self->temp_file_name = NULL; self->fd = fd; - + return php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode); } static php_stream *_php_stream_fopen_from_file_int(FILE *file, const char *mode STREAMS_DC TSRMLS_DC) { php_stdio_stream_data *self; - + self = emalloc_rel_orig(sizeof(*self)); memset(self, 0, sizeof(*self)); self->file = file; @@ -208,7 +215,7 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy self->temp_file_name = opened_path; self->lock_flag = LOCK_UN; - + return stream; } close(fd); @@ -241,7 +248,7 @@ PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, c } } #endif - + if (self->is_pipe) { stream->flags |= PHP_STREAM_FLAG_NO_SEEK; } else { @@ -280,7 +287,7 @@ PHPAPI php_stream *_php_stream_fopen_from_file(FILE *f } } #endif - + if (self->is_pipe) { stream->flags |= PHP_STREAM_FLAG_NO_SEEK; } else { @@ -349,9 +356,9 @@ static size_t php_stdiop_read(php_stream *stream, char so script can retry if desired */ ret = read(data->fd, buf, count); } - + stream->eof = (ret == 0 || (ret == (size_t)-1 && errno != EWOULDBLOCK && errno != EINTR && errno != EBADF)); - + } else { #if HAVE_FLUSHIO if (!data->is_pipe && data->last_op == 'w') @@ -388,7 +395,7 @@ static int php_stdiop_close(php_stream *stream, int cl data->file_mapping = NULL; } #endif - + if (close_handle) { if (data->file) { if (data->is_process_pipe) { @@ -458,14 +465,14 @@ static int php_stdiop_seek(php_stream *stream, off_t o if (data->fd >= 0) { off_t result; - + result = lseek(data->fd, offset, whence); if (result == (off_t)-1) return -1; *newoffset = result; return 0; - + } else { ret = fseek(data->file, offset, whence); *newoffset = ftell(data->file); @@ -479,7 +486,7 @@ static int php_stdiop_cast(php_stream *stream, int cas php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract; assert(data != NULL); - + /* as soon as someone touches the stdio layer, buffering may ensue, * so we need to stop using the fd directly in that case */ @@ -497,7 +504,7 @@ static int php_stdiop_cast(php_stream *stream, int cas return FAILURE; } } - + *(FILE**)ret = data->file; data->fd = -1; } @@ -553,9 +560,9 @@ static int php_stdiop_set_option(php_stream *stream, i int flags; int oldval; #endif - + PHP_STDIOP_GET_FD(fd, data); - + switch(option) { case PHP_STREAM_OPTION_BLOCKING: if (fd == -1) @@ -567,20 +574,20 @@ static int php_stdiop_set_option(php_stream *stream, i flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; - + if (-1 == fcntl(fd, F_SETFL, flags)) return -1; return oldval; #else return -1; /* not yet implemented */ #endif - + case PHP_STREAM_OPTION_WRITE_BUFFER: if (data->file == NULL) { return -1; } - + if (ptrparam) size = *(size_t *)ptrparam; else @@ -588,22 +595,19 @@ static int php_stdiop_set_option(php_stream *stream, i switch(value) { case PHP_STREAM_BUFFER_NONE: - stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; return setvbuf(data->file, NULL, _IONBF, 0); - + case PHP_STREAM_BUFFER_LINE: - stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER; return setvbuf(data->file, NULL, _IOLBF, size); - + case PHP_STREAM_BUFFER_FULL: - stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER; return setvbuf(data->file, NULL, _IOFBF, size); default: return -1; } break; - + case PHP_STREAM_OPTION_LOCKING: if (fd == -1) { return -1; @@ -626,7 +630,7 @@ static int php_stdiop_set_option(php_stream *stream, i { php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam; int prot, flags; - + switch (value) { case PHP_STREAM_MMAP_SUPPORTED: return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK; @@ -791,7 +795,7 @@ static int php_stdiop_set_option(php_stream *stream, i return ftruncate(fd, new_size) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; } } - + default: return PHP_STREAM_OPTION_RETURN_NOTIMPL; } @@ -864,11 +868,7 @@ static php_stream *php_plain_files_dir_opener(php_stre if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) { return NULL; } - - if (PG(safe_mode) &&(!php_checkuid(path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { - return NULL; - } - + dir = VCWD_OPENDIR(path); #ifdef PHP_WIN32 @@ -886,7 +886,7 @@ static php_stream *php_plain_files_dir_opener(php_stre if (stream == NULL) closedir(dir); } - + return stream; } /* }}} */ @@ -934,7 +934,7 @@ PHPAPI php_stream *_php_stream_fopen(const char *filen return ret; } } - + fd = open(realpath, open_flags, 0666); if (fd != -1) { @@ -998,13 +998,6 @@ static php_stream *php_plain_files_stream_opener(php_s return NULL; } - if ((php_check_safe_mode_include_dir(path TSRMLS_CC)) == 0) { - return php_stream_fopen_rel(path, mode, opened_path, options); - } - - if ((options & ENFORCE_SAFE_MODE) && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM))) - return NULL; - return php_stream_fopen_rel(path, mode, opened_path, options); } @@ -1015,10 +1008,6 @@ static int php_plain_files_url_stater(php_stream_wrapp url += sizeof("file://") - 1; } - if (PG(safe_mode) &&(!php_checkuid_ex(url, NULL, CHECKUID_CHECK_FILE_AND_DIR, (flags & PHP_STREAM_URL_STAT_QUIET) ? CHECKUID_NO_ERRORS : 0))) { - return -1; - } - if (php_check_open_basedir_ex(url, (flags & PHP_STREAM_URL_STAT_QUIET) ? 0 : 1 TSRMLS_CC)) { return -1; } @@ -1048,14 +1037,8 @@ static int php_plain_files_unlink(php_stream_wrapper * url = p + 3; } - if (options & ENFORCE_SAFE_MODE) { - if (PG(safe_mode) && !php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR)) { - return 0; - } - - if (php_check_open_basedir(url TSRMLS_CC)) { - return 0; - } + if (php_check_open_basedir(url TSRMLS_CC)) { + return 0; } ret = VCWD_UNLINK(url); @@ -1100,11 +1083,6 @@ static int php_plain_files_rename(php_stream_wrapper * url_to = p + 3; } - if (PG(safe_mode) && (!php_checkuid(url_from, NULL, CHECKUID_CHECK_FILE_AND_DIR) || - !php_checkuid(url_to, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { - return 0; - } - if (php_check_open_basedir(url_from TSRMLS_CC) || php_check_open_basedir(url_to TSRMLS_CC)) { return 0; } @@ -1175,31 +1153,25 @@ static int php_plain_files_mkdir(php_stream_wrapper *w ret = php_mkdir(dir, mode TSRMLS_CC); } else { /* we look for directory separator from the end of string, thus hopefuly reducing our work load */ - char *e, *buf; + char *e; struct stat sb; int dir_len = strlen(dir); int offset = 0; + char buf[MAXPATHLEN]; - buf = estrndup(dir, dir_len); - -#ifdef PHP_WIN32 - e = buf; - while (*e) { - if (*e == '/') { - *e = DEFAULT_SLASH; - } - e++; + if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path"); + return 0; } -#else - e = buf + dir_len; -#endif + e = buf + strlen(buf); + if ((p = memchr(buf, DEFAULT_SLASH, dir_len))) { offset = p - buf + 1; } if (p && dir_len == 1) { - /* buf == "DEFAULT_SLASH" */ + /* buf == "DEFAULT_SLASH" */ } else { /* find a top level directory we need to create */ @@ -1244,7 +1216,6 @@ static int php_plain_files_mkdir(php_stream_wrapper *w } } } - efree(buf); } if (ret < 0) { /* Failure */ @@ -1260,10 +1231,6 @@ static int php_plain_files_rmdir(php_stream_wrapper *w #if PHP_WIN32 int url_len = strlen(url); #endif - if (PG(safe_mode) &&(!php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { - return 0; - } - if (php_check_open_basedir(url TSRMLS_CC)) { return 0; } @@ -1286,6 +1253,92 @@ static int php_plain_files_rmdir(php_stream_wrapper *w return 1; } +static int php_plain_files_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC) +{ + struct utimbuf *newtime; + char *p; +#if !defined(WINDOWS) && !defined(NETWARE) + uid_t uid; + gid_t gid; +#endif + mode_t mode; + int ret = 0; +#if PHP_WIN32 + int url_len = strlen(url); +#endif + +#if PHP_WIN32 + if (!php_win32_check_trailing_space(url, url_len)) { + php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(ENOENT)); + return 0; + } +#endif + + if ((p = strstr(url, "://")) != NULL) { + url = p + 3; + } + + if (php_check_open_basedir(url TSRMLS_CC)) { + return 0; + } + + switch(option) { + case PHP_STREAM_META_TOUCH: + newtime = (struct utimbuf *)value; + if (VCWD_ACCESS(url, F_OK) != 0) { + FILE *file = VCWD_FOPEN(url, "w"); + if (file == NULL) { + php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to create file %s because %s", url, strerror(errno)); + return 0; + } + fclose(file); + } + + ret = VCWD_UTIME(url, newtime); + break; +#if !defined(WINDOWS) && !defined(NETWARE) + case PHP_STREAM_META_OWNER_NAME: + case PHP_STREAM_META_OWNER: + if(option == PHP_STREAM_META_OWNER_NAME) { + if(php_get_uid_by_name((char *)value, &uid TSRMLS_CC) != SUCCESS) { + php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find uid for %s", (char *)value); + return 0; + } + } else { + uid = (uid_t)*(long *)value; + } + ret = VCWD_CHOWN(url, uid, -1); + break; + case PHP_STREAM_META_GROUP: + case PHP_STREAM_META_GROUP_NAME: + if(option == PHP_STREAM_META_OWNER_NAME) { + if(php_get_gid_by_name((char *)value, &gid TSRMLS_CC) != SUCCESS) { + php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find gid for %s", (char *)value); + return 0; + } + } else { + gid = (gid_t)*(long *)value; + } + ret = VCWD_CHOWN(url, -1, gid); + break; +#endif + case PHP_STREAM_META_ACCESS: + mode = (mode_t)*(long *)value; + ret = VCWD_CHMOD(url, mode); + break; + default: + php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unknown option %d for stream_metadata", option); + return 0; + } + if (ret == -1) { + php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Operation failed: %s", strerror(errno)); + return 0; + } + php_clear_stat_cache(0, NULL, 0 TSRMLS_CC); + return 1; +} + + static php_stream_wrapper_ops php_plain_files_wrapper_ops = { php_plain_files_stream_opener, NULL, @@ -1296,7 +1349,8 @@ static php_stream_wrapper_ops php_plain_files_wrapper_ php_plain_files_unlink, php_plain_files_rename, php_plain_files_mkdir, - php_plain_files_rmdir + php_plain_files_rmdir, + php_plain_files_metadata }; php_stream_wrapper php_plain_files_wrapper = { @@ -1310,7 +1364,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *f { /* code ripped off from fopen_wrappers.c */ char *pathbuf, *ptr, *end; - char *exec_fname; + const char *exec_fname; char trypath[MAXPATHLEN]; php_stream *stream; int path_length; @@ -1343,17 +1397,9 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *f return NULL; } - if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { - return NULL; - } return php_stream_fopen_rel(filename, mode, opened_path, options); } - /* - * files in safe_mode_include_dir (or subdir) are excluded from - * safe mode GID/UID checks - */ - not_relative_path: /* Absolute path open */ @@ -1363,16 +1409,9 @@ not_relative_path: return NULL; } - if ((php_check_safe_mode_include_dir(filename TSRMLS_CC)) == 0) - /* filename is in safe_mode_include_dir (or subdir) */ - return php_stream_fopen_rel(filename, mode, opened_path, options); - - if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) - return NULL; - return php_stream_fopen_rel(filename, mode, opened_path, options); } - + #ifdef PHP_WIN32 if (IS_SLASH(filename[0])) { size_t cwd_len; @@ -1380,31 +1419,22 @@ not_relative_path: cwd = virtual_getcwd_ex(&cwd_len TSRMLS_CC); /* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */ *(cwd+3) = '\0'; - + if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN); } - + free(cwd); - + if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(trypath TSRMLS_CC)) { return NULL; } - if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC)) == 0) { - return php_stream_fopen_rel(trypath, mode, opened_path, options); - } - if (PG(safe_mode) && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) { - return NULL; - } - + return php_stream_fopen_rel(trypath, mode, opened_path, options); } #endif if (!path || (path && !*path)) { - if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { - return NULL; - } return php_stream_fopen_rel(filename, mode, opened_path, options); } @@ -1451,24 +1481,9 @@ not_relative_path: if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0 TSRMLS_CC)) { goto stream_skip; } - - if (PG(safe_mode)) { - struct stat sb; - if (VCWD_STAT(trypath, &sb) == 0) { - /* file exists ... check permission */ - if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0) || - php_checkuid_ex(trypath, mode, CHECKUID_CHECK_MODE_PARAM, CHECKUID_NO_ERRORS)) { - /* UID ok, or trypath is in safe_mode_include_dir */ - stream = php_stream_fopen_rel(trypath, mode, opened_path, options); - goto stream_done; - } - } - goto stream_skip; - } stream = php_stream_fopen_rel(trypath, mode, opened_path, options); if (stream) { -stream_done: efree(pathbuf); return stream; }