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

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