entries.
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
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
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
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
.\" 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"
\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),
.\" 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
.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 =\& ,
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@
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
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
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)
./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 + $$?`; \
$(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 \
$(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 \
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);
}
/*
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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
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[]);