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.

415 lines
9.9 KiB

27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP version 4.0 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997, 1998, 1999 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.0 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://www.php.net/license/2_0.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 |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #include <stdio.h>
  20. #include "php.h"
  21. #include <ctype.h>
  22. #include "php3_string.h"
  23. #include "safe_mode.h"
  24. #include "ext/standard/head.h"
  25. #include "exec.h"
  26. #include "php_globals.h"
  27. #include "SAPI.h"
  28. #if HAVE_SYS_WAIT_H
  29. #include <sys/wait.h>
  30. #endif
  31. /*
  32. * If type==0, only last line of output is returned (exec)
  33. * If type==1, all lines will be printed and last lined returned (system)
  34. * If type==2, all lines will be saved to given array (exec with &$array)
  35. * If type==3, output will be printed binary, no lines will be saved or returned (passthru)
  36. *
  37. */
  38. static int _Exec(int type, char *cmd, pval *array, pval *return_value)
  39. {
  40. FILE *fp;
  41. char *buf, *tmp=NULL;
  42. int buflen = 0;
  43. int t, l, ret, output=1;
  44. int overflow_limit, lcmd, ldir;
  45. char *b, *c, *d=NULL;
  46. PLS_FETCH();
  47. buf = (char*) emalloc(EXEC_INPUT_BUF);
  48. if (!buf) {
  49. php_error(E_WARNING, "Unable to emalloc %d bytes for exec buffer", EXEC_INPUT_BUF);
  50. return -1;
  51. }
  52. buflen = EXEC_INPUT_BUF;
  53. if (PG(safe_mode)) {
  54. lcmd = strlen(cmd);
  55. ldir = strlen(PG(safe_mode_exec_dir));
  56. l = lcmd + ldir + 2;
  57. overflow_limit = l;
  58. c = strchr(cmd, ' ');
  59. if (c) *c = '\0';
  60. if (strstr(cmd, "..")) {
  61. php_error(E_WARNING, "No '..' components allowed in path");
  62. efree(buf);
  63. return -1;
  64. }
  65. d = emalloc(l);
  66. strcpy(d, PG(safe_mode_exec_dir));
  67. overflow_limit -= ldir;
  68. b = strrchr(cmd, '/');
  69. if (b) {
  70. strcat(d, b);
  71. overflow_limit -= strlen(b);
  72. } else {
  73. strcat(d, "/");
  74. strcat(d, cmd);
  75. overflow_limit-=(strlen(cmd)+1);
  76. }
  77. if (c) {
  78. *c = ' ';
  79. strncat(d, c, overflow_limit);
  80. }
  81. tmp = _php3_escapeshellcmd(d);
  82. efree(d);
  83. d = tmp;
  84. #if WIN32|WINNT
  85. fp = popen(d, "rb");
  86. #else
  87. fp = popen(d, "r");
  88. #endif
  89. if (!fp) {
  90. php_error(E_WARNING, "Unable to fork [%s]", d);
  91. efree(d);
  92. efree(buf);
  93. return -1;
  94. }
  95. } else { /* not safe_mode */
  96. #if WIN32|WINNT
  97. fp = popen(cmd, "rb");
  98. #else
  99. fp = popen(cmd, "r");
  100. #endif
  101. if (!fp) {
  102. php_error(E_WARNING, "Unable to fork [%s]", cmd);
  103. efree(buf);
  104. return -1;
  105. }
  106. }
  107. buf[0] = '\0';
  108. if (type==2) {
  109. if (array->type != IS_ARRAY) {
  110. pval_destructor(array);
  111. array_init(array);
  112. }
  113. }
  114. if (type != 3) {
  115. l=0;
  116. while ( !feof(fp) || l != 0 ) {
  117. l = 0;
  118. /* Read a line or fill the buffer, whichever comes first */
  119. do {
  120. if ( buflen <= (l+1) ) {
  121. buf = erealloc(buf, buflen + EXEC_INPUT_BUF);
  122. if ( buf == NULL ) {
  123. php_error(E_WARNING, "Unable to erealloc %d bytes for exec buffer",
  124. buflen + EXEC_INPUT_BUF);
  125. return -1;
  126. }
  127. buflen += EXEC_INPUT_BUF;
  128. }
  129. if ( fgets(&(buf[l]), buflen - l, fp) == NULL ) {
  130. /* eof */
  131. break;
  132. }
  133. l += strlen(&(buf[l]));
  134. } while ( (l > 0) && (buf[l-1] != '\n') );
  135. if ( feof(fp) && (l == 0) ) {
  136. break;
  137. }
  138. if (type == 1) {
  139. SLS_FETCH();
  140. if (output) PUTS(buf);
  141. #if APACHE
  142. # if MODULE_MAGIC_NUMBER > 19970110
  143. if (output) rflush(((request_rec *) SG(server_context)));
  144. # else
  145. if (output) bflush(((request_rec *) SG(server_context))->connection->client);
  146. # endif
  147. #endif
  148. #if CGI_BINARY
  149. fflush(stdout);
  150. #endif
  151. #if FHTTPD
  152. /* fhttpd doesn't flush */
  153. #endif
  154. #if USE_SAPI
  155. sapi_rqst->flush(sapi_rqst->scid);
  156. #endif
  157. }
  158. else if (type == 2) {
  159. /* strip trailing whitespaces */
  160. l = strlen(buf);
  161. t = l;
  162. while (l-- && isspace((int)buf[l]));
  163. if (l < t) {
  164. buf[l + 1] = '\0';
  165. }
  166. add_next_index_string(array, buf, 1);
  167. }
  168. }
  169. /* strip trailing spaces */
  170. l = strlen(buf);
  171. t = l;
  172. while (l && isspace((int)buf[--l]));
  173. if (l < t) buf[l + 1] = '\0';
  174. } else {
  175. int b, i;
  176. while ((b = fread(buf, 1, sizeof(buf), fp)) > 0) {
  177. for (i = 0; i < b; i++)
  178. if (output) (void)PUTC(buf[i]);
  179. }
  180. }
  181. /* Return last line from the shell command */
  182. if (PG(magic_quotes_runtime) && type!=3) {
  183. int len;
  184. tmp = php_addslashes(buf, 0, &len, 0);
  185. RETVAL_STRINGL(tmp,len,0);
  186. } else {
  187. RETVAL_STRING(buf,1);
  188. }
  189. ret = pclose(fp);
  190. #if HAVE_SYS_WAIT_H
  191. if (WIFEXITED(ret)) {
  192. ret = WEXITSTATUS(ret);
  193. }
  194. #endif
  195. if (d) efree(d);
  196. efree(buf);
  197. return ret;
  198. }
  199. /* {{{ proto int exec(string command [, array output [, int return_value]])
  200. Execute an external program */
  201. PHP_FUNCTION(exec)
  202. {
  203. pval *arg1, *arg2, *arg3;
  204. int arg_count = ARG_COUNT(ht);
  205. int ret;
  206. if (arg_count > 3 || getParameters(ht, arg_count, &arg1, &arg2, &arg3) == FAILURE) {
  207. WRONG_PARAM_COUNT;
  208. }
  209. switch (arg_count) {
  210. case 1:
  211. ret = _Exec(0, arg1->value.str.val, NULL, return_value);
  212. break;
  213. case 2:
  214. if (!ParameterPassedByReference(ht,2)) {
  215. php_error(E_WARNING,"Array argument to exec() not passed by reference");
  216. }
  217. ret = _Exec(2, arg1->value.str.val, arg2, return_value);
  218. break;
  219. case 3:
  220. if (!ParameterPassedByReference(ht,2)) {
  221. php_error(E_WARNING,"Array argument to exec() not passed by reference");
  222. }
  223. if (!ParameterPassedByReference(ht,3)) {
  224. php_error(E_WARNING,"return_status argument to exec() not passed by reference");
  225. }
  226. ret = _Exec(2, arg1->value.str.val, arg2, return_value);
  227. arg3->type = IS_LONG;
  228. arg3->value.lval=ret;
  229. break;
  230. }
  231. }
  232. /* }}} */
  233. /* {{{ proto int system(string command [, int return_value])
  234. Execute an external program and display output */
  235. PHP_FUNCTION(system)
  236. {
  237. pval *arg1, *arg2;
  238. int arg_count = ARG_COUNT(ht);
  239. int ret;
  240. if (arg_count > 2 || getParameters(ht, arg_count, &arg1, &arg2) == FAILURE) {
  241. WRONG_PARAM_COUNT;
  242. }
  243. switch (arg_count) {
  244. case 1:
  245. ret = _Exec(1, arg1->value.str.val, NULL, return_value);
  246. break;
  247. case 2:
  248. if (!ParameterPassedByReference(ht,2)) {
  249. php_error(E_WARNING,"return_status argument to system() not passed by reference");
  250. }
  251. ret = _Exec(1, arg1->value.str.val, NULL, return_value);
  252. arg2->type = IS_LONG;
  253. arg2->value.lval=ret;
  254. break;
  255. }
  256. }
  257. /* }}} */
  258. /* {{{ proto int passthru(string command [, int return_value])
  259. Execute an external program and display raw output */
  260. PHP_FUNCTION(passthru)
  261. {
  262. pval *arg1, *arg2;
  263. int arg_count = ARG_COUNT(ht);
  264. int ret;
  265. if (arg_count > 2 || getParameters(ht, arg_count, &arg1, &arg2) == FAILURE) {
  266. WRONG_PARAM_COUNT;
  267. }
  268. switch (arg_count) {
  269. case 1:
  270. ret = _Exec(3, arg1->value.str.val, NULL, return_value);
  271. break;
  272. case 2:
  273. if (!ParameterPassedByReference(ht,2)) {
  274. php_error(E_WARNING,"return_status argument to system() not passed by reference");
  275. }
  276. ret = _Exec(3, arg1->value.str.val, NULL, return_value);
  277. arg2->type = IS_LONG;
  278. arg2->value.lval=ret;
  279. break;
  280. }
  281. }
  282. /* }}} */
  283. static int php3_ind(char *s, char c)
  284. {
  285. register int x;
  286. for (x = 0; s[x]; x++)
  287. if (s[x] == c)
  288. return x;
  289. return -1;
  290. }
  291. /* Escape all chars that could possibly be used to
  292. break out of a shell command
  293. This function emalloc's a string and returns the pointer.
  294. Remember to efree it when done with it.
  295. *NOT* safe for binary strings
  296. */
  297. char * _php3_escapeshellcmd(char *str) {
  298. register int x, y, l;
  299. char *cmd;
  300. l = strlen(str);
  301. cmd = emalloc(2 * l + 1);
  302. strcpy(cmd, str);
  303. for (x = 0; cmd[x]; x++) {
  304. if (php3_ind("&;`'\"|*?~<>^()[]{}$\\\x0A\xFF", cmd[x]) != -1) {
  305. for (y = l + 1; y > x; y--)
  306. cmd[y] = cmd[y - 1];
  307. l++; /* length has been increased */
  308. cmd[x] = '\\';
  309. x++; /* skip the character */
  310. }
  311. }
  312. return cmd;
  313. }
  314. /* {{{ proto escapeshellcmd(string command)
  315. escape shell metacharacters */
  316. PHP_FUNCTION(escapeshellcmd)
  317. {
  318. pval *arg1;
  319. char *cmd = NULL;
  320. if (getParameters(ht, 1, &arg1) == FAILURE) {
  321. WRONG_PARAM_COUNT;
  322. }
  323. convert_to_string(arg1);
  324. if (arg1->value.str.len) {
  325. cmd = _php3_escapeshellcmd(arg1->value.str.val);
  326. RETVAL_STRING(cmd, 1);
  327. efree(cmd);
  328. }
  329. }
  330. /* }}} */
  331. PHP_FUNCTION(shell_exec)
  332. {
  333. FILE *in;
  334. int readbytes,total_readbytes=0,allocated_space;
  335. pval *cmd;
  336. PLS_FETCH();
  337. if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &cmd)==FAILURE) {
  338. WRONG_PARAM_COUNT;
  339. }
  340. if (PG(safe_mode)) {
  341. php_error(E_WARNING,"Cannot execute using backquotes in safe mode");
  342. RETURN_FALSE;
  343. }
  344. convert_to_string(cmd);
  345. #if WIN32|WINNT
  346. if ((in=popen(cmd->value.str.val,"rt"))==NULL) {
  347. #else
  348. if ((in=popen(cmd->value.str.val,"r"))==NULL) {
  349. #endif
  350. php_error(E_WARNING,"Unable to execute '%s'",cmd->value.str.val);
  351. }
  352. allocated_space = EXEC_INPUT_BUF;
  353. return_value->value.str.val = (char *) emalloc(allocated_space);
  354. while (1) {
  355. readbytes = fread(return_value->value.str.val+total_readbytes,1,EXEC_INPUT_BUF,in);
  356. if (readbytes<=0) {
  357. break;
  358. }
  359. total_readbytes += readbytes;
  360. allocated_space = total_readbytes+EXEC_INPUT_BUF;
  361. return_value->value.str.val = (char *) erealloc(return_value->value.str.val,allocated_space);
  362. }
  363. fclose(in);
  364. return_value->value.str.val = erealloc(return_value->value.str.val,total_readbytes+1);
  365. return_value->value.str.val[total_readbytes]=0;
  366. return_value->value.str.len = total_readbytes;
  367. return_value->type = IS_STRING;
  368. }
  369. /*
  370. * Local variables:
  371. * tab-width: 4
  372. * c-basic-offset: 4
  373. * End:
  374. */