Escape/unescape commas when serializing/deserializing a stringlist.
This commit is contained in:
3
MANIFEST
3
MANIFEST
@@ -799,6 +799,7 @@ plugins/sudoers/regress/parser/check_digest.out.ok
|
||||
plugins/sudoers/regress/parser/check_fill.c
|
||||
plugins/sudoers/regress/parser/check_gentime.c
|
||||
plugins/sudoers/regress/parser/check_hexchar.c
|
||||
plugins/sudoers/regress/serialize_list/check_serialize_list.c
|
||||
plugins/sudoers/regress/starttime/check_starttime.c
|
||||
plugins/sudoers/regress/sudoers/test1.in
|
||||
plugins/sudoers/regress/sudoers/test1.json.ok
|
||||
@@ -1011,6 +1012,7 @@ plugins/sudoers/regress/visudo/test8.out.ok
|
||||
plugins/sudoers/regress/visudo/test8.sh
|
||||
plugins/sudoers/regress/visudo/test9.out.ok
|
||||
plugins/sudoers/regress/visudo/test9.sh
|
||||
plugins/sudoers/serialize_list.c
|
||||
plugins/sudoers/set_perms.c
|
||||
plugins/sudoers/solaris_audit.c
|
||||
plugins/sudoers/solaris_audit.h
|
||||
@@ -1047,6 +1049,7 @@ plugins/sudoers/toke_util.c
|
||||
plugins/sudoers/tsdump.c
|
||||
plugins/sudoers/tsgetgrpw.c
|
||||
plugins/sudoers/tsgetgrpw.h
|
||||
plugins/sudoers/unesc_str.c
|
||||
plugins/sudoers/visudo.c
|
||||
plugins/system_group/Makefile.in
|
||||
plugins/system_group/system_group.c
|
||||
|
@@ -158,8 +158,8 @@ PROGS = sudoers.la visudo sudoreplay cvtsudoers testsudoers
|
||||
# Regression tests
|
||||
TEST_PROGS = check_addr check_base64 check_digest check_editor \
|
||||
check_env_pattern check_exptilde check_fill check_gentime \
|
||||
check_hexchar check_iolog_plugin check_starttime \
|
||||
check_unesc @SUDOERS_TEST_PROGS@
|
||||
check_hexchar check_iolog_plugin check_serialize_list \
|
||||
check_starttime check_unesc @SUDOERS_TEST_PROGS@
|
||||
|
||||
# Fuzzers
|
||||
LIB_FUZZING_ENGINE = @FUZZ_ENGINE@
|
||||
@@ -185,9 +185,9 @@ SUDOERS_OBJS = $(AUTH_OBJS) audit.lo boottime.lo check.lo editor.lo env.lo \
|
||||
sudoers_hooks.lo env_pattern.lo file.lo find_path.lo \
|
||||
fmtsudoers.lo gc.lo goodpath.lo group_plugin.lo interfaces.lo \
|
||||
iolog.lo iolog_path_escapes.lo locale.lo log_client.lo \
|
||||
logging.lo parse.lo policy.lo prompt.lo set_perms.lo \
|
||||
starttime.lo strlcpy_unesc.lo strvec_join.lo sudo_nss.lo \
|
||||
sudoers.lo timestamp.lo @SUDOERS_OBJS@
|
||||
logging.lo parse.lo policy.lo prompt.lo serialize_list.lo \
|
||||
set_perms.lo starttime.lo strlcpy_unesc.lo strvec_join.lo \
|
||||
sudo_nss.lo sudoers.lo timestamp.lo unesc_str.lo @SUDOERS_OBJS@
|
||||
|
||||
SUDOERS_IOBJS = $(SUDOERS_OBJS:.lo=.i)
|
||||
|
||||
@@ -241,17 +241,22 @@ CHECK_HEXCHAR_OBJS = check_hexchar.o hexchar.lo sudoers_debug.lo
|
||||
|
||||
CHECK_IOLOG_PLUGIN_OBJS = check_iolog_plugin.o iolog.lo log_client.lo \
|
||||
locale.lo pwutil.lo pwutil_impl.lo redblack.lo \
|
||||
strlist.lo sudoers_debug.lo
|
||||
strlist.lo sudoers_debug.lo unesc_str.lo
|
||||
|
||||
CHECK_SYMBOLS_OBJS = check_symbols.o
|
||||
|
||||
CHECK_STARTTIME_OBJS = check_starttime.o starttime.lo sudoers_debug.lo
|
||||
|
||||
CHECK_UNESC_OBJS = check_unesc.o strlcpy_unesc.lo strvec_join.lo sudoers_debug.lo
|
||||
CHECK_UNESC_OBJS = check_unesc.o strlcpy_unesc.lo strvec_join.lo \
|
||||
sudoers_debug.lo unesc_str.lo
|
||||
|
||||
CHECK_SERIALIZE_LIST_OBJS = check_serialize_list.lo serialize_list.lo \
|
||||
sudoers_debug.lo
|
||||
|
||||
FUZZ_POLICY_OBJS = editor.lo env.lo env_pattern.lo fuzz_policy.o fuzz_stubs.o \
|
||||
gc.lo iolog_path_escapes.lo locale.lo policy.lo \
|
||||
strlcpy_unesc.lo strvec_join.lo sudoers.lo sudoers_hooks.lo
|
||||
serialize_list.lo strlcpy_unesc.lo strvec_join.lo \
|
||||
sudoers.lo sudoers_hooks.lo
|
||||
|
||||
FUZZ_POLICY_CORPUS = $(srcdir)/regress/corpus/seed/policy/policy.*
|
||||
|
||||
@@ -386,6 +391,9 @@ check_hexchar: $(CHECK_HEXCHAR_OBJS) $(LIBUTIL)
|
||||
check_iolog_plugin: $(CHECK_IOLOG_PLUGIN_OBJS) $(LIBUTIL) $(LIBIOLOG) $(LIBLOGSRV)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PLUGIN_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBIOLOG) $(LIBLOGSRV) @LIBTLS@
|
||||
|
||||
check_serialize_list: $(CHECK_SERIALIZE_LIST_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_SERIALIZE_LIST_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_starttime: $(CHECK_STARTTIME_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_STARTTIME_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
@@ -659,6 +667,7 @@ check: $(TEST_PROGS) visudo testsudoers cvtsudoers check-fuzzer
|
||||
./check_hexchar || rval=`expr $$rval + $$?`; \
|
||||
mkdir -p regress/iolog_plugin; \
|
||||
./check_iolog_plugin regress/iolog_plugin/iolog || rval=`expr $$rval + $$?`; \
|
||||
./check_serialize_list || rval=`expr $$rval + $$?`; \
|
||||
./check_starttime || rval=`expr $$rval + $$?`; \
|
||||
./check_unesc || rval=`expr $$rval + $$?`; \
|
||||
if test -f check_symbols; then \
|
||||
@@ -1259,6 +1268,34 @@ check_iolog_plugin.i: $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c \
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_iolog_plugin.plog: check_iolog_plugin.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c --i-file $< --output-file $@
|
||||
check_serialize_list.lo: \
|
||||
$(srcdir)/regress/serialize_list/check_serialize_list.c \
|
||||
$(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_eventlog.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)/parse.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)/regress/serialize_list/check_serialize_list.c
|
||||
check_serialize_list.i: \
|
||||
$(srcdir)/regress/serialize_list/check_serialize_list.c \
|
||||
$(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_eventlog.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)/parse.h \
|
||||
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_serialize_list.plog: check_serialize_list.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/serialize_list/check_serialize_list.c --i-file $< --output-file $@
|
||||
check_starttime.o: $(srcdir)/regress/starttime/check_starttime.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_plugin.h \
|
||||
@@ -2671,6 +2708,30 @@ securid5.i: $(authdir)/securid5.c $(authdir)/sudo_auth.h $(devdir)/def_data.h \
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
securid5.plog: securid5.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(authdir)/securid5.c --i-file $< --output-file $@
|
||||
serialize_list.lo: $(srcdir)/serialize_list.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_eventlog.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)/parse.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)/serialize_list.c
|
||||
serialize_list.i: $(srcdir)/serialize_list.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_eventlog.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)/parse.h \
|
||||
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
serialize_list.plog: serialize_list.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/serialize_list.c --i-file $< --output-file $@
|
||||
set_perms.lo: $(srcdir)/set_perms.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
@@ -3213,6 +3274,12 @@ tsgetgrpw.i: $(srcdir)/tsgetgrpw.c $(devdir)/def_data.h \
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
tsgetgrpw.plog: tsgetgrpw.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/tsgetgrpw.c --i-file $< --output-file $@
|
||||
unesc_str.lo: $(srcdir)/unesc_str.c
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/unesc_str.c
|
||||
unesc_str.i: $(srcdir)/unesc_str.c
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
unesc_str.plog: unesc_str.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/unesc_str.c --i-file $< --output-file $@
|
||||
visudo.o: $(srcdir)/visudo.c $(devdir)/def_data.h $(devdir)/gram.h \
|
||||
$(incdir)/compat/getopt.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
|
@@ -211,7 +211,6 @@ free_iolog_details(void)
|
||||
|
||||
/*
|
||||
* Convert a comma-separated list to a string list.
|
||||
* XXX - handle escaped commas
|
||||
*/
|
||||
static struct sudoers_str_list *
|
||||
deserialize_stringlist(const char *s)
|
||||
@@ -235,6 +234,7 @@ deserialize_stringlist(const char *s)
|
||||
free(str);
|
||||
goto bad;
|
||||
}
|
||||
unescape_string(str->str);
|
||||
STAILQ_INSERT_TAIL(strlist, str, entries);
|
||||
}
|
||||
if (STAILQ_EMPTY(strlist))
|
||||
@@ -265,9 +265,9 @@ set_passprompt_regex(const char *cstr)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* XXX - handle escaped commas */
|
||||
for ((cp = strtok_r(str, ",", &last)); cp != NULL;
|
||||
(cp = strtok_r(NULL, ",", &last))) {
|
||||
unescape_string(cp);
|
||||
if (!iolog_pwfilt_add(handle, cp))
|
||||
goto bad;
|
||||
}
|
||||
|
@@ -572,46 +572,6 @@ bad:
|
||||
debug_return_int(MODE_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert struct list_members to a comma-separated string with
|
||||
* the given variable name.
|
||||
* XXX - escape commas in member values
|
||||
*/
|
||||
static char *
|
||||
serialize_list(const char *varname, struct list_members *members)
|
||||
{
|
||||
struct list_member *lm, *next;
|
||||
size_t len, result_size;
|
||||
char *result;
|
||||
debug_decl(serialize_list, SUDOERS_DEBUG_PLUGIN);
|
||||
|
||||
result_size = strlen(varname) + 1;
|
||||
SLIST_FOREACH(lm, members, entries) {
|
||||
result_size += strlen(lm->value) + 1;
|
||||
}
|
||||
if ((result = malloc(result_size)) == NULL)
|
||||
goto bad;
|
||||
/* No need to check len for overflow here. */
|
||||
len = strlcpy(result, varname, result_size);
|
||||
result[len++] = '=';
|
||||
result[len] = '\0';
|
||||
SLIST_FOREACH_SAFE(lm, members, entries, next) {
|
||||
len = strlcat(result, lm->value, result_size);
|
||||
if (len + (next != NULL) >= result_size) {
|
||||
sudo_warnx(U_("internal error, %s overflow"), __func__);
|
||||
goto bad;
|
||||
}
|
||||
if (next != NULL) {
|
||||
result[len++] = ',';
|
||||
result[len] = '\0';
|
||||
}
|
||||
}
|
||||
debug_return_str(result);
|
||||
bad:
|
||||
free(result);
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the execution environment and other front-end settings.
|
||||
* Builds up the command_info list and sets argv and envp.
|
||||
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SUDO_ERROR_WRAP 0
|
||||
|
||||
#include "sudoers.h"
|
||||
|
||||
sudo_dso_public int main(int argc, char *argv[]);
|
||||
|
||||
static void
|
||||
test_serialize_list(int *ntests_out, int *errors_out)
|
||||
{
|
||||
int ntests = *ntests_out;
|
||||
int errors = *errors_out;
|
||||
const char *expected = "myvar=a value with spaces,this\\,and\\,that,\\,";
|
||||
struct list_members members = SLIST_HEAD_INITIALIZER(members);
|
||||
struct list_member lm1, lm2, lm3;
|
||||
char *result;
|
||||
|
||||
lm1.value = "a value with spaces";
|
||||
lm2.value = "this,and,that";
|
||||
lm3.value = ",";
|
||||
SLIST_INSERT_HEAD(&members, &lm3, entries);
|
||||
SLIST_INSERT_HEAD(&members, &lm2, entries);
|
||||
SLIST_INSERT_HEAD(&members, &lm1, entries);
|
||||
|
||||
ntests++;
|
||||
result = serialize_list("myvar", &members);
|
||||
if (result == NULL) {
|
||||
sudo_warnx("serialize_list returns NULL");
|
||||
++errors;
|
||||
goto done;
|
||||
}
|
||||
ntests++;
|
||||
if (strcmp(result, expected) != 0) {
|
||||
sudo_warnx("got \"%s\", expected \"%s\"", result, expected);
|
||||
++errors;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
*ntests_out = ntests;
|
||||
*errors_out = errors;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ntests = 0, errors = 0;
|
||||
|
||||
initprogname(argc > 0 ? argv[0] : "check_serialize_list");
|
||||
|
||||
test_serialize_list(&ntests, &errors);
|
||||
|
||||
if (ntests != 0) {
|
||||
printf("%s: %d tests run, %d errors, %d%% success rate\n",
|
||||
getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
|
||||
}
|
||||
|
||||
exit(errors);
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
* Copyright (c) 2021-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
|
||||
@@ -31,7 +31,10 @@ struct test_data {
|
||||
char *result;
|
||||
size_t result_len;
|
||||
size_t bufsize;
|
||||
} test_data[] = {
|
||||
};
|
||||
|
||||
/* strlcpy_unescape() does not unescape whitespace */
|
||||
static struct test_data strlcpy_unescape_test_data[] = {
|
||||
{ "\\\0ABC", "\\", 1, 2 }, /* 1 */
|
||||
{ "\\ \\;", "\\ ;", 3, 4 }, /* 2 */
|
||||
{ "\\\t\\;", "\\\t;", 3, 4 }, /* 3 */
|
||||
@@ -43,6 +46,20 @@ struct test_data {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* unescape_string() _does_ unescape whitespace */
|
||||
static struct test_data unescape_string_test_data[] = {
|
||||
{ "foo\\ bar", "foo bar", 7, 8 }, /* 1 */
|
||||
{ "foo\\,bar", "foo,bar", 7, 8 }, /* 2 */
|
||||
{ "baz \\", "baz \\", 5, 5 }, /* 3 */
|
||||
{ "\\foo", "foo", 3, 4 }, /* 4 */
|
||||
{ "var=aaa,b\\,b", "var=aaa,b,b", 11, 12 }, /* 5 */
|
||||
{ "\\a\\ b\\ c\\\\", "a b c\\", 6, 10 }, /* 6 */
|
||||
{ "\\", "\\", 1, 1 }, /* 7 */
|
||||
{ "foo", "foo", 3, 3 }, /* 8 */
|
||||
{ "", "", 0, 0 }, /* 9 */
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
sudo_dso_public int main(int argc, char *argv[]);
|
||||
|
||||
static void
|
||||
@@ -54,7 +71,7 @@ test_strlcpy_unescape(int *ntests_out, int *errors_out)
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
|
||||
for (td = test_data; td->input != NULL; td++) {
|
||||
for (td = strlcpy_unescape_test_data; td->input != NULL; td++) {
|
||||
ntests++;
|
||||
memset(buf, 'A', sizeof(buf));
|
||||
len = strlcpy_unescape(buf, td->input, td->bufsize);
|
||||
@@ -85,6 +102,31 @@ test_strlcpy_unescape(int *ntests_out, int *errors_out)
|
||||
*errors_out = errors;
|
||||
}
|
||||
|
||||
static void
|
||||
test_unescape_string(int *ntests_out, int *errors_out)
|
||||
{
|
||||
int ntests = *ntests_out;
|
||||
int errors = *errors_out;
|
||||
struct test_data *td;
|
||||
char buf[1024];
|
||||
|
||||
for (td = unescape_string_test_data; td->input != NULL; td++) {
|
||||
ntests++;
|
||||
memset(buf, 'A', sizeof(buf));
|
||||
memcpy(buf, td->input, td->bufsize);
|
||||
buf[td->bufsize] = '\0';
|
||||
unescape_string(buf);
|
||||
if (strcmp(td->result, buf) != 0) {
|
||||
sudo_warnx("%d: \"%s\": got \"%s\", expected \"%s\"",
|
||||
ntests, td->input, buf, td->result);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
*ntests_out = ntests;
|
||||
*errors_out = errors;
|
||||
}
|
||||
|
||||
static void
|
||||
test_strvec_join(char sep, int *ntests_out, int *errors_out)
|
||||
{
|
||||
@@ -132,6 +174,9 @@ main(int argc, char *argv[])
|
||||
/* strlcpy_unescape tests */
|
||||
test_strlcpy_unescape(&ntests, &errors);
|
||||
|
||||
/* unescape_string test */
|
||||
test_unescape_string(&ntests, &errors);
|
||||
|
||||
/* strvec_join test */
|
||||
test_strvec_join(' ', &ntests, &errors);
|
||||
test_strvec_join('\n', &ntests, &errors);
|
||||
|
82
plugins/sudoers/serialize_list.c
Normal file
82
plugins/sudoers/serialize_list.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2019, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
|
||||
/*
|
||||
* Convert struct list_members to a comma-separated string with
|
||||
* the given variable name. Escapes backslashes and commas.
|
||||
*/
|
||||
char *
|
||||
serialize_list(const char *varname, struct list_members *members)
|
||||
{
|
||||
struct list_member *lm, *next;
|
||||
size_t len, result_size;
|
||||
char *cp, *result;
|
||||
debug_decl(serialize_list, SUDOERS_DEBUG_PLUGIN);
|
||||
|
||||
result_size = strlen(varname) + 1;
|
||||
SLIST_FOREACH(lm, members, entries) {
|
||||
for (cp = lm->value; *cp != '\0'; cp++) {
|
||||
result_size++;
|
||||
if (*cp == '\\' || *cp == ',')
|
||||
result_size++;
|
||||
}
|
||||
result_size++;
|
||||
}
|
||||
if ((result = malloc(result_size)) == NULL)
|
||||
goto bad;
|
||||
/* No need to check len for overflow here. */
|
||||
len = strlcpy(result, varname, result_size);
|
||||
result[len++] = '=';
|
||||
SLIST_FOREACH_SAFE(lm, members, entries, next) {
|
||||
for (cp = lm->value; *cp != '\0'; cp++) {
|
||||
bool escape = (*cp == '\\' || *cp == ',');
|
||||
if (len + 1 + escape >= result_size) {
|
||||
sudo_warnx(U_("internal error, %s overflow"), __func__);
|
||||
goto bad;
|
||||
}
|
||||
if (escape)
|
||||
result[len++] = '\\';
|
||||
result[len++] = *cp;
|
||||
}
|
||||
if (next != NULL) {
|
||||
if (len + 1 >= result_size) {
|
||||
sudo_warnx(U_("internal error, %s overflow"), __func__);
|
||||
goto bad;
|
||||
}
|
||||
result[len++] = ',';
|
||||
}
|
||||
result[len] = '\0';
|
||||
}
|
||||
debug_return_str(result);
|
||||
bad:
|
||||
free(result);
|
||||
debug_return_str(NULL);
|
||||
}
|
@@ -467,4 +467,10 @@ size_t strlcpy_unescape(char *dst, const char *src, size_t size);
|
||||
/* strvec_join.c */
|
||||
char *strvec_join(char *const argv[], char sep, size_t (*cpy)(char *, const char *, size_t));
|
||||
|
||||
/* unesc_str.c */
|
||||
void unescape_string(char *str);
|
||||
|
||||
/* serialize_list.c */
|
||||
char *serialize_list(const char *varname, struct list_members *members);
|
||||
|
||||
#endif /* SUDOERS_SUDOERS_H */
|
||||
|
42
plugins/sudoers/unesc_str.c
Normal file
42
plugins/sudoers/unesc_str.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
/*
|
||||
* Remove backslash escape chars.
|
||||
*/
|
||||
void
|
||||
unescape_string(char *str)
|
||||
{
|
||||
char *cp = str;
|
||||
char *ep = str + strlen(str);
|
||||
|
||||
while ((cp = strchr(cp, '\\')) != NULL) {
|
||||
if (cp[1] == '\0')
|
||||
break;
|
||||
memmove(cp, cp + 1, (size_t)(ep - cp));
|
||||
cp++;
|
||||
ep--;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user