root/sapi/phpdbg/phpdbg_wait.c

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

DEFINITIONS

This source file includes following definitions.
  1. ZEND_EXTERN_MODULE_GLOBALS
  2. phpdbg_dearm_autoglobals
  3. phpdbg_array_data_compare
  4. phpdbg_array_intersect_init
  5. phpdbg_array_intersect
  6. phpdbg_webdata_decompress
  7. PHPDBG_COMMAND

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-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: Bob Weinand <bwoebi@php.net>                                |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 #include "phpdbg_wait.h"
  20 #include "phpdbg_prompt.h"
  21 #include "ext/standard/php_var.h"
  22 #include "ext/standard/basic_functions.h"
  23 
  24 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
  25 
  26 static void phpdbg_rebuild_http_globals_array(int type, const char *name) {
  27         zval *zvp;
  28         if (Z_TYPE(PG(http_globals)[type]) != IS_UNDEF) {
  29                 zval_dtor(&PG(http_globals)[type]);
  30         }
  31         if ((zvp = zend_hash_str_find(&EG(symbol_table), name, strlen(name)))) {
  32                 Z_ADDREF_P(zvp);
  33                 PG(http_globals)[type] = *zvp;
  34         }
  35 }
  36 
  37 
  38 static int phpdbg_dearm_autoglobals(zend_auto_global *auto_global) {
  39         if (ZSTR_LEN(auto_global->name) != sizeof("GLOBALS") - 1 || memcmp(ZSTR_VAL(auto_global->name), "GLOBALS", sizeof("GLOBALS") - 1)) {
  40                 auto_global->armed = 0;
  41         }
  42 
  43         return ZEND_HASH_APPLY_KEEP;
  44 }
  45 
  46 typedef struct {
  47         HashTable *ht[2];
  48         HashPosition pos[2];
  49 } phpdbg_intersect_ptr;
  50 
  51 static int phpdbg_array_data_compare(const void *a, const void *b) {
  52         Bucket *f, *s;
  53         int result;
  54         zval *first, *second;
  55 
  56         f = *((Bucket **) a);
  57         s = *((Bucket **) b);
  58 
  59         first = &f->val;
  60         second = &s->val;
  61 
  62         result = string_compare_function(first, second);
  63 
  64         if (result < 0) {
  65                 return -1;
  66         } else if (result > 0) {
  67                 return 1;
  68         }
  69 
  70         return 0;
  71 }
  72 
  73 static void phpdbg_array_intersect_init(phpdbg_intersect_ptr *info, HashTable *ht1, HashTable *ht2) {
  74         info->ht[0] = ht1;
  75         info->ht[1] = ht2;
  76 
  77         zend_hash_sort(info->ht[0], (compare_func_t) phpdbg_array_data_compare, 0);
  78         zend_hash_sort(info->ht[1], (compare_func_t) phpdbg_array_data_compare, 0);
  79 
  80         zend_hash_internal_pointer_reset_ex(info->ht[0], &info->pos[0]);
  81         zend_hash_internal_pointer_reset_ex(info->ht[1], &info->pos[1]);
  82 }
  83 
  84 /* -1 => first array, 0 => both arrays equal, 1 => second array */
  85 static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval **ptr) {
  86         int ret;
  87         zval *zvp[2];
  88         int invalid = !info->ht[0] + !info->ht[1];
  89 
  90         if (invalid > 0) {
  91                 invalid = !info->ht[0];
  92 
  93                 if (!(*ptr = zend_hash_get_current_data_ex(info->ht[invalid], &info->pos[invalid]))) {
  94                         return 0;
  95                 }
  96 
  97                 zend_hash_move_forward_ex(info->ht[invalid], &info->pos[invalid]);
  98 
  99                 return invalid ? 1 : -1;
 100         }
 101 
 102         if (!(zvp[0] = zend_hash_get_current_data_ex(info->ht[0], &info->pos[0]))) {
 103                 info->ht[0] = NULL;
 104                 return phpdbg_array_intersect(info, ptr);
 105         }
 106         if (!(zvp[1] = zend_hash_get_current_data_ex(info->ht[1], &info->pos[1]))) {
 107                 info->ht[1] = NULL;
 108                 return phpdbg_array_intersect(info, ptr);
 109         }
 110 
 111         ret = zend_binary_zval_strcmp(zvp[0], zvp[1]);
 112 
 113         if (ret <= 0) {
 114                 *ptr = zvp[0];
 115                 zend_hash_move_forward_ex(info->ht[0], &info->pos[0]);
 116         }
 117         if (ret >= 0) {
 118                 *ptr = zvp[1];
 119                 zend_hash_move_forward_ex(info->ht[1], &info->pos[1]);
 120         }
 121 
 122         return ret;
 123 }
 124 
 125 void phpdbg_webdata_decompress(char *msg, int len) {
 126         zval *free_zv = NULL;
 127         zval zv, *zvp;
 128         HashTable *ht;
 129         php_unserialize_data_t var_hash;
 130 
 131         PHP_VAR_UNSERIALIZE_INIT(var_hash);
 132         if (!php_var_unserialize(&zv, (const unsigned char **) &msg, (unsigned char *) msg + len, &var_hash)) {
 133                 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
 134                 phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed serialized was sent to this socket, arborting");
 135                 return;
 136         }
 137         PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
 138 
 139         ht = Z_ARRVAL(zv);
 140 
 141         /* Reapply symbol table */
 142         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("GLOBALS"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
 143                 {
 144                         zval *srv;
 145                         if ((srv = zend_hash_str_find(Z_ARRVAL_P(zvp), ZEND_STRL("_SERVER"))) && Z_TYPE_P(srv) == IS_ARRAY) {
 146                                 zval *script;
 147                                 if ((script = zend_hash_str_find(Z_ARRVAL_P(srv), ZEND_STRL("SCRIPT_FILENAME"))) && Z_TYPE_P(script) == IS_STRING) {
 148                                         phpdbg_param_t param;
 149                                         param.str = Z_STRVAL_P(script);
 150                                         PHPDBG_COMMAND_HANDLER(exec)(&param);
 151                                 }
 152                         }
 153                 }
 154 
 155                 PG(auto_globals_jit) = 0;
 156                 zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_dearm_autoglobals);
 157 
 158                 zend_hash_clean(&EG(symbol_table));
 159                 EG(symbol_table) = *Z_ARR_P(zvp);
 160 
 161                 /* Rebuild cookies, env vars etc. from GLOBALS (PG(http_globals)) */
 162                 phpdbg_rebuild_http_globals_array(TRACK_VARS_POST, "_POST");
 163                 phpdbg_rebuild_http_globals_array(TRACK_VARS_GET, "_GET");
 164                 phpdbg_rebuild_http_globals_array(TRACK_VARS_COOKIE, "_COOKIE");
 165                 phpdbg_rebuild_http_globals_array(TRACK_VARS_SERVER, "_SERVER");
 166                 phpdbg_rebuild_http_globals_array(TRACK_VARS_ENV, "_ENV");
 167                 phpdbg_rebuild_http_globals_array(TRACK_VARS_FILES, "_FILES");
 168 
 169                 Z_ADDREF_P(zvp);
 170                 free_zv = zvp;
 171         }
 172 
 173         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("input"))) && Z_TYPE_P(zvp) == IS_STRING) {
 174                 if (SG(request_info).request_body) {
 175                         php_stream_close(SG(request_info).request_body);
 176                 }
 177                 SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
 178                 php_stream_truncate_set_size(SG(request_info).request_body, 0);
 179                 php_stream_write(SG(request_info).request_body, Z_STRVAL_P(zvp), Z_STRLEN_P(zvp));
 180         }
 181 
 182         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("cwd"))) && Z_TYPE_P(zvp) == IS_STRING) {
 183                 if (VCWD_CHDIR(Z_STRVAL_P(zvp)) == SUCCESS) {
 184                         if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) {
 185                                 efree(BG(CurrentStatFile));
 186                                 BG(CurrentStatFile) = NULL;
 187                         }
 188                         if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) {
 189                                 efree(BG(CurrentLStatFile));
 190                                 BG(CurrentLStatFile) = NULL;
 191                         }
 192                 }
 193         }
 194 
 195         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("sapi_name"))) && (Z_TYPE_P(zvp) == IS_STRING || Z_TYPE_P(zvp) == IS_NULL)) {
 196                 if (PHPDBG_G(sapi_name_ptr)) {
 197                         free(PHPDBG_G(sapi_name_ptr));
 198                 }
 199                 if (Z_TYPE_P(zvp) == IS_STRING) {
 200                         PHPDBG_G(sapi_name_ptr) = sapi_module.name = strdup(Z_STRVAL_P(zvp));
 201                 } else {
 202                         PHPDBG_G(sapi_name_ptr) = sapi_module.name = NULL;
 203                 }
 204         }
 205 
 206         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("modules"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
 207                 phpdbg_intersect_ptr pos;
 208                 zval *module;
 209                 zend_module_entry *mod;
 210                 HashTable zv_registry;
 211 
 212                 /* intersect modules, unregister modules loaded "too much", announce not yet registered modules (phpdbg_notice) */
 213 
 214                 zend_hash_init(&zv_registry, zend_hash_num_elements(&module_registry), 0, ZVAL_PTR_DTOR, 0);
 215                 ZEND_HASH_FOREACH_PTR(&module_registry, mod) {
 216                         if (mod->name) {
 217                                 zval value;
 218                                 ZVAL_NEW_STR(&value, zend_string_init(mod->name, strlen(mod->name), 0));
 219                                 zend_hash_next_index_insert(&zv_registry, &value);
 220                         }
 221                 } ZEND_HASH_FOREACH_END();
 222 
 223                 phpdbg_array_intersect_init(&pos, &zv_registry, Z_ARRVAL_P(zvp));
 224                 do {
 225                         int mode = phpdbg_array_intersect(&pos, &module);
 226                         if (mode < 0) {
 227                                 // loaded module, but not needed
 228                                 if (strcmp(PHPDBG_NAME, Z_STRVAL_P(module))) {
 229                                         zend_hash_del(&module_registry, Z_STR_P(module));
 230                                 }
 231                         } else if (mode > 0) {
 232                                 // not loaded module
 233                                 if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_P(module))) {
 234                                         phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", (int) Z_STRLEN_P(module), Z_STRVAL_P(module), (int) Z_STRLEN_P(module), Z_STRVAL_P(module));
 235                                 }
 236                         }
 237                 } while (module);
 238 
 239                 zend_hash_clean(&zv_registry);
 240         }
 241 
 242         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("extensions"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
 243                 zend_extension *extension;
 244                 zend_llist_position pos;
 245                 zval *name = NULL;
 246                 zend_string *strkey;
 247 
 248                 extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
 249                 while (extension) {
 250                         extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
 251 
 252                         /* php_serach_array() body should be in some ZEND_API function... */
 253                         ZEND_HASH_FOREACH_STR_KEY_PTR(Z_ARRVAL_P(zvp), strkey, name) {
 254                                 if (Z_TYPE_P(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_P(name), Z_STRLEN_P(name))) {
 255                                         break;
 256                                 }
 257                                 name = NULL;
 258                         } ZEND_HASH_FOREACH_END();
 259 
 260                         if (name) {
 261                                 /* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */
 262                                 zend_llist_element *elm = pos;
 263                                 if (elm->prev) {
 264                                         elm->prev->next = elm->next;
 265                                 } else {
 266                                         zend_extensions.head = elm->next;
 267                                 }
 268                                 if (elm->next) {
 269                                         elm->next->prev = elm->prev;
 270                                 } else {
 271                                         zend_extensions.tail = elm->prev;
 272                                 }
 273 #if ZEND_EXTENSIONS_SUPPORT
 274                                 if (extension->shutdown) {
 275                                         extension->shutdown(extension);
 276                                 }
 277 #endif
 278                                 if (zend_extensions.dtor) {
 279                                         zend_extensions.dtor(elm->data);
 280                                 }
 281                                 pefree(elm, zend_extensions.persistent);
 282                                 zend_extensions.count--;
 283                         } else {
 284                                 zend_hash_del(Z_ARRVAL_P(zvp), strkey);
 285                         }
 286                 }
 287 
 288                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) {
 289                         if (Z_TYPE_P(name) == IS_STRING) {
 290                                 phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", (int) Z_STRLEN_P(name), Z_STRVAL_P(name));
 291                         }
 292                 } ZEND_HASH_FOREACH_END();
 293         }
 294 
 295         zend_ini_deactivate();
 296 
 297         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("systemini"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
 298                 zval *ini_entry;
 299                 zend_ini_entry *original_ini;
 300                 zend_string *key;
 301 
 302                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) {
 303                         if (key && Z_TYPE_P(ini_entry) == IS_STRING) {
 304                                 if ((original_ini = zend_hash_find_ptr(EG(ini_directives), key))) {
 305                                         if (!original_ini->on_modify || original_ini->on_modify(original_ini, Z_STR_P(ini_entry), original_ini->mh_arg1, original_ini->mh_arg2, original_ini->mh_arg3, ZEND_INI_STAGE_ACTIVATE) == SUCCESS) {
 306                                                 if (original_ini->modified && original_ini->orig_value != original_ini->value) {
 307                                                         efree(original_ini->value);
 308                                                 }
 309                                                 original_ini->value = Z_STR_P(ini_entry);
 310                                                 Z_ADDREF_P(ini_entry); /* don't free the string */
 311                                         }
 312                                 }
 313                         }
 314                 } ZEND_HASH_FOREACH_END();
 315         }
 316 
 317         if ((zvp = zend_hash_str_find(ht, ZEND_STRL("userini"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
 318                 zval *ini_entry;
 319                 zend_string *key;
 320 
 321                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) {
 322                         if (key && Z_TYPE_P(ini_entry) == IS_STRING) {
 323                                 zend_alter_ini_entry_ex(key, Z_STR_P(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1);
 324                         }
 325                 } ZEND_HASH_FOREACH_END();
 326         }
 327 
 328         zval_dtor(&zv);
 329         if (free_zv) {
 330                 /* separate freeing to not dtor the symtable too, just the container zval... */
 331                 efree(free_zv);
 332         }
 333 
 334         /* Reapply raw input */
 335         /* ??? */
 336 }
 337 
 338 PHPDBG_COMMAND(wait) /* {{{ */
 339 {
 340 #ifndef PHP_WIN32
 341         struct sockaddr_un local, remote;
 342         int rlen, sr, sl;
 343         unlink(PHPDBG_G(socket_path));
 344         if (PHPDBG_G(socket_server_fd) == -1) {
 345                 int len;
 346                 PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0);
 347 
 348                 local.sun_family = AF_UNIX;
 349                 strcpy(local.sun_path, PHPDBG_G(socket_path));
 350                 len = strlen(local.sun_path) + sizeof(local.sun_family);
 351                 if (bind(sl, (struct sockaddr *)&local, len) == -1) {
 352                         phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path));
 353                         return FAILURE;
 354                 }
 355 
 356                 chmod(PHPDBG_G(socket_path), 0666);
 357 
 358                 listen(sl, 2);
 359         } else {
 360                 sl = PHPDBG_G(socket_server_fd);
 361         }
 362 
 363         rlen = sizeof(remote);
 364         sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen);
 365 
 366         char msglen[5];
 367         int recvd = 4;
 368 
 369         do {
 370                 recvd -= recv(sr, &(msglen[4 - recvd]), recvd, 0);
 371         } while (recvd > 0);
 372 
 373         recvd = *(size_t *) msglen;
 374         char *data = emalloc(recvd);
 375 
 376         do {
 377                 recvd -= recv(sr, &(data[(*(int *) msglen) - recvd]), recvd, 0);
 378         } while (recvd > 0);
 379 
 380         phpdbg_webdata_decompress(data, *(int *) msglen);
 381 
 382         if (PHPDBG_G(socket_fd) != -1) {
 383                 close(PHPDBG_G(socket_fd));
 384         }
 385         PHPDBG_G(socket_fd) = sr;
 386 
 387         efree(data);
 388 
 389         phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing");
 390 #endif
 391 
 392         return SUCCESS;
 393 } /* }}} */

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