You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
13 KiB

  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. #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_dtor(&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. /* php_serach_array() body should be in some ZEND_API function... */
  209. ZEND_HASH_FOREACH_STR_KEY_PTR(Z_ARRVAL_P(zvp), strkey, name) {
  210. if (Z_TYPE_P(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_P(name), Z_STRLEN_P(name))) {
  211. break;
  212. }
  213. name = NULL;
  214. } ZEND_HASH_FOREACH_END();
  215. if (name) {
  216. /* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */
  217. zend_llist_element *elm = pos;
  218. if (elm->prev) {
  219. elm->prev->next = elm->next;
  220. } else {
  221. zend_extensions.head = elm->next;
  222. }
  223. if (elm->next) {
  224. elm->next->prev = elm->prev;
  225. } else {
  226. zend_extensions.tail = elm->prev;
  227. }
  228. #if ZEND_EXTENSIONS_SUPPORT
  229. if (extension->shutdown) {
  230. extension->shutdown(extension);
  231. }
  232. #endif
  233. if (zend_extensions.dtor) {
  234. zend_extensions.dtor(elm->data);
  235. }
  236. pefree(elm, zend_extensions.persistent);
  237. zend_extensions.count--;
  238. } else {
  239. /* zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &hpos);
  240. if (Z_TYPE(key) == IS_LONG) {
  241. zend_hash_index_del(Z_ARRVAL_PP(zvpp), Z_LVAL(key));
  242. }
  243. */
  244. zend_hash_del(Z_ARRVAL_P(zvp), strkey);
  245. }
  246. }
  247. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) {
  248. if (Z_TYPE_P(name) == IS_STRING) {
  249. 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));
  250. }
  251. } ZEND_HASH_FOREACH_END();
  252. }
  253. zend_ini_deactivate();
  254. if ((zvp = zend_hash_str_find(ht, ZEND_STRL("systemini"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
  255. zval *ini_entry;
  256. zend_ini_entry *original_ini;
  257. zend_string *key;
  258. ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) {
  259. if (key && Z_TYPE_P(ini_entry) == IS_STRING) {
  260. if ((original_ini = zend_hash_find_ptr(EG(ini_directives), key))) {
  261. 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) {
  262. if (original_ini->modified && original_ini->orig_value != original_ini->value) {
  263. efree(original_ini->value);
  264. }
  265. original_ini->value = Z_STR_P(ini_entry);
  266. Z_ADDREF_P(ini_entry); /* don't free the string */
  267. }
  268. }
  269. }
  270. } ZEND_HASH_FOREACH_END();
  271. }
  272. if ((zvp = zend_hash_str_find(ht, ZEND_STRL("userini"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
  273. zval *ini_entry;
  274. zend_string *key;
  275. ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) {
  276. if (key && Z_TYPE_P(ini_entry) == IS_STRING) {
  277. zend_alter_ini_entry_ex(key, Z_STR_P(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1);
  278. }
  279. } ZEND_HASH_FOREACH_END();
  280. }
  281. zval_dtor(&zv);
  282. if (free_zv) {
  283. /* separate freeing to not dtor the symtable too, just the container zval... */
  284. efree(free_zv);
  285. }
  286. /* Reapply raw input */
  287. /* ??? */
  288. }
  289. PHPDBG_COMMAND(wait) /* {{{ */
  290. {
  291. #ifndef PHP_WIN32
  292. struct sockaddr_un local, remote;
  293. int rlen, sr, sl;
  294. unlink(PHPDBG_G(socket_path));
  295. if (PHPDBG_G(socket_server_fd) == -1) {
  296. int len;
  297. PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0);
  298. local.sun_family = AF_UNIX;
  299. strcpy(local.sun_path, PHPDBG_G(socket_path));
  300. len = strlen(local.sun_path) + sizeof(local.sun_family);
  301. if (bind(sl, (struct sockaddr *)&local, len) == -1) {
  302. 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));
  303. return FAILURE;
  304. }
  305. chmod(PHPDBG_G(socket_path), 0666);
  306. listen(sl, 2);
  307. } else {
  308. sl = PHPDBG_G(socket_server_fd);
  309. }
  310. rlen = sizeof(remote);
  311. sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen);
  312. char msglen[5];
  313. int recvd = 4;
  314. do {
  315. recvd -= recv(sr, &(msglen[4 - recvd]), recvd, 0);
  316. } while (recvd > 0);
  317. recvd = *(size_t *) msglen;
  318. char *data = emalloc(recvd);
  319. do {
  320. recvd -= recv(sr, &(data[(*(int *) msglen) - recvd]), recvd, 0);
  321. } while (recvd > 0);
  322. phpdbg_webdata_decompress(data, *(int *) msglen);
  323. if (PHPDBG_G(socket_fd) != -1) {
  324. close(PHPDBG_G(socket_fd));
  325. }
  326. PHPDBG_G(socket_fd) = sr;
  327. efree(data);
  328. phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing");
  329. #endif
  330. return SUCCESS;
  331. } /* }}} */