summaryrefslogtreecommitdiff
path: root/ext/standard/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/exec.c')
-rw-r--r--ext/standard/exec.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/ext/standard/exec.c b/ext/standard/exec.c
new file mode 100644
index 0000000000..cb953fc9bd
--- /dev/null
+++ b/ext/standard/exec.c
@@ -0,0 +1,388 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP HTML Embedded Scripting Language Version 3.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
+ +----------------------------------------------------------------------+
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) the GNU General Public License as published by the Free Software |
+ | Foundation; either version 2 of the License, or (at your option) |
+ | any later version. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU General Public License for more details. |
+ | |
+ | You should have received a copy of both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+ +----------------------------------------------------------------------+
+ | Author: Rasmus Lerdorf |
+ +----------------------------------------------------------------------+
+ */
+/* $Id$ */
+
+#ifdef THREAD_SAFE
+#include "tls.h"
+#endif
+#include <stdio.h>
+#include "php.h"
+#include <ctype.h>
+#include "php3_string.h"
+#include "safe_mode.h"
+#include "head.h"
+#include "exec.h"
+#include "php_globals.h"
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/*
+ * If type==0, only last line of output is returned (exec)
+ * If type==1, all lines will be printed and last lined returned (system)
+ * If type==2, all lines will be saved to given array (exec with &$array)
+ * If type==3, output will be printed binary, no lines will be saved or returned (passthru)
+ *
+ */
+static int _Exec(int type, char *cmd, pval *array, pval *return_value)
+{
+ FILE *fp;
+ char buf[EXEC_INPUT_BUF], *tmp=NULL;
+ int t, l, ret, output=1;
+ int overflow_limit, lcmd, ldir;
+ char *b, *c, *d=NULL;
+ PLS_FETCH();
+
+ if (PG(safe_mode)) {
+ lcmd = strlen(cmd);
+ ldir = strlen(PG(safe_mode_exec_dir));
+ l = lcmd + ldir + 2;
+ overflow_limit = l;
+ c = strchr(cmd, ' ');
+ if (c) *c = '\0';
+ if (strstr(cmd, "..")) {
+ php3_error(E_WARNING, "No '..' components allowed in path");
+ return -1;
+ }
+ d = emalloc(l);
+ strcpy(d, PG(safe_mode_exec_dir));
+ overflow_limit -= ldir;
+ b = strrchr(cmd, '/');
+ if (b) {
+ strcat(d, b);
+ overflow_limit -= strlen(b);
+ } else {
+ strcat(d, "/");
+ strcat(d, cmd);
+ overflow_limit-=(strlen(cmd)+1);
+ }
+ if (c) {
+ *c = ' ';
+ strncat(d, c, overflow_limit);
+ }
+ tmp = _php3_escapeshellcmd(d);
+ efree(d);
+ d = tmp;
+#if WIN32|WINNT
+ fp = popen(d, "rb");
+#else
+ fp = popen(d, "r");
+#endif
+ if (!fp) {
+ php3_error(E_WARNING, "Unable to fork [%s]", d);
+ efree(d);
+ return -1;
+ }
+ } else { /* not safe_mode */
+#if WIN32|WINNT
+ fp = popen(cmd, "rb");
+#else
+ fp = popen(cmd, "r");
+#endif
+ if (!fp) {
+ php3_error(E_WARNING, "Unable to fork [%s]", cmd);
+ return -1;
+ }
+ }
+ buf[0] = '\0';
+ if (type==2) {
+ if (array->type != IS_ARRAY) {
+ pval_destructor(array _INLINE_TLS);
+ array_init(array);
+ }
+ }
+ if (type != 3) {
+ while (fgets(buf, EXEC_INPUT_BUF - 1, fp)) {
+ if (type == 1) {
+ if (output) PUTS(buf);
+#if APACHE
+# if MODULE_MAGIC_NUMBER > 19970110
+ if (output) rflush(GLOBAL(php3_rqst));
+# else
+ if (output) bflush(GLOBAL(php3_rqst)->connection->client);
+# endif
+#endif
+#if CGI_BINARY
+ fflush(stdout);
+#endif
+#if FHTTPD
+ /* fhttpd doesn't flush */
+#endif
+#if USE_SAPI
+ GLOBAL(sapi_rqst)->flush(GLOBAL(sapi_rqst)->scid);
+#endif
+ }
+ else if (type == 2) {
+ pval tmp;
+
+ /* strip trailing whitespaces */
+ l = strlen(buf);
+ t = l;
+ while (l && isspace((int)buf[--l]));
+ if (l < t) buf[l + 1] = '\0';
+ tmp.value.str.len = strlen(buf);
+ tmp.value.str.val = estrndup(buf,tmp.value.str.len);
+ tmp.type = IS_STRING;
+ _php3_hash_next_index_insert(array->value.ht,(void *) &tmp, sizeof(pval), NULL);
+ }
+ }
+
+ /* strip trailing spaces */
+ l = strlen(buf);
+ t = l;
+ while (l && isspace((int)buf[--l]));
+ if (l < t) buf[l + 1] = '\0';
+
+ } else {
+ int b, i;
+
+ while ((b = fread(buf, 1, sizeof(buf), fp)) > 0) {
+ for (i = 0; i < b; i++)
+ if (output) PUTC(buf[i]);
+ }
+ }
+
+ /* Return last line from the shell command */
+ if (PG(magic_quotes_runtime) && type!=3) {
+ int len;
+
+ tmp = _php3_addslashes(buf, 0, &len, 0);
+ RETVAL_STRINGL(tmp,len,0);
+ } else {
+ RETVAL_STRING(buf,1);
+ }
+
+ ret = pclose(fp);
+#if HAVE_SYS_WAIT_H
+ if (WIFEXITED(ret)) {
+ ret = WEXITSTATUS(ret);
+ }
+#endif
+
+ if (d) efree(d);
+ return ret;
+}
+
+/* {{{ proto int exec(string command [, array output [, int return_value]])
+ Execute an external program */
+void php3_exec(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg1, *arg2, *arg3;
+ int arg_count = ARG_COUNT(ht);
+ int ret;
+
+ if (arg_count > 3 || getParameters(ht, arg_count, &arg1, &arg2, &arg3) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ switch (arg_count) {
+ case 1:
+ ret = _Exec(0, arg1->value.str.val, NULL, return_value);
+ break;
+ case 2:
+ if (!ParameterPassedByReference(ht,2)) {
+ php3_error(E_WARNING,"Array argument to exec() not passed by reference");
+ }
+ ret = _Exec(2, arg1->value.str.val, arg2, return_value);
+ break;
+ case 3:
+ if (!ParameterPassedByReference(ht,2)) {
+ php3_error(E_WARNING,"Array argument to exec() not passed by reference");
+ }
+ if (!ParameterPassedByReference(ht,3)) {
+ php3_error(E_WARNING,"return_status argument to exec() not passed by reference");
+ }
+ ret = _Exec(2, arg1->value.str.val, arg2, return_value);
+ arg3->type = IS_LONG;
+ arg3->value.lval=ret;
+ break;
+ }
+}
+/* }}} */
+
+/* {{{ proto int system(string command [, int return_value])
+ Execute an external program and display output */
+void php3_system(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg1, *arg2;
+ int arg_count = ARG_COUNT(ht);
+ int ret;
+
+ if (arg_count > 2 || getParameters(ht, arg_count, &arg1, &arg2) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ switch (arg_count) {
+ case 1:
+ ret = _Exec(1, arg1->value.str.val, NULL, return_value);
+ break;
+ case 2:
+ if (!ParameterPassedByReference(ht,2)) {
+ php3_error(E_WARNING,"return_status argument to system() not passed by reference");
+ }
+ ret = _Exec(1, arg1->value.str.val, NULL, return_value);
+ arg2->type = IS_LONG;
+ arg2->value.lval=ret;
+ break;
+ }
+}
+/* }}} */
+
+/* {{{ proto int passthru(string command [, int return_value])
+ Execute an external program and display raw output */
+void php3_passthru(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg1, *arg2;
+ int arg_count = ARG_COUNT(ht);
+ int ret;
+
+ if (arg_count > 2 || getParameters(ht, arg_count, &arg1, &arg2) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ switch (arg_count) {
+ case 1:
+ ret = _Exec(3, arg1->value.str.val, NULL, return_value);
+ break;
+ case 2:
+ if (!ParameterPassedByReference(ht,2)) {
+ php3_error(E_WARNING,"return_status argument to system() not passed by reference");
+ }
+ ret = _Exec(3, arg1->value.str.val, NULL, return_value);
+ arg2->type = IS_LONG;
+ arg2->value.lval=ret;
+ break;
+ }
+}
+/* }}} */
+
+static int php3_ind(char *s, char c)
+{
+ register int x;
+
+ for (x = 0; s[x]; x++)
+ if (s[x] == c)
+ return x;
+
+ return -1;
+}
+
+/* Escape all chars that could possibly be used to
+ break out of a shell command
+
+ This function emalloc's a string and returns the pointer.
+ Remember to efree it when done with it.
+
+ *NOT* safe for binary strings
+*/
+char * _php3_escapeshellcmd(char *str) {
+ register int x, y, l;
+ char *cmd;
+
+ l = strlen(str);
+ cmd = emalloc(2 * l + 1);
+ strcpy(cmd, str);
+ for (x = 0; cmd[x]; x++) {
+ if (php3_ind("&;`'\"|*?~<>^()[]{}$\\\x0A\xFF", cmd[x]) != -1) {
+ for (y = l + 1; y > x; y--)
+ cmd[y] = cmd[y - 1];
+ l++; /* length has been increased */
+ cmd[x] = '\\';
+ x++; /* skip the character */
+ }
+ }
+ return cmd;
+}
+
+/* {{{ proto escapeshellcmd(string command)
+ escape shell metacharacters */
+void php3_escapeshellcmd(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg1;
+ char *cmd;
+ TLS_VARS;
+
+ if (getParameters(ht, 1, &arg1) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ cmd = _php3_escapeshellcmd(arg1->value.str.val);
+
+ RETVAL_STRING(cmd,1);
+ efree(cmd);
+}
+/* }}} */
+
+
+PHP_FUNCTION(shell_exec)
+{
+ FILE *in;
+ int readbytes,total_readbytes=0,allocated_space;
+ pval *cmd;
+
+ if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &cmd)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (PG(safe_mode)) {
+ php3_error(E_WARNING,"Cannot execute using backquotes in safe mode");
+ RETURN_FALSE;
+ }
+
+ convert_to_string(cmd);
+#if WIN32|WINNT
+ if ((in=popen(cmd->value.str.val,"rt"))==NULL) {
+#else
+ if ((in=popen(cmd->value.str.val,"r"))==NULL) {
+#endif
+ php3_error(E_WARNING,"Unable to execute '%s'",cmd->value.str.val);
+ }
+ allocated_space = EXEC_INPUT_BUF;
+ return_value->value.str.val = (char *) emalloc(allocated_space);
+ while (1) {
+ readbytes = fread(return_value->value.str.val+total_readbytes,1,EXEC_INPUT_BUF,in);
+ if (readbytes<=0) {
+ break;
+ }
+ total_readbytes += readbytes;
+ allocated_space = total_readbytes+EXEC_INPUT_BUF;
+ return_value->value.str.val = (char *) erealloc(return_value->value.str.val,allocated_space);
+ }
+ fclose(in);
+
+ return_value->value.str.val = erealloc(return_value->value.str.val,total_readbytes+1);
+ return_value->value.str.val[total_readbytes]=0;
+ return_value->value.str.len = total_readbytes;
+ return_value->type = IS_STRING;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */