summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2007-05-14 14:23:51 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:22:02 -0500
commitd34f6bb969092166c961e328229b1b05a30f6930 (patch)
tree5cad4256a4dab7d6a7545188f877b7c78cf7c8f0 /source3/lib
parent00790cb8afaf768ba650ee40796ccdafc535ae8d (diff)
downloadsamba-d34f6bb969092166c961e328229b1b05a30f6930.tar.gz
samba-d34f6bb969092166c961e328229b1b05a30f6930.tar.bz2
samba-d34f6bb969092166c961e328229b1b05a30f6930.zip
r22852: merge fixes for CVE-2007-2446 and CVE-2007-2447 to all branches
(This used to be commit f65214be68c1a59d9598bfb9f3b19e71cc3fa07b)
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/smbrun.c31
-rw-r--r--source3/lib/util_str.c163
2 files changed, 190 insertions, 4 deletions
diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c
index 4400aeb443..e81224b5af 100644
--- a/source3/lib/smbrun.c
+++ b/source3/lib/smbrun.c
@@ -55,7 +55,7 @@ run a command being careful about uid/gid handling and putting the output in
outfd (or discard it if outfd is NULL).
****************************************************************************/
-int smbrun(const char *cmd, int *outfd)
+static int smbrun_internal(const char *cmd, int *outfd, BOOL sanitize)
{
pid_t pid;
uid_t uid = current_user.ut.uid;
@@ -173,13 +173,36 @@ int smbrun(const char *cmd, int *outfd)
}
#endif
- execl("/bin/sh","sh","-c",cmd,NULL);
+ {
+ const char *newcmd = sanitize ? escape_shell_string(cmd) : cmd;
+ if (!newcmd) {
+ exit(82);
+ }
+ execl("/bin/sh","sh","-c",newcmd,NULL);
+ }
/* not reached */
- exit(82);
+ exit(83);
return 1;
}
+/****************************************************************************
+ Use only in known safe shell calls (printing).
+****************************************************************************/
+
+int smbrun_no_sanitize(const char *cmd, int *outfd)
+{
+ return smbrun_internal(cmd, outfd, False);
+}
+
+/****************************************************************************
+ By default this now sanitizes shell expansion.
+****************************************************************************/
+
+int smbrun(const char *cmd, int *outfd)
+{
+ return smbrun_internal(cmd, outfd, True);
+}
/****************************************************************************
run a command being careful about uid/gid handling and putting the output in
@@ -302,7 +325,7 @@ int smbrunsecret(const char *cmd, const char *secret)
#endif
execl("/bin/sh", "sh", "-c", cmd, NULL);
-
+
/* not reached */
exit(82);
return 1;
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index 457232c2b2..1439ac6fcd 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -2616,3 +2616,166 @@ size_t utf16_len_n(const void *src, size_t n)
return len;
}
+
+/*******************************************************************
+ Add a shell escape character '\' to any character not in a known list
+ of characters. UNIX charset format.
+*******************************************************************/
+
+#define INCLUDE_LIST "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabdefghijklmnopqrstuvwxyz_/ \t.,"
+#define INSIDE_DQUOTE_LIST "$`\n\"\\"
+
+char *escape_shell_string(const char *src)
+{
+ size_t srclen = strlen(src);
+ char *ret = SMB_MALLOC((srclen * 2) + 1);
+ char *dest = ret;
+ BOOL in_s_quote = False;
+ BOOL in_d_quote = False;
+ BOOL next_escaped = False;
+
+ if (!ret) {
+ return NULL;
+ }
+
+ while (*src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(src, &c_size);
+
+ if (c == INVALID_CODEPOINT) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ if (c_size > 1) {
+ memcpy(dest, src, c_size);
+ src += c_size;
+ dest += c_size;
+ next_escaped = False;
+ continue;
+ }
+
+ /*
+ * Deal with backslash escaped state.
+ * This only lasts for one character.
+ */
+
+ if (next_escaped) {
+ *dest++ = *src++;
+ next_escaped = False;
+ continue;
+ }
+
+ /*
+ * Deal with single quote state. The
+ * only thing we care about is exiting
+ * this state.
+ */
+
+ if (in_s_quote) {
+ if (*src == '\'') {
+ in_s_quote = False;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * Deal with double quote state. The most
+ * complex state. We must cope with \, meaning
+ * possibly escape next char (depending what it
+ * is), ", meaning exit this state, and possibly
+ * add an \ escape to any unprotected character
+ * (listed in INSIDE_DQUOTE_LIST).
+ */
+
+ if (in_d_quote) {
+ if (*src == '\\') {
+ /*
+ * Next character might be escaped.
+ * We have to peek. Inside double
+ * quotes only INSIDE_DQUOTE_LIST
+ * characters are escaped by a \.
+ */
+
+ char nextchar;
+
+ c = next_codepoint(&src[1], &c_size);
+ if (c == INVALID_CODEPOINT) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+ if (c_size > 1) {
+ /*
+ * Don't escape the next char.
+ * Just copy the \.
+ */
+ *dest++ = *src++;
+ continue;
+ }
+
+ nextchar = src[1];
+
+ if (nextchar && strchr(INSIDE_DQUOTE_LIST, (int)nextchar)) {
+ next_escaped = True;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\"') {
+ /* Exit double quote state. */
+ in_d_quote = False;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * We know the character isn't \ or ",
+ * so escape it if it's any of the other
+ * possible unprotected characters.
+ */
+
+ if (strchr(INSIDE_DQUOTE_LIST, (int)*src)) {
+ *dest++ = '\\';
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * From here to the end of the loop we're
+ * not in the single or double quote state.
+ */
+
+ if (*src == '\\') {
+ /* Next character must be escaped. */
+ next_escaped = True;
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\'') {
+ /* Go into single quote state. */
+ in_s_quote = True;
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\"') {
+ /* Go into double quote state. */
+ in_d_quote = True;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* Check if we need to escape the character. */
+
+ if (!strchr(INCLUDE_LIST, (int)*src)) {
+ *dest++ = '\\';
+ }
+ *dest++ = *src++;
+ }
+ *dest++ = '\0';
+ return ret;
+}