>From bc98c33cb2471df9855435c8e1997314e5172f8f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 17 Jan 2014 14:00:27 +0100 Subject: [PATCH 1/7] libcli/auth: add netlogon_creds_cli_set_global_db() This can be used to inject a db_context from dbwrap_ctdb. Signed-off-by: Stefan Metzmacher --- libcli/auth/netlogon_creds_cli.c | 10 ++++++++++ libcli/auth/netlogon_creds_cli.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 51b30a1..37bdf74 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -199,6 +199,16 @@ static NTSTATUS netlogon_creds_cli_context_common( static struct db_context *netlogon_creds_cli_global_db; +NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db) +{ + if (netlogon_creds_cli_global_db != NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; + } + + netlogon_creds_cli_global_db = talloc_move(talloc_autofree_context(), db); + return NT_STATUS_OK; +} + NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx) { char *fname; diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h index 5bd8bd3..90d0182 100644 --- a/libcli/auth/netlogon_creds_cli.h +++ b/libcli/auth/netlogon_creds_cli.h @@ -28,7 +28,9 @@ struct netlogon_creds_cli_context; struct messaging_context; struct dcerpc_binding_handle; +struct db_context; +NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db); NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx); NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, -- 1.7.9.5 >From 06f8fb115682934b453a01e6e6c79f60820b33c4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 17 Jan 2014 14:07:37 +0100 Subject: [PATCH 2/7] s3:rpc_client: use db_open() to open "netlogon_creds_cli.tdb" This uses dbwrap_ctdb if running in a cluster. Signed-off-by: Stefan Metzmacher --- source3/rpc_client/cli_netlogon.c | 38 +++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index ca2d9bf..b7b490f 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -21,6 +21,7 @@ */ #include "includes.h" +#include "system/filesys.h" #include "libsmb/libsmb.h" #include "rpc_client/rpc_client.h" #include "rpc_client/cli_pipe.h" @@ -34,26 +35,53 @@ #include "../libcli/security/security.h" #include "lib/param/param.h" #include "libcli/smb/smbXcli_base.h" +#include "dbwrap/dbwrap.h" +#include "dbwrap/dbwrap_open.h" +#include "util_tdb.h" NTSTATUS rpccli_pre_open_netlogon_creds(void) { - TALLOC_CTX *frame = talloc_stackframe(); + static bool already_open = false; + TALLOC_CTX *frame; struct loadparm_context *lp_ctx; + char *fname; + struct db_context *global_db; NTSTATUS status; + if (already_open) { + return NT_STATUS_OK; + } + + frame = talloc_stackframe(); + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } - status = netlogon_creds_cli_open_global_db(lp_ctx); + fname = lpcfg_private_db_path(frame, lp_ctx, "netlogon_creds_cli"); + if (fname == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + global_db = db_open(talloc_autofree_context(), fname, + 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, + O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2); + if (global_db == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + status = netlogon_creds_cli_set_global_db(&global_db); TALLOC_FREE(frame); if (!NT_STATUS_IS_OK(status)) { return status; } + already_open = true; return NT_STATUS_OK; } @@ -69,6 +97,12 @@ NTSTATUS rpccli_create_netlogon_creds(const char *server_computer, struct loadparm_context *lp_ctx; NTSTATUS status; + status = rpccli_pre_open_netlogon_creds(); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { TALLOC_FREE(frame); -- 1.7.9.5 >From caf4f73ae8424617be8c309eeebc1d410740d672 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 17 Jan 2014 14:08:59 +0100 Subject: [PATCH 3/7] libcli/auth: don't alter the computer_name in cluster mode. This breaks NTLMv2 authentication. Signed-off-by: Stefan Metzmacher --- libcli/auth/netlogon_creds_cli.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 37bdf74..88893ad 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -261,28 +261,12 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, bool seal_secure_channel = true; enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; bool neutralize_nt4_emulation = false; - struct server_id self = { - .vnn = NONCLUSTER_VNN, - .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY, - }; - - if (msg_ctx != NULL) { - self = messaging_server_id(msg_ctx); - } *_context = NULL; - if (self.vnn != NONCLUSTER_VNN) { - client_computer = talloc_asprintf(frame, - "%s_cluster_vnn_%u", - lpcfg_netbios_name(lp_ctx), - (unsigned)self.vnn); - if (client_computer == NULL) { - TALLOC_FREE(frame); - return NT_STATUS_NO_MEMORY; - } - } else { - client_computer = lpcfg_netbios_name(lp_ctx); + client_computer = lpcfg_netbios_name(lp_ctx); + if (strlen(client_computer) > 15) { + return NT_STATUS_INVALID_PARAMETER_MIX; } /* -- 1.7.9.5 >From 6c0baa794c2e653b9f2e245c425f545390c73cff Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 10 Jan 2014 13:13:40 +0100 Subject: [PATCH 4/7] libcli/auth: reject computer_name longer than 15 chars This matches Windows, it seems they use a fixed size field to store netlogon_creds_CredentialState. Signed-off-by: Stefan Metzmacher --- libcli/auth/schannel_state_tdb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libcli/auth/schannel_state_tdb.c b/libcli/auth/schannel_state_tdb.c index 8c893ee..6669b46 100644 --- a/libcli/auth/schannel_state_tdb.c +++ b/libcli/auth/schannel_state_tdb.c @@ -78,6 +78,14 @@ NTSTATUS schannel_store_session_key_tdb(struct db_context *db_sc, char *name_upper; NTSTATUS status; + if (strlen(creds->computer_name) > 15) { + /* + * We may want to check for a completely + * valid netbios name. + */ + return STATUS_BUFFER_OVERFLOW; + } + name_upper = strupper_talloc(mem_ctx, creds->computer_name); if (!name_upper) { return NT_STATUS_NO_MEMORY; -- 1.7.9.5 >From de80ebc34fdb986878b07f6f6fbc4a5879542a57 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 11 Jan 2014 17:13:04 +0100 Subject: [PATCH 5/7] s3:rpc_server/netlogon: return a zero return_authenticator on error Signed-off-by: Stefan Metzmacher --- source3/rpc_server/netlogon/srv_netlog_nt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index c839633..e3e7a3e 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1018,6 +1018,7 @@ NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p, talloc_unlink(p->mem_ctx, lp_ctx); if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCTP(r->out.return_credentials); goto out; } -- 1.7.9.5 >From 8f743d08a9a55ca86910e4987d2e918bc807919e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 11 Jan 2014 17:13:04 +0100 Subject: [PATCH 6/7] s4:rpc_server/netlogon: return a zero return_authenticator and rid on error Signed-off-by: Stefan Metzmacher --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 0dd215d..c3e33bd 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -268,9 +268,6 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca return NT_STATUS_INTERNAL_ERROR; } - *r->out.rid = samdb_result_rid_from_sid(mem_ctx, msgs[0], - "objectSid", 0); - mach_pwd = samdb_result_hash(mem_ctx, msgs[0], "unicodePwd"); if (mach_pwd == NULL) { return NT_STATUS_ACCESS_DENIED; @@ -300,8 +297,15 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca nt_status = schannel_save_creds_state(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, creds); + if (!NT_STATUS_IS_OK(nt_status)) { + ZERO_STRUCTP(r->out.return_credentials); + return nt_status; + } - return nt_status; + *r->out.rid = samdb_result_rid_from_sid(mem_ctx, msgs[0], + "objectSid", 0); + + return NT_STATUS_OK; } static NTSTATUS dcesrv_netr_ServerAuthenticate(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, -- 1.7.9.5 >From 9923e5112b41d95b48ccca3f10c9016068043553 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 10 Jan 2014 12:19:08 +0100 Subject: [PATCH 7/7] s4:torture/rpc: add invalidAuthenticate2 This add 'rpc.netlogon.netlogon.invalidAuthenticate2' as new test it demonstrates the STATUS_BUFFER_OVERFLOW on computer names larger than 15 characters. Signed-off-by: Stefan Metzmacher --- source4/torture/rpc/netlogon.c | 88 +++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 6f2f629..90bfe7e 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -202,28 +202,28 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, return true; } -bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx, - uint32_t negotiate_flags, - struct cli_credentials *machine_credentials, - enum netr_SchannelType sec_chan_type, - struct netlogon_creds_CredentialState **creds_out) +bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tctx, + uint32_t negotiate_flags, + struct cli_credentials *machine_credentials, + const char *computer_name, + enum netr_SchannelType sec_chan_type, + NTSTATUS expected_result, + struct netlogon_creds_CredentialState **creds_out) { struct netr_ServerReqChallenge r; struct netr_ServerAuthenticate2 a; struct netr_Credential credentials1, credentials2, credentials3; struct netlogon_creds_CredentialState *creds; const struct samr_Password *mach_password; - const char *machine_name; struct dcerpc_binding_handle *b = p->binding_handle; + const char *account_name = cli_credentials_get_username(machine_credentials); mach_password = cli_credentials_get_nt_hash(machine_credentials, tctx); - machine_name = cli_credentials_get_workstation(machine_credentials); torture_comment(tctx, "Testing ServerReqChallenge\n"); - r.in.server_name = NULL; - r.in.computer_name = machine_name; + r.in.computer_name = computer_name; r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; @@ -234,9 +234,9 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx, torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed"); a.in.server_name = NULL; - a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name); + a.in.account_name = account_name; a.in.secure_channel_type = sec_chan_type; - a.in.computer_name = machine_name; + a.in.computer_name = computer_name; a.in.negotiate_flags = &negotiate_flags; a.out.negotiate_flags = &negotiate_flags; a.in.credentials = &credentials3; @@ -255,10 +255,16 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx, torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), "ServerAuthenticate2 failed"); - torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate2 failed"); + torture_assert_ntstatus_equal(tctx, a.out.result, expected_result, + "ServerAuthenticate2 unexpected"); - torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), - "Credential chaining failed"); + if (NT_STATUS_IS_OK(expected_result)) { + torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), + "Credential chaining failed"); + } else { + torture_assert(tctx, !netlogon_creds_client_check(creds, &credentials3), + "Credential chaining passed unexptected"); + } torture_comment(tctx, "negotiate_flags=0x%08x\n", negotiate_flags); @@ -266,6 +272,22 @@ bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx, return true; } +bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx, + uint32_t negotiate_flags, + struct cli_credentials *machine_credentials, + enum netr_SchannelType sec_chan_type, + struct netlogon_creds_CredentialState **creds_out) +{ + const char *computer_name = + cli_credentials_get_workstation(machine_credentials); + + return test_SetupCredentials2ex(p, tctx, negotiate_flags, + machine_credentials, + computer_name, + sec_chan_type, + NT_STATUS_OK, + creds_out); +} bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx, uint32_t negotiate_flags, @@ -1044,6 +1066,43 @@ static bool test_SamLogon(struct torture_context *tctx, return test_netlogon_ops(p, tctx, credentials, creds); } +static bool test_invalidAuthenticate2(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + struct netlogon_creds_CredentialState *creds; + uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES; + + torture_comment(tctx, "Testing invalidAuthenticate2\n"); + + if (!test_SetupCredentials2(p, tctx, flags, + credentials, + cli_credentials_get_secure_channel_type(credentials), + &creds)) { + return false; + } + + if (!test_SetupCredentials2ex(p, tctx, flags, + credentials, + "1234567890123456", + cli_credentials_get_secure_channel_type(credentials), + STATUS_BUFFER_OVERFLOW, + &creds)) { + return false; + } + + if (!test_SetupCredentials2ex(p, tctx, flags, + credentials, + "123456789012345", + cli_credentials_get_secure_channel_type(credentials), + NT_STATUS_OK, + &creds)) { + return false; + } + + return true; +} + static bool test_SamLogon_NULL_domain(struct torture_context *tctx, struct dcerpc_pipe *p, struct cli_credentials *credentials) @@ -3883,6 +3942,7 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx) torture_rpc_tcase_add_test(tcase, "LogonUasLogon", test_LogonUasLogon); torture_rpc_tcase_add_test(tcase, "LogonUasLogoff", test_LogonUasLogoff); torture_rpc_tcase_add_test_creds(tcase, "SamLogon", test_SamLogon); + torture_rpc_tcase_add_test_creds(tcase, "invalidAuthenticate2", test_invalidAuthenticate2); torture_rpc_tcase_add_test_creds(tcase, "SetPassword", test_SetPassword); torture_rpc_tcase_add_test_creds(tcase, "SetPassword2", test_SetPassword2); torture_rpc_tcase_add_test_creds(tcase, "SetPassword2_AES", test_SetPassword2_AES); -- 1.7.9.5