From: Andreas Schneider Date: Wed, 2 Sep 2020 15:19:00 +0000 (+0200) Subject: lib:cmdline: Add sanity check for options X-Git-Tag: tevent-0.11.0~971 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8560c31080881f746946bb88ea8e549b3df97d63;p=thirdparty%2Fsamba.git lib:cmdline: Add sanity check for options Make sure we don't have duplicate options! Signed-off-by: Andreas Schneider Reviewed-by: Andrew Bartlett --- diff --git a/lib/cmdline/cmdline.c b/lib/cmdline/cmdline.c index bddb27642e5..fd104b196cd 100644 --- a/lib/cmdline/cmdline.c +++ b/lib/cmdline/cmdline.c @@ -161,6 +161,120 @@ void samba_cmdline_burn(int argc, char *argv[]) } } +static bool is_popt_table_end(const struct poptOption *o) +{ + if (o->longName == NULL && + o->shortName == 0 && + o->argInfo == 0 && + o->arg == NULL && + o->val == 0 && + o->descrip == NULL && + o->argDescrip == NULL) { + return true; + } + + return false; +} + +static void find_duplicates(const struct poptOption *needle, + const struct poptOption *haystack, + size_t *count) +{ + for(; + !is_popt_table_end(haystack); + haystack++) { + switch (haystack->argInfo) { + case POPT_ARG_INCLUDE_TABLE: + if (haystack->arg != NULL) { + find_duplicates(needle, haystack->arg, count); + } + + break; + default: + if (needle->shortName != 0 && + needle->shortName == haystack->shortName) { + (*count)++; + break; + } + + if (needle->longName != NULL && + haystack->longName != NULL && + strequal(needle->longName, haystack->longName)) { + (*count)++; + break; + } + break; + } + + if (*count > 1) { + return; + } + } +} + +static bool opt_sanity_check(const struct poptOption *current_opts, + const struct poptOption *full_opts) +{ + const struct poptOption *o = current_opts; + + for(; + !is_popt_table_end(o); + o++) { + bool ok; + + switch (o->argInfo) { + case POPT_ARG_INCLUDE_TABLE: + if (o->arg != NULL) { + ok = opt_sanity_check(o->arg, full_opts); + if (!ok) { + return false; + } + } + + break; + default: + if (o->longName != NULL || o->shortName != 0) { + size_t count = 0; + + find_duplicates(o, full_opts, &count); + if (count > 1) { + DBG_ERR("Duplicate %s (%c) detected!\n", + o->longName, + o->shortName != 0 ? + o->shortName : + '-'); + return false; + } + } + + break; + } + } + + return true; +} + +bool samba_cmdline_sanity_check(const struct poptOption *opts) +{ + return opt_sanity_check(opts, opts); +} + +poptContext samba_popt_get_context(const char * name, + int argc, const char ** argv, + const struct poptOption * options, + unsigned int flags) +{ +#ifdef DEVELOPER + bool ok; + + ok = samba_cmdline_sanity_check(options); + if (!ok) { + return NULL; + } +#endif + return poptGetContext(name, argc, argv, options, flags); +} + /********************************************************** * COMMON SAMBA POPT **********************************************************/ diff --git a/lib/cmdline/cmdline.h b/lib/cmdline/cmdline.h index 25055a532ee..490d38216d0 100644 --- a/lib/cmdline/cmdline.h +++ b/lib/cmdline/cmdline.h @@ -106,6 +106,39 @@ struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt); */ void samba_cmdline_burn(int argc, char *argv[]); +/** + * @brief Sanity check the commadline options. + * + * This checks for duplicates in short and long options. + * + * @param[in] opts The options array to check. + * + * @return true if valid, false otherwise. + */ +bool samba_cmdline_sanity_check(const struct poptOption *opts); + +/** + * @brief This is a wrapper for the poptGetContext() which initializes the popt + * context. + * + * If Samba is build in developer mode, this will call + * samba_cmdline_sanity_check() before poptGetContext(). + * + * @param name The context name (usually argv[0] program name) + * + * @param argc Number of arguments + * + * @param argv The argument array + * @param options The address of popt option table + * @param flags The OR'd POPT_CONTEXT_* bits + * + * @return The initialized popt context or NULL on error. + */ +poptContext samba_popt_get_context(const char * name, + int argc, const char ** argv, + const struct poptOption * options, + unsigned int flags); + /** * @brief A popt structure for common samba options. */ diff --git a/lib/cmdline/tests/test_cmdline.c b/lib/cmdline/tests/test_cmdline.c index 0326c2857be..5148243ccaa 100644 --- a/lib/cmdline/tests/test_cmdline.c +++ b/lib/cmdline/tests/test_cmdline.c @@ -25,6 +25,38 @@ #include "lib/cmdline/cmdline.h" +static void torture_cmdline_sanity_check_good(void **state) +{ + bool ok; + struct poptOption long_options_good[] = { + POPT_AUTOHELP + POPT_COMMON_SAMBA + POPT_COMMON_CONNECTION + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + POPT_LEGACY_S3 + POPT_TABLEEND + }; + + ok = samba_cmdline_sanity_check(long_options_good); + assert_true(ok); +} + +static void torture_cmdline_sanity_check_bad(void **state) +{ + bool ok; + + struct poptOption long_options_bad[] = { + POPT_AUTOHELP + POPT_COMMON_SAMBA + POPT_COMMON_SAMBA + POPT_TABLEEND + }; + + ok = samba_cmdline_sanity_check(long_options_bad); + assert_false(ok); +} + static void torture_cmdline_burn(void **state) { char arg1[] = "-U Administrator%secret"; @@ -47,6 +79,8 @@ int main(int argc, char *argv[]) { int rc; const struct CMUnitTest tests[] = { + cmocka_unit_test(torture_cmdline_sanity_check_good), + cmocka_unit_test(torture_cmdline_sanity_check_bad), cmocka_unit_test(torture_cmdline_burn), };