}
}
+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
**********************************************************/
*/
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.
*/
#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";
{
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),
};