From 1c9216f36cc451156d6c65f0e971ce48f05da3e5 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 11 Aug 2004 18:09:40 +0000 Subject: r1731: Add server-side SPNEGO support to Samba (disabled, until SMB signing is reworked). Andrew Bartlett (This used to be commit 73ee549b8c54e93556ff0105941996e0d4de8303) --- source4/smb_server/negprot.c | 100 ++++++++++++++++------------------- source4/smb_server/sesssetup.c | 117 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 149 insertions(+), 68 deletions(-) (limited to 'source4/smb_server') diff --git a/source4/smb_server/negprot.c b/source4/smb_server/negprot.c index c9c775e62f..9e8a8f1f2c 100644 --- a/source4/smb_server/negprot.c +++ b/source4/smb_server/negprot.c @@ -171,54 +171,9 @@ static void reply_lanman2(struct smbsrv_request *req, uint16_t choice) req_push_str(req, NULL, lp_workgroup(), -1, STR_TERMINATE); - req_send_reply(req); -} - -#if 0 -/**************************************************************************** - Generate the spnego negprot reply blob. Return the number of bytes used. -****************************************************************************/ -static DATA_BLOB negprot_spnego(struct smbsrv_connection *smb_conn) -{ - DATA_BLOB blob; - uint8_t guid[16]; - const char *OIDs_krb5[] = {OID_KERBEROS5, - OID_KERBEROS5_OLD, - OID_NTLMSSP, - NULL}; - const char *OIDs_plain[] = {OID_NTLMSSP, NULL}; - char *principal; - - smb_conn->negotiate.spnego_negotiated = True; - - memset(guid, 0, 16); - safe_strcpy((char *)guid, lp_netbios_name(), 16); - strlower((char *)guid); - -#if 0 - /* strangely enough, NT does not send the single OID NTLMSSP when - not a ADS member, it sends no OIDs at all - - we can't do this until we teach our sesssion setup parser to know - about raw NTLMSSP (clients send no ASN.1 wrapping if we do this) - */ - if (lp_security() != SEC_ADS) { - memcpy(p, guid, 16); - return 16; - } -#endif - if (lp_security() != SEC_ADS) { - blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE"); - } else { - asprintf(&principal, "%s$@%s", guid, lp_realm()); - blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal); - free(principal); - } - - return blob; + req_send_reply(req); } -#endif /**************************************************************************** Reply for the nt protocol. @@ -243,13 +198,12 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) /* do spnego in user level security if the client supports it and we can do encrypted passwords */ - if (req->smb_conn->negotiate.encrypted_passwords && + if (0 && req->smb_conn->negotiate.encrypted_passwords && (lp_security() != SEC_SHARE) && lp_use_spnego() && (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { -/* REWRITE negotiate_spnego = True; + negotiate_spnego = True; capabilities |= CAP_EXTENDED_SECURITY; -*/ } if (lp_unix_extensions()) { @@ -335,15 +289,51 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) req_push_str(req, NULL, lp_netbios_name(), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN); DEBUG(3,("not using SPNEGO\n")); } else { -#if 0 - DATA_BLOB blob = negprot_spnego(req->smb_conn); + struct gensec_security *gensec_security; + DATA_BLOB null_data_blob = data_blob(NULL, 0); + DATA_BLOB blob; + NTSTATUS nt_status = gensec_server_start(&gensec_security); + + if (req->smb_conn->negotiate.auth_context) { + smbsrv_terminate_connection(req->smb_conn, "reply_nt1: is this a secondary negprot? auth_context is non-NULL!\n"); + return; + } + + req->smb_conn->negotiate.auth_context = NULL; + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status))); + smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n"); + return; + } + + nt_status = gensec_start_mech_by_oid(gensec_security, OID_SPNEGO); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("Failed to start SPNEGO: %s\n", nt_errstr(nt_status))); + smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO\n"); + return; + } + + nt_status = gensec_update(gensec_security, req->mem_ctx, null_data_blob, &blob); + + if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + DEBUG(0, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status))); + smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO - no first token\n"); + return; + } + + req->smb_conn->negotiate.spnego_negotiated = True; + + req_grow_data(req, blob.length + 16); + /* a NOT very random guid */ + memset(req->out.ptr, '\0', 16); + req->out.ptr += 16; - req_grow_data(req, blob.length); memcpy(req->out.ptr, blob.data, blob.length); + SCVAL(req->out.vwv+1, VWV(16), blob.length + 16); + req->out.ptr += blob.length; DEBUG(3,("using SPNEGO\n")); -#else - smbsrv_terminate_connection(req->smb_conn, "no SPNEGO please"); -#endif } req_send_reply_nosign(req); diff --git a/source4/smb_server/sesssetup.c b/source4/smb_server/sesssetup.c index cb0b3a6c5c..39aadf8778 100644 --- a/source4/smb_server/sesssetup.c +++ b/source4/smb_server/sesssetup.c @@ -103,19 +103,41 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities; } - status = make_user_info_for_reply_enc(&user_info, - sess->nt1.in.user, sess->nt1.in.domain, - sess->nt1.in.password1, - sess->nt1.in.password2); - if (!NT_STATUS_IS_OK(status)) { - return NT_STATUS_ACCESS_DENIED; + if (req->smb_conn->negotiate.spnego_negotiated) { + struct auth_context *auth_context; + + status = make_auth_context_subsystem(&auth_context); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sess->nt1.in.user || !*sess->nt1.in.user) { + make_user_info_guest(&user_info); + } + + status = auth_context->check_ntlm_password(auth_context, + user_info, + &server_info); + + free_auth_context(&auth_context); + + } else { + status = make_user_info_for_reply_enc(&user_info, + sess->nt1.in.user, sess->nt1.in.domain, + sess->nt1.in.password1, + sess->nt1.in.password2); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_ACCESS_DENIED; + } + + status = req->smb_conn->negotiate + .auth_context->check_ntlm_password(req->smb_conn->negotiate + .auth_context, + user_info, + &server_info); } - status = req->smb_conn->negotiate - .auth_context->check_ntlm_password(req->smb_conn->negotiate - .auth_context, - user_info, - &server_info); if (!NT_STATUS_IS_OK(status)) { return nt_status_squash(status); } @@ -149,8 +171,74 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s */ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess) { - /* defer this one for now */ - return NT_STATUS_INVALID_LEVEL; + NTSTATUS status = NT_STATUS_ACCESS_DENIED; + struct smbsrv_session *smb_sess; + struct gensec_security *gensec_ctx = NULL; + struct auth_session_info *session_info = NULL; + uint16_t vuid; + + if (!req->smb_conn->negotiate.done_sesssetup) { + req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize; + req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities; + } + + vuid = SVAL(req->in.hdr,HDR_UID); + smb_sess = smbsrv_session_find(req->smb_conn, vuid); + if (smb_sess) { + if (!smb_sess->gensec_ctx) { + return NT_STATUS_INVALID_HANDLE; + } + + /* what is when the client is already successful authentificated? */ + if (smb_sess->session_info) { + return NT_STATUS_ACCESS_DENIED; + } + + status = gensec_update(smb_sess->gensec_ctx, req->mem_ctx, sess->spnego.in.secblob, &sess->spnego.out.secblob); + } else { + status = gensec_server_start(&gensec_ctx); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status))); + return status; + } + + status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status))); + return status; + } + + status = gensec_update(gensec_ctx, req->mem_ctx, sess->spnego.in.secblob, &sess->spnego.out.secblob); + + } + + if (NT_STATUS_IS_OK(status)) { + DATA_BLOB session_key; + DATA_BLOB null_data_blob = data_blob(NULL, 0); + status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info); + if (NT_STATUS_IS_OK(gensec_session_key(smb_sess->gensec_ctx, + &session_key))) { + srv_setup_signing(req->smb_conn, &session_key, &null_data_blob); + req->seq_num = 0; + req->smb_conn->signing.next_seq_num = 2; + } + } + + if (!smb_sess) { + vuid = smbsrv_register_session(req->smb_conn, session_info, gensec_ctx); + if (vuid == UID_FIELD_INVALID) { + return NT_STATUS_ACCESS_DENIED; + } + } + + sess->spnego.out.action = 0; + sess->spnego.out.vuid = vuid; + sesssetup_common_strings(req, + &sess->spnego.out.os, + &sess->spnego.out.lanman, + &sess->spnego.out.domain); + + return status; } /* @@ -162,6 +250,9 @@ NTSTATUS sesssetup_backend(struct smbsrv_request *req, NTSTATUS status = NT_STATUS_INVALID_LEVEL; switch (sess->generic.level) { + case RAW_SESSSETUP_GENERIC: + status = NT_STATUS_INVALID_LEVEL; + break; case RAW_SESSSETUP_OLD: status = sesssetup_old(req, sess); break; -- cgit