PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/session - mod_files.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 174 214 81.3 %
Date: 2019-07-17 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2018 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Author: Sascha Schumann <sascha@schumann.cx>                         |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /**************************************************************************
      20             :  * Files save handler should be used as reference implementations of session
      21             :  * save handlers. PS_* functions are called as follows with standard usage.
      22             :  *
      23             :  *    PS_OPEN_FUNC()  - Create module data that manages save handler.
      24             :  *    PS_CREATE_SID() and/or PS_VALIDATE_SID()
      25             :  *                    - PS_CREATE_ID() is called if session ID(key) is not
      26             :  *                      provided or invalid. PS_VALIDATE_SID() is called to
      27             :  *                      verify session ID already exists or not to mitigate
      28             :  *                      session adoption vulnerability risk.
      29             :  *    PS_READ_FUNC()  - Read data from storage.
      30             :  *    PS_GC_FUNC()    - Perform GC. Called by probability
      31             :  *                                (session.gc_probability/session.gc_divisor).
      32             :  *    PS_WRITE_FUNC() or PS_UPDATE_TIMESTAMP()
      33             :  *                    - Write session data or update session data timestamp.
      34             :  *                      It depends on session data change.
      35             :  *    PS_CLOSE_FUNC() - Clean up module data created by PS_OPEN_FUNC().
      36             :  *
      37             :  * Session module guarantees PS_OPEN_FUNC() is called before calling other
      38             :  * PS_*_FUNC() functions. Other than this, session module may call any
      39             :  * PS_*_FUNC() at any time. You may assume non null *mod_data created by
      40             :  * PS_OPEN_FUNC() is passed to PS_*_FUNC().
      41             :  *
      42             :  * NOTE:
      43             :  *  - Save handlers _MUST_NOT_ change/refer PS() values.
      44             :  *    i.e. PS(id), PS(session_status), PS(mod) and any other PS() values.
      45             :  *    Use only function parameters passed from session module.
      46             :  *  - Save handler _MUST_ use PS_GET_MOD_DATA()/PS_SET_MOD_DATA() macro to
      47             :  *    set/get save handler module data(mod_data). mod_data contains
      48             :  *    data required by PS modules. It will not be NULL except PS_OPEN_FUNC().
      49             :  *  - Refer to PS_* macros in php_session.h for function/parameter definitions.
      50             :  *  - Returning FAILURE state from PS_* function results in raising errors.
      51             :  *    Avoid failure state as much as possible.
      52             :  *  - Use static ps_[module name]_[function name] functions for internal use.
      53             :  *************************************************************************/
      54             : 
      55             : #include "php.h"
      56             : 
      57             : #include <sys/stat.h>
      58             : #include <sys/types.h>
      59             : 
      60             : #if HAVE_SYS_FILE_H
      61             : #include <sys/file.h>
      62             : #endif
      63             : 
      64             : #if HAVE_DIRENT_H
      65             : #include <dirent.h>
      66             : #endif
      67             : 
      68             : #ifdef PHP_WIN32
      69             : #include "win32/readdir.h"
      70             : #endif
      71             : #include <time.h>
      72             : 
      73             : #include <fcntl.h>
      74             : #include <errno.h>
      75             : 
      76             : #if HAVE_UNISTD_H
      77             : #include <unistd.h>
      78             : #endif
      79             : 
      80             : #include "php_session.h"
      81             : #include "mod_files.h"
      82             : #include "ext/standard/flock_compat.h"
      83             : #include "php_open_temporary_file.h"
      84             : 
      85             : #define FILE_PREFIX "sess_"
      86             : 
      87             : #ifdef PHP_WIN32
      88             : # ifndef O_NOFOLLOW
      89             : #  define O_NOFOLLOW 0
      90             : # endif
      91             : #endif
      92             : 
      93             : typedef struct {
      94             :         char *lastkey;
      95             :         char *basedir;
      96             :         size_t basedir_len;
      97             :         size_t dirdepth;
      98             :         size_t st_size;
      99             :         int filemode;
     100             :         int fd;
     101             : } ps_files;
     102             : 
     103             : ps_module ps_mod_files = {
     104             :         /* New save handlers MUST use PS_MOD_UPDATE_TIMESTAMP macro */
     105             :         PS_MOD_UPDATE_TIMESTAMP(files)
     106             : };
     107             : 
     108             : 
     109         841 : static char *ps_files_path_create(char *buf, size_t buflen, ps_files *data, const char *key)
     110             : {
     111             :         size_t key_len;
     112             :         const char *p;
     113             :         int i;
     114             :         size_t n;
     115             : 
     116         841 :         key_len = strlen(key);
     117        1679 :         if (!data || key_len <= data->dirdepth ||
     118         838 :                 buflen < (strlen(data->basedir) + 2 * data->dirdepth + key_len + 5 + sizeof(FILE_PREFIX))) {
     119           3 :                 return NULL;
     120             :         }
     121             : 
     122         838 :         p = key;
     123         838 :         memcpy(buf, data->basedir, data->basedir_len);
     124         838 :         n = data->basedir_len;
     125         838 :         buf[n++] = PHP_DIR_SEPARATOR;
     126         838 :         for (i = 0; i < (int)data->dirdepth; i++) {
     127           0 :                 buf[n++] = *p++;
     128           0 :                 buf[n++] = PHP_DIR_SEPARATOR;
     129             :         }
     130         838 :         memcpy(buf + n, FILE_PREFIX, sizeof(FILE_PREFIX) - 1);
     131         838 :         n += sizeof(FILE_PREFIX) - 1;
     132         838 :         memcpy(buf + n, key, key_len);
     133         838 :         n += key_len;
     134         838 :         buf[n] = '\0';
     135             : 
     136         838 :         return buf;
     137             : }
     138             : 
     139             : #ifndef O_BINARY
     140             : # define O_BINARY 0
     141             : #endif
     142             : 
     143         968 : static void ps_files_close(ps_files *data)
     144             : {
     145         968 :         if (data->fd != -1) {
     146             : #ifdef PHP_WIN32
     147             :                 /* On Win32 locked files that are closed without being explicitly unlocked
     148             :                    will be unlocked only when "system resources become available". */
     149             :                 flock(data->fd, LOCK_UN);
     150             : #endif
     151         375 :                 close(data->fd);
     152         375 :                 data->fd = -1;
     153             :         }
     154         968 : }
     155             : 
     156         534 : static void ps_files_open(ps_files *data, const char *key)
     157             : {
     158             :         char buf[MAXPATHLEN];
     159             : #if !defined(O_NOFOLLOW) || !defined(PHP_WIN32)
     160             :     struct stat sbuf;
     161             : #endif
     162             :         int ret;
     163             : 
     164         534 :         if (data->fd < 0 || !data->lastkey || strcmp(key, data->lastkey)) {
     165         380 :                 if (data->lastkey) {
     166           1 :                         efree(data->lastkey);
     167           1 :                         data->lastkey = NULL;
     168             :                 }
     169             : 
     170         380 :                 ps_files_close(data);
     171             : 
     172         380 :                 if (php_session_valid_key(key) == FAILURE) {
     173           2 :                         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 '-,'");
     174           2 :                         return;
     175             :                 }
     176             : 
     177         378 :                 if (!ps_files_path_create(buf, sizeof(buf), data, key)) {
     178           1 :                         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);
     179           1 :                         return;
     180             :                 }
     181             : 
     182         377 :                 data->lastkey = estrdup(key);
     183             : 
     184             :                 /* O_NOFOLLOW to prevent us from following evil symlinks */
     185             : #ifdef O_NOFOLLOW
     186         377 :                 data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY | O_NOFOLLOW, data->filemode);
     187             : #else
     188             :                 /* Check to make sure that the opened file is not outside of allowable dirs.
     189             :                    This is not 100% safe but it's hard to do something better without O_NOFOLLOW */
     190             :                 if(PG(open_basedir) && lstat(buf, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) && php_check_open_basedir(buf)) {
     191             :                         return;
     192             :                 }
     193             :                 data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY, data->filemode);
     194             : #endif
     195             : 
     196         377 :                 if (data->fd != -1) {
     197             : #ifndef PHP_WIN32
     198             :                         /* check that this session file was created by us or root – we
     199             :                            don't want to end up accepting the sessions of another webapp
     200             : 
     201             :                            If the process is ran by root, we ignore session file ownership
     202             :                            Use case: session is initiated by Apache under non-root and then
     203             :                            accessed by backend with root permissions to execute some system tasks.
     204             : 
     205             :                            */
     206         375 :                         if (zend_fstat(data->fd, &sbuf) || (sbuf.st_uid != 0 && sbuf.st_uid != getuid() && sbuf.st_uid != geteuid() && getuid() != 0)) {
     207           0 :                                 close(data->fd);
     208           0 :                                 data->fd = -1;
     209           0 :                                 php_error_docref(NULL, E_WARNING, "Session data file is not created by your uid");
     210           0 :                                 return;
     211             :                         }
     212             : #endif
     213             :                         do {
     214         375 :                                 ret = flock(data->fd, LOCK_EX);
     215         375 :                         } while (ret == -1 && errno == EINTR);
     216             : 
     217             : #ifdef F_SETFD
     218             : # ifndef FD_CLOEXEC
     219             : #  define FD_CLOEXEC 1
     220             : # endif
     221         375 :                         if (fcntl(data->fd, F_SETFD, FD_CLOEXEC)) {
     222           0 :                                 php_error_docref(NULL, E_WARNING, "fcntl(%d, F_SETFD, FD_CLOEXEC) failed: %s (%d)", data->fd, strerror(errno), errno);
     223             :                         }
     224             : #endif
     225             :                 } else {
     226           2 :                         php_error_docref(NULL, E_WARNING, "open(%s, O_RDWR) failed: %s (%d)", buf, strerror(errno), errno);
     227             :                 }
     228             :         }
     229             : }
     230             : 
     231         155 : static int ps_files_write(ps_files *data, zend_string *key, zend_string *val)
     232             : {
     233         155 :         size_t n = 0;
     234             : 
     235             :         /* PS(id) may be changed by calling session_regenerate_id().
     236             :            Re-initialization should be tried here. ps_files_open() checks
     237             :        data->lastkey and reopen when it is needed. */
     238         155 :         ps_files_open(data, ZSTR_VAL(key));
     239         155 :         if (data->fd < 0) {
     240           0 :                 return FAILURE;
     241             :         }
     242             : 
     243             :         /* Truncate file if the amount of new data is smaller than the existing data set. */
     244         155 :         if (ZSTR_LEN(val) < data->st_size) {
     245           4 :                 php_ignore_value(ftruncate(data->fd, 0));
     246             :         }
     247             : 
     248             : #if defined(HAVE_PWRITE)
     249         155 :         n = pwrite(data->fd, ZSTR_VAL(val), ZSTR_LEN(val), 0);
     250             : #else
     251             :         lseek(data->fd, 0, SEEK_SET);
     252             : #ifdef PHP_WIN32
     253             :         {
     254             :                 unsigned int to_write = ZSTR_LEN(val) > UINT_MAX ? UINT_MAX : (unsigned int)ZSTR_LEN(val);
     255             :                 char *buf = ZSTR_VAL(val);
     256             :                 int wrote;
     257             : 
     258             :                 do {
     259             :                         wrote = _write(data->fd, buf, to_write);
     260             : 
     261             :                         n += wrote;
     262             :                         buf = wrote > -1 ? buf + wrote : 0;
     263             :                         to_write = wrote > -1 ? (ZSTR_LEN(val) - n > UINT_MAX ? UINT_MAX : (unsigned int)(ZSTR_LEN(val) - n)): 0;
     264             : 
     265             :                 } while(wrote > 0);
     266             :         }
     267             : #else
     268             :         n = write(data->fd, ZSTR_VAL(val), ZSTR_LEN(val));
     269             : #endif
     270             : #endif
     271             : 
     272         155 :         if (n != ZSTR_LEN(val)) {
     273           0 :                 if (n == (size_t)-1) {
     274           0 :                         php_error_docref(NULL, E_WARNING, "write failed: %s (%d)", strerror(errno), errno);
     275             :                 } else {
     276           0 :                         php_error_docref(NULL, E_WARNING, "write wrote less bytes than requested");
     277             :                 }
     278           0 :                 return FAILURE;
     279             :         }
     280             : 
     281         155 :         return SUCCESS;
     282             : }
     283             : 
     284           9 : static int ps_files_cleanup_dir(const char *dirname, zend_long maxlifetime)
     285             : {
     286             :         DIR *dir;
     287             :         char dentry[sizeof(struct dirent) + MAXPATHLEN];
     288           9 :         struct dirent *entry = (struct dirent *) &dentry;
     289             :         zend_stat_t sbuf;
     290             :         char buf[MAXPATHLEN];
     291             :         time_t now;
     292           9 :         int nrdels = 0;
     293             :         size_t dirname_len;
     294             : 
     295           9 :         dir = opendir(dirname);
     296           9 :         if (!dir) {
     297           0 :                 php_error_docref(NULL, E_NOTICE, "ps_files_cleanup_dir: opendir(%s) failed: %s (%d)", dirname, strerror(errno), errno);
     298           0 :                 return (0);
     299             :         }
     300             : 
     301           9 :         time(&now);
     302             : 
     303           9 :         dirname_len = strlen(dirname);
     304             : 
     305           9 :         if (dirname_len >= MAXPATHLEN) {
     306           0 :                 php_error_docref(NULL, E_NOTICE, "ps_files_cleanup_dir: dirname(%s) is too long", dirname);
     307           0 :                 closedir(dir);
     308           0 :                 return (0);
     309             :         }
     310             : 
     311             :         /* Prepare buffer (dirname never changes) */
     312           9 :         memcpy(buf, dirname, dirname_len);
     313           9 :         buf[dirname_len] = PHP_DIR_SEPARATOR;
     314             : 
     315        5831 :         while (php_readdir_r(dir, (struct dirent *) dentry, &entry) == 0 && entry) {
     316             :                 /* does the file start with our prefix? */
     317        5813 :                 if (!strncmp(entry->d_name, FILE_PREFIX, sizeof(FILE_PREFIX) - 1)) {
     318         289 :                         size_t entry_len = strlen(entry->d_name);
     319             : 
     320             :                         /* does it fit into our buffer? */
     321         289 :                         if (entry_len + dirname_len + 2 < MAXPATHLEN) {
     322             :                                 /* create the full path.. */
     323         289 :                                 memcpy(buf + dirname_len + 1, entry->d_name, entry_len);
     324             : 
     325             :                                 /* NUL terminate it and */
     326         289 :                                 buf[dirname_len + entry_len + 1] = '\0';
     327             : 
     328             :                                 /* check whether its last access was more than maxlifetime ago */
     329         578 :                                 if (VCWD_STAT(buf, &sbuf) == 0 &&
     330         289 :                                                 (now - sbuf.st_mtime) > maxlifetime) {
     331          77 :                                         VCWD_UNLINK(buf);
     332          77 :                                         nrdels++;
     333             :                                 }
     334             :                         }
     335             :                 }
     336             :         }
     337             : 
     338           9 :         closedir(dir);
     339             : 
     340           9 :         return (nrdels);
     341             : }
     342             : 
     343         248 : static int ps_files_key_exists(ps_files *data, const char *key)
     344             : {
     345             :         char buf[MAXPATHLEN];
     346             :         zend_stat_t sbuf;
     347             : 
     348         248 :         if (!key || !ps_files_path_create(buf, sizeof(buf), data, key)) {
     349           1 :                 return FAILURE;
     350             :         }
     351         247 :         if (VCWD_STAT(buf, &sbuf)) {
     352         247 :                 return FAILURE;
     353             :         }
     354           0 :         return SUCCESS;
     355             : }
     356             : 
     357             : 
     358             : #define PS_FILES_DATA ps_files *data = PS_GET_MOD_DATA()
     359             : 
     360             : 
     361             : /*
     362             :  * Open save handler. Setup resources that are needed by the handler.
     363             :  * PARAMETERS: PS_OPEN_ARGS in php_session.h
     364             :  * RETURN VALUE: SUCCESS or FAILURE. Must set non-NULL valid module data
     365             :  * (void **mod_data) with SUCCESS, NULL(default) for FAILUREs.
     366             :  *
     367             :  * Files save handler checks/create save_path directory and setup ps_files data.
     368             :  * Note that files save handler supports splitting session data into multiple
     369             :  * directories.
     370             :  * *mod_data, *save_path, *session_name are guaranteed to have non-NULL values.
     371             :  */
     372         380 : PS_OPEN_FUNC(files)
     373             : {
     374             :         ps_files *data;
     375             :         const char *p, *last;
     376             :         const char *argv[3];
     377         380 :         int argc = 0;
     378         380 :         size_t dirdepth = 0;
     379         380 :         int filemode = 0600;
     380             : 
     381         380 :         if (*save_path == '\0') {
     382             :                 /* if save path is an empty string, determine the temporary dir */
     383         359 :                 save_path = php_get_temporary_directory();
     384             : 
     385         359 :                 if (php_check_open_basedir(save_path)) {
     386           1 :                         return FAILURE;
     387             :                 }
     388             :         }
     389             : 
     390             :         /* split up input parameter */
     391         379 :         last = save_path;
     392         379 :         p = strchr(save_path, ';');
     393         760 :         while (p) {
     394           4 :                 argv[argc++] = last;
     395           4 :                 last = ++p;
     396           4 :                 p = strchr(p, ';');
     397           4 :                 if (argc > 1) break;
     398             :         }
     399         379 :         argv[argc++] = last;
     400             : 
     401         379 :         if (argc > 1) {
     402           2 :                 errno = 0;
     403           2 :                 dirdepth = (size_t) ZEND_STRTOL(argv[0], NULL, 10);
     404           2 :                 if (errno == ERANGE) {
     405           0 :                         php_error(E_WARNING, "The first parameter in session.save_path is invalid");
     406           0 :                         return FAILURE;
     407             :                 }
     408             :         }
     409             : 
     410         379 :         if (argc > 2) {
     411           2 :                 errno = 0;
     412           2 :                 filemode = (int)ZEND_STRTOL(argv[1], NULL, 8);
     413           2 :                 if (errno == ERANGE || filemode < 0 || filemode > 07777) {
     414           0 :                         php_error(E_WARNING, "The second parameter in session.save_path is invalid");
     415           0 :                         return FAILURE;
     416             :                 }
     417             :         }
     418         379 :         save_path = argv[argc - 1];
     419             : 
     420         379 :         data = ecalloc(1, sizeof(*data));
     421             : 
     422         379 :         data->fd = -1;
     423         379 :         data->dirdepth = dirdepth;
     424         379 :         data->filemode = filemode;
     425         379 :         data->basedir_len = strlen(save_path);
     426         379 :         data->basedir = estrndup(save_path, data->basedir_len);
     427             : 
     428         379 :         if (PS_GET_MOD_DATA()) {
     429           1 :                 ps_close_files(mod_data);
     430             :         }
     431         379 :         PS_SET_MOD_DATA(data);
     432             : 
     433         379 :         return SUCCESS;
     434             : }
     435             : 
     436             : 
     437             : /*
     438             :  * Clean up opened resources.
     439             :  * PARAMETERS: PS_CLOSE_ARGS in php_session.h
     440             :  * RETURN VALUE: SUCCESS. Must set PS module data(void **mod_data) to NULL.
     441             :  *
     442             :  * Files save handler closes open files and it's memory.
     443             :  * *mod_data is guaranteed to have non-NULL value.
     444             :  * PS_CLOSE_FUNC() must set *mod_data to NULL. PS_CLOSE_FUNC() should not
     445             :  * fail.
     446             :  */
     447         379 : PS_CLOSE_FUNC(files)
     448             : {
     449         379 :         PS_FILES_DATA;
     450             : 
     451         379 :         ps_files_close(data);
     452             : 
     453         379 :         if (data->lastkey) {
     454         376 :                 efree(data->lastkey);
     455         376 :                 data->lastkey = NULL;
     456             :         }
     457             : 
     458         379 :         efree(data->basedir);
     459         379 :         efree(data);
     460         379 :         PS_SET_MOD_DATA(NULL);
     461             : 
     462         379 :         return SUCCESS;
     463             : }
     464             : 
     465             : 
     466             : /*
     467             :  * Read session data from opened resource.
     468             :  * PARAMETERS: PS_READ_ARGS in php_session.h
     469             :  * RETURN VALUE: SUCCESS or FAILURE. Must set non-NULL session data to (zend_string **val)
     470             :  * for SUCCESS. NULL(default) for FAILUREs.
     471             :  *
     472             :  * Files save handler supports splitting session data into multiple
     473             :  * directories.
     474             :  * *mod_data, *key are guaranteed to have non-NULL values.
     475             :  */
     476         379 : PS_READ_FUNC(files)
     477             : {
     478         379 :         zend_long n = 0;
     479             :         zend_stat_t sbuf;
     480         379 :         PS_FILES_DATA;
     481             : 
     482         379 :         ps_files_open(data, ZSTR_VAL(key));
     483         379 :         if (data->fd < 0) {
     484           5 :                 return FAILURE;
     485             :         }
     486             : 
     487         374 :         if (zend_fstat(data->fd, &sbuf)) {
     488           0 :                 return FAILURE;
     489             :         }
     490             : 
     491         374 :         data->st_size = sbuf.st_size;
     492             : 
     493         374 :         if (sbuf.st_size == 0) {
     494         332 :                 *val = ZSTR_EMPTY_ALLOC();
     495         332 :                 return SUCCESS;
     496             :         }
     497             : 
     498          84 :         *val = zend_string_alloc(sbuf.st_size, 0);
     499             : 
     500             : #if defined(HAVE_PREAD)
     501          42 :         n = pread(data->fd, ZSTR_VAL(*val), ZSTR_LEN(*val), 0);
     502             : #else
     503             :         lseek(data->fd, 0, SEEK_SET);
     504             : #ifdef PHP_WIN32
     505             :         {
     506             :                 unsigned int to_read = ZSTR_LEN(*val) > UINT_MAX ? UINT_MAX : (unsigned int)ZSTR_LEN(*val);
     507             :                 char *buf = ZSTR_VAL(*val);
     508             :                 int read_in;
     509             : 
     510             :                 do {
     511             :                         read_in = _read(data->fd, buf, to_read);
     512             : 
     513             :                         n += read_in;
     514             :                         buf = read_in > -1 ? buf + read_in : 0;
     515             :                         to_read = read_in > -1 ? (ZSTR_LEN(*val) - n > UINT_MAX ? UINT_MAX : (unsigned int)(ZSTR_LEN(*val) - n)): 0;
     516             : 
     517             :                 } while(read_in > 0);
     518             : 
     519             :         }
     520             : #else
     521             :         n = read(data->fd, ZSTR_VAL(*val), ZSTR_LEN(*val));
     522             : #endif
     523             : #endif
     524             : 
     525          42 :         if (n != (zend_long)sbuf.st_size) {
     526           0 :                 if (n == -1) {
     527           0 :                         php_error_docref(NULL, E_WARNING, "read failed: %s (%d)", strerror(errno), errno);
     528             :                 } else {
     529           0 :                         php_error_docref(NULL, E_WARNING, "read returned less bytes than requested");
     530             :                 }
     531           0 :                 zend_string_release(*val);
     532           0 :                 *val =  ZSTR_EMPTY_ALLOC();
     533           0 :                 return FAILURE;
     534             :         }
     535             : 
     536          42 :         ZSTR_VAL(*val)[ZSTR_LEN(*val)] = '\0';
     537          42 :         return SUCCESS;
     538             : }
     539             : 
     540             : 
     541             : /*
     542             :  * Write session data.
     543             :  * PARAMETERS: PS_WRITE_ARGS in php_session.h
     544             :  * RETURN VALUE: SUCCESS or FAILURE.
     545             :  *
     546             :  * PS_WRITE_FUNC() must write session data(zend_string *val) unconditionally.
     547             :  * *mod_data, *key, *val are guaranteed to have non-NULL values.
     548             :  */
     549         155 : PS_WRITE_FUNC(files)
     550             : {
     551         155 :         PS_FILES_DATA;
     552             : 
     553         155 :         return ps_files_write(data, key, val);
     554             : }
     555             : 
     556             : 
     557             : /*
     558             :  * Update session data modification/access time stamp.
     559             :  * PARAMETERS: PS_UPDATE_TIMESTAMP_ARGS in php_session.h
     560             :  * RETURN VALUE: SUCCESS or FAILURE.
     561             :  *
     562             :  * PS_UPDATE_TIMESTAMP_FUNC() updates time stamp(mtime) so that active session
     563             :  * data files will not be purged by GC. If session data storage does not need to
     564             :  * update timestamp, it should return SUCCESS simply. (e.g. Memcache)
     565             :  * *mod_data, *key, *val are guaranteed to have non-NULL values.
     566             :  *
     567             :  * NOTE: Updating access timestamp at PS_READ_FUNC() may extend life of obsolete
     568             :  * session data. Use of PS_UPDATE_TIMESTAMP_FUNC() is preferred whenever it is
     569             :  * possible.
     570             :  */
     571           5 : PS_UPDATE_TIMESTAMP_FUNC(files)
     572             : {
     573             :         char buf[MAXPATHLEN];
     574             :         struct utimbuf newtimebuf;
     575           5 :         struct utimbuf *newtime = &newtimebuf;
     576             :         int ret;
     577           5 :         PS_FILES_DATA;
     578             : 
     579           5 :         if (!ps_files_path_create(buf, sizeof(buf), data, ZSTR_VAL(key))) {
     580           0 :                 return FAILURE;
     581             :         }
     582             : 
     583             :         /* Update mtime */
     584             : #ifdef HAVE_UTIME_NULL
     585           5 :         newtime = NULL;
     586             : #else
     587             :         newtime->modtime = newtime->actime = time(NULL);
     588             : #endif
     589           5 :         ret = VCWD_UTIME(buf, newtime);
     590           5 :         if (ret == -1) {
     591             :                 /* New session ID, create data file */
     592           0 :                 return ps_files_write(data, key, val);
     593             :         }
     594             : 
     595           5 :         return SUCCESS;
     596             : }
     597             : 
     598             : 
     599             : /*
     600             :  * Delete session data.
     601             :  * PARAMETERS: PS_DESTROY_ARGS in php_session.h
     602             :  * RETURN VALUE: SUCCESS or FAILURE.
     603             :  *
     604             :  * PS_DESTROY_FUNC() must remove the session data specified by *key from
     605             :  * session data storage unconditionally. It must not return FAILURE for
     606             :  * non-existent session data.
     607             :  * *mod_data, *key are guaranteed to have non-NULL values.
     608             :  */
     609         210 : PS_DESTROY_FUNC(files)
     610             : {
     611             :         char buf[MAXPATHLEN];
     612         210 :         PS_FILES_DATA;
     613             : 
     614         210 :         if (!ps_files_path_create(buf, sizeof(buf), data, ZSTR_VAL(key))) {
     615           1 :                 return FAILURE;
     616             :         }
     617             : 
     618         209 :         if (data->fd != -1) {
     619         209 :                 ps_files_close(data);
     620             : 
     621         209 :                 if (VCWD_UNLINK(buf) == -1) {
     622             :                         /* This is a little safety check for instances when we are dealing with a regenerated session
     623             :                          * that was not yet written to disk. */
     624           6 :                         if (!VCWD_ACCESS(buf, F_OK)) {
     625           0 :                                 return FAILURE;
     626             :                         }
     627             :                 }
     628             :         }
     629             : 
     630         209 :         return SUCCESS;
     631             : }
     632             : 
     633             : 
     634             : /*
     635             :  * Cleanup expired session data.
     636             :  * PARAMETERS: PS_GC_ARGS in php_session.h
     637             :  * RETURN VALUE: SUCCESS or FAILURE. Number of deleted records(int *nrdels(default=-1)).
     638             :  *
     639             :  * PS_GC_FUNC() must remove session data that are not accessed
     640             :  * 'session.maxlifetime'(seconds). If storage does not need manual GC, it
     641             :  * may return SUCCESS simply. (e.g. Memcache) It must set number of records
     642             :  * deleted(nrdels).
     643             :  * *mod_data is guaranteed to have non-NULL value.
     644             :  */
     645           9 : PS_GC_FUNC(files)
     646             : {
     647           9 :         PS_FILES_DATA;
     648             : 
     649             :         /* We don't perform any cleanup, if dirdepth is larger than 0.
     650             :            we return SUCCESS, since all cleanup should be handled by
     651             :            an external entity (i.e. find -ctime x | xargs rm) */
     652             : 
     653           9 :         if (data->dirdepth == 0) {
     654           9 :                 *nrdels = ps_files_cleanup_dir(data->basedir, maxlifetime);
     655             :         } else {
     656           0 :                 *nrdels = -1; // Cannot process multiple depth save dir
     657             :         }
     658             : 
     659           9 :         return *nrdels;
     660             : }
     661             : 
     662             : 
     663             : /*
     664             :  * Create session ID.
     665             :  * PARAMETERS: PS_CREATE_SID_ARGS in php_session.h
     666             :  * RETURN VALUE: Valid session ID(zend_string *) or NULL for FAILURE.
     667             :  *
     668             :  * PS_CREATE_SID_FUNC() must check collision. i.e. Check session data if
     669             :  * new sid exists already.
     670             :  * *mod_data is guaranteed to have non-NULL value.
     671             :  * NOTE: Default php_session_create_id() does not check collision. If
     672             :  * NULL is returned, session module create new ID by using php_session_create_id().
     673             :  * If php_session_create_id() fails due to invalid configuration, it raises E_ERROR.
     674             :  * NULL return value checks from php_session_create_id() is not required generally.
     675             :  */
     676         247 : PS_CREATE_SID_FUNC(files)
     677             : {
     678             :         zend_string *sid;
     679         247 :         int maxfail = 3;
     680         247 :         PS_FILES_DATA;
     681             : 
     682             :         do {
     683         247 :                 sid = php_session_create_id((void**)&data);
     684         247 :                 if (!sid) {
     685           0 :                         if (--maxfail < 0) {
     686           0 :                                 return NULL;
     687             :                         } else {
     688           0 :                                 continue;
     689             :                         }
     690             :                 }
     691             :                 /* Check collision */
     692             :                 /* FIXME: mod_data(data) should not be NULL (User handler could be NULL) */
     693         247 :                 if (data && ps_files_key_exists(data, ZSTR_VAL(sid)) == SUCCESS) {
     694           0 :                         if (sid) {
     695             :                                 zend_string_release(sid);
     696           0 :                                 sid = NULL;
     697             :                         }
     698           0 :                         if (--maxfail < 0) {
     699           0 :                                 return NULL;
     700             :                         }
     701             :                 }
     702         247 :         } while(!sid);
     703             : 
     704         247 :         return sid;
     705             : }
     706             : 
     707             : 
     708             : /*
     709             :  * Check session ID existence for use_strict_mode support.
     710             :  * PARAMETERS: PS_VALIDATE_SID_ARGS in php_session.h
     711             :  * RETURN VALUE: SUCCESS or FAILURE.
     712             :  *
     713             :  * Return SUCCESS for valid key(already existing session).
     714             :  * Return FAILURE for invalid key(non-existing session).
     715             :  * *mod_data, *key are guaranteed to have non-NULL values.
     716             :  */
     717           4 : PS_VALIDATE_SID_FUNC(files)
     718             : {
     719           4 :         PS_FILES_DATA;
     720             : 
     721           4 :         return ps_files_key_exists(data, ZSTR_VAL(key));
     722             : }
     723             : 
     724             : /*
     725             :  * Local variables:
     726             :  * tab-width: 4
     727             :  * c-basic-offset: 4
     728             :  * End:
     729             :  * vim600: sw=4 ts=4 fdm=marker
     730             :  * vim<600: sw=4 ts=4
     731             :  */

Generated by: LCOV version 1.10

Generated at Wed, 17 Jul 2019 14:54:06 +0000 (30 hours ago)

Copyright © 2005-2019 The PHP Group
All rights reserved.