summaryrefslogtreecommitdiff
path: root/src/core/wee-string.c
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2012-11-18 10:38:30 +0100
committerSebastien Helleu <flashcode@flashtux.org>2012-11-18 10:38:30 +0100
commitefb795c74fe954b9544074aafcebb1be4452b03a (patch)
treead48e01d3a394f2e981f9534585b050e3b5889cc /src/core/wee-string.c
parentc1389f8fe19068790d29e39c3f94b71b8c33ea03 (diff)
downloadweechat-efb795c74fe954b9544074aafcebb1be4452b03a.zip
core: do not call shell to execute command in hook_process (fix security problem when a plugin/script gives untrusted command) (bug #37764)
Diffstat (limited to 'src/core/wee-string.c')
-rw-r--r--src/core/wee-string.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/core/wee-string.c b/src/core/wee-string.c
index 269663cb8..38dde2de1 100644
--- a/src/core/wee-string.c
+++ b/src/core/wee-string.c
@@ -1138,6 +1138,196 @@ string_split (const char *string, const char *separators, int keep_eol,
}
/*
+ * string_split_shell: split a string like the shell does for a command with
+ * arguments.
+ * Note: result must be freed with string_free_split.
+ * This function is a C conversion of python class "shlex"
+ * (file: Lib/shlex.py in python repository)
+ * Doc: http://docs.python.org/3/library/shlex.html
+ * Copyrights in shlex.py:
+ * Module and documentation by Eric S. Raymond, 21 Dec 1998
+ * Input stacking and error message cleanup added by ESR, March 2000
+ * push_source() and pop_source() made explicit by ESR, January 2001.
+ * Posix compliance, split(), string arguments, and
+ * iterator interface by Gustavo Niemeyer, April 2003.
+ */
+
+char **
+string_split_shell (const char *string)
+{
+ int temp_len, num_args, add_char_to_temp, add_temp_to_args, quoted;
+ char *string2, *temp, **args, **args2, state, escapedstate;
+ char *ptr_string, *ptr_next, saved_char;
+
+ if (!string)
+ return NULL;
+
+ string2 = strdup (string);
+ if (!string2)
+ return NULL;
+
+ /*
+ * prepare "args" with one pointer to NULL, the "args" will be reallocated
+ * later, each time a new argument is added
+ */
+ num_args = 0;
+ args = malloc ((num_args + 1) * sizeof (args[0]));
+ if (!args)
+ {
+ free (string2);
+ return NULL;
+ }
+ args[0] = NULL;
+
+ /* prepare a temp string for working (adding chars one by one) */
+ temp = malloc ((2 * strlen (string)) + 1);
+ if (!temp)
+ {
+ free (string2);
+ free (args);
+ return NULL;
+ }
+ temp[0] = '\0';
+ temp_len = 0;
+
+ state = ' ';
+ escapedstate = ' ';
+ quoted = 0;
+ ptr_string = string2;
+ while (ptr_string[0])
+ {
+ add_char_to_temp = 0;
+ add_temp_to_args = 0;
+ ptr_next = utf8_next_char (ptr_string);
+ saved_char = ptr_next[0];
+ ptr_next[0] = '\0';
+ if (state == ' ')
+ {
+ if ((ptr_string[0] == ' ') || (ptr_string[0] == '\t')
+ || (ptr_string[0] == '\r') || (ptr_string[0] == '\n'))
+ {
+ if (temp[0] || quoted)
+ add_temp_to_args = 1;
+ }
+ else if (ptr_string[0] == '\\')
+ {
+ escapedstate = 'a';
+ state = ptr_string[0];
+ }
+ else if ((ptr_string[0] == '\'') || (ptr_string[0] == '"'))
+ {
+ state = ptr_string[0];
+ }
+ else
+ {
+ add_char_to_temp = 1;
+ state = 'a';
+ }
+ }
+ else if ((state == '\'') || (state == '"'))
+ {
+ quoted = 1;
+ if (ptr_string[0] == state)
+ {
+ state = 'a';
+ }
+ else if ((state == '"') && (ptr_string[0] == '\\'))
+ {
+ escapedstate = state;
+ state = ptr_string[0];
+ }
+ else
+ {
+ add_char_to_temp = 1;
+ }
+ }
+ else if (state == '\\')
+ {
+ if (((escapedstate == '\'') || (escapedstate == '"'))
+ && (ptr_string[0] != state) && (ptr_string[0] != escapedstate))
+ {
+ temp[temp_len] = state;
+ temp_len++;
+ temp[temp_len] = '\0';
+ }
+ add_char_to_temp = 1;
+ state = escapedstate;
+ }
+ else if (state == 'a')
+ {
+ if ((ptr_string[0] == ' ') || (ptr_string[0] == '\t')
+ || (ptr_string[0] == '\r') || (ptr_string[0] == '\n'))
+ {
+ state = ' ';
+ if (temp[0] || quoted)
+ add_temp_to_args = 1;
+ }
+ else if (ptr_string[0] == '\\')
+ {
+ escapedstate = 'a';
+ state = ptr_string[0];
+ }
+ else if ((ptr_string[0] == '\'') || (ptr_string[0] == '"'))
+ {
+ state = ptr_string[0];
+ }
+ else
+ {
+ add_char_to_temp = 1;
+ }
+ }
+ if (add_char_to_temp)
+ {
+ memcpy (temp + temp_len, ptr_string, ptr_next - ptr_string);
+ temp_len += (ptr_next - ptr_string);
+ temp[temp_len] = '\0';
+ }
+ if (add_temp_to_args)
+ {
+ num_args++;
+ args2 = realloc (args, (num_args + 1) * sizeof (args[0]));
+ if (!args2)
+ {
+ free (string2);
+ free (temp);
+ return args;
+ }
+ args = args2;
+ args[num_args - 1] = strdup (temp);
+ args[num_args] = NULL;
+ temp[0] = '\0';
+ temp_len = 0;
+ escapedstate = ' ';
+ quoted = 0;
+ }
+ ptr_next[0] = saved_char;
+ ptr_string = ptr_next;
+ }
+
+ if (temp[0] || (state != ' '))
+ {
+ num_args++;
+ args2 = realloc (args, (num_args + 1) * sizeof (args[0]));
+ if (!args2)
+ {
+ free (string2);
+ free (temp);
+ return args;
+ }
+ args = args2;
+ args[num_args - 1] = strdup (temp);
+ args[num_args] = NULL;
+ temp[0] = '\0';
+ temp_len = 0;
+ }
+
+ free (string2);
+ free (temp);
+
+ return args;
+}
+
+/*
* string_free_split: free a split string
*/