Annotation of embedaddon/php/ext/standard/exec.c, revision 1.1.1.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>