exec.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  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. | Author: Rasmus Lerdorf <rasmus@php.net> |
  16. | Ilia Alshanetsky <iliaa@php.net> |
  17. +----------------------------------------------------------------------+
  18. */
  19. /* $Id$ */
  20. #include <stdio.h>
  21. #include "php.h"
  22. #include <ctype.h>
  23. #include "php_string.h"
  24. #include "ext/standard/head.h"
  25. #include "ext/standard/file.h"
  26. #include "basic_functions.h"
  27. #include "exec.h"
  28. #include "php_globals.h"
  29. #include "SAPI.h"
  30. #if HAVE_SYS_WAIT_H
  31. #include <sys/wait.h>
  32. #endif
  33. #if HAVE_SIGNAL_H
  34. #include <signal.h>
  35. #endif
  36. #if HAVE_SYS_TYPES_H
  37. #include <sys/types.h>
  38. #endif
  39. #if HAVE_SYS_STAT_H
  40. #include <sys/stat.h>
  41. #endif
  42. #if HAVE_FCNTL_H
  43. #include <fcntl.h>
  44. #endif
  45. #if HAVE_UNISTD_H
  46. #include <unistd.h>
  47. #endif
  48. #if HAVE_LIMITS_H
  49. #include <limits.h>
  50. #endif
  51. #ifdef PHP_WIN32
  52. # include "win32/php_stdint.h"
  53. #else
  54. # if HAVE_INTTYPES_H
  55. # include <inttypes.h>
  56. # elif HAVE_STDINT_H
  57. # include <stdint.h>
  58. # endif
  59. #endif
  60. static int cmd_max_len;
  61. /* {{{ PHP_MINIT_FUNCTION(exec) */
  62. PHP_MINIT_FUNCTION(exec)
  63. {
  64. #ifdef _SC_ARG_MAX
  65. cmd_max_len = sysconf(_SC_ARG_MAX);
  66. if (-1 == cmd_max_len) {
  67. #ifdef _POSIX_ARG_MAX
  68. cmd_max_len = _POSIX_ARG_MAX;
  69. #else
  70. cmd_max_len = 4096;
  71. #endif
  72. }
  73. #elif defined(ARG_MAX)
  74. cmd_max_len = ARG_MAX;
  75. #elif defined(PHP_WIN32)
  76. /* Executed commands will run through cmd.exe. As long as it's the case,
  77. it's just the constant limit.*/
  78. cmd_max_len = 8192;
  79. #else
  80. /* This is just an arbitrary value for the fallback case. */
  81. cmd_max_len = 4096;
  82. #endif
  83. return SUCCESS;
  84. }
  85. /* }}} */
  86. /* {{{ php_exec
  87. * If type==0, only last line of output is returned (exec)
  88. * If type==1, all lines will be printed and last lined returned (system)
  89. * If type==2, all lines will be saved to given array (exec with &$array)
  90. * If type==3, output will be printed binary, no lines will be saved or returned (passthru)
  91. *
  92. */
  93. PHPAPI int php_exec(int type, char *cmd, zval *array, zval *return_value TSRMLS_DC)
  94. {
  95. FILE *fp;
  96. char *buf;
  97. int l = 0, pclose_return;
  98. char *b, *d=NULL;
  99. php_stream *stream;
  100. size_t buflen, bufl = 0;
  101. #if PHP_SIGCHILD
  102. void (*sig_handler)() = NULL;
  103. #endif
  104. #if PHP_SIGCHILD
  105. sig_handler = signal (SIGCHLD, SIG_DFL);
  106. #endif
  107. #ifdef PHP_WIN32
  108. fp = VCWD_POPEN(cmd, "rb");
  109. #else
  110. fp = VCWD_POPEN(cmd, "r");
  111. #endif
  112. if (!fp) {
  113. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", cmd);
  114. goto err;
  115. }
  116. stream = php_stream_fopen_from_pipe(fp, "rb");
  117. buf = (char *) emalloc(EXEC_INPUT_BUF);
  118. buflen = EXEC_INPUT_BUF;
  119. if (type != 3) {
  120. b = buf;
  121. while (php_stream_get_line(stream, b, EXEC_INPUT_BUF, &bufl)) {
  122. /* no new line found, let's read some more */
  123. if (b[bufl - 1] != '\n' && !php_stream_eof(stream)) {
  124. if (buflen < (bufl + (b - buf) + EXEC_INPUT_BUF)) {
  125. bufl += b - buf;
  126. buflen = bufl + EXEC_INPUT_BUF;
  127. buf = erealloc(buf, buflen);
  128. b = buf + bufl;
  129. } else {
  130. b += bufl;
  131. }
  132. continue;
  133. } else if (b != buf) {
  134. bufl += b - buf;
  135. }
  136. if (type == 1) {
  137. PHPWRITE(buf, bufl);
  138. if (php_output_get_level(TSRMLS_C) < 1) {
  139. sapi_flush(TSRMLS_C);
  140. }
  141. } else if (type == 2) {
  142. /* strip trailing whitespaces */
  143. l = bufl;
  144. while (l-- && isspace(((unsigned char *)buf)[l]));
  145. if (l != (int)(bufl - 1)) {
  146. bufl = l + 1;
  147. buf[bufl] = '\0';
  148. }
  149. add_next_index_stringl(array, buf, bufl, 1);
  150. }
  151. b = buf;
  152. }
  153. if (bufl) {
  154. /* strip trailing whitespaces if we have not done so already */
  155. if ((type == 2 && buf != b) || type != 2) {
  156. l = bufl;
  157. while (l-- && isspace(((unsigned char *)buf)[l]));
  158. if (l != (int)(bufl - 1)) {
  159. bufl = l + 1;
  160. buf[bufl] = '\0';
  161. }
  162. if (type == 2) {
  163. add_next_index_stringl(array, buf, bufl, 1);
  164. }
  165. }
  166. /* Return last line from the shell command */
  167. RETVAL_STRINGL(buf, bufl, 1);
  168. } else { /* should return NULL, but for BC we return "" */
  169. RETVAL_EMPTY_STRING();
  170. }
  171. } else {
  172. while((bufl = php_stream_read(stream, buf, EXEC_INPUT_BUF)) > 0) {
  173. PHPWRITE(buf, bufl);
  174. }
  175. }
  176. pclose_return = php_stream_close(stream);
  177. efree(buf);
  178. done:
  179. #if PHP_SIGCHILD
  180. if (sig_handler) {
  181. signal(SIGCHLD, sig_handler);
  182. }
  183. #endif
  184. if (d) {
  185. efree(d);
  186. }
  187. return pclose_return;
  188. err:
  189. pclose_return = -1;
  190. goto done;
  191. }
  192. /* }}} */
  193. static void php_exec_ex(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
  194. {
  195. char *cmd;
  196. int cmd_len;
  197. zval *ret_code=NULL, *ret_array=NULL;
  198. int ret;
  199. if (mode) {
  200. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/", &cmd, &cmd_len, &ret_code) == FAILURE) {
  201. RETURN_FALSE;
  202. }
  203. } else {
  204. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/z/", &cmd, &cmd_len, &ret_array, &ret_code) == FAILURE) {
  205. RETURN_FALSE;
  206. }
  207. }
  208. if (!cmd_len) {
  209. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot execute a blank command");
  210. RETURN_FALSE;
  211. }
  212. if (strlen(cmd) != cmd_len) {
  213. php_error_docref(NULL TSRMLS_CC, E_WARNING, "NULL byte detected. Possible attack");
  214. RETURN_FALSE;
  215. }
  216. if (!ret_array) {
  217. ret = php_exec(mode, cmd, NULL, return_value TSRMLS_CC);
  218. } else {
  219. if (Z_TYPE_P(ret_array) != IS_ARRAY) {
  220. zval_dtor(ret_array);
  221. array_init(ret_array);
  222. }
  223. ret = php_exec(2, cmd, ret_array, return_value TSRMLS_CC);
  224. }
  225. if (ret_code) {
  226. zval_dtor(ret_code);
  227. ZVAL_LONG(ret_code, ret);
  228. }
  229. }
  230. /* }}} */
  231. /* {{{ proto string exec(string command [, array &output [, int &return_value]])
  232. Execute an external program */
  233. PHP_FUNCTION(exec)
  234. {
  235. php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  236. }
  237. /* }}} */
  238. /* {{{ proto int system(string command [, int &return_value])
  239. Execute an external program and display output */
  240. PHP_FUNCTION(system)
  241. {
  242. php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  243. }
  244. /* }}} */
  245. /* {{{ proto void passthru(string command [, int &return_value])
  246. Execute an external program and display raw output */
  247. PHP_FUNCTION(passthru)
  248. {
  249. php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
  250. }
  251. /* }}} */
  252. /* {{{ php_escape_shell_cmd
  253. Escape all chars that could possibly be used to
  254. break out of a shell command
  255. This function emalloc's a string and returns the pointer.
  256. Remember to efree it when done with it.
  257. *NOT* safe for binary strings
  258. */
  259. PHPAPI char *php_escape_shell_cmd(char *str)
  260. {
  261. register int x, y;
  262. size_t l = strlen(str);
  263. uint64_t estimate = (2 * (uint64_t)l) + 1;
  264. char *cmd;
  265. char *p = NULL;
  266. TSRMLS_FETCH();
  267. /* max command line length - two single quotes - \0 byte length */
  268. if (l > cmd_max_len - 2 - 1) {
  269. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Command exceeds the allowed length of %d bytes", cmd_max_len);
  270. return NULL;
  271. }
  272. cmd = safe_emalloc(2, l, 1);
  273. for (x = 0, y = 0; x < l; x++) {
  274. int mb_len = php_mblen(str + x, (l - x));
  275. /* skip non-valid multibyte characters */
  276. if (mb_len < 0) {
  277. continue;
  278. } else if (mb_len > 1) {
  279. memcpy(cmd + y, str + x, mb_len);
  280. y += mb_len;
  281. x += mb_len - 1;
  282. continue;
  283. }
  284. switch (str[x]) {
  285. #ifndef PHP_WIN32
  286. case '"':
  287. case '\'':
  288. if (!p && (p = memchr(str + x + 1, str[x], l - x - 1))) {
  289. /* noop */
  290. } else if (p && *p == str[x]) {
  291. p = NULL;
  292. } else {
  293. cmd[y++] = '\\';
  294. }
  295. cmd[y++] = str[x];
  296. break;
  297. #else
  298. /* % is Windows specific for enviromental variables, ^%PATH% will
  299. output PATH while ^%PATH^% will not. escapeshellcmd will escape all % and !.
  300. */
  301. case '%':
  302. case '!':
  303. case '"':
  304. case '\'':
  305. #endif
  306. case '#': /* This is character-set independent */
  307. case '&':
  308. case ';':
  309. case '`':
  310. case '|':
  311. case '*':
  312. case '?':
  313. case '~':
  314. case '<':
  315. case '>':
  316. case '^':
  317. case '(':
  318. case ')':
  319. case '[':
  320. case ']':
  321. case '{':
  322. case '}':
  323. case '$':
  324. case '\\':
  325. case '\x0A': /* excluding these two */
  326. case '\xFF':
  327. #ifdef PHP_WIN32
  328. cmd[y++] = '^';
  329. #else
  330. cmd[y++] = '\\';
  331. #endif
  332. /* fall-through */
  333. default:
  334. cmd[y++] = str[x];
  335. }
  336. }
  337. cmd[y] = '\0';
  338. if (y > cmd_max_len + 1) {
  339. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Escaped command exceeds the allowed length of %d bytes", cmd_max_len);
  340. efree(cmd);
  341. return NULL;
  342. }
  343. if ((estimate - y) > 4096) {
  344. /* realloc if the estimate was way overill
  345. * Arbitrary cutoff point of 4096 */
  346. cmd = erealloc(cmd, y + 1);
  347. }
  348. return cmd;
  349. }
  350. /* }}} */
  351. /* {{{ php_escape_shell_arg
  352. */
  353. PHPAPI char *php_escape_shell_arg(char *str)
  354. {
  355. int x, y = 0;
  356. size_t l = strlen(str);
  357. char *cmd;
  358. uint64_t estimate = (4 * (uint64_t)l) + 3;
  359. TSRMLS_FETCH();
  360. /* max command line length - two single quotes - \0 byte length */
  361. if (l > cmd_max_len - 2 - 1) {
  362. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Argument exceeds the allowed length of %d bytes", cmd_max_len);
  363. return NULL;
  364. }
  365. cmd = safe_emalloc(4, l, 3); /* worst case */
  366. #ifdef PHP_WIN32
  367. cmd[y++] = '"';
  368. #else
  369. cmd[y++] = '\'';
  370. #endif
  371. for (x = 0; x < l; x++) {
  372. int mb_len = php_mblen(str + x, (l - x));
  373. /* skip non-valid multibyte characters */
  374. if (mb_len < 0) {
  375. continue;
  376. } else if (mb_len > 1) {
  377. memcpy(cmd + y, str + x, mb_len);
  378. y += mb_len;
  379. x += mb_len - 1;
  380. continue;
  381. }
  382. switch (str[x]) {
  383. #ifdef PHP_WIN32
  384. case '"':
  385. case '%':
  386. case '!':
  387. cmd[y++] = ' ';
  388. break;
  389. #else
  390. case '\'':
  391. cmd[y++] = '\'';
  392. cmd[y++] = '\\';
  393. cmd[y++] = '\'';
  394. #endif
  395. /* fall-through */
  396. default:
  397. cmd[y++] = str[x];
  398. }
  399. }
  400. #ifdef PHP_WIN32
  401. if (y > 0 && '\\' == cmd[y - 1]) {
  402. int k = 0, n = y - 1;
  403. for (; n >= 0 && '\\' == cmd[n]; n--, k++);
  404. if (k % 2) {
  405. cmd[y++] = '\\';
  406. }
  407. }
  408. cmd[y++] = '"';
  409. #else
  410. cmd[y++] = '\'';
  411. #endif
  412. cmd[y] = '\0';
  413. if (y > cmd_max_len + 1) {
  414. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Escaped argument exceeds the allowed length of %d bytes", cmd_max_len);
  415. efree(cmd);
  416. return NULL;
  417. }
  418. if ((estimate - y) > 4096) {
  419. /* realloc if the estimate was way overill
  420. * Arbitrary cutoff point of 4096 */
  421. cmd = erealloc(cmd, y + 1);
  422. }
  423. return cmd;
  424. }
  425. /* }}} */
  426. /* {{{ proto string escapeshellcmd(string command)
  427. Escape shell metacharacters */
  428. PHP_FUNCTION(escapeshellcmd)
  429. {
  430. char *command;
  431. int command_len;
  432. char *cmd = NULL;
  433. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &command, &command_len) == FAILURE) {
  434. return;
  435. }
  436. if (command_len) {
  437. if (command_len != strlen(command)) {
  438. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Input string contains NULL bytes");
  439. return;
  440. }
  441. cmd = php_escape_shell_cmd(command);
  442. RETVAL_STRINGL_CHECK(cmd, strlen(cmd), 0);
  443. } else {
  444. RETVAL_EMPTY_STRING();
  445. }
  446. }
  447. /* }}} */
  448. /* {{{ proto string escapeshellarg(string arg)
  449. Quote and escape an argument for use in a shell command */
  450. PHP_FUNCTION(escapeshellarg)
  451. {
  452. char *argument;
  453. int argument_len;
  454. char *cmd = NULL;
  455. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &argument, &argument_len) == FAILURE) {
  456. return;
  457. }
  458. if (argument) {
  459. if (argument_len != strlen(argument)) {
  460. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Input string contains NULL bytes");
  461. return;
  462. }
  463. cmd = php_escape_shell_arg(argument);
  464. RETVAL_STRINGL_CHECK(cmd, strlen(cmd), 0);
  465. }
  466. }
  467. /* }}} */
  468. /* {{{ proto string shell_exec(string cmd)
  469. Execute command via shell and return complete output as string */
  470. PHP_FUNCTION(shell_exec)
  471. {
  472. FILE *in;
  473. size_t total_readbytes;
  474. char *command;
  475. int command_len;
  476. char *ret;
  477. php_stream *stream;
  478. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &command, &command_len) == FAILURE) {
  479. return;
  480. }
  481. #ifdef PHP_WIN32
  482. if ((in=VCWD_POPEN(command, "rt"))==NULL) {
  483. #else
  484. if ((in=VCWD_POPEN(command, "r"))==NULL) {
  485. #endif
  486. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to execute '%s'", command);
  487. RETURN_FALSE;
  488. }
  489. stream = php_stream_fopen_from_pipe(in, "rb");
  490. total_readbytes = php_stream_copy_to_mem(stream, &ret, PHP_STREAM_COPY_ALL, 0);
  491. php_stream_close(stream);
  492. if (total_readbytes > 0) {
  493. RETVAL_STRINGL_CHECK(ret, total_readbytes, 0);
  494. }
  495. }
  496. /* }}} */
  497. #ifdef HAVE_NICE
  498. /* {{{ proto bool proc_nice(int priority)
  499. Change the priority of the current process */
  500. PHP_FUNCTION(proc_nice)
  501. {
  502. long pri;
  503. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pri) == FAILURE) {
  504. RETURN_FALSE;
  505. }
  506. errno = 0;
  507. php_ignore_value(nice(pri));
  508. if (errno) {
  509. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only a super user may attempt to increase the priority of a process");
  510. RETURN_FALSE;
  511. }
  512. RETURN_TRUE;
  513. }
  514. /* }}} */
  515. #endif
  516. /*
  517. * Local variables:
  518. * tab-width: 4
  519. * c-basic-offset: 4
  520. * End:
  521. * vim600: sw=4 ts=4 fdm=marker
  522. * vim<600: sw=4 ts=4
  523. */