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>