From d3524f2eaeef06059fcdc7af5b742cd46064fd20 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 26 Jul 2011 15:11:47 +1000 Subject: s3-auth use auth_generic_start to get full GENSEC in Samba3 session setup This tests if the auth_generic_start() hook is available on the auth context during the negprot, and if so it uses auth_generic_start() to hook to GENSEC to handle the full SPNEGO blob. Andrew Bartlett Signed-off-by: Andrew Tridgell --- source3/smbd/globals.h | 3 +++ source3/smbd/negprot.c | 28 +++++++++++++++++++++- source3/smbd/sesssetup.c | 54 +++++++++++++++++++++++++------------------ source3/smbd/smb2_sesssetup.c | 25 ++++++++++++++------ 4 files changed, 80 insertions(+), 30 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 9e8059be19..26125ce805 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -474,6 +474,9 @@ struct smbd_server_connection { unsigned long file_gen_counter; int first_file; + /* Try GENSEC hook */ + bool use_gensec_hook; + /* number of open connections (tcons) */ int num_tcons_open; diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index f1d2fc2545..a58744281c 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -24,8 +24,10 @@ #include "../libcli/auth/spnego.h" #include "serverid.h" #include "auth.h" +#include "ntlmssp_wrap.h" #include "messages.h" #include "smbprofile.h" +#include "auth/gensec/gensec.h" extern fstring remote_proto; @@ -187,6 +189,7 @@ DATA_BLOB negprot_spnego(TALLOC_CTX *ctx, struct smbd_server_connection *sconn) DATA_BLOB blob_out = data_blob_null; nstring dos_name; fstring unix_name; + NTSTATUS status; #ifdef DEVELOPER size_t slen; #endif @@ -195,8 +198,29 @@ DATA_BLOB negprot_spnego(TALLOC_CTX *ctx, struct smbd_server_connection *sconn) OID_NTLMSSP, NULL}; const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL}; + struct auth_ntlmssp_state *auth_ntlmssp_state; + + sconn->use_gensec_hook = false; + + /* See if we can get an SPNEGO blob out of the gensec hook (if auth_samba4 is loaded) */ + status = auth_ntlmssp_prepare(sconn->remote_address, + &auth_ntlmssp_state); + if (NT_STATUS_IS_OK(status)) { + status = auth_generic_start(auth_ntlmssp_state, GENSEC_OID_SPNEGO); + if (NT_STATUS_IS_OK(status)) { + status = auth_ntlmssp_update(auth_ntlmssp_state, ctx, + data_blob_null, &blob); + /* If we get the list of OIDs, the 'OK' answer + * is NT_STATUS_MORE_PROCESSING_REQUIRED */ + if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + sconn->use_gensec_hook = true; + } + } + TALLOC_FREE(auth_ntlmssp_state); + } sconn->smb1.negprot.spnego = true; + /* strangely enough, NT does not sent the single OID NTLMSSP when not a ADS member, it sends no OIDs at all @@ -210,7 +234,9 @@ DATA_BLOB negprot_spnego(TALLOC_CTX *ctx, struct smbd_server_connection *sconn) */ - if (lp_security() != SEC_ADS && !USE_KERBEROS_KEYTAB) { + if (sconn->use_gensec_hook) { + /* blob initialised above */ + } else if (lp_security() != SEC_ADS && !USE_KERBEROS_KEYTAB) { #if 0 /* Code for PocketPC client */ blob = data_blob(guid, 16); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 2f3bbd6171..020c62cad8 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -36,6 +36,7 @@ #include "messages.h" #include "smbprofile.h" #include "../libcli/security/security.h" +#include "auth/gensec/gensec.h" /* For split krb5 SPNEGO blobs. */ struct pending_auth_data { @@ -1134,27 +1135,12 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) return; } - if (blob1.data[0] == ASN1_APPLICATION(0)) { - - /* its a negTokenTarg packet */ - - reply_spnego_negotiate(req, vuid, blob1, - &vuser->auth_ntlmssp_state); - data_blob_free(&blob1); - return; - } - - if (blob1.data[0] == ASN1_CONTEXT(1)) { - - /* its a auth packet */ - - reply_spnego_auth(req, vuid, blob1, - &vuser->auth_ntlmssp_state); - data_blob_free(&blob1); - return; - } - - if (blob1.length > 7 && strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) { + /* Handle either raw NTLMSSP or hand off the whole blob to + * GENSEC. The processing at this layer is essentially + * identical regardless. In particular, both rely only on the + * status code (not the contents of the packet) and do not + * wrap the result */ + if (sconn->use_gensec_hook || (blob1.length > 7 && strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0)) { DATA_BLOB chal; if (!vuser->auth_ntlmssp_state) { @@ -1170,7 +1156,11 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) auth_ntlmssp_want_feature(vuser->auth_ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY); - status = auth_ntlmssp_start(vuser->auth_ntlmssp_state); + if (sconn->use_gensec_hook) { + status = auth_generic_start(vuser->auth_ntlmssp_state, GENSEC_OID_SPNEGO); + } else { + status = auth_ntlmssp_start(vuser->auth_ntlmssp_state); + } if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(sconn, vuid); @@ -1193,6 +1183,26 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) return; } + if (blob1.data[0] == ASN1_APPLICATION(0)) { + + /* its a negTokenTarg packet */ + + reply_spnego_negotiate(req, vuid, blob1, + &vuser->auth_ntlmssp_state); + data_blob_free(&blob1); + return; + } + + if (blob1.data[0] == ASN1_CONTEXT(1)) { + + /* its a auth packet */ + + reply_spnego_auth(req, vuid, blob1, + &vuser->auth_ntlmssp_state); + data_blob_free(&blob1); + return; + } + /* what sort of packet is this? */ DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n")); diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index a3283117b4..d1022cd2cf 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -25,6 +25,7 @@ #include "../libcli/smb/smb_common.h" #include "../libcli/auth/spnego.h" #include "../libcli/auth/ntlmssp.h" +#include "../auth/gensec/gensec.h" #include "ntlmssp_wrap.h" #include "../librpc/gen_ndr/krb5pac.h" #include "libads/kerberos_proto.h" @@ -649,7 +650,11 @@ static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session, auth_ntlmssp_want_feature(session->auth_ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY); - status = auth_ntlmssp_start(session->auth_ntlmssp_state); + if (session->sconn->use_gensec_hook) { + status = auth_generic_start(session->auth_ntlmssp_state, GENSEC_OID_SPNEGO); + } else { + status = auth_ntlmssp_start(session->auth_ntlmssp_state); + } if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return status; @@ -742,24 +747,30 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req, return NT_STATUS_REQUEST_NOT_ACCEPTED; } - if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) { - return smbd_smb2_spnego_negotiate(session, + /* Handle either raw NTLMSSP or hand off the whole blob to + * GENSEC. The processing at this layer is essentially + * identical regardless. In particular, both rely only on the + * status code (not the contents of the packet) and do not + * wrap the result */ + if (session->sconn->use_gensec_hook + || (in_security_buffer.length > 7 && strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0)) { + return smbd_smb2_raw_ntlmssp_auth(session, smb2req, in_security_mode, in_security_buffer, out_session_flags, out_security_buffer, out_session_id); - } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) { - return smbd_smb2_spnego_auth(session, + } else if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) { + return smbd_smb2_spnego_negotiate(session, smb2req, in_security_mode, in_security_buffer, out_session_flags, out_security_buffer, out_session_id); - } else if (in_security_buffer.length > 7 && strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) { - return smbd_smb2_raw_ntlmssp_auth(session, + } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) { + return smbd_smb2_spnego_auth(session, smb2req, in_security_mode, in_security_buffer, -- cgit