From 6e5debf33bfb28ec0135a19f9cfb48b39d17fc83 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 16 Feb 2015 08:56:28 +0100 Subject: [PATCH] torture: Add netr_setPassword(2) schannel test. Thanks to Florian Weimer for the help to write this torture test. Pair-Programmed-With: Guenther Deschner Signed-off-by: Andreas Schneider Signed-off-by: Guenther Deschner Autobuild-User(master): Karolin Seeger Autobuild-Date(master): Mon Feb 23 20:01:01 CET 2015 on sn-devel-104 --- selftest/target/Samba.pm | 1 + selftest/target/Samba3.pm | 50 +++++++++++++++++++ source3/selftest/tests.py | 6 ++- source4/torture/rpc/rpc.c | 1 + source4/torture/rpc/schannel.c | 109 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 166 insertions(+), 1 deletion(-) diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm index 2b7343d62d6..47bc1310296 100644 --- a/selftest/target/Samba.pm +++ b/selftest/target/Samba.pm @@ -164,6 +164,7 @@ sub get_interface($) $interfaces{"localktest6"} = 7; $interfaces{"maptoguest"} = 8; + $interfaces{"locals3dc9"} = 9; # 11-16 used by selftest.pl for client interfaces diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 8926ae13e97..8209402de2a 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -175,6 +175,8 @@ sub setup_env($$$) if ($envname eq "s3dc") { return $self->setup_s3dc("$path/s3dc"); + } elsif ($envname eq "s3dc_schannel") { + return $self->setup_s3dc_schannel("$path/s3dc_schannel"); } elsif ($envname eq "simpleserver") { return $self->setup_simpleserver("$path/simpleserver"); } elsif ($envname eq "maptoguest") { @@ -239,6 +241,54 @@ sub setup_s3dc($$) return $vars; } +sub setup_s3dc_schannel($$) +{ + my ($self, $path) = @_; + + print "PROVISIONING S3DC WITH SERVER SCHANNEL ..."; + + my $pdc_options = " + domain master = yes + domain logons = yes + lanman auth = yes + + rpc_server:epmapper = external + rpc_server:spoolss = external + rpc_server:lsarpc = external + rpc_server:samr = external + rpc_server:netlogon = external + rpc_server:register_embedded_np = yes + + rpc_daemon:epmd = fork + rpc_daemon:spoolssd = fork + rpc_daemon:lsasd = fork + + server schannel = yes +"; + + my $vars = $self->provision($path, + "LOCALS3DC9", + "locals3dc9pass", + $pdc_options); + + $vars or return undef; + + if (not $self->check_or_start($vars, "yes", "yes", "yes")) { + return undef; + } + + $vars->{DC_SERVER} = $vars->{SERVER}; + $vars->{DC_SERVER_IP} = $vars->{SERVER_IP}; + $vars->{DC_SERVER_IPV6} = $vars->{SERVER_IPV6}; + $vars->{DC_NETBIOSNAME} = $vars->{NETBIOSNAME}; + $vars->{DC_USERNAME} = $vars->{USERNAME}; + $vars->{DC_PASSWORD} = $vars->{PASSWORD}; + + $self->{vars}->{s3dc_schannel} = $vars; + + return $vars; +} + sub setup_member($$$) { my ($self, $prefix, $s3dcvars) = @_; diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index c60f531e06e..0a59903a533 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -278,7 +278,7 @@ rpc = ["rpc.authcontext", "rpc.samba3.bind", "rpc.samba3.srvsvc", "rpc.samba3.sh "rpc.samr.passwords.pwdlastset", "rpc.samr.passwords.lockout", "rpc.samr.passwords.badpwdcount", "rpc.samr.large-dc", "rpc.samr.machine.auth", "rpc.samr.priv", "rpc.samr.passwords.validate", "rpc.netlogon.admin", - "rpc.schannel", "rpc.schannel2", "rpc.bench-schannel1", "rpc.join", "rpc.bind"] + "rpc.schannel", "rpc.schannel2", "rpc.bench-schannel1", "rpc.schannel_anon_setpw", "rpc.join", "rpc.bind"] local = ["local.ndr"] @@ -372,6 +372,10 @@ for t in tests: elif t == "vfs.fruit": plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --option=torture:share1=vfs_fruit --option=torture:share2=tmp --option=torture:localdir=$SELFTEST_PREFIX/s3dc/share') plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --option=torture:share1=vfs_fruit --option=torture:share2=tmp --option=torture:localdir=$SELFTEST_PREFIX/plugin_s4_dc/share') + elif t == "rpc.schannel_anon_setpw": + plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/tmp -U$%', description="anonymous password set") + plansmbtorture4testsuite(t, "s3dc_schannel", '//$SERVER_IP/tmp -U$%', description="anonymous password set (schannel enforced server-side)") + plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER/tmp -U$%', description="anonymous password set") else: plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD') diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c index 7557901efb7..b7fd3bc1eb0 100644 --- a/source4/torture/rpc/rpc.c +++ b/source4/torture/rpc/rpc.c @@ -507,6 +507,7 @@ NTSTATUS torture_rpc_init(void) torture_suite_add_simple_test(suite, "schannel", torture_rpc_schannel); torture_suite_add_simple_test(suite, "schannel2", torture_rpc_schannel2); torture_suite_add_simple_test(suite, "bench-schannel1", torture_rpc_schannel_bench1); + torture_suite_add_simple_test(suite, "schannel_anon_setpw", torture_rpc_schannel_anon_setpw); torture_suite_add_suite(suite, torture_rpc_srvsvc(suite)); torture_suite_add_suite(suite, torture_rpc_svcctl(suite)); torture_suite_add_suite(suite, torture_rpc_samr_accessmask(suite)); diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index de93fcad1a6..eff1c7ab1d6 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -543,6 +543,86 @@ static bool test_schannel(struct torture_context *tctx, return true; } +/* + * Purpose of this test is to demonstrate that a netlogon server carefully deals + * with anonymous attempts to set passwords, in particular when the server + * enforces the use of schannel. This test makes most sense to be run in an + * environment where the netlogon server enforces use of schannel. + */ + +static bool test_schannel_anonymous_setPassword(struct torture_context *tctx, + uint32_t dcerpc_flags, + bool use2) +{ + struct test_join *join_ctx; + NTSTATUS status, result; + const char *binding = torture_setting_string(tctx, "binding", NULL); + struct dcerpc_binding *b; + struct dcerpc_pipe *p = NULL; + struct cli_credentials *credentials; + bool ok = true; + + credentials = cli_credentials_init(NULL); + torture_assert(tctx, credentials != NULL, "Bad credentials"); + cli_credentials_set_anonymous(credentials); + + status = dcerpc_parse_binding(tctx, binding, &b); + torture_assert_ntstatus_ok(tctx, status, "Bad binding string"); + + status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS); + torture_assert_ntstatus_ok(tctx, status, "set flags"); + + status = dcerpc_pipe_connect_b(tctx, + &p, + b, + &ndr_table_netlogon, + credentials, + tctx->ev, + tctx->lp_ctx); + torture_assert_ntstatus_ok(tctx, status, "Failed to connect without schannel"); + + if (use2) { + struct netr_ServerPasswordSet2 r = {}; + struct netr_Authenticator credential = {}; + struct netr_Authenticator return_authenticator = {}; + struct netr_CryptPassword new_password = {}; + + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME); + r.in.secure_channel_type = 0; + r.in.computer_name = TEST_MACHINE_NAME; + r.in.credential = &credential; + r.in.new_password = &new_password; + r.out.return_authenticator = &return_authenticator; + + status = dcerpc_netr_ServerPasswordSet2_r(p->binding_handle, tctx, &r); + result = r.out.result; + } else { + struct netr_ServerPasswordSet r = {}; + struct netr_Authenticator credential = {}; + struct netr_Authenticator return_authenticator = {}; + struct samr_Password new_password = {}; + + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME); + r.in.secure_channel_type = 0; + r.in.computer_name = TEST_MACHINE_NAME; + r.in.credential = &credential; + r.in.new_password = &new_password; + r.out.return_authenticator = &return_authenticator; + + status = dcerpc_netr_ServerPasswordSet_r(p->binding_handle, tctx, &r); + result = r.out.result; + } + + torture_assert_ntstatus_ok(tctx, status, "ServerPasswordSet failed"); + + if (NT_STATUS_IS_OK(result)) { + torture_fail(tctx, "unexpectedly received NT_STATUS_OK"); + } + + return ok; +} /* @@ -586,6 +666,35 @@ bool torture_rpc_schannel(struct torture_context *torture) return ret; } +bool torture_rpc_schannel_anon_setpw(struct torture_context *torture) +{ + bool ret = true; + bool ok; + uint32_t dcerpc_flags = DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_AUTO; + + ok = test_schannel_anonymous_setPassword(torture, + dcerpc_flags, + true); + if (!ok) { + torture_comment(torture, + "Failed with dcerpc_flags=0x%x\n", + dcerpc_flags); + ret = false; + } + + ok = test_schannel_anonymous_setPassword(torture, + dcerpc_flags, + false); + if (!ok) { + torture_comment(torture, + "Failed with dcerpc_flags=0x%x\n", + dcerpc_flags); + ret = false; + } + + return ret; +} + /* test two schannel connections */ -- 2.11.4.GIT