Annotation of embedaddon/php/ext/standard/exec.c, revision 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>