static void ps_files_open(ps_files *data, const char *key) { char buf[MAXPATHLEN]; #if !defined(O_NOFOLLOW) || !defined(PHP_WIN32) struct stat sbuf; #endif int ret; if (data->fd < 0 || !data->lastkey || strcmp(key, data->lastkey)) { if (data->lastkey) { efree(data->lastkey); data->lastkey = NULL; } ps_files_close(data); if (php_session_valid_key(key) == FAILURE) { if (data->basedir) { efree(data->basedir); data->basedir = NULL; data->basedir_len = 0; } efree(data); php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,'"); return; } if (!ps_files_path_create(buf, sizeof(buf), data, key)) { return; } data->lastkey = estrdup(key); /* O_NOFOLLOW to prevent us from following evil symlinks */ #ifdef O_NOFOLLOW data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY | O_NOFOLLOW, data->filemode); #else /* Check to make sure that the opened file is not outside of allowable dirs. This is not 100% safe but it's hard to do something better without O_NOFOLLOW */ if(PG(open_basedir) && lstat(buf, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) && php_check_open_basedir(buf)) { return; } data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY, data->filemode); #endif if (data->fd != -1) { #ifndef PHP_WIN32 /* check that this session file was created by us or root – we don't want to end up accepting the sessions of another webapp */ if (fstat(data->fd, &sbuf) || (sbuf.st_uid != 0 && sbuf.st_uid != getuid() && sbuf.st_uid != geteuid())) { close(data->fd); data->fd = -1; return; } #endif do { ret = flock(data->fd, LOCK_EX); } while (ret == -1 && errno == EINTR); #ifdef F_SETFD # ifndef FD_CLOEXEC # define FD_CLOEXEC 1 # endif if (fcntl(data->fd, F_SETFD, FD_CLOEXEC)) { php_error_docref(NULL, E_WARNING, "fcntl(%d, F_SETFD, FD_CLOEXEC) failed: %s (%d)", data->fd, strerror(errno), errno); } #endif } else { php_error_docref(NULL, E_WARNING, "open(%s, O_RDWR) failed: %s (%d)", buf, strerror(errno), errno); } } }
static int php_do_open_temporary_file(const char *path, const char *pfx, zend_string **opened_path_p) { char *trailing_slash; #ifdef PHP_WIN32 char *opened_path = NULL; size_t opened_path_len; wchar_t *cwdw, *pfxw, pathw[MAXPATHLEN]; #else char opened_path[MAXPATHLEN]; #endif char cwd[MAXPATHLEN]; cwd_state new_state; int fd = -1; #ifndef HAVE_MKSTEMP int open_flags = O_CREAT | O_TRUNC | O_RDWR #ifdef PHP_WIN32 | _O_BINARY #endif ; #endif if (!path || !path[0]) { return -1; } #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(pfx, (const int)strlen(pfx))) { SetLastError(ERROR_INVALID_NAME); return -1; } #endif if (!VCWD_GETCWD(cwd, MAXPATHLEN)) { cwd[0] = '\0'; } new_state.cwd = estrdup(cwd); new_state.cwd_length = (int)strlen(cwd); if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) { efree(new_state.cwd); return -1; } if (IS_SLASH(new_state.cwd[new_state.cwd_length - 1])) { trailing_slash = ""; } else { trailing_slash = "/"; } #ifndef PHP_WIN32 if (snprintf(opened_path, MAXPATHLEN, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) { efree(new_state.cwd); return -1; } #endif #ifdef PHP_WIN32 cwdw = php_win32_ioutil_any_to_w(new_state.cwd); pfxw = php_win32_ioutil_any_to_w(pfx); if (!cwdw || !pfxw) { free(cwdw); free(pfxw); efree(new_state.cwd); return -1; } if (GetTempFileNameW(cwdw, pfxw, 0, pathw)) { opened_path = php_win32_ioutil_conv_w_to_any(pathw, PHP_WIN32_CP_IGNORE_LEN, &opened_path_len); if (!opened_path || opened_path_len >= MAXPATHLEN) { free(cwdw); free(pfxw); efree(new_state.cwd); return -1; } assert(strlen(opened_path) == opened_path_len); /* Some versions of windows set the temp file to be read-only, * which means that opening it will fail... */ if (VCWD_CHMOD(opened_path, 0600)) { free(cwdw); free(pfxw); efree(new_state.cwd); free(opened_path); return -1; } fd = VCWD_OPEN_MODE(opened_path, open_flags, 0600); } free(cwdw); free(pfxw); #elif defined(HAVE_MKSTEMP) fd = mkstemp(opened_path); #else if (mktemp(opened_path)) { fd = VCWD_OPEN(opened_path, open_flags); } #endif #ifdef PHP_WIN32 if (fd != -1 && opened_path_p) { *opened_path_p = zend_string_init(opened_path, opened_path_len, 0); } free(opened_path); #else if (fd != -1 && opened_path_p) { *opened_path_p = zend_string_init(opened_path, strlen(opened_path), 0); } #endif efree(new_state.cwd); return fd; }