From 960bd9df1f4c7bec95be5362fa7fa66d5ac591e9 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 27 Aug 2008 21:36:27 +1000 Subject: Add a test to explore Netlogon PAC validation However, I have still not figured out this protocol yet, and the docs are rather unclear... :-( Andrew Bartlett (This used to be commit d878643071a1477435a267e2944461d367cdfa79) --- source4/librpc/idl/krb5pac.idl | 14 +++ source4/librpc/idl/netlogon.idl | 18 +++- source4/samba4-skip | 1 + source4/torture/config.mk | 2 +- source4/torture/rpc/netlogon.c | 15 ++- source4/torture/rpc/remote_pac.c | 220 +++++++++++++++++++++++++++++++++++++++ source4/torture/rpc/rpc.c | 1 + source4/torture/rpc/testjoin.c | 1 + 8 files changed, 263 insertions(+), 9 deletions(-) create mode 100644 source4/torture/rpc/remote_pac.c (limited to 'source4') diff --git a/source4/librpc/idl/krb5pac.idl b/source4/librpc/idl/krb5pac.idl index ca0efaed3e..07f747a0c4 100644 --- a/source4/librpc/idl/krb5pac.idl +++ b/source4/librpc/idl/krb5pac.idl @@ -100,6 +100,14 @@ interface krb5pac PAC_BUFFER_RAW buffers[num_buffers]; } PAC_DATA_RAW; + typedef [public] struct { + uint32 MessageType; + uint32 ChecksumLength; + uint32 SignatureType; + uint32 SignatureLength; + [size_is(ChecksumLength),length_is(ChecksumLength)] uint8 *data; + } PAC_Validate; + void decode_pac( [in] PAC_DATA pac ); @@ -111,4 +119,10 @@ interface krb5pac void decode_login_info( [in] PAC_LOGON_INFO logon_info ); + + void decode_pac_validate( + [in] PAC_Validate pac_validate + ); + + } diff --git a/source4/librpc/idl/netlogon.idl b/source4/librpc/idl/netlogon.idl index 62f1b8843a..006411dfbf 100644 --- a/source4/librpc/idl/netlogon.idl +++ b/source4/librpc/idl/netlogon.idl @@ -127,7 +127,7 @@ interface netlogon netr_IdentityInfo identity_info; lsa_String package_name; uint32 length; - [size_is(length),length_is(length)] uint8 *data; + [size_is(length)] uint8 *data; } netr_GenericInfo; typedef enum { @@ -240,12 +240,20 @@ interface netlogon lsa_String unknown4; } netr_PacInfo; + typedef enum { + NetlogonValidationUasInfo = 1, + NetlogonValidationSamInfo = 2, + NetlogonValidationSamInfo2 = 3, + NetlogonValidationGenericInfo2 = 5, + NetlogonValidationSamInfo4 = 6 + } netr_ValidationInfoClass; + typedef [public,switch_type(uint16)] union { - [case(2)] netr_SamInfo2 *sam2; - [case(3)] netr_SamInfo3 *sam3; + [case(NetlogonValidationSamInfo)] netr_SamInfo2 *sam2; + [case(NetlogonValidationSamInfo2)] netr_SamInfo3 *sam3; [case(4)] netr_PacInfo *pac; - [case(5)] netr_PacInfo *pac; - [case(6)] netr_SamInfo6 *sam6; + [case(NetlogonValidationGenericInfo2)] netr_PacInfo *pac; + [case(NetlogonValidationSamInfo4)] netr_SamInfo6 *sam6; } netr_Validation; typedef [public, flag(NDR_PAHEX)] struct { diff --git a/source4/samba4-skip b/source4/samba4-skip index b1313adea0..35b274f63f 100644 --- a/source4/samba4-skip +++ b/source4/samba4-skip @@ -41,6 +41,7 @@ ntvfs.cifs.raw.context ntvfs.cifs.raw.qfileinfo.ipc rpc.dssync rpc.samsync +rpc.pac # Not finished yet ldap.uptodatevector # Segfaults rpc.remact # Not provided by Samba 4 rpc.oxidresolve # Not provided by Samba 4 diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 5a1746c215..96da10b5df 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -114,7 +114,7 @@ torture_rpc_OBJ_FILES = $(addprefix $(torturesrcdir)/rpc/, \ drsuapi_cracknames.o dssync.o spoolss.o spoolss_notify.o spoolss_win.o \ unixinfo.o samr.o samr_accessmask.o wkssvc.o srvsvc.o svcctl.o atsvc.o \ eventlog.o epmapper.o winreg.o initshutdown.o oxidresolve.o remact.o mgmt.o \ - scanner.o autoidl.o countcalls.o testjoin.o schannel.o netlogon.o samlogon.o \ + scanner.o autoidl.o countcalls.o testjoin.o schannel.o netlogon.o remote_pac.o samlogon.o \ samsync.o bind.o dssetup.o alter_context.o bench.o samba3rpc.o rpc.o async_bind.o \ handles.o frsapi.o) diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 5b92ce1382..5ec2c29a20 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -25,8 +25,10 @@ #include "torture/torture.h" #include "lib/events/events.h" #include "auth/auth.h" +#include "auth/gensec/gensec.h" #include "lib/cmdline/popt_common.h" #include "torture/rpc/rpc.h" +#include "torture/rpc/netlogon.h" #include "libcli/auth/libcli_auth.h" #include "librpc/gen_ndr/ndr_netlogon_c.h" #include "librpc/gen_ndr/ndr_lsa_c.h" @@ -67,8 +69,8 @@ static bool test_LogonUasLogoff(struct torture_context *tctx, } static bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, - struct cli_credentials *credentials, - struct creds_CredentialState **creds_out) + struct cli_credentials *credentials, + struct creds_CredentialState **creds_out) { NTSTATUS status; struct netr_ServerReqChallenge r; @@ -113,6 +115,13 @@ static bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context torture_comment(tctx, "Testing ServerAuthenticate\n"); status = dcerpc_netr_ServerAuthenticate(p, tctx, &a); + + /* This allows the tests to continue against the more fussy windows 2008 */ + if (NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED)) { + return test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + credentials, SEC_CHAN_BDC, creds_out); + } + torture_assert_ntstatus_ok(tctx, status, "ServerAuthenticate"); torture_assert(tctx, creds_client_check(creds, &credentials3), @@ -122,7 +131,7 @@ static bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context return true; } -static bool test_SetupCredentials2(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, diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c new file mode 100644 index 0000000000..a9e0bbca64 --- /dev/null +++ b/source4/torture/rpc/remote_pac.c @@ -0,0 +1,220 @@ +/* + Unix SMB/CIFS implementation. + + test suite for netlogon PAC operations + + Copyright (C) Andrew Bartlett 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "torture/torture.h" +#include "lib/events/events.h" +#include "auth/auth.h" +#include "auth/gensec/gensec.h" +#include "lib/cmdline/popt_common.h" +#include "torture/rpc/rpc.h" +#include "torture/rpc/netlogon.h" +#include "libcli/auth/libcli_auth.h" +#include "librpc/gen_ndr/ndr_netlogon_c.h" +#include "librpc/gen_ndr/ndr_krb5pac.h" +#include "param/param.h" +#include "lib/messaging/irpc.h" +#include "cluster/cluster.h" + +#include "system/kerberos.h" +#include "auth/kerberos/kerberos.h" +#include "librpc/gen_ndr/krb5pac.h" +#include +#include +#include "auth/gensec/gensec_gssapi.h" + +#define TEST_MACHINE_NAME "torturepactest" + +/* Check to see if we can pass the PAC across to the NETLOGON server for validation */ + +/* Also happens to be a really good one-step verfication of our Kerberos stack */ + +static bool test_PACVerify(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + NTSTATUS status; + + struct netr_LogonSamLogon r; + + struct netr_GenericInfo generic; + struct netr_Authenticator auth, auth2; + + + struct creds_CredentialState *creds; + struct gensec_security *gensec_client_context; + struct gensec_security *gensec_server_context; + struct gensec_gssapi_state *gensec_gssapi_state; + + struct messaging_context *msg_server_ctx; + DATA_BLOB client_to_server, server_to_client, pac_blob, pac_wrapped; + gss_buffer_desc pac; + struct PAC_Validate pac_wrapped_struct; + + enum ndr_err_code ndr_err; + + struct auth_session_info *session_info; + + char *tmp_dir; + OM_uint32 maj_stat, min_stat; + + TALLOC_CTX *tmp_ctx = talloc_new(tctx); + + torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed"); + + if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + credentials, SEC_CHAN_BDC, + &creds)) { + return false; + } + + status = torture_temp_dir(tctx, "PACVerify", &tmp_dir); + torture_assert_ntstatus_ok(tctx, status, "torture_temp_dir failed"); + + msg_server_ctx = messaging_init(tctx, + tmp_dir, + cluster_id(0, 1), + lp_iconv_convenience(tctx->lp_ctx), + tctx->ev); + + torture_assert(tctx, msg_server_ctx != NULL, "Failed to init messaging context"); + + status = gensec_client_start(tctx, &gensec_client_context, tctx->ev, 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, tctx->lp_ctx, msg_server_ctx, &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"); + } + + if (client_to_server.length == 0) { + break; + } + + 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 (server_to_client.length == 0) { + break; + } + } while (1); + + /* Extract the PAC using Samba's code */ + + status = gensec_session_info(gensec_server_context, &session_info); + torture_assert_ntstatus_ok(tctx, status, "gensec_gssapi_session_info failed"); + + /* Extract a raw PAC */ + + gensec_gssapi_state = talloc_get_type(gensec_server_context->private_data, struct gensec_gssapi_state); + + maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, + gensec_gssapi_state->gssapi_context, + KRB5_AUTHDATA_WIN2K_PAC, + &pac); + + if (maj_stat == 0) { + pac_blob = data_blob_talloc(tmp_ctx, pac.value, pac.length); + gss_release_buffer(&min_stat, &pac); + + } else { + pac_blob = data_blob(NULL, 0); + } + + pac_wrapped_struct.MessageType = 0x3; + pac_wrapped_struct.ChecksumLength = pac_blob.length; + pac_wrapped_struct.SignatureType = 0; + pac_wrapped_struct.SignatureLength = 0; + pac_wrapped_struct.data = pac_blob.data; + + ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, + (ndr_push_flags_fn_t)ndr_push_PAC_Validate); + torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); + + + /* Validate it over the netlogon pipe */ + + generic.identity_info.parameter_control = 0; + generic.identity_info.logon_id_high = 0; + 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.package_name.string = "Kerberos"; + generic.length = pac_wrapped.length; + generic.data = pac_wrapped.data; + + ZERO_STRUCT(auth2); + creds_client_authenticator(creds, &auth); + r.in.credential = &auth; + r.in.return_authenticator = &auth2; + r.in.logon_level = NetlogonGenericInformation; + r.in.logon.generic = &generic; + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.validation_level = NetlogonValidationGenericInfo2; + + status = dcerpc_netr_LogonSamLogon(p, tctx, &r); + + torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed"); + + torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), + "Credential chaining failed"); + + return true; +} + +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; + struct torture_test *test; + + tcase = torture_suite_add_machine_rpc_iface_tcase(suite, "netlogon", + &ndr_table_netlogon, TEST_MACHINE_NAME); + torture_rpc_tcase_add_test_creds(tcase, "verify", test_PACVerify); + + return suite; +} diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c index 23867f2a77..85f7bde16c 100644 --- a/source4/torture/rpc/rpc.c +++ b/source4/torture/rpc/rpc.c @@ -395,6 +395,7 @@ NTSTATUS torture_rpc_init(void) torture_suite_add_simple_test(suite, "SAMR-USERS", torture_rpc_samr_users); torture_suite_add_simple_test(suite, "SAMR-PASSWORDS", torture_rpc_samr_passwords); torture_suite_add_suite(suite, torture_rpc_netlogon(suite)); + torture_suite_add_suite(suite, torture_rpc_remote_pac(suite)); torture_suite_add_simple_test(suite, "SAMLOGON", torture_rpc_samlogon); torture_suite_add_simple_test(suite, "SAMSYNC", torture_rpc_samsync); torture_suite_add_simple_test(suite, "SCHANNEL", torture_rpc_schannel); diff --git a/source4/torture/rpc/testjoin.c b/source4/torture/rpc/testjoin.c index 9fd9d2f0c6..2af8c4f872 100644 --- a/source4/torture/rpc/testjoin.c +++ b/source4/torture/rpc/testjoin.c @@ -400,6 +400,7 @@ _PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx, } cli_credentials_set_username(*machine_credentials, libnet_r->in.account_name, CRED_SPECIFIED); cli_credentials_set_password(*machine_credentials, libnet_r->out.join_password, CRED_SPECIFIED); + cli_credentials_set_kvno(*machine_credentials, libnet_r->out.kvno); if (acct_flags & ACB_SVRTRUST) { cli_credentials_set_secure_channel_type(*machine_credentials, SEC_CHAN_BDC); -- cgit