Add support for multiple '*' in env_keep, env_check and env_delete

entries.
This commit is contained in:
Todd C. Miller
2017-05-12 10:02:17 -06:00
parent 15790b69c2
commit 17514b55ea
10 changed files with 261 additions and 30 deletions

View File

@@ -264,6 +264,7 @@ plugins/sudoers/defaults.h
plugins/sudoers/digestname.c plugins/sudoers/digestname.c
plugins/sudoers/editor.c plugins/sudoers/editor.c
plugins/sudoers/env.c plugins/sudoers/env.c
plugins/sudoers/env_pattern.c
plugins/sudoers/filedigest.c plugins/sudoers/filedigest.c
plugins/sudoers/filedigest_gcrypt.c plugins/sudoers/filedigest_gcrypt.c
plugins/sudoers/filedigest_openssl.c plugins/sudoers/filedigest_openssl.c
@@ -370,6 +371,8 @@ plugins/sudoers/rcstr.c
plugins/sudoers/redblack.c plugins/sudoers/redblack.c
plugins/sudoers/redblack.h plugins/sudoers/redblack.h
plugins/sudoers/regress/check_symbols/check_symbols.c 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/check_iolog_path.c
plugins/sudoers/regress/iolog_path/data plugins/sudoers/regress/iolog_path/data
plugins/sudoers/regress/logging/check_wrap.c plugins/sudoers/regress/logging/check_wrap.c

View File

@@ -143,6 +143,10 @@ DDEESSCCRRIIPPTTIIOONN
environment variables, use of the default _e_n_v___r_e_s_e_t behavior is environment variables, use of the default _e_n_v___r_e_s_e_t behavior is
encouraged. encouraged.
Environment variables specified by _e_n_v___c_h_e_c_k, _e_n_v___d_e_l_e_t_e, or _e_n_v___k_e_e_p 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 By default, environment variables are matched by name. However, if the
pattern includes an equal sign (`='), both the variables name and value pattern includes an equal sign (`='), both the variables name and value
must match. For example, an old-style (pre-shellshock) bbaasshh shell must match. For example, an old-style (pre-shellshock) bbaasshh shell
@@ -2813,4 +2817,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or https://www.sudo.ws/license.html for file distributed with ssuuddoo or https://www.sudo.ws/license.html for
complete details. complete details.
Sudo 1.8.20 May 8, 2017 Sudo 1.8.20 Sudo 1.8.20 May 10, 2017 Sudo 1.8.20

View File

@@ -21,7 +21,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" 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 .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -354,6 +354,16 @@ of the default
\fIenv_reset\fR \fIenv_reset\fR
behavior is encouraged. behavior is encouraged.
.PP .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. By default, environment variables are matched by name.
However, if the pattern includes an equal sign However, if the pattern includes an equal sign
(\(oq=\&\(cq), (\(oq=\&\(cq),

View File

@@ -19,7 +19,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.Dd May 8, 2017 .Dd May 10, 2017
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -343,6 +343,16 @@ of the default
.Em env_reset .Em env_reset
behavior is encouraged. behavior is encouraged.
.Pp .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. By default, environment variables are matched by name.
However, if the pattern includes an equal sign However, if the pattern includes an equal sign
.Pq Ql =\& , .Pq Ql =\& ,

View File

@@ -145,8 +145,9 @@ SHELL = @SHELL@
PROGS = sudoers.la visudo sudoreplay testsudoers PROGS = sudoers.la visudo sudoreplay testsudoers
TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_base64 \ TEST_PROGS = check_addr check_base64 check_digest check_env_pattern \
check_gentime check_hexchar check_digest @SUDOERS_TEST_PROGS@ check_fill check_gentime check_hexchar check_iolog_path \
check_wrap @SUDOERS_TEST_PROGS@
AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@ 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 \ rcstr.lo redblack.lo sudoers_debug.lo timeout.lo \
timestr.lo toke.lo toke_util.lo timestr.lo toke.lo toke_util.lo
SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo find_path.lo \ SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
gc.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \ env_pattern.lo find_path.lo gc.lo goodpath.lo group_plugin.lo \
iolog_path.lo locale.lo logging.lo logwrap.lo mkdir_parents.lo \ interfaces.lo iolog.lo iolog_path.lo locale.lo logging.lo \
parse.lo policy.lo prompt.lo set_perms.lo sudo_nss.lo \ logwrap.lo mkdir_parents.lo parse.lo policy.lo prompt.lo \
sudoers.lo timestamp.lo @SUDOERS_OBJS@ 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_OBJS = editor.o find_path.o goodpath.o locale.o sudo_printf.o visudo.o \
visudo_json.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_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_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_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) 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@ $(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) check_fill: $(CHECK_FILL_OBJS) $(LT_LIBS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_FILL_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(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; \ ./check_digest > regress/parser/check_digest.out; \
diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \ diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \
fi; \ fi; \
./check_env_pattern $(srcdir)/regress/env_match/data || rval=`expr $$rval + $$?`; \
./check_fill || rval=`expr $$rval + $$?`; \ ./check_fill || rval=`expr $$rval + $$?`; \
./check_gentime || rval=`expr $$rval + $$?`; \ ./check_gentime || rval=`expr $$rval + $$?`; \
./check_hexchar || 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 \ $(incdir)/sudo_fatal.h $(incdir)/sudo_queue.h \
$(srcdir)/parse.h $(top_builddir)/config.h $(srcdir)/parse.h $(top_builddir)/config.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/parser/check_digest.c $(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 \ check_fill.o: $(srcdir)/regress/parser/check_fill.c $(devdir)/gram.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.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 \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/env.c $(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 \ filedigest.lo: $(srcdir)/filedigest.c $(devdir)/def_data.h \
$(incdir)/compat/sha2.h $(incdir)/compat/stdbool.h \ $(incdir)/compat/sha2.h $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \

View File

@@ -570,30 +570,13 @@ static bool
matches_env_list(const char *var, struct list_members *list, bool *full_match) matches_env_list(const char *var, struct list_members *list, bool *full_match)
{ {
struct list_member *cur; struct list_member *cur;
bool match = false;
debug_decl(matches_env_list, SUDOERS_DEBUG_ENV) debug_decl(matches_env_list, SUDOERS_DEBUG_ENV)
SLIST_FOREACH(cur, list, entries) { SLIST_FOREACH(cur, list, entries) {
size_t sep_pos, len = strlen(cur->value); if (matches_env_pattern(cur->value, var, full_match))
bool iswild = false; debug_return_bool(true);
/* 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;
}
} }
debug_return_bool(match); debug_return_bool(false);
} }
/* /*

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View 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_setenv(const char *name, const char *value, int overwrite, void *closure);
int sudoers_hook_unsetenv(const char *name, 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 */ /* sudoers.c */
FILE *open_sudoers(const char *, bool, bool *); FILE *open_sudoers(const char *, bool, bool *);
int sudoers_policy_init(void *info, char * const envp[]); int sudoers_policy_init(void *info, char * const envp[]);