root/ext/opcache/zend_accelerator_blacklist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_accel_blacklist_init
  2. blacklist_report_regexp_error
  3. zend_accel_blacklist_update_regexp
  4. zend_accel_blacklist_shutdown
  5. zend_accel_blacklist_allocate
  6. zend_accel_blacklist_loadone
  7. zend_accel_blacklist_load
  8. zend_accel_blacklist_is_blacklisted
  9. zend_accel_blacklist_apply

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend OPcache                                                         |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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    | Authors: Andi Gutmans <andi@zend.com>                                |
  16    |          Zeev Suraski <zeev@zend.com>                                |
  17    |          Stanislav Malyshev <stas@zend.com>                          |
  18    |          Dmitry Stogov <dmitry@zend.com>                             |
  19    +----------------------------------------------------------------------+
  20 */
  21 
  22 #include "main/php.h"
  23 #include "main/fopen_wrappers.h"
  24 #include "ZendAccelerator.h"
  25 #include "zend_accelerator_blacklist.h"
  26 
  27 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  28 # include "ext/ereg/php_regex.h"
  29 #else
  30 # include "main/php_regex.h"
  31 #endif
  32 
  33 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  34 # include "ext/standard/php_string.h"
  35 #endif
  36 
  37 #ifdef ZEND_WIN32
  38 # define REGEX_MODE (REG_EXTENDED|REG_NOSUB|REG_ICASE)
  39 #else
  40 # define REGEX_MODE (REG_EXTENDED|REG_NOSUB)
  41 #endif
  42 
  43 #ifdef HAVE_GLOB
  44 #ifdef PHP_WIN32
  45 #include "win32/glob.h"
  46 #else
  47 #include <glob.h>
  48 #endif
  49 #endif
  50 
  51 #define ZEND_BLACKLIST_BLOCK_SIZE       32
  52 
  53 struct _zend_regexp_list {
  54         regex_t           comp_regex;
  55         zend_regexp_list *next;
  56 };
  57 
  58 zend_blacklist accel_blacklist;
  59 
  60 void zend_accel_blacklist_init(zend_blacklist *blacklist)
  61 {
  62         blacklist->pos = 0;
  63         blacklist->size = ZEND_BLACKLIST_BLOCK_SIZE;
  64 
  65         if (blacklist->entries != NULL) {
  66                 zend_accel_blacklist_shutdown(blacklist);
  67         }
  68 
  69         blacklist->entries = (zend_blacklist_entry *) calloc(sizeof(zend_blacklist_entry), blacklist->size);
  70         if (!blacklist->entries) {
  71                 zend_accel_error(ACCEL_LOG_FATAL, "Blacklist initialization: no memory\n");
  72                 return;
  73         }
  74         blacklist->regexp_list = NULL;
  75 }
  76 
  77 static void blacklist_report_regexp_error(regex_t *comp_regex, int reg_err)
  78 {
  79         char *errbuf;
  80         int errsize = regerror(reg_err, comp_regex, NULL, 0);
  81         errbuf = malloc(errsize);
  82         if (!errbuf) {
  83                 zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation: no memory\n");
  84                 return;
  85         }
  86         regerror(reg_err, comp_regex, errbuf, errsize);
  87         zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation: %s\n", errbuf);
  88         free(errbuf);
  89 }
  90 
  91 static void zend_accel_blacklist_update_regexp(zend_blacklist *blacklist)
  92 {
  93         int i, reg_err;
  94         zend_regexp_list **regexp_list_it, *it;
  95         char regexp[12*1024], *p, *end, *c, *backtrack = NULL;
  96 
  97         if (blacklist->pos == 0) {
  98                 /* we have no blacklist to talk about */
  99                 return;
 100         }
 101 
 102         regexp_list_it = &(blacklist->regexp_list);
 103 
 104         regexp[0] = '^';
 105         regexp[1] = '(';
 106         p = regexp + 2;
 107         end = regexp + sizeof(regexp) - sizeof("[^\\\\]*)\0");
 108 
 109         for (i = 0; i < blacklist->pos; ) {
 110                 c = blacklist->entries[i].path;
 111                 if (p + blacklist->entries[i].path_length < end) {
 112                         while (*c && p < end) {
 113                                 switch (*c) {
 114                                         case '?':
 115                                                 c++;
 116 #ifdef ZEND_WIN32
 117                                                 p[0] = '[';                     /* * => [^\\] on Win32 */
 118                                                 p[1] = '^';
 119                                                 p[2] = '\\';
 120                                                 p[3] = '\\';
 121                                                 p[4] = ']';
 122                                                 p += 5;
 123 #else
 124                                                 p[0] = '[';                     /* * => [^/] on *nix */
 125                                                 p[1] = '^';
 126                                                 p[2] = '/';
 127                                                 p[3] = ']';
 128                                                 p += 4;
 129 #endif
 130                                                 break;
 131                                         case '*':
 132                                                 c++;
 133                                                 if (*c == '*') {
 134                                                         c++;
 135                                                         p[0] = '.';                     /* ** => .* */
 136                                                         p[1] = '*';
 137                                                         p += 2;
 138                                                 } else {
 139 #ifdef ZEND_WIN32
 140                                                         p[0] = '[';                     /* * => [^\\]* on Win32 */
 141                                                         p[1] = '^';
 142                                                         p[2] = '\\';
 143                                                         p[3] = '\\';
 144                                                         p[4] = ']';
 145                                                         p[5] = '*';
 146                                                         p += 6;
 147 #else
 148                                                         p[0] = '[';                     /* * => [^/]* on *nix */
 149                                                         p[1] = '^';
 150                                                         p[2] = '/';
 151                                                         p[3] = ']';
 152                                                         p[4] = '*';
 153                                                         p += 5;
 154 #endif
 155                                                 }
 156                                                 break;
 157                                         case '^':
 158                                         case '.':
 159                                         case '[':
 160                                         case ']':
 161                                         case '$':
 162                                         case '(':
 163                                         case ')':
 164                                         case '|':
 165                                         case '+':
 166                                         case '{':
 167                                         case '}':
 168                                         case '\\':
 169                                                 *p++ = '\\';
 170                                                 /* break missing intentionally */
 171                                         default:
 172                                                 *p++ = *c++;
 173                                 }
 174                         }
 175                 }
 176 
 177                 if (*c || i == blacklist->pos - 1) {
 178                         if (*c) {
 179                                 if (!backtrack) {
 180                                         zend_accel_error(ACCEL_LOG_ERROR, "Too long blacklist entry\n");
 181                                 }
 182                                 p = backtrack;
 183                         } else {
 184                                 i++;
 185                         }
 186                         *p++ = ')';
 187                         *p++ = '\0';
 188 
 189                         it = (zend_regexp_list*)malloc(sizeof(zend_regexp_list));
 190                         if (!it) {
 191                                 zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
 192                                 return;
 193                         }
 194                         it->next = NULL;
 195 
 196                         if ((reg_err = regcomp(&it->comp_regex, regexp, REGEX_MODE)) != 0) {
 197                                 blacklist_report_regexp_error(&it->comp_regex, reg_err);
 198                         }
 199                         /* prepare for the next iteration */
 200                         p = regexp + 2;
 201                         *regexp_list_it = it;
 202                         regexp_list_it = &it->next;
 203                 } else {
 204                         backtrack = p;
 205                         *p++ = '|';
 206                         i++;
 207                 }
 208         }
 209 }
 210 
 211 void zend_accel_blacklist_shutdown(zend_blacklist *blacklist)
 212 {
 213         zend_blacklist_entry *p = blacklist->entries, *end = blacklist->entries + blacklist->pos;
 214 
 215         while (p<end) {
 216                 free(p->path);
 217                 p++;
 218         }
 219         free(blacklist->entries);
 220         blacklist->entries = NULL;
 221         if (blacklist->regexp_list) {
 222                 zend_regexp_list *temp, *it = blacklist->regexp_list;
 223                 while (it) {
 224                         regfree(&it->comp_regex);
 225                         temp = it;
 226                         it = it->next;
 227                         free(temp);
 228                 }
 229         }
 230 }
 231 
 232 static inline void zend_accel_blacklist_allocate(zend_blacklist *blacklist)
 233 {
 234         if (blacklist->pos == blacklist->size) {
 235                 blacklist->size += ZEND_BLACKLIST_BLOCK_SIZE;
 236                 blacklist->entries = (zend_blacklist_entry *) realloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size);
 237         }
 238 }
 239 
 240 #ifdef HAVE_GLOB
 241 static void zend_accel_blacklist_loadone(zend_blacklist *blacklist, char *filename)
 242 #else
 243 void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename)
 244 #endif
 245 {
 246         char buf[MAXPATHLEN + 1], real_path[MAXPATHLEN + 1], *blacklist_path = NULL;
 247         FILE *fp;
 248         int path_length, blacklist_path_length;
 249         TSRMLS_FETCH();
 250 
 251         if ((fp = fopen(filename, "r")) == NULL) {
 252                 zend_accel_error(ACCEL_LOG_WARNING, "Cannot load blacklist file: %s\n", filename);
 253                 return;
 254         }
 255 
 256         zend_accel_error(ACCEL_LOG_DEBUG,"Loading blacklist file:  '%s'", filename);
 257 
 258         if (VCWD_REALPATH(filename, buf)) {
 259 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
 260                 blacklist_path_length = php_dirname(buf, strlen(buf));
 261 #else
 262                 blacklist_path_length = zend_dirname(buf, strlen(buf));
 263 #endif
 264                 blacklist_path = zend_strndup(buf, blacklist_path_length);
 265         }
 266 
 267         memset(buf, 0, sizeof(buf));
 268         memset(real_path, 0, sizeof(real_path));
 269 
 270         while (fgets(buf, MAXPATHLEN, fp) != NULL) {
 271                 char *path_dup, *pbuf;
 272                 path_length = strlen(buf);
 273                 if (path_length > 0 && buf[path_length - 1] == '\n') {
 274                         buf[--path_length] = 0;
 275                         if (path_length > 0 && buf[path_length - 1] == '\r') {
 276                                 buf[--path_length] = 0;
 277                         }
 278                 }
 279 
 280                 /* Strip ctrl-m prefix */
 281                 pbuf = &buf[0];
 282                 while (*pbuf == '\r') {
 283                         *pbuf++ = 0;
 284                         path_length--;
 285                 }
 286 
 287                 /* strip \" */
 288                 if (pbuf[0] == '\"' && pbuf[path_length - 1]== '\"') {
 289                         *pbuf++ = 0;
 290                         path_length -= 2;
 291                 }
 292 
 293                 if (path_length == 0) {
 294                         continue;
 295                 }
 296 
 297                 /* skip comments */
 298                 if (pbuf[0]==';') {
 299                         continue;
 300                 }
 301 
 302                 path_dup = zend_strndup(pbuf, path_length);
 303                 if (blacklist_path) {
 304                         expand_filepath_ex(path_dup, real_path, blacklist_path, blacklist_path_length TSRMLS_CC);
 305                 } else {
 306                         expand_filepath(path_dup, real_path TSRMLS_CC);
 307                 }
 308                 path_length = strlen(real_path);
 309 
 310                 free(path_dup);
 311 
 312                 zend_accel_blacklist_allocate(blacklist);
 313                 blacklist->entries[blacklist->pos].path_length = path_length;
 314                 blacklist->entries[blacklist->pos].path = (char *)malloc(path_length + 1);
 315                 if (!blacklist->entries[blacklist->pos].path) {
 316                         zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
 317                         fclose(fp);
 318                         return;
 319                 }
 320                 blacklist->entries[blacklist->pos].id = blacklist->pos;
 321                 memcpy(blacklist->entries[blacklist->pos].path, real_path, path_length + 1);
 322                 blacklist->pos++;
 323         }
 324         fclose(fp);
 325         if (blacklist_path) {
 326                 free(blacklist_path);
 327         }
 328         zend_accel_blacklist_update_regexp(blacklist);
 329 }
 330 
 331 #ifdef HAVE_GLOB
 332 void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename)
 333 {
 334         glob_t globbuf;
 335         int    ret;
 336         unsigned int i;
 337 
 338         memset(&globbuf, 0, sizeof(glob_t));
 339 
 340         ret = glob(filename, 0, NULL, &globbuf);
 341 #ifdef GLOB_NOMATCH
 342         if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
 343 #else
 344         if (!globbuf.gl_pathc) {
 345 #endif
 346                 zend_accel_error(ACCEL_LOG_WARNING, "No blacklist file found matching: %s\n", filename);
 347         } else {
 348                 for(i=0 ; i<globbuf.gl_pathc; i++) {
 349                         zend_accel_blacklist_loadone(blacklist, globbuf.gl_pathv[i]);
 350                 }
 351                 globfree(&globbuf);
 352         }
 353 }
 354 #endif
 355 
 356 zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path)
 357 {
 358         int ret = 0;
 359         zend_regexp_list *regexp_list_it = blacklist->regexp_list;
 360 
 361         if (regexp_list_it == NULL) {
 362                 return 0;
 363         }
 364         while (regexp_list_it != NULL) {
 365                 if (regexec(&(regexp_list_it->comp_regex), verify_path, 0, NULL, 0) == 0) {
 366                         ret = 1;
 367                         break;
 368                 }
 369                 regexp_list_it = regexp_list_it->next;
 370         }
 371         return ret;
 372 }
 373 
 374 void zend_accel_blacklist_apply(zend_blacklist *blacklist, apply_func_arg_t func, void *argument TSRMLS_DC)
 375 {
 376         int i;
 377 
 378         for (i = 0; i < blacklist->pos; i++) {
 379                 func(&blacklist->entries[i], argument TSRMLS_CC);
 380         }
 381 }

/* [<][>][^][v][top][bottom][index][help] */