]> granicus.if.org Git - sudo/commitdiff
Add support for multiple '*' in env_keep, env_check and env_delete
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 12 May 2017 16:02:17 +0000 (10:02 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 12 May 2017 16:02:17 +0000 (10:02 -0600)
entries.

MANIFEST
doc/sudoers.cat
doc/sudoers.man.in
doc/sudoers.mdoc.in
plugins/sudoers/Makefile.in
plugins/sudoers/env.c
plugins/sudoers/env_pattern.c [new file with mode: 0644]
plugins/sudoers/regress/env_match/check_env_pattern.c [new file with mode: 0644]
plugins/sudoers/regress/env_match/data [new file with mode: 0644]
plugins/sudoers/sudoers.h

index 25ceea8cef39459b4b7437e4c17f166d88a9bfe1..3d123d046891f04cf63bf4c26ffa952a440c06f1 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -264,6 +264,7 @@ plugins/sudoers/defaults.h
 plugins/sudoers/digestname.c
 plugins/sudoers/editor.c
 plugins/sudoers/env.c
+plugins/sudoers/env_pattern.c
 plugins/sudoers/filedigest.c
 plugins/sudoers/filedigest_gcrypt.c
 plugins/sudoers/filedigest_openssl.c
@@ -370,6 +371,8 @@ plugins/sudoers/rcstr.c
 plugins/sudoers/redblack.c
 plugins/sudoers/redblack.h
 plugins/sudoers/regress/check_symbols/check_symbols.c
+plugins/sudoers/regress/env_match/check_env_pattern.c
+plugins/sudoers/regress/env_match/data
 plugins/sudoers/regress/iolog_path/check_iolog_path.c
 plugins/sudoers/regress/iolog_path/data
 plugins/sudoers/regress/logging/check_wrap.c
index a647432e17b32252630d4bdd6cac40cc7407c957..a2f04de40767f51e71c8d08393699e35528cf3cf 100644 (file)
@@ -143,6 +143,10 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
      environment variables, use of the default _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt behavior is
      encouraged.
 
+     Environment variables specified by _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or _\be_\bn_\bv_\b__\bk_\be_\be_\bp may
+     include one or more `*' characters which will match zero or more
+     characters.  No other wildcard characters are supported.
+
      By default, environment variables are matched by name.  However, if the
      pattern includes an equal sign (`='), both the variables name and value
      must match.  For example, an old-style (pre-shellshock) b\bba\bas\bsh\bh shell
@@ -2813,4 +2817,4 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
      file distributed with s\bsu\bud\bdo\bo or https://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.20                       May 8, 2017                      Sudo 1.8.20
+Sudo 1.8.20                      May 10, 2017                      Sudo 1.8.20
index 18de06b835cf83204188b0ddf26a519b54a1001f..97d71c60d96e7903f1872cff41343f81d41a2eb8 100644 (file)
@@ -21,7 +21,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.TH "SUDOERS" "5" "May 8, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.TH "SUDOERS" "5" "May 10, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -354,6 +354,16 @@ of the default
 \fIenv_reset\fR
 behavior is encouraged.
 .PP
+Environment variables specified by
+\fIenv_check\fR,
+\fIenv_delete\fR,
+or
+\fIenv_keep\fR
+may include one or more
+\(oq*\(cq
+characters which will match zero or more characters.
+No other wildcard characters are supported.
+.PP
 By default, environment variables are matched by name.
 However, if the pattern includes an equal sign
 (\(oq=\&\(cq),
index a69a7acc5d29151869935e09458f7ceb654084d5..8dbd4db81a0be2b319f088760133a07489054641 100644 (file)
@@ -19,7 +19,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.Dd May 8, 2017
+.Dd May 10, 2017
 .Dt SUDOERS @mansectform@
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -343,6 +343,16 @@ of the default
 .Em env_reset
 behavior is encouraged.
 .Pp
+Environment variables specified by
+.Em env_check ,
+.Em env_delete ,
+or
+.Em env_keep
+may include one or more
+.Ql *
+characters which will match zero or more characters.
+No other wildcard characters are supported.
+.Pp
 By default, environment variables are matched by name.
 However, if the pattern includes an equal sign
 .Pq Ql =\& ,
index 2ac252f2a50af1fcb6ba79f6a225cb1b961c475e..dedc08bf604554c0bfff1fe3b1800e9654018e21 100644 (file)
@@ -145,8 +145,9 @@ SHELL = @SHELL@
 
 PROGS = sudoers.la visudo sudoreplay testsudoers
 
-TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_base64 \
-            check_gentime check_hexchar check_digest @SUDOERS_TEST_PROGS@
+TEST_PROGS = check_addr check_base64 check_digest check_env_pattern \
+            check_fill check_gentime check_hexchar check_iolog_path \
+            check_wrap @SUDOERS_TEST_PROGS@
 
 AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@
 
@@ -156,11 +157,11 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo digestname.lo \
                       rcstr.lo redblack.lo sudoers_debug.lo timeout.lo \
                       timestr.lo toke.lo toke_util.lo
 
-SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo find_path.lo \
-              gc.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
-              iolog_path.lo locale.lo logging.lo logwrap.lo mkdir_parents.lo \
-              parse.lo policy.lo prompt.lo set_perms.lo sudo_nss.lo \
-              sudoers.lo timestamp.lo @SUDOERS_OBJS@
+SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
+              env_pattern.lo find_path.lo gc.lo goodpath.lo group_plugin.lo \
+              interfaces.lo iolog.lo iolog_path.lo locale.lo logging.lo \
+              logwrap.lo mkdir_parents.lo parse.lo policy.lo prompt.lo \
+              set_perms.lo sudo_nss.lo sudoers.lo timestamp.lo @SUDOERS_OBJS@
 
 VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o sudo_printf.o visudo.o \
              visudo_json.o
@@ -177,6 +178,8 @@ CHECK_BASE64_OBJS = check_base64.o base64.o sudoers_debug.o
 
 CHECK_DIGEST_OBJS = check_digest.o @FILEDIGEST@ digestname.o sudoers_debug.o
 
+CHECK_ENV_MATCH_OBJS = check_env_pattern.o env_pattern.o sudoers_debug.o
+
 CHECK_FILL_OBJS = check_fill.o hexchar.o toke_util.o sudoers_debug.o
 
 CHECK_GENTIME_OBJS = check_gentime.o gentime.o gmtoff.o sudoers_debug.o
@@ -248,6 +251,9 @@ check_base64: $(CHECK_BASE64_OBJS) $(LT_LIBS)
 check_digest: $(CHECK_DIGEST_OBJS) $(LT_LIBS)
        $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_DIGEST_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) @LIBMD@
 
+check_env_pattern: $(CHECK_ENV_MATCH_OBJS) $(LT_LIBS)
+       $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_ENV_MATCH_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
+
 check_fill: $(CHECK_FILL_OBJS) $(LT_LIBS)
        $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_FILL_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
 
@@ -383,6 +389,7 @@ check: $(TEST_PROGS) visudo testsudoers
                ./check_digest > regress/parser/check_digest.out; \
                diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \
            fi; \
+           ./check_env_pattern $(srcdir)/regress/env_match/data || rval=`expr $$rval + $$?`; \
            ./check_fill || rval=`expr $$rval + $$?`; \
            ./check_gentime || rval=`expr $$rval + $$?`; \
            ./check_hexchar || rval=`expr $$rval + $$?`; \
@@ -607,6 +614,17 @@ check_digest.o: $(srcdir)/regress/parser/check_digest.c \
                 $(incdir)/sudo_fatal.h $(incdir)/sudo_queue.h \
                 $(srcdir)/parse.h $(top_builddir)/config.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_digest.c
+check_env_pattern.o: $(srcdir)/regress/env_match/check_env_pattern.c \
+                     $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
+                     $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
+                     $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
+                     $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
+                     $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
+                     $(srcdir)/defaults.h $(srcdir)/logging.h \
+                     $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
+                     $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
+                     $(top_builddir)/pathnames.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/env_match/check_env_pattern.c
 check_fill.o: $(srcdir)/regress/parser/check_fill.c $(devdir)/gram.h \
               $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
               $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
@@ -685,6 +703,17 @@ env.lo: $(srcdir)/env.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
         $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
         $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/env.c
+env_pattern.lo: $(srcdir)/env_pattern.c $(devdir)/def_data.h \
+                $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+                $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
+                $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
+                $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
+                $(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
+                $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
+                $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
+                $(top_builddir)/pathnames.h
+       $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/env_pattern.c
+env_pattern.o: env_pattern.lo
 filedigest.lo: $(srcdir)/filedigest.c $(devdir)/def_data.h \
                $(incdir)/compat/sha2.h $(incdir)/compat/stdbool.h \
                $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
index 2cf5e778719a004c4be0ef4857ef41121a66a9fd..547639e06f97803cdb36157583486119825ec4b2 100644 (file)
@@ -570,30 +570,13 @@ static bool
 matches_env_list(const char *var, struct list_members *list, bool *full_match)
 {
     struct list_member *cur;
-    bool match = false;
     debug_decl(matches_env_list, SUDOERS_DEBUG_ENV)
 
     SLIST_FOREACH(cur, list, entries) {
-       size_t sep_pos, len = strlen(cur->value);
-       bool iswild = false;
-
-       /* Locate position of the '=' separator in var=value. */
-       sep_pos = strcspn(var, "=");
-
-       /* Deal with '*' wildcard at the end of the pattern. */
-       if (cur->value[len - 1] == '*') {
-           len--;
-           iswild = true;
-       }
-       if (strncmp(cur->value, var, len) == 0 &&
-           (iswild || len == sep_pos || var[len] == '\0')) {
-           /* If we matched past the '=', count as a full match. */
-           *full_match = len > sep_pos + 1;
-           match = true;
-           break;
-       }
+       if (matches_env_pattern(cur->value, var, full_match))
+           debug_return_bool(true);
     }
-    debug_return_bool(match);
+    debug_return_bool(false);
 }
 
 /*
diff --git a/plugins/sudoers/env_pattern.c b/plugins/sudoers/env_pattern.c
new file mode 100644 (file)
index 0000000..e00214c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#include "sudoers.h"
+
+/* extern for regress tests */
+bool
+matches_env_pattern(const char *pattern, const char *var, bool *full_match)
+{
+    size_t len, sep_pos;
+    bool iswild = false, match = false;
+    bool saw_sep = false;
+    const char *cp;
+    debug_decl(matches_env_pattern, SUDOERS_DEBUG_ENV)
+
+    /* Locate position of the '=' separator in var=value. */
+    sep_pos = strcspn(var, "=");
+
+    /* Locate '*' wildcard and compute len. */
+    for (cp = pattern; *cp != '\0'; cp++) {
+       if (*cp == '*') {
+           iswild = true;
+           break;
+       }
+    }
+    len = (size_t)(cp - pattern);
+
+    if (iswild) {
+       /* Match up to the '*' wildcard. */
+       if (strncmp(pattern, var, len) == 0) {
+           while (*cp != '\0') {
+               if (*cp == '*') {
+                   /* Collapse sequential '*'s */
+                   do {
+                       cp++;
+                   } while (*cp == '*');
+                   /* A '*' at the end of a pattern matches anything. */
+                   if (*cp == '\0') {
+                       match = true;
+                       break;
+                   }
+                   /* Keep track of whether we matched an equal sign. */
+                   if (*cp == '=')
+                       saw_sep = true;
+                   /* Look for first match of text after the '*' */
+                   while ((saw_sep || len != sep_pos) &&
+                       var[len] != '\0' && var[len] != *cp)
+                       len++;
+               }
+               if (var[len] != *cp)
+                   break;
+               cp++;
+               len++;
+           }
+           if (*cp == '\0' && (len == sep_pos || var[len] == '\0'))
+               match = true;
+       }
+    } else {
+       if (strncmp(pattern, var, len) == 0 &&
+           (len == sep_pos || var[len] == '\0')) {
+           match = true;
+       }
+    }
+    if (match)
+       *full_match = len > sep_pos + 1;
+    debug_return_bool(match);
+}
diff --git a/plugins/sudoers/regress/env_match/check_env_pattern.c b/plugins/sudoers/regress/env_match/check_env_pattern.c
new file mode 100644 (file)
index 0000000..76917a6
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#include "sudo_compat.h"
+#include "sudoers.h"
+
+__dso_public int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+    FILE *fp = stdin;
+    char pattern[1024], string[1024];
+    int errors = 0, tests = 0, got, want;
+
+    if (argc > 1) {
+       if ((fp = fopen(argv[1], "r")) == NULL) {
+           perror(argv[1]);
+           exit(1);
+       }
+    }
+
+    /*
+     * Read in test file, which is formatted thusly:
+     *
+     * pattern string 1/0
+     *
+     */
+    for (;;) {
+       bool full_match = false;
+
+       got = fscanf(fp, "%s %s %d\n", pattern, string, &want);
+       if (got == EOF)
+           break;
+       if (got == 3) {
+           got = matches_env_pattern(pattern, string, &full_match);
+           if (full_match)
+               got++;
+           if (got != want) {
+               fprintf(stderr,
+                   "%s: %s %s: want %d, got %d\n",
+                   getprogname(), pattern, string, want, got);
+               errors++;
+           }
+           tests++;
+       }
+    }
+    if (tests != 0) {
+       printf("%s: %d test%s run, %d errors, %d%% success rate\n",
+           getprogname(), tests, tests == 1 ? "" : "s", errors,
+           (tests - errors) * 100 / tests);
+    }
+    exit(errors);
+}
diff --git a/plugins/sudoers/regress/env_match/data b/plugins/sudoers/regress/env_match/data
new file mode 100644 (file)
index 0000000..a8e92ef
--- /dev/null
@@ -0,0 +1,19 @@
+foo=(){false;} foo=(){false;} 2
+foo foo=(){false;} 1
+foo= foo=(){false;} 0
+foo=* foo=(){false;} 1
+foo=(* foo=(){false;} 2
+foo=()* foo=(){false;} 2
+foo=*()* foo=(){false;} 2
+foo() foo()=a 1
+foo*() foo()=b 1
+foo*()* foo()= 1
+foo()* foo()= 1
+foo* foo()= 1
+fo*o*() foo()= 1
+fo*o*() fooo()== 1
+fo*o*() foooo()= 1
+fo*o*() foooo 0
+MYPATH=*:/mydir:* MYPATH=/dir1/subdir1:/mydir:/dir2:/dir3/subdir2 2
+MYPATH=*:/mydir:** MYPATH=/dir1/subdir1:/mydir:/dir2:/dir3/subdir2 2
+MYPATH=*:/mdir:* MYPATH=/dir1/subdir1:/mydir:/dir2:/dir3/subdir2 0
index d4c01ddb07091ab7c16280419e5ef9f7744c072b..4caa857ea40acc3d8e987a3f94c1e8dee6db1487 100644 (file)
@@ -359,6 +359,9 @@ int sudoers_hook_putenv(char *string, void *closure);
 int sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure);
 int sudoers_hook_unsetenv(const char *name, void *closure);
 
+/* env_pattern.c */
+bool matches_env_pattern(const char *pattern, const char *var, bool *full_match);
+
 /* sudoers.c */
 FILE *open_sudoers(const char *, bool, bool *);
 int sudoers_policy_init(void *info, char * const envp[]);