Beispiel #1
0
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;
}