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>