From 7cbc768376ed0a839afca64aeea99cd53d0fbc6f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 16 Jan 2005 11:15:08 +0000 Subject: r4777: added a smb_composite_sesssetup() async composite function. This encapsulates all the different session setup methods, including the multi-pass spnego code. I have hooked this into all the places that previously used the RAW_SESSSETUP_GENERIC method, and have removed the old RAW_SESSSETUP_GENERIC code from clisession.c and clitree.c. A nice side effect is that these two modules are now very simple again, back to being "raw" session setup handling, which was what was originally intended. I have also used this to replace the session setup code in the smb_composite_connect() code, and used that to build a very simple replacement for smbcli_tree_full_connection(). As a result, smbclient, smbtorture and all our other SMB connection code now goes via these composite async functions. That should give them a good workout! (This used to be commit 080d0518bc7d6fd4bc3ef783e7d4d2e3275d0799) --- source4/libcli/raw/clisession.c | 358 +--------------------------------------- 1 file changed, 6 insertions(+), 352 deletions(-) (limited to 'source4/libcli/raw/clisession.c') diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c index 46236217ea..ed50601c25 100644 --- a/source4/libcli/raw/clisession.c +++ b/source4/libcli/raw/clisession.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. SMB client session context management functions - Copyright (C) Andrew Tridgell 1994-1998 + + Copyright (C) Andrew Tridgell 1994-2005 Copyright (C) James Myers 2003 This program is free software; you can redistribute it and/or modify @@ -76,11 +77,7 @@ struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session { struct smbcli_request *req = NULL; - switch (parms->generic.level) { - case RAW_SESSSETUP_GENERIC: - /* handled elsewhere */ - return NULL; - + switch (parms->old.level) { case RAW_SESSSETUP_OLD: SETUP_REQUEST_SESSION(SMBsesssetupX, 10, 0); SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE); @@ -164,11 +161,7 @@ NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req, return smbcli_request_destroy(req); } - switch (parms->generic.level) { - case RAW_SESSSETUP_GENERIC: - /* handled elsewhere */ - return NT_STATUS_INVALID_LEVEL; - + switch (parms->old.level) { case RAW_SESSSETUP_OLD: SMBCLI_CHECK_WCT(req, 3); ZERO_STRUCT(parms->old.out); @@ -220,353 +213,14 @@ failed: return smbcli_request_destroy(req); } -/* - form an encrypted lanman password from a plaintext password - and the server supplied challenge -*/ -static DATA_BLOB lanman_blob(const char *pass, DATA_BLOB challenge) -{ - DATA_BLOB blob = data_blob(NULL, 24); - SMBencrypt(pass, challenge.data, blob.data); - return blob; -} - -/* - form an encrypted NT password from a plaintext password - and the server supplied challenge -*/ -static DATA_BLOB nt_blob(const char *pass, DATA_BLOB challenge) -{ - DATA_BLOB blob = data_blob(NULL, 24); - SMBNTencrypt(pass, challenge.data, blob.data); - return blob; -} - -/* - store the user session key for a transport -*/ -void smbcli_session_set_user_session_key(struct smbcli_session *session, - const DATA_BLOB *session_key) -{ - session->user_session_key = data_blob_talloc(session, - session_key->data, - session_key->length); -} /* - setup signing for a NT1 style session setup -*/ -void smb_session_use_nt1_session_keys(struct smbcli_session *session, - const char *password, const DATA_BLOB *nt_response) -{ - struct smbcli_transport *transport = session->transport; - uint8_t nt_hash[16]; - DATA_BLOB session_key = data_blob(NULL, 16); - - E_md4hash(password, nt_hash); - SMBsesskeygen_ntv1(nt_hash, session_key.data); - - smbcli_transport_simple_set_signing(transport, session_key, *nt_response); - - smbcli_session_set_user_session_key(session, &session_key); - data_blob_free(&session_key); -} - -/**************************************************************************** - Perform a session setup (sync interface) using generic interface and the old - style sesssetup call -****************************************************************************/ -static NTSTATUS smb_raw_session_setup_generic_old(struct smbcli_session *session, - TALLOC_CTX *mem_ctx, - union smb_sesssetup *parms) -{ - NTSTATUS status; - union smb_sesssetup s2; - - /* use the old interface */ - s2.generic.level = RAW_SESSSETUP_OLD; - s2.old.in.bufsize = session->transport->options.max_xmit; - s2.old.in.mpx_max = session->transport->options.max_mux; - s2.old.in.vc_num = 1; - s2.old.in.sesskey = parms->generic.in.sesskey; - s2.old.in.domain = parms->generic.in.domain; - s2.old.in.user = parms->generic.in.user; - s2.old.in.os = "Unix"; - s2.old.in.lanman = "Samba"; - - if (!parms->generic.in.password) { - s2.old.in.password = data_blob(NULL, 0); - } else if (session->transport->negotiate.sec_mode & - NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { - s2.old.in.password = lanman_blob(parms->generic.in.password, - session->transport->negotiate.secblob); - } else { - s2.old.in.password = data_blob(parms->generic.in.password, - strlen(parms->generic.in.password)); - } - - status = smb_raw_session_setup(session, mem_ctx, &s2); - - data_blob_free(&s2.old.in.password); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - parms->generic.out.vuid = s2.old.out.vuid; - parms->generic.out.os = s2.old.out.os; - parms->generic.out.lanman = s2.old.out.lanman; - parms->generic.out.domain = s2.old.out.domain; - - return NT_STATUS_OK; -} - -/**************************************************************************** - Perform a session setup (sync interface) using generic interface and the NT1 - style sesssetup call -****************************************************************************/ -static NTSTATUS smb_raw_session_setup_generic_nt1(struct smbcli_session *session, - TALLOC_CTX *mem_ctx, - union smb_sesssetup *parms) -{ - NTSTATUS status; - union smb_sesssetup s2; - - s2.generic.level = RAW_SESSSETUP_NT1; - s2.nt1.in.bufsize = session->transport->options.max_xmit; - s2.nt1.in.mpx_max = session->transport->options.max_mux; - s2.nt1.in.vc_num = 1; - s2.nt1.in.sesskey = parms->generic.in.sesskey; - s2.nt1.in.capabilities = parms->generic.in.capabilities; - s2.nt1.in.domain = parms->generic.in.domain; - s2.nt1.in.user = parms->generic.in.user; - s2.nt1.in.os = "Unix"; - s2.nt1.in.lanman = "Samba"; - - if (!parms->generic.in.password) { - s2.nt1.in.password1 = data_blob(NULL, 0); - s2.nt1.in.password2 = data_blob(NULL, 0); - } else if (session->transport->negotiate.sec_mode & - NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { - s2.nt1.in.password1 = lanman_blob(parms->generic.in.password, - session->transport->negotiate.secblob); - s2.nt1.in.password2 = nt_blob(parms->generic.in.password, - session->transport->negotiate.secblob); - smb_session_use_nt1_session_keys(session, parms->generic.in.password, &s2.nt1.in.password2); - - } else { - s2.nt1.in.password1 = data_blob(parms->generic.in.password, - strlen(parms->generic.in.password)); - s2.nt1.in.password2 = data_blob(NULL, 0); - } - - status = smb_raw_session_setup(session, mem_ctx, &s2); - - data_blob_free(&s2.nt1.in.password1); - data_blob_free(&s2.nt1.in.password2); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - parms->generic.out.vuid = s2.nt1.out.vuid; - parms->generic.out.os = s2.nt1.out.os; - parms->generic.out.lanman = s2.nt1.out.lanman; - parms->generic.out.domain = s2.nt1.out.domain; - - return NT_STATUS_OK; -} - -/**************************************************************************** - Perform a session setup (sync interface) using generic interface and the SPNEGO - style sesssetup call -****************************************************************************/ -static NTSTATUS smb_raw_session_setup_generic_spnego(struct smbcli_session *session, - TALLOC_CTX *mem_ctx, - union smb_sesssetup *parms) -{ - NTSTATUS status; - NTSTATUS session_key_err = NT_STATUS_NO_USER_SESSION_KEY; - union smb_sesssetup s2; - DATA_BLOB session_key = data_blob(NULL, 0); - DATA_BLOB null_data_blob = data_blob(NULL, 0); - const char *chosen_oid = NULL; - - s2.generic.level = RAW_SESSSETUP_SPNEGO; - s2.spnego.in.bufsize = session->transport->options.max_xmit; - s2.spnego.in.mpx_max = session->transport->options.max_mux; - s2.spnego.in.vc_num = 1; - s2.spnego.in.sesskey = parms->generic.in.sesskey; - s2.spnego.in.capabilities = parms->generic.in.capabilities; - s2.spnego.in.domain = parms->generic.in.domain; - s2.spnego.in.os = "Unix"; - s2.spnego.in.lanman = "Samba"; - s2.spnego.out.vuid = session->vuid; - - smbcli_temp_set_signing(session->transport); - - status = gensec_client_start(session, &session->gensec); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status))); - return status; - } - - gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY); - - status = gensec_set_domain(session->gensec, parms->generic.in.domain); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", - parms->generic.in.domain, nt_errstr(status))); - goto done; - } - - status = gensec_set_username(session->gensec, parms->generic.in.user); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", - parms->generic.in.user, nt_errstr(status))); - goto done; - } - - status = gensec_set_password(session->gensec, parms->generic.in.password); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client password: %s\n", - nt_errstr(status))); - goto done; - } - - status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", - nt_errstr(status))); - goto done; - } - - if (session->transport->negotiate.secblob.length) { - chosen_oid = GENSEC_OID_SPNEGO; - } else { - /* without a sec blob, means raw NTLMSSP */ - chosen_oid = GENSEC_OID_NTLMSSP; - } - - status = gensec_start_mech_by_oid(session->gensec, chosen_oid); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism %s: %s\n", - gensec_get_name_by_oid(chosen_oid), nt_errstr(status))); - goto done; - } - - status = gensec_update(session->gensec, mem_ctx, - session->transport->negotiate.secblob, - &s2.spnego.in.secblob); - - while(1) { - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { - break; - } - - if (!NT_STATUS_IS_OK(session_key_err)) { - 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); - } - - if (NT_STATUS_IS_OK(status) && s2.spnego.in.secblob.length == 0) { - break; - } - - session->vuid = s2.spnego.out.vuid; - status = smb_raw_session_setup(session, mem_ctx, &s2); - session->vuid = UID_FIELD_INVALID; - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - break; - } - - status = gensec_update(session->gensec, mem_ctx, - s2.spnego.out.secblob, - &s2.spnego.in.secblob); - - } - -done: - if (NT_STATUS_IS_OK(status)) { - if (!NT_STATUS_IS_OK(session_key_err)) { - DEBUG(1, ("Failed to get user session key: %s\n", nt_errstr(session_key_err))); - return session_key_err; - } - - smbcli_session_set_user_session_key(session, &session_key); - - parms->generic.out.vuid = s2.spnego.out.vuid; - parms->generic.out.os = s2.spnego.out.os; - parms->generic.out.lanman = s2.spnego.out.lanman; - parms->generic.out.domain = s2.spnego.out.domain; - } else { - talloc_free(session->gensec); - session->gensec = NULL; - DEBUG(1, ("Failed to login with %s: %s\n", gensec_get_name_by_oid(chosen_oid), nt_errstr(status))); - return status; - } - - return status; -} - -/**************************************************************************** - Perform a session setup (sync interface) using generic interface -****************************************************************************/ -static NTSTATUS smb_raw_session_setup_generic(struct smbcli_session *session, - TALLOC_CTX *mem_ctx, - union smb_sesssetup *parms) -{ - if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) { - /* no session setup at all in earliest protocols */ - ZERO_STRUCT(parms->generic.out); - return NT_STATUS_OK; - } - - /* see if we need to use the original session setup interface */ - if (session->transport->negotiate.protocol < PROTOCOL_NT1) { - return smb_raw_session_setup_generic_old(session, mem_ctx, parms); - } - - /* see if we should use the NT1 interface */ - if (!session->transport->options.use_spnego || - !(parms->generic.in.capabilities & CAP_EXTENDED_SECURITY)) { - return smb_raw_session_setup_generic_nt1(session, mem_ctx, parms); - } - - /* default to using SPNEGO/NTLMSSP */ - return smb_raw_session_setup_generic_spnego(session, mem_ctx, parms); -} - - -/**************************************************************************** Perform a session setup (sync interface) -this interface allows for RAW_SESSSETUP_GENERIC to auto-select session -setup variant based on negotiated protocol options -****************************************************************************/ +*/ NTSTATUS smb_raw_session_setup(struct smbcli_session *session, TALLOC_CTX *mem_ctx, union smb_sesssetup *parms) { - struct smbcli_request *req; - - if (parms->generic.level == RAW_SESSSETUP_GENERIC) { - NTSTATUS ret = smb_raw_session_setup_generic(session, mem_ctx, parms); - - if (NT_STATUS_IS_OK(ret) - && parms->generic.in.user - && *parms->generic.in.user) { - if (!session->transport->negotiate.sign_info.doing_signing - && session->transport->negotiate.sign_info.mandatory_signing) { - DEBUG(0, ("SMB signing required, but server does not support it\n")); - return NT_STATUS_ACCESS_DENIED; - } - } - return ret; - } - - req = smb_raw_session_setup_send(session, parms); + struct smbcli_request *req = smb_raw_session_setup_send(session, parms); return smb_raw_session_setup_recv(req, mem_ctx, parms); } -- cgit