From c01426ce731e2cf0b04ee3a0376e613f4970fb30 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 9 Sep 2008 18:02:07 +0200 Subject: libcli/smb_composite: for spnego session setups check the smb signature manually We need to start signing when we got NT_STATUS_OK from the server and manually check the signature of the servers response. This is needed as the response might be signed with the krb5 acceptor subkey, which comes within the server response. With NTLMSSP this happens for the session setup: request1 => BSRSPYL seqnum: 0 response1 => BSRSPYL seqnum: 0 request2 => BSRSPYL seqnum: 0 response2 => seqnum: 1 and with krb5: request1 => BSRSPYL seqnum: 0 response1 => seqnum: 1 metze --- source4/libcli/smb_composite/sesssetup.c | 80 +++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 23 deletions(-) (limited to 'source4/libcli/smb_composite') diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c index 11ac37e257..92b49dc3d4 100644 --- a/source4/libcli/smb_composite/sesssetup.c +++ b/source4/libcli/smb_composite/sesssetup.c @@ -35,6 +35,7 @@ struct sesssetup_state { union smb_sesssetup setup; + NTSTATUS remote_status; NTSTATUS gensec_status; struct smb_composite_sesssetup *io; struct smbcli_request *req; @@ -85,8 +86,15 @@ static void request_handler(struct smbcli_request *req) DATA_BLOB session_key = data_blob(NULL, 0); DATA_BLOB null_data_blob = data_blob(NULL, 0); NTSTATUS session_key_err, nt_status; + struct smbcli_request *check_req = NULL; - c->status = smb_raw_sesssetup_recv(req, state, &state->setup); + if (req->sign_caller_checks) { + req->do_not_free = true; + check_req = req; + } + + state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup); + c->status = state->remote_status; state->req = NULL; switch (state->setup.old.level) { @@ -102,6 +110,7 @@ static void request_handler(struct smbcli_request *req) state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; @@ -120,6 +129,7 @@ static void request_handler(struct smbcli_request *req) state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; @@ -138,6 +148,7 @@ static void request_handler(struct smbcli_request *req) state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; @@ -169,12 +180,16 @@ static void request_handler(struct smbcli_request *req) state->setup.spnego.in.secblob = data_blob(NULL, 0); } - /* we need to do another round of session setup. We keep going until both sides - are happy */ - session_key_err = gensec_session_key(session->gensec, &session_key); - if (NT_STATUS_IS_OK(session_key_err)) { - set_user_session_key(session, &session_key); - smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob); + if (NT_STATUS_IS_OK(state->remote_status)) { + if (state->setup.spnego.in.secblob.length) { + c->status = NT_STATUS_INTERNAL_ERROR; + break; + } + session_key_err = gensec_session_key(session->gensec, &session_key); + if (NT_STATUS_IS_OK(session_key_err)) { + set_user_session_key(session, &session_key); + smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob); + } } if (state->setup.spnego.in.secblob.length) { @@ -186,6 +201,9 @@ static void request_handler(struct smbcli_request *req) session->vuid = state->io->out.vuid; state->req = smb_raw_sesssetup_send(session, &state->setup); session->vuid = vuid; + if (state->req) { + state->req->sign_caller_checks = true; + } composite_continue_smb(c, state->req, request_handler, c); return; } @@ -196,6 +214,15 @@ static void request_handler(struct smbcli_request *req) break; } + if (check_req) { + check_req->sign_caller_checks = false; + if (!smbcli_request_check_sign_mac(check_req)) { + c->status = NT_STATUS_ACCESS_DENIED; + } + talloc_free(check_req); + check_req = NULL; + } + /* enforce the local signing required flag */ if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) { if (!session->transport->negotiate.sign_info.doing_signing @@ -222,11 +249,14 @@ static NTSTATUS session_setup_nt1(struct composite_context *c, struct smb_composite_sesssetup *io, struct smbcli_request **req) { - NTSTATUS nt_status; + NTSTATUS nt_status = NT_STATUS_INTERNAL_ERROR; struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, lp_iconv_convenience(global_loadparm), session->transport->socket->hostname, lp_workgroup(global_loadparm)); - DATA_BLOB session_key; + DATA_BLOB session_key = data_blob(NULL, 0); int flags = CLI_CRED_NTLM_AUTH; + + smbcli_temp_set_signing(session->transport); + if (session->options.lanman_auth) { flags |= CLI_CRED_LANMAN_AUTH; } @@ -258,12 +288,6 @@ static NTSTATUS session_setup_nt1(struct composite_context *c, &state->setup.nt1.in.password2, NULL, &session_key); NT_STATUS_NOT_OK_RETURN(nt_status); - - smbcli_transport_simple_set_signing(session->transport, session_key, - state->setup.nt1.in.password2); - set_user_session_key(session, &session_key); - - data_blob_free(&session_key); } else if (session->options.plaintext_auth) { const char *password = cli_credentials_get_password(io->in.credentials); state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password)); @@ -277,6 +301,15 @@ static NTSTATUS session_setup_nt1(struct composite_context *c, if (!*req) { return NT_STATUS_NO_MEMORY; } + + if (NT_STATUS_IS_OK(nt_status)) { + smbcli_transport_simple_set_signing(session->transport, session_key, + state->setup.nt1.in.password2); + set_user_session_key(session, &session_key); + + data_blob_free(&session_key); + } + return (*req)->status; } @@ -350,9 +383,7 @@ static NTSTATUS session_setup_spnego(struct composite_context *c, struct smbcli_request **req) { struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); - NTSTATUS status, session_key_err; - DATA_BLOB session_key = data_blob(NULL, 0); - DATA_BLOB null_data_blob = data_blob(NULL, 0); + NTSTATUS status; const char *chosen_oid = NULL; state->setup.spnego.level = RAW_SESSSETUP_SPNEGO; @@ -440,15 +471,18 @@ static NTSTATUS session_setup_spnego(struct composite_context *c, } state->gensec_status = status; - session_key_err = gensec_session_key(session->gensec, &session_key); - if (NT_STATUS_IS_OK(session_key_err)) { - smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob); - } - *req = smb_raw_sesssetup_send(session, &state->setup); if (!*req) { return NT_STATUS_NO_MEMORY; } + + /* + * we need to check the signature ourself + * as the session key might be the acceptor subkey + * which comes within the response itself + */ + (*req)->sign_caller_checks = true; + return (*req)->status; } -- cgit From b7d2ff38f54250db52c495d26a2b2923e5dcc83e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 24 Sep 2008 03:59:53 +0200 Subject: s4:libcli/smb_composite: we only check the signature when the server return OK We need to manually free the request, otherwise the timeout handler is triggered later. metze --- source4/libcli/smb_composite/sesssetup.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'source4/libcli/smb_composite') diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c index 92b49dc3d4..645f5362ac 100644 --- a/source4/libcli/smb_composite/sesssetup.c +++ b/source4/libcli/smb_composite/sesssetup.c @@ -97,6 +97,15 @@ static void request_handler(struct smbcli_request *req) c->status = state->remote_status; state->req = NULL; + /* + * we only need to check the signature if the + * NT_STATUS_OK is returned + */ + if (!NT_STATUS_IS_OK(state->remote_status)) { + talloc_free(check_req); + check_req = NULL; + } + switch (state->setup.old.level) { case RAW_SESSSETUP_OLD: state->io->out.vuid = state->setup.old.out.vuid; -- cgit From c8a19f0b8373bec27f4d3638bb731963896f3ff5 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 30 Sep 2008 01:29:53 +0200 Subject: Pass options struct into session initialization functions rather than using global_loadparm. --- source4/libcli/smb_composite/connect.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4/libcli/smb_composite') diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index e56339f96b..5f651f4865 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -229,12 +229,15 @@ static NTSTATUS connect_negprot(struct composite_context *c, { struct connect_state *state = talloc_get_type(c->private_data, struct connect_state); NTSTATUS status; + struct smbcli_session_options options; + + lp_smbcli_session_options(global_loadparm, &options); status = smb_raw_negotiate_recv(state->req); NT_STATUS_NOT_OK_RETURN(status); /* next step is a session setup */ - state->session = smbcli_session_init(state->transport, state, true); + state->session = smbcli_session_init(state->transport, state, true, options); NT_STATUS_HAVE_NO_MEMORY(state->session); /* setup for a tconx (or at least have the structure ready to -- cgit From 4e8cb60222ea13295eaff477625164dfd61e288f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 30 Sep 2008 02:11:55 +0200 Subject: Remove global_loadparm instance. --- source4/libcli/smb_composite/fsinfo.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source4/libcli/smb_composite') diff --git a/source4/libcli/smb_composite/fsinfo.c b/source4/libcli/smb_composite/fsinfo.c index 270d71f518..cd6e98547b 100644 --- a/source4/libcli/smb_composite/fsinfo.c +++ b/source4/libcli/smb_composite/fsinfo.c @@ -127,7 +127,8 @@ static void fsinfo_composite_handler(struct composite_context *creq) composite fsinfo call - connects to a tree and queries a file system information */ struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree, - struct smb_composite_fsinfo *io) + struct smb_composite_fsinfo *io, + struct resolve_context *resolve_ctx) { struct composite_context *c; struct fsinfo_state *state; @@ -160,7 +161,7 @@ struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree, c->private_data = state; state->creq = smb_composite_connect_send(state->connect, state, - lp_resolve_context(global_loadparm), c->event_ctx); + resolve_ctx, c->event_ctx); if (state->creq == NULL) goto failed; @@ -197,9 +198,10 @@ NTSTATUS smb_composite_fsinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ */ NTSTATUS smb_composite_fsinfo(struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, - struct smb_composite_fsinfo *io) + struct smb_composite_fsinfo *io, + struct resolve_context *resolve_ctx) { - struct composite_context *c = smb_composite_fsinfo_send(tree, io); + struct composite_context *c = smb_composite_fsinfo_send(tree, io, resolve_ctx); return smb_composite_fsinfo_recv(c, mem_ctx); } -- cgit From 181ee01da67985f5db684500247d655ce72fe611 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 30 Sep 2008 02:47:19 +0200 Subject: Pass session options around; saves another use of global_loadparm. --- source4/libcli/smb_composite/connect.c | 5 +---- source4/libcli/smb_composite/fetchfile.c | 1 + source4/libcli/smb_composite/fsinfo.c | 1 + source4/libcli/smb_composite/smb_composite.h | 2 ++ 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'source4/libcli/smb_composite') diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index 5f651f4865..a4137290bb 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -229,15 +229,12 @@ static NTSTATUS connect_negprot(struct composite_context *c, { struct connect_state *state = talloc_get_type(c->private_data, struct connect_state); NTSTATUS status; - struct smbcli_session_options options; - - lp_smbcli_session_options(global_loadparm, &options); status = smb_raw_negotiate_recv(state->req); NT_STATUS_NOT_OK_RETURN(status); /* next step is a session setup */ - state->session = smbcli_session_init(state->transport, state, true, options); + state->session = smbcli_session_init(state->transport, state, true, io->in.session_options); NT_STATUS_HAVE_NO_MEMORY(state->session); /* setup for a tconx (or at least have the structure ready to diff --git a/source4/libcli/smb_composite/fetchfile.c b/source4/libcli/smb_composite/fetchfile.c index 9cd02a51f4..ff4f0e7930 100644 --- a/source4/libcli/smb_composite/fetchfile.c +++ b/source4/libcli/smb_composite/fetchfile.c @@ -147,6 +147,7 @@ struct composite_context *smb_composite_fetchfile_send(struct smb_composite_fetc state->connect->in.workgroup = io->in.workgroup; state->connect->in.options = io->in.options; + state->connect->in.session_options = io->in.session_options; state->creq = smb_composite_connect_send(state->connect, state, io->in.resolve_ctx, event_ctx); diff --git a/source4/libcli/smb_composite/fsinfo.c b/source4/libcli/smb_composite/fsinfo.c index cd6e98547b..dc5327a29c 100644 --- a/source4/libcli/smb_composite/fsinfo.c +++ b/source4/libcli/smb_composite/fsinfo.c @@ -155,6 +155,7 @@ struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree, state->connect->in.workgroup = io->in.workgroup; state->connect->in.options = tree->session->transport->options; + state->connect->in.session_options = tree->session->options; c->state = COMPOSITE_STATE_IN_PROGRESS; state->stage = FSINFO_CONNECT; diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h index 7f4b9d73e4..08ca40c833 100644 --- a/source4/libcli/smb_composite/smb_composite.h +++ b/source4/libcli/smb_composite/smb_composite.h @@ -57,6 +57,7 @@ struct smb_composite_fetchfile { const char *workgroup; const char *filename; struct smbcli_options options; + struct smbcli_session_options session_options; struct resolve_context *resolve_ctx; } in; struct { @@ -98,6 +99,7 @@ struct smb_composite_connect { bool fallback_to_anonymous; const char *workgroup; struct smbcli_options options; + struct smbcli_session_options session_options; } in; struct { struct smbcli_tree *tree; -- cgit