static size_t zend_stream_fsize(zend_file_handle *file_handle) /* {{{ */ { zend_stat_t buf; if (zend_stream_is_mmap(file_handle)) { return file_handle->handle.stream.mmap.len; } if (file_handle->type == ZEND_HANDLE_STREAM || file_handle->type == ZEND_HANDLE_MAPPED) { return file_handle->handle.stream.fsizer(file_handle->handle.stream.handle); } if (file_handle->handle.fp && zend_fstat(fileno(file_handle->handle.fp), &buf) == 0) { #ifdef S_ISREG if (!S_ISREG(buf.st_mode)) { return 0; } #endif return buf.st_size; } return -1; } /* }}} */
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) { 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)) { php_error_docref(NULL, E_WARNING, "Failed to create session data file path. Too short session ID, invalid save_path or path lentgth exceeds MAXPATHLEN(%d)", MAXPATHLEN); 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 the process is ran by root, we ignore session file ownership Use case: session is initiated by Apache under non-root and then accessed by backend with root permissions to execute some system tasks. */ if (zend_fstat(data->fd, &sbuf) || (sbuf.st_uid != 0 && sbuf.st_uid != getuid() && sbuf.st_uid != geteuid() && getuid() != 0)) { close(data->fd); data->fd = -1; php_error_docref(NULL, E_WARNING, "Session data file is not created by your uid"); 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); } } }