Return to exec.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */