From 46b7eb7737b5ce7e0f6b9d03a502baf051a7f3cf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher <metze@samba.org> Date: Wed, 2 Oct 2024 19:06:59 +0200 Subject: [PATCH] libcli/auth: also use netlogon_creds_CredentialState_extra_info for the client In order to allow backports and cluster updates we simulate a dom_sid, so that the old code is able to parse the blob. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15425 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> (cherry picked from commit 8b972fea0978101575f847eac33b09d2fd8d02e7) --- libcli/auth/credentials.c | 15 ++++++++- libcli/auth/netlogon_creds_cli.c | 13 ++++++-- libcli/auth/proto.h | 1 + librpc/idl/schannel.idl | 47 ++++++++++++++++++++++++++- source4/librpc/rpc/dcerpc_schannel.c | 1 + source4/torture/ntp/ntp_signd.c | 1 + source4/torture/rpc/lsa.c | 2 ++ source4/torture/rpc/netlogon.c | 22 +++++++++++++ source4/torture/rpc/netlogon_crypto.c | 1 + source4/torture/rpc/samba3rpc.c | 8 +++-- 10 files changed, 104 insertions(+), 7 deletions(-) diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index 59db4bc28ea..75ac4ddb0f2 100644 --- a/libcli/auth/credentials.c +++ b/libcli/auth/credentials.c @@ -491,16 +491,19 @@ struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *me const struct netr_Credential *server_challenge, const struct samr_Password *machine_password, struct netr_Credential *initial_credential, + uint32_t client_requested_flags, uint32_t negotiate_flags) { struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState); + struct timeval tv = timeval_current(); + NTTIME now = timeval_to_nttime(&tv); NTSTATUS status; if (!creds) { return NULL; } - creds->sequence = time(NULL); + creds->sequence = tv.tv_sec; creds->negotiate_flags = negotiate_flags; creds->secure_channel_type = secure_channel_type; @@ -515,6 +518,16 @@ struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *me return NULL; } + creds->ex = talloc_zero(creds, + struct netlogon_creds_CredentialState_extra_info); + if (creds->ex == NULL) { + talloc_free(creds); + return NULL; + } + creds->ex->client_requested_flags = client_requested_flags; + creds->ex->auth_time = now; + creds->ex->client_sid = global_sid_NULL; + dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data)); dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data)); dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash)); diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 40a40cb99ae..35a5462ff2e 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -1355,6 +1355,7 @@ static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq) &state->server_challenge, state->used_nt_hash, &state->client_credential, + state->context->client.proposed_flags, state->current_flags); if (tevent_req_nomem(state->creds, req)) { return; @@ -1558,6 +1559,7 @@ static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq) return; } + state->creds->ex->client_sid.sub_auths[0] = state->rid; status = netlogon_creds_cli_store_internal(state->context, state->creds); if (tevent_req_nterror(req, status)) { @@ -1935,6 +1937,7 @@ static void netlogon_creds_cli_check_client_caps(struct tevent_req *subreq) struct netlogon_creds_cli_check_state *state = tevent_req_data(req, struct netlogon_creds_cli_check_state); + uint32_t requested_flags; NTSTATUS status; NTSTATUS result; bool ok; @@ -1986,9 +1989,13 @@ static void netlogon_creds_cli_check_client_caps(struct tevent_req *subreq) return; } - if (state->client_caps.requested_flags != - state->context->client.proposed_flags) - { + if (state->creds->ex != NULL) { + requested_flags = state->creds->ex->client_requested_flags; + } else { + requested_flags = state->context->client.proposed_flags; + } + + if (state->client_caps.requested_flags != requested_flags) { status = NT_STATUS_DOWNGRADE_DETECTED; tevent_req_nterror(req, status); netlogon_creds_cli_check_cleanup(req, status); diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h index 3094292657a..ae68aab192a 100644 --- a/libcli/auth/proto.h +++ b/libcli/auth/proto.h @@ -46,6 +46,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *me const struct netr_Credential *server_challenge, const struct samr_Password *machine_password, struct netr_Credential *initial_credential, + uint32_t client_requested_flags, uint32_t negotiate_flags); NTSTATUS netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds, diff --git a/librpc/idl/schannel.idl b/librpc/idl/schannel.idl index 619e9e5591c..8905d514f55 100644 --- a/librpc/idl/schannel.idl +++ b/librpc/idl/schannel.idl @@ -20,8 +20,53 @@ interface schannel * with a single dom_sid for the client_sid. * * On the server we use CLEAR_IF_FIRST, - * so db layout changes don't matter there. + * so db layout changes don't matter there, + * but on the client side we need to handle + * the ctdb case were CLEAR_IF_FIRST only + * works if all cluster nodes are restarted. + * + * As this was a single dom_sid before, + * we add some magic in order to let + * old code (on other nodes to parse the new layout). + * + * We have basically this definition of dom_sid: + * + * typedef struct { + * uint8 sid_rev_num; + * [range(0,15)] int8 num_auths; + * uint8 id_auth[6]; + * uint32 sub_auths[num_auths]; + * } dom_sid; + * + * It means it consumes at least 8 bytes while + * and it's also 4 byte aligned (before sid_rev_num). + * The largest sid would have 68 bytes. + * + * The old client side code would see a sid like + * this: S-1-RSV-CRF-ATL-ATH-257-0-RID + * + * RSV => reserved (the last 4 bytes of id_auth) + * + * CRF => client_requested_flags (sub_auths[0] + * + * Note NTTIME used ndr_pull_udlong, it's not NTTIME_hyper! + * ATL => low 4 bytes of auth_time (sub_auths[1]) + * ATH => high 4 bytes of auth_time (sub_auths[2]) + * + * From client_sid (S-1-0-RID): sub_auth[3-5] + * + * 257 => 0x01 0x01 0x00 0x00 = + * (sid_rev_num = 1, num_auths =1, + * id_auth[0] = 0, id_auth[1] = 0) + * 0 => id_auth[2-6] + * + * RID => the RID of the client + * + * It means the magic needs to simulate + * num_auths = 6 */ + [value(0x00000601)] uint32 magic; + [value(0)] uint32 reserved; netr_NegotiateFlags client_requested_flags; NTTIME auth_time; dom_sid client_sid; diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index 9d96abd2521..ca0495c4d47 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -197,6 +197,7 @@ static void continue_srv_challenge(struct tevent_req *subreq) s->a.in.secure_channel_type, &s->credentials1, &s->credentials2, s->mach_pwd, &s->credentials3, + s->requested_negotiate_flags, s->local_negotiate_flags); if (composite_nomem(s->creds, c)) { return; diff --git a/source4/torture/ntp/ntp_signd.c b/source4/torture/ntp/ntp_signd.c index fd7da67c551..2bf8e0fe127 100644 --- a/source4/torture/ntp/ntp_signd.c +++ b/source4/torture/ntp/ntp_signd.c @@ -119,6 +119,7 @@ static bool test_ntp_signd(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, pwhash, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index d91a5414de1..60186693ea2 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -2951,6 +2951,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p, a.in.secure_channel_type, &credentials1, &credentials2, new_password, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2976,6 +2977,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p, a.in.secure_channel_type, &credentials1, &credentials2, old_password, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 6b403e2cf50..c9a9202892e 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -180,6 +180,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, mach_password, &credentials3, + 0, 0); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -251,6 +252,7 @@ bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tct a.in.secure_channel_type, &credentials1, &credentials2, mach_password, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -349,6 +351,7 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -421,6 +424,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -437,6 +441,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + negotiate_flags, negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -541,6 +546,7 @@ static bool test_ServerReqChallenge( a.in.secure_channel_type, &credentials1, &credentials2, mach_password, &credentials3, + in_negotiate_flags, in_negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -618,6 +624,7 @@ static bool test_ServerReqChallenge_zero_challenge( a.in.secure_channel_type, &credentials1, &credentials2, mach_password, &credentials3, + in_negotiate_flags, in_negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -702,6 +709,7 @@ static bool test_ServerReqChallenge_5_repeats( a.in.secure_channel_type, &credentials1, &credentials2, mach_password, &credentials3, + in_negotiate_flags, in_negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -788,6 +796,7 @@ static bool test_ServerReqChallenge_4_repeats( a.in.secure_channel_type, &credentials1, &credentials2, mach_password, &credentials3, + in_negotiate_flags, in_negotiate_flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -881,6 +890,7 @@ static bool test_ServerAuthenticate2_encrypts_to_zero( &credentials2, mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2272,6 +2282,7 @@ static bool test_ServerReqChallengeGlobal(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2361,6 +2372,7 @@ static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2378,6 +2390,7 @@ static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b3, tctx, &a), @@ -2450,6 +2463,7 @@ static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2467,6 +2481,7 @@ static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a), @@ -2540,6 +2555,7 @@ static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2557,6 +2573,7 @@ static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2655,6 +2672,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2672,6 +2690,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b1, tctx, &a), @@ -2731,6 +2750,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); @@ -2748,6 +2768,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a), @@ -2762,6 +2783,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx, a.in.secure_channel_type, &credentials1, &credentials2, &mach_password, &credentials3, + flags, flags); torture_assert(tctx, creds != NULL, "memory allocation"); diff --git a/source4/torture/rpc/netlogon_crypto.c b/source4/torture/rpc/netlogon_crypto.c index eec8a753179..858a17e0ea8 100644 --- a/source4/torture/rpc/netlogon_crypto.c +++ b/source4/torture/rpc/netlogon_crypto.c @@ -124,6 +124,7 @@ static bool test_ServerAuth3Crypto(struct dcerpc_pipe *p, &netr_creds2, &machine_password, &netr_creds3, + negotiate_flags, negotiate_flags); GNUTLS_FIPS140_SET_STRICT_MODE(); /* Test that we fail to encrypt with RC4 */ diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index 10f0fccde73..96ff34f5270 100644 --- a/source4/torture/rpc/samba3rpc.c +++ b/source4/torture/rpc/samba3rpc.c @@ -1091,7 +1091,9 @@ static bool auth2(struct torture_context *tctx, a.in.secure_channel_type, r.in.credentials, r.out.return_credentials, &mach_pw, - &netr_cred, negotiate_flags); + &netr_cred, + negotiate_flags, + negotiate_flags); torture_assert(tctx, (creds_state != NULL), "memory allocation failed"); status = dcerpc_netr_ServerAuthenticate2_r(net_handle, mem_ctx, &a); @@ -2158,7 +2160,9 @@ static bool torture_samba3_rpc_randomauth2(struct torture_context *torture) a.in.secure_channel_type, r.in.credentials, r.out.return_credentials, &mach_pw, - &netr_cred, negotiate_flags); + &netr_cred, + negotiate_flags, + negotiate_flags); torture_assert(torture, (creds_state != NULL), "memory allocation failed"); status = dcerpc_netr_ServerAuthenticate2_r(net_handle, mem_ctx, &a);