s4:torture Add tests to demonstrate S2U4Self in the RPC-PAC test
authorAndrew Bartlett <abartlet@samba.org>
Thu, 4 Mar 2010 09:07:12 +0000 (20:07 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 20 May 2010 07:39:09 +0000 (17:39 +1000)
We also compare against SamLogon to try and validate the whole thing.
Note that we must represent NULL as "" when comparing between the PAC
and SamLogon, due to different marshalling of the structures.

Andrew Bartlett

source4/torture/rpc/netlogon.c
source4/torture/rpc/remote_pac.c

index 49693ffa84a3bb07865f3402c96c26b13700b007..96ae4c0dfe442c795ee25781924929b53b855686 100644 (file)
@@ -146,7 +146,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx,
 bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
                            uint32_t negotiate_flags,
                            struct cli_credentials *machine_credentials,
-                           int sec_chan_type,
+                           enum netr_SchannelType sec_chan_type,
                            struct netlogon_creds_CredentialState **creds_out)
 {
        struct netr_ServerReqChallenge r;
index 9358d44ca85fdbf6b08c1023d0f1f9a72dd6f0cf..ba031c13a6c21b6d8a16e015a0bd824b684a593e 100644 (file)
 
 #include "includes.h"
 #include "auth/auth.h"
+#include "auth/auth_sam_reply.h"
 #include "auth/gensec/gensec.h"
 #include "lib/cmdline/popt_common.h"
 #include "torture/rpc/torture_rpc.h"
 #include "libcli/auth/libcli_auth.h"
+#include "libcli/security/dom_sid.h"
 #include "librpc/gen_ndr/ndr_netlogon_c.h"
 #include "param/param.h"
 
-#define TEST_MACHINE_NAME "torturepactest"
+#define TEST_MACHINE_NAME_BDC "torturepacbdc"
+#define TEST_MACHINE_NAME_WKSTA "torturepacwksta"
+#define TEST_MACHINE_NAME_S2U4SELF_BDC "tests2u4selfbdc"
+#define TEST_MACHINE_NAME_S2U4SELF_WKSTA "tests2u4selfwk"
 
 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
 
@@ -36,7 +41,9 @@
 
 static bool test_PACVerify(struct torture_context *tctx, 
                           struct dcerpc_pipe *p,
-                          struct cli_credentials *credentials)
+                          struct cli_credentials *credentials,
+                          enum netr_SchannelType secure_channel_type,
+                          const char *test_machine_name)
 {
        NTSTATUS status;
 
@@ -70,7 +77,7 @@ static bool test_PACVerify(struct torture_context *tctx,
        torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
 
        if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, 
-                                   credentials, SEC_CHAN_BDC, 
+                                   credentials, secure_channel_type,
                                    &creds)) {
                return false;
        }
@@ -82,7 +89,7 @@ static bool test_PACVerify(struct torture_context *tctx,
                                     lp_gensec_settings(tctx, tctx->lp_ctx));
        torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
 
-       status = gensec_set_target_hostname(gensec_client_context, TEST_MACHINE_NAME);
+       status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
 
        status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
        torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
@@ -156,7 +163,7 @@ static bool test_PACVerify(struct torture_context *tctx,
        generic.identity_info.logon_id_low = 0;
        generic.identity_info.domain_name.string = session_info->server_info->domain_name;
        generic.identity_info.account_name.string = session_info->server_info->account_name;
-       generic.identity_info.workstation.string = TEST_MACHINE_NAME;
+       generic.identity_info.workstation.string = test_machine_name;
 
        generic.package_name.string = "Kerberos";
 
@@ -322,17 +329,308 @@ static bool test_PACVerify(struct torture_context *tctx,
        
        torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred), 
                       "Credential chaining failed");
+
+       return true;
+}
+
+static bool test_PACVerify_bdc(struct torture_context *tctx,
+                              struct dcerpc_pipe *p,
+                              struct cli_credentials *credentials)
+{
+       return test_PACVerify(tctx, p, credentials, SEC_CHAN_BDC, TEST_MACHINE_NAME_BDC);
+}
+
+static bool test_PACVerify_workstation(struct torture_context *tctx,
+                                 struct dcerpc_pipe *p,
+                                 struct cli_credentials *credentials)
+{
+       return test_PACVerify(tctx, p, credentials, SEC_CHAN_WKSTA, TEST_MACHINE_NAME_WKSTA);
+}
+
+
+/* Check various ways to get the PAC, in particular check the group membership and other details between the PAC from a normal kinit, S2U4Self and a SamLogon */
+static bool test_S2U4Self(struct torture_context *tctx,
+                         struct dcerpc_pipe *p,
+                         struct cli_credentials *credentials,
+                         enum netr_SchannelType secure_channel_type,
+                         const char *test_machine_name)
+{
+       NTSTATUS status;
+
+       struct netr_LogonSamLogon r;
+
+       union netr_LogonLevel logon;
+       union netr_Validation validation;
+       uint8_t authoritative;
+
+       struct netr_Authenticator auth, auth2;
+
+       DATA_BLOB client_to_server, server_to_client;
+
+       struct netlogon_creds_CredentialState *creds;
+       struct gensec_security *gensec_client_context;
+       struct gensec_security *gensec_server_context;
+
+       struct auth_session_info *kinit_session_info;
+       struct auth_session_info *s2u4self_session_info;
+       struct auth_serversupplied_info *netlogon_server_info;
+
+       struct netr_NetworkInfo ninfo;
+       DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+       size_t i;
+       int flags = CLI_CRED_NTLMv2_AUTH;
+
+       struct dom_sid *builtin_domain;
+
+       char *tmp_dir;
+
+       TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+
+       torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
+
+       /* First, do a normal Kerberos connection */
+
+       status = torture_temp_dir(tctx, "S2U4Self", &tmp_dir);
+       torture_assert_ntstatus_ok(tctx, status, "torture_temp_dir failed");
+
+       status = gensec_client_start(tctx, &gensec_client_context, tctx->ev,
+                                    lp_gensec_settings(tctx, tctx->lp_ctx));
+       torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+       status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
+
+       status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+       status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
+       torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+       status = gensec_server_start(tctx, tctx->ev,
+                                    lp_gensec_settings(tctx, tctx->lp_ctx),
+                                    NULL, &gensec_server_context);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+       status = gensec_set_credentials(gensec_server_context, credentials);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+       status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
+       torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+
+       server_to_client = data_blob(NULL, 0);
+
+       do {
+               /* Do a client-server update dance */
+               status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+                       torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+               }
+
+               status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+                       torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+               }
+
+               if (NT_STATUS_IS_OK(status)) {
+                       break;
+               }
+       } while (1);
+
+       /* Extract the PAC using Samba's code */
+
+       status = gensec_session_info(gensec_server_context, &kinit_session_info);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+
+       /* Now do the dance with S2U4Self */
+
+       /* Wipe out any existing ccache */
+       cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+       cli_credentials_set_target_service(credentials, talloc_asprintf(tmp_ctx, "host/%s", test_machine_name));
+       cli_credentials_set_impersonate_principal(credentials, cli_credentials_get_principal(cmdline_credentials, tmp_ctx));
+
+       status = gensec_client_start(tctx, &gensec_client_context, tctx->ev,
+                                    lp_gensec_settings(tctx, tctx->lp_ctx));
+       torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+       status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
+
+       /* We now set the same credentials on both client and server contexts */
+       status = gensec_set_credentials(gensec_client_context, credentials);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+       status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
+       torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+       status = gensec_server_start(tctx, tctx->ev,
+                                    lp_gensec_settings(tctx, tctx->lp_ctx),
+                                    NULL, &gensec_server_context);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+       status = gensec_set_credentials(gensec_server_context, credentials);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+       status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
+       torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+
+       server_to_client = data_blob(NULL, 0);
+
+       do {
+               /* Do a client-server update dance */
+               status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+                       torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+               }
+
+               status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+                       torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+               }
+
+               if (NT_STATUS_IS_OK(status)) {
+                       break;
+               }
+       } while (1);
+
+       /* Don't pollute the remaining tests with the changed credentials */
+       cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+       cli_credentials_set_target_service(credentials, NULL);
+       cli_credentials_set_impersonate_principal(credentials, NULL);
+
+       /* Extract the PAC using Samba's code */
+
+       status = gensec_session_info(gensec_server_context, &s2u4self_session_info);
+       torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+       cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx,
+                                                &ninfo.identity_info.account_name.string,
+                                                &ninfo.identity_info.domain_name.string);
+
+       /* Now try with SamLogon */
+       generate_random_buffer(ninfo.challenge,
+                              sizeof(ninfo.challenge));
+       chal = data_blob_const(ninfo.challenge,
+                              sizeof(ninfo.challenge));
+
+       names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials),
+                                               cli_credentials_get_domain(credentials));
+
+       status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx,
+                                                  &flags,
+                                                  chal,
+                                                  names_blob,
+                                                  &lm_resp, &nt_resp,
+                                                  NULL, NULL);
+       torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
+
+       ninfo.lm.data = lm_resp.data;
+       ninfo.lm.length = lm_resp.length;
+
+       ninfo.nt.data = nt_resp.data;
+       ninfo.nt.length = nt_resp.length;
+
+       ninfo.identity_info.parameter_control = 0;
+       ninfo.identity_info.logon_id_low = 0;
+       ninfo.identity_info.logon_id_high = 0;
+       ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
+
+       logon.network = &ninfo;
+
+       r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+       r.in.computer_name = cli_credentials_get_workstation(credentials);
+       r.in.credential = &auth;
+       r.in.return_authenticator = &auth2;
+       r.in.logon_level = 2;
+       r.in.logon = &logon;
+       r.out.validation = &validation;
+       r.out.authoritative = &authoritative;
+
+       if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
+                                   credentials, secure_channel_type,
+                                   &creds)) {
+               return false;
+       }
+
+       ZERO_STRUCT(auth2);
+       netlogon_creds_client_authenticator(creds, &auth);
+
+       r.in.validation_level = 3;
+
+       status = dcerpc_netr_LogonSamLogon(p, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed");
+
+       torture_assert(tctx, netlogon_creds_client_check(creds,
+                                                        &r.out.return_authenticator->cred),
+                      "Credential chaining failed");
+
+       status = make_server_info_netlogon_validation(tmp_ctx,
+                                                     ninfo.identity_info.account_name.string,
+                                                     r.in.validation_level,
+                                                     r.out.validation,
+                                                     &netlogon_server_info);
+
+       torture_assert_ntstatus_ok(tctx, status, "make_server_info_netlogon_validation failed");
+
+       torture_assert_str_equal(tctx, netlogon_server_info->account_name == NULL ? "" : netlogon_server_info->account_name,
+                                kinit_session_info->server_info->account_name, "Account name differs for kinit-based PAC");
+       torture_assert_str_equal(tctx,netlogon_server_info->account_name == NULL ? "" : netlogon_server_info->account_name,
+                                s2u4self_session_info->server_info->account_name, "Account name differs for S2U4Self");
+       torture_assert_str_equal(tctx, netlogon_server_info->full_name == NULL ? "" : netlogon_server_info->full_name, kinit_session_info->server_info->full_name, "Full name differs for kinit-based PAC");
+       torture_assert_str_equal(tctx, netlogon_server_info->full_name == NULL ? "" : netlogon_server_info->full_name, s2u4self_session_info->server_info->full_name, "Full name differs for S2U4Self");
+       torture_assert(tctx, dom_sid_equal(netlogon_server_info->account_sid, kinit_session_info->server_info->account_sid), "Account SID differs for kinit-based PAC");
+       torture_assert(tctx, dom_sid_equal(netlogon_server_info->primary_group_sid, kinit_session_info->server_info->primary_group_sid), "Primary Group SID differs for kinit-based PAC");
+       torture_assert(tctx, dom_sid_equal(netlogon_server_info->account_sid, s2u4self_session_info->server_info->account_sid), "Account SID differs for S2U4Self");
+       torture_assert(tctx, dom_sid_equal(netlogon_server_info->primary_group_sid, s2u4self_session_info->server_info->primary_group_sid), "Primary Group SID differs for S2U4Self");
+       torture_assert_int_equal(tctx, netlogon_server_info->n_domain_groups, kinit_session_info->server_info->n_domain_groups, "Different numbers of domain groups for kinit-based PAC");
+       torture_assert_int_equal(tctx, netlogon_server_info->n_domain_groups, s2u4self_session_info->server_info->n_domain_groups, "Different numbers of domain groups for S2U4Self");
+
+       builtin_domain = dom_sid_parse_talloc(tmp_ctx, SID_BUILTIN);
+
+       for (i = 0; i < kinit_session_info->server_info->n_domain_groups; i++) {
+               torture_assert(tctx, dom_sid_equal(netlogon_server_info->domain_groups[i], kinit_session_info->server_info->domain_groups[i]), "Different domain groups for kinit-based PAC");
+               torture_assert(tctx, dom_sid_equal(netlogon_server_info->domain_groups[i], s2u4self_session_info->server_info->domain_groups[i]), "Different domain groups for S2U4Self");
+               torture_assert(tctx, !dom_sid_in_domain(builtin_domain, s2u4self_session_info->server_info->domain_groups[i]), "Returned BUILTIN domain in groups for S2U4Self");
+               torture_assert(tctx, !dom_sid_in_domain(builtin_domain, kinit_session_info->server_info->domain_groups[i]), "Returned BUILTIN domain in groups kinit-based PAC");
+               torture_assert(tctx, !dom_sid_in_domain(builtin_domain, netlogon_server_info->domain_groups[i]), "Returned BUILTIN domian in groups from NETLOGON SamLogon reply");
+       }
+
        return true;
 }
 
+static bool test_S2U4Self_bdc(struct torture_context *tctx,
+                              struct dcerpc_pipe *p,
+                              struct cli_credentials *credentials)
+{
+       return test_S2U4Self(tctx, p, credentials, SEC_CHAN_BDC, TEST_MACHINE_NAME_S2U4SELF_BDC);
+}
+
+static bool test_S2U4Self_workstation(struct torture_context *tctx,
+                                 struct dcerpc_pipe *p,
+                                 struct cli_credentials *credentials)
+{
+       return test_S2U4Self(tctx, p, credentials, SEC_CHAN_WKSTA, TEST_MACHINE_NAME_S2U4SELF_WKSTA);
+}
+
 struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
 {
        struct torture_suite *suite = torture_suite_create(mem_ctx, "PAC");
        struct torture_rpc_tcase *tcase;
 
-       tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netlogon",
-                                                 &ndr_table_netlogon, TEST_MACHINE_NAME);
-       torture_rpc_tcase_add_test_creds(tcase, "verify", test_PACVerify);
+       /* It is important to use different names, so that old entries in our credential cache are not used */
+       tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netlogon-bdc",
+                                                             &ndr_table_netlogon, TEST_MACHINE_NAME_BDC);
+       torture_rpc_tcase_add_test_creds(tcase, "verify-sig", test_PACVerify_bdc);
+
+       tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netlogon-member",
+                                                                     &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA);
+       torture_rpc_tcase_add_test_creds(tcase, "verify-sig", test_PACVerify_workstation);
+
+       tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netlogon-bdc",
+                                                             &ndr_table_netlogon, TEST_MACHINE_NAME_S2U4SELF_BDC);
+       torture_rpc_tcase_add_test_creds(tcase, "s2u4self", test_S2U4Self_bdc);
+
+       tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netlogon-member",
+                                                                     &ndr_table_netlogon, TEST_MACHINE_NAME_S2U4SELF_WKSTA);
 
+       torture_rpc_tcase_add_test_creds(tcase, "s2u4self", test_S2U4Self_workstation);
        return suite;
 }