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