Back to index

php5  5.3.10
Classes | Defines | Functions | Variables
mod_files.c File Reference
#include "php.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include "php_session.h"
#include "mod_files.h"
#include "ext/standard/flock_compat.h"
#include "php_open_temporary_file.h"

Go to the source code of this file.

Classes

struct  ps_files

Defines

#define FILE_PREFIX   "sess_"
#define O_BINARY   0
#define PS_FILES_DATA   ps_files *data = PS_GET_MOD_DATA()

Functions

static int ps_files_valid_key (const char *key)
static char * ps_files_path_create (char *buf, size_t buflen, ps_files *data, const char *key)
static void ps_files_close (ps_files *data)
static void ps_files_open (ps_files *data, const char *key TSRMLS_DC)
static int ps_files_cleanup_dir (const char *dirname, int maxlifetime TSRMLS_DC)
 PS_OPEN_FUNC (files)
 PS_CLOSE_FUNC (files)
 PS_READ_FUNC (files)
 PS_WRITE_FUNC (files)
 PS_DESTROY_FUNC (files)
 PS_GC_FUNC (files)

Variables

ps_module ps_mod_files

Class Documentation

struct ps_files

Definition at line 53 of file mod_files.c.

Class Members
char * basedir
size_t basedir_len
size_t dirdepth
int fd
int filemode
char * lastkey
size_t st_size

Define Documentation

#define FILE_PREFIX   "sess_"

Definition at line 51 of file mod_files.c.

#define O_BINARY   0

Definition at line 130 of file mod_files.c.

#define PS_FILES_DATA   ps_files *data = PS_GET_MOD_DATA()

Definition at line 262 of file mod_files.c.


Function Documentation

PS_CLOSE_FUNC ( files  )

Definition at line 328 of file mod_files.c.

{
       PS_FILES_DATA;

       ps_files_close(data);

       if (data->lastkey) {
              efree(data->lastkey);
       }

       efree(data->basedir);
       efree(data);
       *mod_data = NULL;

       return SUCCESS;
}

Here is the call graph for this function:

PS_DESTROY_FUNC ( files  )

Definition at line 424 of file mod_files.c.

{
       char buf[MAXPATHLEN];
       PS_FILES_DATA;

       if (!ps_files_path_create(buf, sizeof(buf), data, key)) {
              return FAILURE;
       }

       if (data->fd != -1) {
              ps_files_close(data);

              if (VCWD_UNLINK(buf) == -1) {
                     /* This is a little safety check for instances when we are dealing with a regenerated session
                      * that was not yet written to disk. */
                     if (!VCWD_ACCESS(buf, F_OK)) {
                            return FAILURE;
                     }
              }
       }

       return SUCCESS;
}

Here is the call graph for this function:

static int ps_files_cleanup_dir ( const char *  dirname,
int maxlifetime  TSRMLS_DC 
) [static]

Definition at line 209 of file mod_files.c.

{
       DIR *dir;
       char dentry[sizeof(struct dirent) + MAXPATHLEN];
       struct dirent *entry = (struct dirent *) &dentry;
       struct stat sbuf;
       char buf[MAXPATHLEN];
       time_t now;
       int nrdels = 0;
       size_t dirname_len;

       dir = opendir(dirname);
       if (!dir) {
              php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ps_files_cleanup_dir: opendir(%s) failed: %s (%d)", dirname, strerror(errno), errno);
              return (0);
       }

       time(&now);

       dirname_len = strlen(dirname);

       /* Prepare buffer (dirname never changes) */
       memcpy(buf, dirname, dirname_len);
       buf[dirname_len] = PHP_DIR_SEPARATOR;

       while (php_readdir_r(dir, (struct dirent *) dentry, &entry) == 0 && entry) {
              /* does the file start with our prefix? */
              if (!strncmp(entry->d_name, FILE_PREFIX, sizeof(FILE_PREFIX) - 1)) {
                     size_t entry_len = strlen(entry->d_name);

                     /* does it fit into our buffer? */
                     if (entry_len + dirname_len + 2 < MAXPATHLEN) {
                            /* create the full path.. */
                            memcpy(buf + dirname_len + 1, entry->d_name, entry_len);

                            /* NUL terminate it and */
                            buf[dirname_len + entry_len + 1] = '\0';

                            /* check whether its last access was more than maxlifet ago */
                            if (VCWD_STAT(buf, &sbuf) == 0 &&
                                          (now - sbuf.st_mtime) > maxlifetime) {
                                   VCWD_UNLINK(buf);
                                   nrdels++;
                            }
                     }
              }
       }

       closedir(dir);

       return (nrdels);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ps_files_close ( ps_files data) [static]

Definition at line 133 of file mod_files.c.

{
       if (data->fd != -1) {
#ifdef PHP_WIN32
              /* On Win32 locked files that are closed without being explicitly unlocked
                 will be unlocked only when "system resources become available". */
              flock(data->fd, LOCK_UN);
#endif
              close(data->fd);
              data->fd = -1;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ps_files_open ( ps_files data,
const char *key  TSRMLS_DC 
) [static]

Definition at line 146 of file mod_files.c.

{
       char buf[MAXPATHLEN];

       if (data->fd < 0 || !data->lastkey || strcmp(key, data->lastkey)) {
              if (data->lastkey) {
                     efree(data->lastkey);
                     data->lastkey = NULL;
              }

              ps_files_close(data);

              if (!ps_files_valid_key(key)) {
                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,'");
                     PS(invalid_session_id) = 1;
                     return;
              }
              if (!ps_files_path_create(buf, sizeof(buf), data, key)) {
                     return;
              }

              data->lastkey = estrdup(key);

              data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY, data->filemode);

              if (data->fd != -1) {
#ifndef PHP_WIN32
                     /* check to make sure that the opened file is not a symlink, linking to data outside of allowable dirs */
                     if (PG(safe_mode) || PG(open_basedir)) {
                            struct stat sbuf;

                            if (fstat(data->fd, &sbuf)) {
                                   close(data->fd);
                                   return;
                            }
                            if (
                                   S_ISLNK(sbuf.st_mode) &&
                                   (
                                          php_check_open_basedir(buf TSRMLS_CC) ||
                                          (PG(safe_mode) && !php_checkuid(buf, NULL, CHECKUID_CHECK_FILE_AND_DIR))
                                   )
                            ) {
                                   close(data->fd);
                                   return;
                            }
                     }
#endif
                     flock(data->fd, LOCK_EX);

#ifdef F_SETFD
# ifndef FD_CLOEXEC
#  define FD_CLOEXEC 1
# endif
                     if (fcntl(data->fd, F_SETFD, FD_CLOEXEC)) {
                            php_error_docref(NULL TSRMLS_CC, E_WARNING, "fcntl(%d, F_SETFD, FD_CLOEXEC) failed: %s (%d)", data->fd, strerror(errno), errno);
                     }
#endif
              } else {
                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "open(%s, O_RDWR) failed: %s (%d)", buf, strerror(errno), errno);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* ps_files_path_create ( char *  buf,
size_t  buflen,
ps_files data,
const char *  key 
) [static]

Definition at line 99 of file mod_files.c.

{
       size_t key_len;
       const char *p;
       int i;
       int n;

       key_len = strlen(key);
       if (key_len <= data->dirdepth ||
              buflen < (strlen(data->basedir) + 2 * data->dirdepth + key_len + 5 + sizeof(FILE_PREFIX))) {
              return NULL;
       }

       p = key;
       memcpy(buf, data->basedir, data->basedir_len);
       n = data->basedir_len;
       buf[n++] = PHP_DIR_SEPARATOR;
       for (i = 0; i < (int)data->dirdepth; i++) {
              buf[n++] = *p++;
              buf[n++] = PHP_DIR_SEPARATOR;
       }
       memcpy(buf + n, FILE_PREFIX, sizeof(FILE_PREFIX) - 1);
       n += sizeof(FILE_PREFIX) - 1;
       memcpy(buf + n, key, key_len);
       n += key_len;
       buf[n] = '\0';

       return buf;
}

Here is the caller graph for this function:

static int ps_files_valid_key ( const char *  key) [static]

Definition at line 69 of file mod_files.c.

{
       size_t len;
       const char *p;
       char c;
       int ret = 1;

       for (p = key; (c = *p); p++) {
              /* valid characters are a..z,A..Z,0..9 */
              if (!((c >= 'a' && c <= 'z')
                            || (c >= 'A' && c <= 'Z')
                            || (c >= '0' && c <= '9')
                            || c == ','
                            || c == '-')) {
                     ret = 0;
                     break;
              }
       }

       len = p - key;

       /* Somewhat arbitrary length limit here, but should be way more than
          anyone needs and avoids file-level warnings later on if we exceed MAX_PATH */
       if (len == 0 || len > 128) {
              ret = 0;
       }

       return ret;
}

Here is the caller graph for this function:

PS_GC_FUNC ( files  )

Definition at line 448 of file mod_files.c.

{
       PS_FILES_DATA;

       /* we don't perform any cleanup, if dirdepth is larger than 0.
          we return SUCCESS, since all cleanup should be handled by
          an external entity (i.e. find -ctime x | xargs rm) */

       if (data->dirdepth == 0) {
              *nrdels = ps_files_cleanup_dir(data->basedir, maxlifetime TSRMLS_CC);
       }

       return SUCCESS;
}

Here is the call graph for this function:

PS_OPEN_FUNC ( files  )

Definition at line 264 of file mod_files.c.

{
       ps_files *data;
       const char *p, *last;
       const char *argv[3];
       int argc = 0;
       size_t dirdepth = 0;
       int filemode = 0600;

       if (*save_path == '\0') {
              /* if save path is an empty string, determine the temporary dir */
              save_path = php_get_temporary_directory();

              if (PG(safe_mode) && (!php_checkuid(save_path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
                     return FAILURE;
              }
              if (php_check_open_basedir(save_path TSRMLS_CC)) {
                     return FAILURE;
              }
       }

       /* split up input parameter */
       last = save_path;
       p = strchr(save_path, ';');
       while (p) {
              argv[argc++] = last;
              last = ++p;
              p = strchr(p, ';');
              if (argc > 1) break;
       }
       argv[argc++] = last;

       if (argc > 1) {
              errno = 0;
              dirdepth = (size_t) strtol(argv[0], NULL, 10);
              if (errno == ERANGE) {
                     php_error(E_WARNING, "The first parameter in session.save_path is invalid");
                     return FAILURE;
              }
       }

       if (argc > 2) {
              errno = 0;
              filemode = strtol(argv[1], NULL, 8);
              if (errno == ERANGE || filemode < 0 || filemode > 07777) {
                     php_error(E_WARNING, "The second parameter in session.save_path is invalid");
                     return FAILURE;
              }
       }
       save_path = argv[argc - 1];

       data = ecalloc(1, sizeof(*data));

       data->fd = -1;
       data->dirdepth = dirdepth;
       data->filemode = filemode;
       data->basedir_len = strlen(save_path);
       data->basedir = estrndup(save_path, data->basedir_len);

       PS_SET_MOD_DATA(data);

       return SUCCESS;
}

Here is the call graph for this function:

PS_READ_FUNC ( files  )

Definition at line 345 of file mod_files.c.

{
       long n;
       struct stat sbuf;
       PS_FILES_DATA;

       ps_files_open(data, key TSRMLS_CC);
       if (data->fd < 0) {
              return FAILURE;
       }

       if (fstat(data->fd, &sbuf)) {
              return FAILURE;
       }

       data->st_size = *vallen = sbuf.st_size;

       if (sbuf.st_size == 0) {
              *val = STR_EMPTY_ALLOC();
              return SUCCESS;
       }

       *val = emalloc(sbuf.st_size);

#if defined(HAVE_PREAD)
       n = pread(data->fd, *val, sbuf.st_size, 0);
#else
       lseek(data->fd, 0, SEEK_SET);
       n = read(data->fd, *val, sbuf.st_size);
#endif

       if (n != sbuf.st_size) {
              if (n == -1) {
                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "read failed: %s (%d)", strerror(errno), errno);
              } else {
                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "read returned less bytes than requested");
              }
              efree(*val);
              return FAILURE;
       }

       return SUCCESS;
}

Here is the call graph for this function:

PS_WRITE_FUNC ( files  )

Definition at line 389 of file mod_files.c.

{
       long n;
       PS_FILES_DATA;

       ps_files_open(data, key TSRMLS_CC);
       if (data->fd < 0) {
              return FAILURE;
       }

       /* Truncate file if the amount of new data is smaller than the existing data set. */

       if (vallen < (int)data->st_size) {
              ftruncate(data->fd, 0);
       }

#if defined(HAVE_PWRITE)
       n = pwrite(data->fd, val, vallen, 0);
#else
       lseek(data->fd, 0, SEEK_SET);
       n = write(data->fd, val, vallen);
#endif

       if (n != vallen) {
              if (n == -1) {
                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "write failed: %s (%d)", strerror(errno), errno);
              } else {
                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "write wrote less bytes than requested");
              }
              return FAILURE;
       }

       return SUCCESS;
}

Here is the call graph for this function:


Variable Documentation

Initial value:
 {

}

Definition at line 63 of file mod_files.c.