diff -urNp php-4.3.10.org/ext/standard/exec.c php-4.3.10/ext/standard/exec.c --- php-4.3.10.org/ext/standard/exec.c 2004-11-11 05:28:27.000000000 +0900 +++ php-4.3.10/ext/standard/exec.c 2005-01-30 06:06:30.000000000 +0900 @@ -52,7 +52,8 @@ static int php_make_safe_mode_command(ch char *space, *sep, *arg0; if (!PG(safe_mode)) { - *safecmd = estrdup(cmd); + //*safecmd = estrdup(cmd); + *safecmd = get_nosafe_shell_cmd (cmd); return SUCCESS; } @@ -116,7 +117,7 @@ int php_Exec(int type, char *cmd, pval * int buflen = 0; int t, l, output=1; int overflow_limit, lcmd, ldir; - char *b, *c, *d=NULL; + char *b=NULL, *c, *d=NULL; php_stream *stream = NULL; int pclose_return = 0; #if PHP_SIGCHILD @@ -180,16 +181,18 @@ int php_Exec(int type, char *cmd, pval * } } else { /* not safe_mode */ + d = get_nosafe_shell_cmd (cmd); + #if PHP_SIGCHILD sig_handler = signal (SIGCHLD, SIG_DFL); #endif #ifdef PHP_WIN32 - fp = VCWD_POPEN(cmd, "rb"); + fp = VCWD_POPEN(d, "rb"); #else - fp = VCWD_POPEN(cmd, "r"); + fp = VCWD_POPEN(d, "r"); #endif if (!fp) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", cmd); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", d); efree(buf); #if PHP_SIGCHILD signal (SIGCHLD, sig_handler); @@ -504,6 +507,344 @@ char *php_escape_shell_arg(char *str) { } /* }}} */ +/* {{{ get_nosafe_shell_cmd + */ +char *get_nosafe_shell_cmd (char *cmd) { + size_t exec_len; + char *_cmd; + + exec_len = strlen (PG(safe_mode_exec_dir)); + + if ( exec_len ) { + char *b = NULL, *c = NULL; + char *tmp; + char *__cmd; + size_t c_len = 0; + + c = strchr (cmd, ' '); + if ( c ) { + c_len = strlen (c); + *c = 0; + } + + //php_printf ("g --> %s : %s : %s : '%c'\n", c, b, PG(safe_mode_exec_dir), PHP_DIR_SEPARATOR); + //php_printf ("g ==> %s\n", cmd); + + tmp = estrdup (cmd); + b = strrchr (tmp, '/'); + + if ( c ) *c = ' '; + + if ( b ) + c_len = sizeof (char *) * (strlen (b) + c_len + 1); + else + c_len = sizeof (char *) * (strlen (tmp) + c_len + 1); + + __cmd = emalloc (c_len); + memset (__cmd, 0, c_len); + if ( c ) + sprintf (__cmd, "%s%s", b ? b : tmp, c); + else { + if ( b ) + memcpy (__cmd, b, strlen (b)); + else + memcpy (__cmd, tmp, strlen (tmp)); + } + efree (tmp); + _cmd = php_nosafe_shell_cmd (__cmd, PG(safe_mode_exec_dir)); + + } else { + _cmd = estrdup (cmd); + } + + //php_printf ("g **> %s\n", _cmd); + + return _cmd; +} +/* }}} */ + +/* {{{ check_quote_block + * case by single quote or double quote + * single quote (') is digit 39 + * double quote (") is digit 34 + * reverse slash (\) is digit 92 + */ +int check_quote_block (struct quote_chk_char qc, struct quote_value *_qv) { + if ( qc.cur != 39 && qc.cur != 34 ) { + switch (qc.cur) { + case ';' : + case '|' : + case '`' : + case '$' : + case '&' : + if ( qc.mcur == 92 ) + return 0; + + if ( (*_qv).quote > 0 ) { + if ( (*_qv).dquote ) { + if ( (*_qv).bquote ) + return 0; + else if ( (*_qv).daquote ) + return 0; + } + + return 1; + } + } + return 0; + } + + if ( qc.mcur == 92 ) + return 0; + + if ( (*_qv).quote > 0 ) { + if ( qc.cur == 34 ) { + if ( (*_qv).squote ) return 0; + } else { + if ( (*_qv).dquote ) return 0; + } + + (*_qv).quote = 0; + (*_qv).squote = 0; + (*_qv).dquote = 0; + } else { + (*_qv).quote = 1; + if ( qc.cur == 34 ) { + (*_qv).dquote = 1; + (*_qv).squote = 0; + } else { + (*_qv).dquote = 0; + (*_qv).squote = 1; + } + } + + return 0; +} +/* }}} */ + +/* {{{ php_nosafe_shell_cmd + */ +char *php_nosafe_shell_cmd (char *cmd, char *path) { + int cmd_len = 0; + int path_len = 0; + int buf_len = 0; + int ep = 0; + int i, j, b, _len = 0; + char *buf; + char *_cmd, *x_cmd, *debug_cmd; + char *_path, *_tpath; + int _start; + int debug = 0; + struct quote_value qv = { 0, 0, 0, 0, 0 }; + struct quote_chk_char qc; + + cmd_len = strlen (cmd); + debug_cmd = emalloc (sizeof (char *) * cmd_len + 1); + memset (debug_cmd, 0, cmd_len); + if ( ! strncmp ("DEBUG:", cmd, 6) ) { + debug = 1; + memcpy (debug_cmd, cmd + 6, cmd_len - 6); + } else if ( ! strncmp ("DDEBUG:", cmd, 7) ) { + debug = 2; + memcpy (debug_cmd, cmd + 7, cmd_len - 7); + } else { + debug_cmd = estrdup (cmd); + } + + _tpath = php_trim (path, strlen (path), NULL, 0, NULL, 3 TSRMLS_CC); + x_cmd = php_trim (debug_cmd, strlen (debug_cmd), NULL, 0, NULL, 3 TSRMLS_CC); + _cmd = ( x_cmd[0] == '/' ) ? estrdup (x_cmd + 1) : estrdup (x_cmd); + efree (x_cmd); + efree (debug_cmd); + + cmd_len = strlen(_cmd); + path_len = strlen (_tpath); + + if ( path_len == 1 ) + b = ( _tpath == "/" ) ? 0 : 1; + else if ( _tpath[path_len - 1] != '/' ) + b = 1; + else + b = 0; + + _path= emalloc (sizeof (char *) * (cmd_len + 2)); + memset (_path, 0, sizeof (char *) * (cmd_len + 2)); + sprintf (_path, "%s%s", _tpath, !b ? "" : "/"); + path_len = strlen (_path); + efree (_tpath); + + for ( i=0; i %s\n", _cmd); + + for ( i=0; i 1 ) { + php_printf ("#### " + "_cmd[i] => %c : " + "i => %2d : " + "cmd_len => %2d : " + "_start => %2d : " + "quote => %2d : " + "squote => %2d : " + "dquote => %2d : " + "bquote => %2d : " + "daquote => %2d\n", + _cmd[i], i, cmd_len, _start, + qv.quote, qv.squote, qv.dquote, qv.bquote, qv.daquote); + } + + qc.mcur = _cmd[i-1]; + qc.cur = _cmd[i]; + qc.acur = _cmd[i+1]; + + if ( qc.mcur != '\\' && qc.cur == '`' ) { + if ( ! qv.bquote ) qv.bquote = 1; + else qv.bquote = 0; + } + + if ( qc.mcur != '\\' && qc.cur == '$' && qc.acur == '(' ) { + qv.daquote = 1; + } else if ( qv.daquote && qc.mcur != '\\' && qc.cur == ')' ) { + qv.daquote = 0; + } + + if ( i == cmd_len - 1 && _start <= i ) { + memcpy (buf + ep, _cmd + _start, i - _start + 1); + break; + } + + if ( check_quote_block (qc, &qv) ) { + i++; + goto roopstart; + } + + switch (_cmd[i]) { + case ';' : + case '|' : + case '`' : + case '$' : + case '&' : + if ( _cmd[i-1] == '\\' ) { + i++; + goto roopstart; + } + + memcpy (buf + ep, _cmd + _start, i - _start + 1); + _start = i + 1; + ep = strlen (buf); + + /* + if ( _cmd[i] == '`' && ! qv.bquote ) qv.bquote = 1; + else if ( _cmd[i] == '`' && qv.bquote ) { + qv.bquote = 0; + i++; + + goto roopstart; + } + */ + if ( _cmd[i] == '`' && ! qv.bquote ) { + i++; + goto roopstart; + } + + // if not case of $() or && or ||, skip + if ( _cmd[i] == '$' && _cmd[i+1] != '(' ) { + i++; + goto roopstart; + } + + // if case of `` or ;; that include any charactors, skip + if ( (_cmd[i] == ';' && _cmd[i+1] == ';') || (_cmd[i] == '`' && _cmd[i+1] == '`') ) { + i++; + goto roopstart; + } + + + i++; + if ( (_cmd[i] == '(' && _cmd[i-1] == '$') || (_cmd[i] == '&' && _cmd[i-1] == '&') || + (_cmd[i] == '|' && _cmd[i-1] == '|') ) { + memset (buf + ep, _cmd[i], 1); + _start++; + ep++; + i++; + } + + for ( j=i; j 32 + // tab (\t) => 9 + if ( _cmd[j] == 32 || _cmd[j] == 9 ) { + memset (buf + ep, _cmd[j], 1); + _start++; + ep++; + i++; + } else { + int y; + int _vcmd_len = 0; + char vcmd[256] = { 0, }; + char *_vcmd = NULL; + char *_tvcmd = NULL; + + for ( y=j; y 32 + // tab (\t) => 9 + if ( _cmd[y] == 32 || _cmd[y] == 9 || (qv.bquote && _cmd[y] == '`') ) { + memcpy (vcmd, _cmd + j, y - j ); + _tvcmd = strrchr (vcmd, '/'); + _vcmd = _tvcmd ? _tvcmd + 1 : vcmd; + _vcmd_len = strlen (_vcmd); + i = y; + + //php_printf ("***** => %s : %s, %d, %d\n", vcmd, _vcmd, qv.bquote, i); + if ( _cmd[y] == '`' ) + qv.bquote = 0; + + break; + } + } + memcpy (buf + ep, _path, path_len); + memcpy (buf + ep + path_len, _vcmd, _vcmd_len); + ep += path_len + _vcmd_len; + _start = i; + break; + } + } + break; + } + } + + if ( debug ) + php_printf ("p ==> %s\n--\n", buf); + + efree (_cmd); + efree (_path); + + return buf; +} +/* }}} */ + /* {{{ proto string escapeshellcmd(string command) Escape shell metacharacters */ PHP_FUNCTION(escapeshellcmd) @@ -552,6 +893,7 @@ PHP_FUNCTION(shell_exec) int readbytes, total_readbytes=0, allocated_space; pval **cmd; char *ret; + char *buf; if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &cmd)==FAILURE) { WRONG_PARAM_COUNT; @@ -563,14 +905,18 @@ PHP_FUNCTION(shell_exec) } convert_to_string_ex(cmd); + buf = get_nosafe_shell_cmd (Z_STRVAL_PP(cmd)); + #ifdef PHP_WIN32 - if ((in=VCWD_POPEN(Z_STRVAL_PP(cmd), "rt"))==NULL) { + if ((in=VCWD_POPEN(buf, "rt"))==NULL) { #else - if ((in=VCWD_POPEN(Z_STRVAL_PP(cmd), "r"))==NULL) { + if ((in=VCWD_POPEN(buf, "r"))==NULL) { #endif - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to execute '%s'", Z_STRVAL_PP(cmd)); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to execute '%s'", buf); + efree (buf); RETURN_FALSE; } + efree (buf); allocated_space = EXEC_INPUT_BUF; ret = (char *) emalloc(allocated_space); while (1) { diff -urNp php-4.3.10.org/ext/standard/exec.h php-4.3.10/ext/standard/exec.h --- php-4.3.10.org/ext/standard/exec.h 2003-01-01 01:35:27.000000000 +0900 +++ php-4.3.10/ext/standard/exec.h 2005-01-30 04:35:04.000000000 +0900 @@ -31,8 +31,25 @@ PHP_FUNCTION(proc_open); PHP_FUNCTION(proc_close); PHP_MINIT_FUNCTION(proc_open); +struct quote_value { + int quote; + int squote; + int dquote; + int bquote; + int daquote; +}; + +struct quote_chk_char { + char mcur; + char cur; + char acur; +}; + char *php_escape_shell_cmd(char *); char *php_escape_shell_arg(char *); +char *get_nosafe_shell_cmd (char *); +char *php_nosafe_shell_cmd (char *, char *); +int check_quote_block (struct quote_chk_char, struct quote_value *); int php_Exec(int type, char *cmd, pval *array, pval *return_value TSRMLS_DC); #define PHP_EMPTY_EXEC_PARAM { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot execute a blank command"); RETURN_FALSE; } diff -urNp php-4.3.10.org/ext/standard/file.c php-4.3.10/ext/standard/file.c --- php-4.3.10.org/ext/standard/file.c 2005-01-28 23:58:44.000000000 +0900 +++ php-4.3.10/ext/standard/file.c 2005-01-29 22:22:21.000000000 +0900 @@ -1244,7 +1244,10 @@ PHP_FUNCTION(popen) efree(buf); } else { - fp = VCWD_POPEN(Z_STRVAL_PP(arg1), p); + tmp = get_nosafe_shell_cmd (Z_STRVAL_PP(arg1)); + fp = VCWD_POPEN(tmp, p); + efree (tmp); + if (!fp) { php_error_docref2(NULL TSRMLS_CC, Z_STRVAL_PP(arg1), p, E_WARNING, "%s", strerror(errno)); efree(p);