Add helper function to compile a regex that supports (?i).

This commit is contained in:
Todd C. Miller
2022-02-11 12:01:31 -07:00
parent 86d2173937
commit 7c17f84a35
23 changed files with 231 additions and 140 deletions

View File

@@ -245,6 +245,7 @@ lib/util/progname.c
lib/util/pw_dup.c lib/util/pw_dup.c
lib/util/pwrite.c lib/util/pwrite.c
lib/util/rcstr.c lib/util/rcstr.c
lib/util/regex.c
lib/util/reallocarray.c lib/util/reallocarray.c
lib/util/regress/corpus/seed/sudo_conf/sudo.conf.1 lib/util/regress/corpus/seed/sudo_conf/sudo.conf.1
lib/util/regress/corpus/seed/sudo_conf/sudo.conf.2 lib/util/regress/corpus/seed/sudo_conf/sudo.conf.2

View File

@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "February 10, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDO_LOGSRVD.CONF" "@mansectform@" "February 11, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -641,6 +641,9 @@ One or more POSIX extended regular expressions used to
match password prompts in the terminal output when match password prompts in the terminal output when
\fIlog_passwords\fR \fIlog_passwords\fR
is disabled. is disabled.
As an extension, if the regular expression begins with
\(lq(?i)\(rq,
it will be matched in a case-insensitive manner.
Multiple Multiple
\fIpassprompt_regex\fR \fIpassprompt_regex\fR
settings may be specified. settings may be specified.

View File

@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd February 10, 2022 .Dd February 11, 2022
.Dt SUDO_LOGSRVD.CONF @mansectform@ .Dt SUDO_LOGSRVD.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -571,6 +571,9 @@ One or more POSIX extended regular expressions used to
match password prompts in the terminal output when match password prompts in the terminal output when
.Em log_passwords .Em log_passwords
is disabled. is disabled.
As an extension, if the regular expression begins with
.Dq (?i) ,
it will be matched in a case-insensitive manner.
Multiple Multiple
.Em passprompt_regex .Em passprompt_regex
settings may be specified. settings may be specified.

View File

@@ -25,7 +25,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.TH "SUDOERS" "@mansectform@" "February 10, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDOERS" "@mansectform@" "February 11, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@@ -5424,6 +5424,9 @@ This setting is only supported by version 1.9.0 or higher.
passprompt_regex passprompt_regex
A list of POSIX extended regular expressions used to A list of POSIX extended regular expressions used to
match password prompts in the terminal output. match password prompts in the terminal output.
As an extension, if the regular expression begins with
\(lq(?i)\(rq,
it will be matched in a case-insensitive manner.
This option is only used when This option is only used when
\fIlog_passwords\fR \fIlog_passwords\fR
has been disabled. has been disabled.

View File

@@ -24,7 +24,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.Dd February 10, 2022 .Dd February 11, 2022
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -5062,6 +5062,9 @@ This setting is only supported by version 1.9.0 or higher.
.It passprompt_regex .It passprompt_regex
A list of POSIX extended regular expressions used to A list of POSIX extended regular expressions used to
match password prompts in the terminal output. match password prompts in the terminal output.
As an extension, if the regular expression begins with
.Dq (?i) ,
it will be matched in a case-insensitive manner.
This option is only used when This option is only used when
.Em log_passwords .Em log_passwords
has been disabled. has been disabled.

View File

@@ -256,6 +256,10 @@ sudo_dso_public char *sudo_rcstr_alloc(size_t len);
sudo_dso_public char *sudo_rcstr_addref(const char *s); sudo_dso_public char *sudo_rcstr_addref(const char *s);
sudo_dso_public void sudo_rcstr_delref(const char *s); sudo_dso_public void sudo_rcstr_delref(const char *s);
/* regex.c */
sudo_dso_public bool sudo_regex_compile_v1(void *v, const char *pattern, const char **errstr);
#define sudo_regex_compile(_a, _b, _c) sudo_regex_compile_v1((_a), (_b), (_c))
/* roundup.c */ /* roundup.c */
sudo_dso_public unsigned int sudo_pow2_roundup_v1(unsigned int len); sudo_dso_public unsigned int sudo_pow2_roundup_v1(unsigned int len);
#define sudo_pow2_roundup(_a) sudo_pow2_roundup_v1((_a)) #define sudo_pow2_roundup(_a) sudo_pow2_roundup_v1((_a))

View File

@@ -41,6 +41,7 @@
#include "sudo_gettext.h" #include "sudo_gettext.h"
#include "sudo_iolog.h" #include "sudo_iolog.h"
#include "sudo_queue.h" #include "sudo_queue.h"
#include "sudo_util.h"
struct pwfilt_regex { struct pwfilt_regex {
TAILQ_ENTRY(pwfilt_regex) entries; TAILQ_ENTRY(pwfilt_regex) entries;
@@ -110,51 +111,6 @@ iolog_pwfilt_free(void *vhandle)
debug_return; debug_return;
} }
/*
* Like strdup but collapses repeated '?', '*' and '+' ops in a regex.
* Glibc regcomp() has a bug where it uses excessive memory for repeated
* '+' ops. Collapse them to avoid running the fuzzer out of memory.
*/
static char *
dup_pattern(const char *src)
{
char *dst, *ret;
char ch, prev = '\0';
size_t len;
debug_decl(dup_pattern, SUDO_DEBUG_UTIL);
len = strlen(src);
ret = malloc(len + 1);
if (ret == NULL)
debug_return_ptr(NULL);
dst = ret;
while ((ch = *src++) != '\0') {
switch (ch) {
case '\\':
if (*src != '\0') {
*dst++ = '\\';
*dst++ = *src++;
prev = '\0';
continue;
}
break;
case '?':
case '*':
case '+':
if (ch == prev) {
continue;
}
break;
}
*dst++ = ch;
prev = ch;
}
*dst = '\0';
debug_return_ptr(ret);
}
/* /*
* Add a pattern to the password filter list. * Add a pattern to the password filter list.
*/ */
@@ -163,22 +119,19 @@ iolog_pwfilt_add(void *vhandle, const char *pattern)
{ {
struct pwfilt_handle *handle = vhandle; struct pwfilt_handle *handle = vhandle;
struct pwfilt_regex *filt; struct pwfilt_regex *filt;
char errbuf[1024]; const char *errstr;
int errcode;
debug_decl(iolog_pwfilt_add, SUDO_DEBUG_UTIL); debug_decl(iolog_pwfilt_add, SUDO_DEBUG_UTIL);
filt = malloc(sizeof(*filt)); filt = malloc(sizeof(*filt));
if (filt == NULL) if (filt == NULL)
goto oom; goto oom;
filt->pattern = dup_pattern(pattern); filt->pattern = strdup(pattern);
if (filt->pattern == NULL) if (filt->pattern == NULL)
goto oom; goto oom;
errcode = regcomp(&filt->regex, filt->pattern, REG_EXTENDED|REG_NOSUB); if (!sudo_regex_compile(&filt->regex, filt->pattern, &errstr)) {
if (errcode != 0) {
regerror(errcode, &filt->regex, errbuf, sizeof(errbuf));
sudo_warnx(U_("invalid regular expression \"%s\": %s"), sudo_warnx(U_("invalid regular expression \"%s\": %s"),
pattern, errbuf); pattern, U_(errstr));
goto bad; goto bad;
} }

View File

@@ -1,7 +1,7 @@
# #
# SPDX-License-Identifier: ISC # SPDX-License-Identifier: ISC
# #
# Copyright (c) 2011-2021 Todd C. Miller <Todd.Miller@sudo.ws> # Copyright (c) 2011-2022 Todd C. Miller <Todd.Miller@sudo.ws>
# #
# Permission to use, copy, modify, and distribute this software for any # Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above # purpose with or without fee is hereby granted, provided that the above
@@ -141,8 +141,8 @@ SHELL = @SHELL@
LTOBJS = basename.lo @DIGEST@ event.lo fatal.lo key_val.lo gethostname.lo \ LTOBJS = basename.lo @DIGEST@ event.lo fatal.lo key_val.lo gethostname.lo \
gettime.lo getgrouplist.lo gidlist.lo json.lo lbuf.lo locking.lo \ gettime.lo getgrouplist.lo gidlist.lo json.lo lbuf.lo locking.lo \
logfac.lo logpri.lo mkdir_parents.lo parseln.lo progname.lo rcstr.lo \ logfac.lo logpri.lo mkdir_parents.lo parseln.lo progname.lo rcstr.lo \
roundup.lo secure_path.lo setgroups.lo strsplit.lo strtobool.lo \ regex.lo roundup.lo secure_path.lo setgroups.lo strsplit.lo \
strtoid.lo strtomode.lo strtonum.lo sudo_conf.lo \ strtobool.lo strtoid.lo strtomode.lo strtonum.lo sudo_conf.lo \
sudo_debug.lo sudo_dso.lo term.lo ttyname_dev.lo \ sudo_debug.lo sudo_dso.lo term.lo ttyname_dev.lo \
ttysize.lo uuid.lo @COMMON_OBJS@ @LTLIBOBJS@ ttysize.lo uuid.lo @COMMON_OBJS@ @LTLIBOBJS@
@@ -1212,6 +1212,16 @@ reallocarray.i: $(srcdir)/reallocarray.c $(incdir)/sudo_compat.h \
$(CC) -E -o $@ $(CPPFLAGS) $< $(CC) -E -o $@ $(CPPFLAGS) $<
reallocarray.plog: reallocarray.i reallocarray.plog: reallocarray.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/reallocarray.c --i-file $< --output-file $@ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/reallocarray.c --i-file $< --output-file $@
regex.lo: $(srcdir)/regex.c $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(top_builddir)/config.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regex.c
regex.i: $(srcdir)/regex.c $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(top_builddir)/config.h
$(CC) -E -o $@ $(CPPFLAGS) $<
regex.plog: regex.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regex.c --i-file $< --output-file $@
roundup.lo: $(srcdir)/roundup.c $(incdir)/compat/stdbool.h \ roundup.lo: $(srcdir)/roundup.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \

131
lib/util/regex.c Normal file
View File

@@ -0,0 +1,131 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* 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.
*/
/*
* This is an open source non-commercial project. Dear PVS-Studio, please check it.
* PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
*/
#include <config.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include "sudo_compat.h"
#include "sudo_debug.h"
#include "sudo_util.h"
#include "sudo_gettext.h"
static char errbuf[1024];
/*
* Like strdup but collapses repeated '?', '*' and '+' ops in a regex.
* Glibc regcomp() has a bug where it uses excessive memory for repeated
* '+' ops. Collapse them to avoid running the fuzzer out of memory.
*/
static char *
dup_pattern(const char *src)
{
char *dst, *ret;
char ch, prev = '\0';
size_t len;
debug_decl(dup_pattern, SUDO_DEBUG_UTIL);
len = strlen(src);
ret = malloc(len + 1);
if (ret == NULL)
debug_return_ptr(NULL);
dst = ret;
while ((ch = *src++) != '\0') {
switch (ch) {
case '\\':
if (*src != '\0') {
*dst++ = '\\';
*dst++ = *src++;
prev = '\0';
continue;
}
break;
case '?':
case '*':
case '+':
if (ch == prev) {
continue;
}
break;
}
*dst++ = ch;
prev = ch;
}
*dst = '\0';
debug_return_ptr(ret);
}
/*
* Wrapper around regcomp() that handles a regex starting with (?i).
* Avoid using regex_t in the function args so we don't need to
* include regex.h everywhere.
*/
bool
sudo_regex_compile_v1(void *v, const char *pattern, const char **errstr)
{
int errcode, cflags = REG_EXTENDED|REG_NOSUB;
regex_t *preg;
char *copy = NULL;
const char *cp;
regex_t rebuf;
debug_decl(regex_compile, SUDO_DEBUG_UTIL);
/* Some callers just want to check the validity of the pattern. */
preg = v ? v : &rebuf;
/* Check for (?i) to enable case-insensitive matching. */
cp = pattern[0] == '^' ? pattern + 1 : pattern;
if (strncmp(cp, "(?i)", 4) == 0) {
cflags |= REG_ICASE;
copy = dup_pattern(pattern + 4);
if (copy == NULL) {
*errstr = N_("unable to allocate memory");
debug_return_bool(false);
}
if (pattern[0] == '^')
copy[0] = '^';
} else {
copy = dup_pattern(pattern);
if (copy == NULL) {
*errstr = N_("unable to allocate memory");
debug_return_bool(false);
}
}
errcode = regcomp(preg, copy, cflags);
if (errcode == 0) {
if (preg == &rebuf)
regfree(&rebuf);
} else {
regerror(errcode, preg, errbuf, sizeof(errbuf));
*errstr = errbuf;
}
free(copy);
debug_return_bool(errcode == 0);
}

View File

@@ -119,6 +119,7 @@ sudo_rcstr_addref
sudo_rcstr_alloc sudo_rcstr_alloc
sudo_rcstr_delref sudo_rcstr_delref
sudo_rcstr_dup sudo_rcstr_dup
sudo_regex_compile_v1
sudo_secure_dir_v1 sudo_secure_dir_v1
sudo_secure_file_v1 sudo_secure_file_v1
sudo_setgroups_v1 sudo_setgroups_v1

View File

@@ -36,7 +36,6 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <regex.h>
#include <syslog.h> #include <syslog.h>
#include "sudoers.h" #include "sudoers.h"
@@ -1287,22 +1286,17 @@ bool
cb_passprompt_regex(const union sudo_defs_val *sd_un, int op) cb_passprompt_regex(const union sudo_defs_val *sd_un, int op)
{ {
struct list_member *lm; struct list_member *lm;
int errcode; const char *errstr;
char errbuf[1024];
regex_t re;
debug_decl(cb_passprompt_regex, SUDOERS_DEBUG_DEFAULTS); debug_decl(cb_passprompt_regex, SUDOERS_DEBUG_DEFAULTS);
/* If adding one or more regexps, validate them with regcomp(). */ /* If adding one or more regexps, make sure they are valid. */
if (op == '+' || op == true) { if (op == '+' || op == true) {
SLIST_FOREACH(lm, &sd_un->list, entries) { SLIST_FOREACH(lm, &sd_un->list, entries) {
errcode = regcomp(&re, lm->value, REG_EXTENDED|REG_NOSUB); if (!sudo_regex_compile(NULL, lm->value, &errstr)) {
if (errcode != 0) {
regerror(errcode, &re, errbuf, sizeof(errbuf));
sudo_warnx(U_("invalid regular expression \"%s\": %s"), sudo_warnx(U_("invalid regular expression \"%s\": %s"),
lm->value, errbuf); lm->value, U_(errstr));
debug_return_bool(false); debug_return_bool(false);
} }
regfree(&re);
} }
} }

View File

@@ -60,36 +60,20 @@
static bool static bool
regex_matches(const char *pattern, const char *str) regex_matches(const char *pattern, const char *str)
{ {
int errcode, cflags = REG_EXTENDED|REG_NOSUB; const char *errstr;
char *copy = NULL; int errcode;
regex_t re; regex_t re;
debug_decl(regex_matches, SUDOERS_DEBUG_MATCH); debug_decl(regex_matches, SUDOERS_DEBUG_MATCH);
/* Check for (?i) to enable case-insensitive matching. */ if (!sudo_regex_compile(&re, pattern, &errstr)) {
if (strncmp(pattern, "^(?i)", 5) == 0) {
cflags |= REG_ICASE;
copy = strdup(pattern + 4);
if (copy == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_bool(false);
}
copy[0] = '^';
pattern = copy;
}
errcode = regcomp(&re, pattern, cflags);
if (errcode == 0) {
errcode = regexec(&re, str, 0, NULL, 0);
regfree(&re);
} else {
char errbuf[1024];
regerror(errcode, &re, errbuf, sizeof(errbuf));
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to compile regular expression \"%s\": %s", "unable to compile regular expression \"%s\": %s",
pattern, errbuf); pattern, errstr);
debug_return_bool(false);
} }
free(copy);
errcode = regexec(&re, str, 0, NULL, 0);
regfree(&re);
debug_return_bool(errcode == 0); debug_return_bool(errcode == 0);
} }

View File

@@ -1,3 +1,6 @@
# Test passprompt_regex
Defaults passprompt_regex="(?i)password: *"
# Test simple command with regex args # Test simple command with regex args
user ALL = /bin/ls ^/etc/(hosts|motd|issue)$ user ALL = /bin/ls ^/etc/(hosts|motd|issue)$

View File

@@ -1,4 +1,17 @@
{ {
"Defaults": [
{
"Options": [
{
"operation": "list_assign",
"passprompt_regex": [
"(?i)password:",
"*"
]
}
]
}
],
"User_Specs": [ "User_Specs": [
{ {
"User_List": [ "User_List": [

View File

@@ -1,3 +1,10 @@
dn: cn=defaults,ou=SUDOers,dc=sudo,dc=ws
objectClass: top
objectClass: sudoRole
cn: defaults
description: Default sudoOption's go here
sudoOption: passprompt_regex=(?i)password: *
dn: cn=user,ou=SUDOers,dc=sudo,dc=ws dn: cn=user,ou=SUDOers,dc=sudo,dc=ws
objectClass: top objectClass: top
objectClass: sudoRole objectClass: sudoRole

View File

@@ -1,3 +1,5 @@
Defaults passprompt_regex="(?i)password: *"
# sudoRole user, user_1, user_2, user_3, user_4, user_5, user_6, user_7, # sudoRole user, user_1, user_2, user_3, user_4, user_5, user_6, user_7,
# user_8, user_9, user_10, user_11 # user_8, user_9, user_10, user_11
user ALL = /bin/ls ^/etc/(hosts|motd|issue)$, /usr/bin/c*\ user ALL = /bin/ls ^/etc/(hosts|motd|issue)$, /usr/bin/c*\

View File

@@ -1,5 +1,7 @@
Parses OK Parses OK
Defaults passprompt_regex="(?i)password: *"
user ALL = /bin/ls ^/etc/(hosts|motd|issue)$ user ALL = /bin/ls ^/etc/(hosts|motd|issue)$
user ALL = /usr/bin/c* ^/etc/(hosts|motd|issue)$ user ALL = /usr/bin/c* ^/etc/(hosts|motd|issue)$
user ALL = ^/usr/bin/(who|w|id|whoami)$ user ALL = ^/usr/bin/(who|w|id|whoami)$

View File

@@ -1,3 +1,6 @@
#
DEFAULTS DEFVAR = BEGINSTR STRBODY ENDSTR WORD(4)
# #
WORD(6) ALL = COMMAND ARG REGEX WORD(6) ALL = COMMAND ARG REGEX

View File

@@ -1195,6 +1195,7 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr)
bool or = false, not = false; bool or = false, not = false;
struct search_node *sn; struct search_node *sn;
char type, **av; char type, **av;
const char *errstr;
debug_decl(parse_expr, SUDO_DEBUG_UTIL); debug_decl(parse_expr, SUDO_DEBUG_UTIL);
for (av = argv; *av != NULL; av++) { for (av = argv; *av != NULL; av++) {
@@ -1288,8 +1289,10 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr)
if (*(++av) == NULL) if (*(++av) == NULL)
sudo_fatalx(U_("%s requires an argument"), av[-1]); sudo_fatalx(U_("%s requires an argument"), av[-1]);
if (type == ST_PATTERN) { if (type == ST_PATTERN) {
if (regcomp(&sn->u.cmdre, *av, REG_EXTENDED|REG_NOSUB) != 0) if (!sudo_regex_compile(&sn->u.cmdre, *av, &errstr)) {
sudo_fatalx(U_("invalid regular expression: %s"), *av); sudo_fatalx(U_("invalid regular expression \"%s\": %s"),
*av, U_(errstr));
}
} else if (type == ST_TODATE || type == ST_FROMDATE) { } else if (type == ST_TODATE || type == ST_FROMDATE) {
sn->u.tstamp.tv_sec = get_date(*av); sn->u.tstamp.tv_sec = get_date(*av);
sn->u.tstamp.tv_nsec = 0; sn->u.tstamp.tv_nsec = 0;
@@ -1542,6 +1545,7 @@ list_sessions(int argc, char **argv, const char *pattern, const char *user,
const char *tty) const char *tty)
{ {
regex_t rebuf, *re = NULL; regex_t rebuf, *re = NULL;
const char *errstr;
debug_decl(list_sessions, SUDO_DEBUG_UTIL); debug_decl(list_sessions, SUDO_DEBUG_UTIL);
/* Parse search expression if present */ /* Parse search expression if present */
@@ -1550,8 +1554,10 @@ list_sessions(int argc, char **argv, const char *pattern, const char *user,
/* optional regex */ /* optional regex */
if (pattern) { if (pattern) {
re = &rebuf; re = &rebuf;
if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0) if (!sudo_regex_compile(re, pattern, &errstr)) {
sudo_fatalx(U_("invalid regular expression: %s"), pattern); sudo_fatalx(U_("invalid regular expression \"%s\": %s"),
pattern, U_(errstr));
}
} }
debug_return_int(find_sessions(session_dir, re, user, tty)); debug_return_int(find_sessions(session_dir, re, user, tty));

View File

@@ -3083,7 +3083,7 @@ char *sudoerstext;
int sudolineno; /* current sudoers line number. */ int sudolineno; /* current sudoers line number. */
char *sudoers; /* sudoers file being parsed. */ char *sudoers; /* sudoers file being parsed. */
char *sudoers_errstr; /* description of last error from lexer. */ const char *sudoers_errstr; /* description of last error from lexer. */
struct sudolinebuf sudolinebuf; /* sudoers line being parsed. */ struct sudolinebuf sudolinebuf; /* sudoers line being parsed. */
/* Default sudoers path, mode and owner (may be set via sudo.conf) */ /* Default sudoers path, mode and owner (may be set via sudo.conf) */
@@ -3648,7 +3648,7 @@ YY_RULE_SETUP
BEGIN INITIAL; BEGIN INITIAL;
continued = false; continued = false;
if (sudoers_strict) { if (sudoers_strict) {
if (!regex_valid(sudoerstext, &sudoers_errstr)) { if (!sudo_regex_compile(NULL, sudoerstext, &sudoers_errstr)) {
LEXTRACE("ERROR "); LEXTRACE("ERROR ");
return ERROR; return ERROR;
} }
@@ -4283,7 +4283,7 @@ YY_RULE_SETUP
#line 774 "toke.l" #line 774 "toke.l"
{ {
if (sudoers_strict) { if (sudoers_strict) {
if (!regex_valid(sudoerstext, &sudoers_errstr)) { if (!sudo_regex_compile(NULL, sudoerstext, &sudoers_errstr)) {
LEXTRACE("ERROR "); LEXTRACE("ERROR ");
return ERROR; return ERROR;
} }

View File

@@ -27,7 +27,7 @@ struct sudolinebuf {
size_t toke_start; /* starting column of current token */ size_t toke_start; /* starting column of current token */
size_t toke_end; /* ending column of current token */ size_t toke_end; /* ending column of current token */
}; };
extern char *sudoers_errstr; extern const char *sudoers_errstr;
extern struct sudolinebuf sudolinebuf; extern struct sudolinebuf sudolinebuf;
bool append(const char *, size_t); bool append(const char *, size_t);
@@ -35,7 +35,6 @@ bool fill_args(const char *, size_t, int);
bool fill_cmnd(const char *, size_t); bool fill_cmnd(const char *, size_t);
bool fill(const char *, size_t); bool fill(const char *, size_t);
bool ipv6_valid(const char *s); bool ipv6_valid(const char *s);
bool regex_valid(const char *pattern, char **errstr);
int sudoers_trace_print(const char *); int sudoers_trace_print(const char *);
void sudoerserrorf(const char *, ...) __printf0like(1, 2); void sudoerserrorf(const char *, ...) __printf0like(1, 2);
void sudoerserror(const char *); void sudoerserror(const char *);

View File

@@ -55,7 +55,7 @@
int sudolineno; /* current sudoers line number. */ int sudolineno; /* current sudoers line number. */
char *sudoers; /* sudoers file being parsed. */ char *sudoers; /* sudoers file being parsed. */
char *sudoers_errstr; /* description of last error from lexer. */ const char *sudoers_errstr; /* description of last error from lexer. */
struct sudolinebuf sudolinebuf; /* sudoers line being parsed. */ struct sudolinebuf sudolinebuf; /* sudoers line being parsed. */
/* Default sudoers path, mode and owner (may be set via sudo.conf) */ /* Default sudoers path, mode and owner (may be set via sudo.conf) */
@@ -297,7 +297,7 @@ DEFVAR [a-z_]+
BEGIN INITIAL; BEGIN INITIAL;
continued = false; continued = false;
if (sudoers_strict) { if (sudoers_strict) {
if (!regex_valid(sudoerstext, &sudoers_errstr)) { if (!sudo_regex_compile(NULL, sudoerstext, &sudoers_errstr)) {
LEXTRACE("ERROR "); LEXTRACE("ERROR ");
return ERROR; return ERROR;
} }
@@ -773,7 +773,7 @@ sudoedit {
{REGEX} { {REGEX} {
if (sudoers_strict) { if (sudoers_strict) {
if (!regex_valid(sudoerstext, &sudoers_errstr)) { if (!sudo_regex_compile(NULL, sudoerstext, &sudoers_errstr)) {
LEXTRACE("ERROR "); LEXTRACE("ERROR ");
return ERROR; return ERROR;
} }

View File

@@ -39,7 +39,6 @@
static unsigned int arg_len = 0; static unsigned int arg_len = 0;
static unsigned int arg_size = 0; static unsigned int arg_size = 0;
static char errbuf[1024];
/* /*
* Copy the string and collapse any escaped characters. * Copy the string and collapse any escaped characters.
@@ -247,36 +246,3 @@ ipv6_valid(const char *s)
debug_return_bool(nmatch <= 1); debug_return_bool(nmatch <= 1);
} }
bool
regex_valid(const char *pattern, char **errstr)
{
int errcode, cflags = REG_EXTENDED|REG_NOSUB;
char *copy = NULL;
regex_t re;
debug_decl(regex_valid, SUDOERS_DEBUG_PARSER);
/* Check for (?i) to enable case-insensitive matching. */
if (strncmp(pattern, "^(?i)", 5) == 0) {
cflags |= REG_ICASE;
copy = strdup(pattern + 4);
if (copy == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
sudoerserror(NULL);
debug_return_bool(false);
}
copy[0] = '^';
pattern = copy;
}
errcode = regcomp(&re, pattern, cflags);
if (errcode == 0) {
regfree(&re);
} else {
regerror(errcode, &re, errbuf, sizeof(errbuf));
*errstr = errbuf;
}
free(copy);
debug_return_bool(errcode == 0);
}