]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2026-4408: s3:torture: tests for password complexity scripts
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Sat, 2 May 2026 10:14:43 +0000 (22:14 +1200)
committerStefan Metzmacher <metze@samba.org>
Tue, 26 May 2026 12:51:32 +0000 (12:51 +0000)
This tries to demonstrate the new logic for %u in
'check password script'.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=16034

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
selftest/tests.py
source3/torture/test_rpc_samr.c [new file with mode: 0644]
source3/torture/wscript_build

index 0a369e4c47a509b6cb2dac9340da67ec08c48c7c..144c8927f39162b9a577fccf4b4685080cd39aea 100644 (file)
@@ -576,6 +576,8 @@ plantestsuite("samba.unittests.test_oLschema2ldif", "none",
               [os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")])
 plantestsuite("samba.unittests.auth.sam", "none",
               [os.path.join(bindir(), "test_auth_sam")])
+plantestsuite("samba.unittests.test_rpc_samr", "none",
+              [os.path.join(bindir(), "test_rpc_samr")])
 if have_heimdal_support and not using_system_gssapi:
     plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none",
                   [valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))])
diff --git a/source3/torture/test_rpc_samr.c b/source3/torture/test_rpc_samr.c
new file mode 100644 (file)
index 0000000..8d4f398
--- /dev/null
@@ -0,0 +1,358 @@
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+#include <cmocka.h>
+#include "includes.h"
+#include "talloc.h"
+#include "libcli/util/ntstatus.h"
+#include "../librpc/gen_ndr/samr.h"
+#include "rpc_server/samr/srv_samr_util.h"
+
+/* set SAMR_DEBUG_VERBOSE to true to print more. */
+#define SAMR_DEBUG_VERBOSE true
+
+#if SAMR_DEBUG_VERBOSE
+#define debug_message(...) print_message(__VA_ARGS__)
+#else
+#define debug_message(...) /* debug_message */
+#endif
+
+static int setup_talloc_context(void **state)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       *state = mem_ctx;
+       return 0;
+}
+
+static int teardown_talloc_context(void **state)
+{
+       TALLOC_CTX *mem_ctx = *state;
+       TALLOC_FREE(mem_ctx);
+       return 0;
+}
+
+struct cmd_expansion {
+       const char *lp_cmd;
+       const char *username;
+       const char *result_cmd;
+       NTSTATUS result_code;
+};
+
+static struct cmd_expansion expansions[] = {
+       {
+               "/bin/echo '%u'",
+               "bob",
+               "/bin/echo 'bob'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "bob",
+               "/bin/echo 'bob'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "bob'",
+               "/bin/echo 'bob_'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "bob\'",
+               "/bin/echo 'bob_'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "bob'''",
+               "/bin/echo 'bob___'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "bob*",
+               NULL,
+               NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+       },
+       {
+               "/bin/echo %u",
+               "bob\"",
+               NULL,
+               NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+       },
+       {
+               "/bin/echo '%u",
+               "bob bob bob",
+               "/bin/echo '__CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo \"%u\"",
+               " ",
+               "/bin/echo ' '",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo \"--uu=%u\"",
+               "bob",
+               "/bin/echo \"--uu=__CVE-2026-4408_FallbackUsername__\"",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo \"--uu=%u\"",
+               "bob !0",
+               "/bin/echo \"--uu=__CVE-2026-4408_FallbackUsername__\"",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "!0",
+               "/bin/echo '!0'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo \"--uu=%u\"",
+               "bob \\",
+               NULL,
+               NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+       },
+       {
+               "/bin/echo --uu='%u'",
+               "bob >> x",
+               NULL,
+               NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+       },
+       {
+               "/bin/echo '--uu=%u\"",
+               "bob",
+               "/bin/echo '--uu=__CVE-2026-4408_FallbackUsername__\"",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu='%u'",
+               "bob",
+               "/bin/echo --uu='bob'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu'=%u'",
+               "bob",
+               "/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu'=%u'",
+               "`ls`",
+               "/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu'=%u'",
+               "$(ls)",
+               "/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu='%u'",
+               "$(ls)",
+               "/bin/echo --uu='_(ls)'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu=\"'%u'\"",
+               "bob",
+               "/bin/echo --uu=\"'bob'\"",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu='%u' --yy='%u' '%u' %u",
+               "bob",
+               "/bin/echo --uu='bob' --yy='bob' 'bob' __CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo --uu=%u%u'' %user 50%u",
+               "bob",
+               "/bin/echo --uu=__CVE-2026-4408_FallbackUsername____CVE-2026-4408_FallbackUsername__'' __CVE-2026-4408_FallbackUsername__ser 50__CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "!!",
+               "/bin/echo '!!'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               ">xxx",
+               NULL,
+               NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+       },
+       {
+               "/bin/echo %u",
+               "\\",
+               NULL,
+               NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+       },
+       {
+               "/bin/echo %u",
+               "3",
+               "/bin/echo '3'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo '%u'",
+               "3$",
+               "/bin/echo '3_'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo '%u'",
+               "comp$",
+               "/bin/echo 'comp_'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo '%u'",
+               "3$3",
+               "/bin/echo '3_3'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo '%u'",
+               "q $3",
+               "/bin/echo 'q _3'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -s '%u' %u",
+               "āāā",
+               "/bin/echo -s 'āāā' __CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -s '%u' %u",
+               "-āāā",
+               "/bin/echo -s '_āāā' __CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -s %u",
+               "āāā",
+               "/bin/echo -s 'āāā'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -s %u",
+               "a -a",
+               "/bin/echo -s 'a -a'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -s=%u %u",
+               "ā -a",
+               "/bin/echo -s='ā -a' 'ā -a'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -s=\"%u %u\"",
+               "ā -a",
+               "/bin/echo -s=\"__CVE-2026-4408_FallbackUsername__ __CVE-2026-4408_FallbackUsername__\"",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -m='fridge' %u",
+               "ā -x -ß",
+               "/bin/echo -m='fridge' __CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo -m='fridge' %u",
+               "-ā -a",
+               "/bin/echo -m='fridge' __CVE-2026-4408_FallbackUsername__",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "-n",
+               "/bin/echo '_n'",
+               NT_STATUS_OK
+       },
+       {
+               "/bin/echo %u",
+               "o'clock",
+               "/bin/echo 'o_clock'",
+               NT_STATUS_OK
+       },
+};
+
+static void test_expansions(void **state)
+{
+       TALLOC_CTX *mem_ctx = *state;
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(expansions); i++) {
+               struct cmd_expansion t = expansions[i];
+               char *result_cmd = NULL;
+               NTSTATUS status;
+
+               status = check_password_complexity_internal(mem_ctx,
+                                                           t.lp_cmd,
+                                                           t.username,
+                                                           &result_cmd);
+               if (NT_STATUS_IS_OK(t.result_code) && NT_STATUS_IS_OK(status)) {
+                       int cmp;
+
+                       cmp = strcmp(t.result_cmd, result_cmd);
+                       if (cmp == 0) {
+                               debug_message("[%zu] «%s» «%s»   ->   «%s», nstatus %s; AS EXPECTED\n",
+                                             i, t.lp_cmd,
+                                             t.username,
+                                             result_cmd,
+                                             nt_errstr(status));
+                       } else {
+                               debug_message("[%zu] «%s» «%s», nstatus %s; "
+                                             "expected   «%s»   got  «%s»\033[1;31m BAD! \033[0m\n",
+                                             i, t.lp_cmd,
+                                             t.username,
+                                             nt_errstr(status),
+                                             t.result_cmd,
+                                             result_cmd);
+                       }
+                       assert_int_equal(cmp, 0);
+               } else if (NT_STATUS_EQUAL(status, t.result_code)) {
+                       debug_message("[%zu] «%s» «%s», nstatus %s FAILED AS EXPECTED\n",
+                                     i, t.lp_cmd,
+                                     t.username,
+                                     nt_errstr(status));
+               } else {
+                       debug_message("[%zu] «%s» «%s» -> «%s», nstatus %s; "
+                                     "EXPECTED result «%s»   ntstatus %s; \033[1;31m BAD! \033[0m\n",
+                                     i, t.lp_cmd,
+                                     t.username,
+                                     result_cmd,
+                                     nt_errstr(status),
+                                     t.result_cmd,
+                                     nt_errstr(t.result_code));
+                       assert_int_equal(true, false);
+               }
+       }
+       debug_message("ALL correct\n");
+}
+
+int main(void)
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_expansions),
+       };
+       if (!isatty(1)) {
+               cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       }
+       return cmocka_run_group_tests(tests,
+                                     setup_talloc_context,
+                                     teardown_talloc_context);
+}
index 1d2520099e3553d5bbef712c6fc09d035ceec631..d04008b3df1706bd5d71d6569688215233e5d998 100644 (file)
@@ -133,3 +133,9 @@ bld.SAMBA3_BINARY('vfstest',
                       SMBREADLINE
                       ''',
                  for_selftest=True)
+
+bld.SAMBA3_BINARY('test_rpc_samr',
+                 source='test_rpc_samr.c',
+                 deps='''RPC_SERVICE cmocka
+                 ''',
+                 for_selftest=True)