phpdbg_wait.c 13 KB

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