X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Fsmb2_sesssetup.c;h=bf7001938a57abe3c004d32f50511a1537092985;hb=f91aec92ec9418dc2521bb68e5c3635c4fc9a304;hp=511df8639dd957bfd9b3845e4f7ee6838a0763b0;hpb=8a650243b336f5a85ff119aa40c7744542c005e7;p=metze%2Fsamba%2Fwip.git diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 511df8639dd9..bf7001938a57 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -23,62 +23,61 @@ #include "smbd/smbd.h" #include "smbd/globals.h" #include "../libcli/smb/smb_common.h" -#include "../libcli/auth/spnego.h" -#include "../libcli/auth/ntlmssp.h" -#include "ntlmssp_wrap.h" -#include "../librpc/gen_ndr/krb5pac.h" -#include "libads/kerberos_proto.h" -#include "../lib/util/asn1.h" +#include "../auth/gensec/gensec.h" #include "auth.h" #include "../lib/tsocket/tsocket.h" #include "../libcli/security/security.h" +#include "../lib/util/tevent_ntstatus.h" -static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req, +static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req, uint64_t in_session_id, + uint8_t in_flags, uint8_t in_security_mode, - DATA_BLOB in_security_buffer, + uint64_t in_previous_session_id, + DATA_BLOB in_security_buffer); +static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req, uint16_t *out_session_flags, + TALLOC_CTX *mem_ctx, DATA_BLOB *out_security_buffer, uint64_t *out_session_id); +static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq); + NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req) { const uint8_t *inhdr; const uint8_t *inbody; int i = smb2req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - size_t expected_body_size = 0x19; - size_t body_size; uint64_t in_session_id; + uint8_t in_flags; uint8_t in_security_mode; + uint64_t in_previous_session_id; uint16_t in_security_offset; uint16_t in_security_length; DATA_BLOB in_security_buffer; - uint16_t out_session_flags; - uint64_t out_session_id; - uint16_t out_security_offset; - DATA_BLOB out_security_buffer; NTSTATUS status; + struct tevent_req *subreq; - inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base; - - if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); + status = smbd_smb2_request_verify_sizes(smb2req, 0x19); + if (!NT_STATUS_IS_OK(status)) { + return smbd_smb2_request_error(smb2req, status); } - + inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base; inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base; - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); - } + in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID); + in_flags = CVAL(inbody, 0x02); + in_security_mode = CVAL(inbody, 0x03); + /* Capabilities = IVAL(inbody, 0x04) */ + /* Channel = IVAL(inbody, 0x08) */ in_security_offset = SVAL(inbody, 0x0C); in_security_length = SVAL(inbody, 0x0E); + in_previous_session_id = BVAL(inbody, 0x10); - if (in_security_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { + if (in_security_offset != (SMB2_HDR_BODY + smb2req->in.vector[i+1].iov_len)) { return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); } @@ -86,22 +85,57 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req) return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); } - in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID); - in_security_mode = CVAL(inbody, 0x03); in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base; in_security_buffer.length = in_security_length; - status = smbd_smb2_session_setup(smb2req, - in_session_id, - in_security_mode, - in_security_buffer, - &out_session_flags, - &out_security_buffer, - &out_session_id); + subreq = smbd_smb2_session_setup_send(smb2req, + smb2req->sconn->ev_ctx, + smb2req, + in_session_id, + in_flags, + in_security_mode, + in_previous_session_id, + in_security_buffer); + if (subreq == NULL) { + return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); + } + tevent_req_set_callback(subreq, smbd_smb2_request_sesssetup_done, smb2req); + + return smbd_smb2_request_pending_queue(smb2req, subreq, 500); +} + +static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq) +{ + struct smbd_smb2_request *smb2req = + tevent_req_callback_data(subreq, + struct smbd_smb2_request); + int i = smb2req->current_idx; + uint8_t *outhdr; + DATA_BLOB outbody; + DATA_BLOB outdyn; + uint16_t out_session_flags; + uint64_t out_session_id; + uint16_t out_security_offset; + DATA_BLOB out_security_buffer = data_blob_null; + NTSTATUS status; + NTSTATUS error; /* transport error */ + + status = smbd_smb2_session_setup_recv(subreq, + &out_session_flags, + smb2req, + &out_security_buffer, + &out_session_id); + TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { status = nt_status_squash(status); - return smbd_smb2_request_error(smb2req, status); + error = smbd_smb2_request_error(smb2req, status); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; } out_security_offset = SMB2_HDR_BODY + 0x08; @@ -110,7 +144,13 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req) outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x08); if (outbody.data == NULL) { - return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); + error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; + } + return; } SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id); @@ -125,684 +165,523 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req) outdyn = out_security_buffer; - return smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn, - __location__); -} - -static int smbd_smb2_session_destructor(struct smbd_smb2_session *session) -{ - if (session->sconn == NULL) { - return 0; + error = smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn, + __location__); + if (!NT_STATUS_IS_OK(error)) { + smbd_server_connection_terminate(smb2req->sconn, + nt_errstr(error)); + return; } - - /* first free all tcons */ - while (session->tcons.list) { - talloc_free(session->tcons.list); - } - - idr_remove(session->sconn->smb2.sessions.idtree, session->vuid); - DLIST_REMOVE(session->sconn->smb2.sessions.list, session); - invalidate_vuid(session->sconn, session->vuid); - - session->vuid = 0; - session->status = NT_STATUS_USER_SESSION_DELETED; - session->sconn = NULL; - - return 0; } -#ifdef HAVE_KRB5 -static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session, +static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, - const DATA_BLOB *secblob, - const char *mechOID, + uint64_t in_previous_session_id, + DATA_BLOB in_security_buffer, uint16_t *out_session_flags, - DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { - DATA_BLOB ap_rep = data_blob_null; - DATA_BLOB ap_rep_wrapped = data_blob_null; - DATA_BLOB ticket = data_blob_null; - DATA_BLOB session_key = data_blob_null; - DATA_BLOB secblob_out = data_blob_null; - uint8 tok_id[2]; - struct PAC_LOGON_INFO *logon_info = NULL; - char *principal = NULL; - char *user = NULL; - char *domain = NULL; - struct passwd *pw = NULL; NTSTATUS status; - char *real_username; - fstring tmp; - bool username_was_mapped = false; - bool map_domainuser_to_guest = false; + bool guest = false; + uint8_t session_key[16]; + struct smbXsrv_session *x = session; + struct auth_session_info *session_info; + struct smbXsrv_connection *conn = session->connection; - if (!spnego_parse_krb5_wrap(talloc_tos(), *secblob, &ticket, tok_id)) { - status = NT_STATUS_LOGON_FAILURE; - goto fail; + if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || + lp_server_signing() == SMB_SIGNING_REQUIRED) { + x->global->signing_required = true; } - status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket, - &principal, &logon_info, &ap_rep, - &session_key, true); - + status = gensec_session_info(session->gensec, + session->global, + &session_info); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n", - nt_errstr(status))); - if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { - status = NT_STATUS_LOGON_FAILURE; - } - goto fail; + TALLOC_FREE(session); + return status; } - status = get_user_from_kerberos_info(talloc_tos(), - session->sconn->remote_hostname, - principal, logon_info, - &username_was_mapped, - &map_domainuser_to_guest, - &user, &domain, - &real_username, &pw); - if (!NT_STATUS_IS_OK(status)) { - goto fail; + if (security_session_user_level(session_info, NULL) < SECURITY_USER) { + /* we map anonymous to guest internally */ + *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; + *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; + /* force no signing */ + x->global->signing_required = false; + guest = true; } - /* save the PAC data if we have it */ - if (logon_info) { - netsamlogon_cache_store(user, &logon_info->info3); - } + ZERO_STRUCT(session_key); + memcpy(session_key, session_info->session_key.data, + MIN(session_info->session_key.length, sizeof(session_key))); - /* setup the string used by %U */ - sub_set_smb_name(real_username); + x->global->signing_key = data_blob_talloc(x->global, + session_key, + sizeof(session_key)); + if (x->global->signing_key.data == NULL) { + ZERO_STRUCT(session_key); + TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; + } - /* reload services so that the new %U is taken into account */ - reload_services(smb2req->sconn->msg_ctx, smb2req->sconn->sock, true); + if (conn->protocol >= PROTOCOL_SMB2_24) { + const DATA_BLOB label = data_blob_string_const_null("SMB2AESCMAC"); + const DATA_BLOB context = data_blob_string_const_null("SmbSign"); - status = make_session_info_krb5(session, - user, domain, real_username, pw, - logon_info, map_domainuser_to_guest, - username_was_mapped, - &session_key, - &session->session_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("smb2: make_server_info_krb5 failed\n")); - goto fail; + smb2_key_derivation(session_key, sizeof(session_key), + label.data, label.length, + context.data, context.length, + x->global->signing_key.data); } - if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || - lp_server_signing() == Required) { - session->do_signing = true; + x->global->application_key = data_blob_dup_talloc(x->global, + x->global->signing_key); + if (x->global->application_key.data == NULL) { + ZERO_STRUCT(session_key); + TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; } - if (security_session_user_level(session->session_info, NULL) < SECURITY_USER) { - /* we map anonymous to guest internally */ - *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; - *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; - /* force no signing */ - session->do_signing = false; + if (conn->protocol >= PROTOCOL_SMB2_24) { + const DATA_BLOB label = data_blob_string_const_null("SMB2APP"); + const DATA_BLOB context = data_blob_string_const_null("SmbRpc"); + + smb2_key_derivation(session_key, sizeof(session_key), + label.data, label.length, + context.data, context.length, + x->global->application_key.data); } + ZERO_STRUCT(session_key); - session->session_key = session->session_info->session_key; + x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels, + x->global->signing_key); + if (x->global->channels[0].signing_key.data == NULL) { + TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; + } - session->compat_vuser = talloc_zero(session, user_struct); - if (session->compat_vuser == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; + data_blob_clear_free(&session_info->session_key); + session_info->session_key = data_blob_dup_talloc(session_info, + x->global->application_key); + if (session_info->session_key.data == NULL) { + TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; } - session->compat_vuser->auth_ntlmssp_state = NULL; - session->compat_vuser->homes_snum = -1; - session->compat_vuser->session_info = session->session_info; - session->compat_vuser->session_keystr = NULL; - session->compat_vuser->vuid = session->vuid; - DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser); - /* This is a potentially untrusted username */ - alpha_strcpy(tmp, user, ". _-$", sizeof(tmp)); - session->session_info->unix_info->sanitized_username = - talloc_strdup(session->session_info, tmp); + session->compat = talloc_zero(session, user_struct); + if (session->compat == NULL) { + TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; + } + session->compat->homes_snum = -1; + session->compat->session_info = session_info; + session->compat->session_keystr = NULL; + session->compat->vuid = session->global->session_wire_id; + DLIST_ADD(smb2req->sconn->users, session->compat); + smb2req->sconn->num_users++; - if (security_session_user_level(session->session_info, NULL) >= SECURITY_USER) { - session->compat_vuser->homes_snum = - register_homes_share(session->session_info->unix_info->unix_name); + if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { + session->compat->homes_snum = + register_homes_share(session_info->unix_info->unix_name); } - if (!session_claim(session->sconn, session->compat_vuser)) { + if (!session_claim(smb2req->sconn, session->compat)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%d\n", - session->compat_vuser->vuid)); - goto fail; + session->compat->vuid)); + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; } + set_current_user_info(session_info->unix_info->sanitized_username, + session_info->unix_info->unix_name, + session_info->info->domain_name); + + reload_services(smb2req->sconn, conn_snum_used, true); + session->status = NT_STATUS_OK; + session->global->auth_session_info = session->session_info; + session->global->auth_session_info_seqnum += 1; + session->global->channels[0].auth_session_info_seqnum = + session->global->auth_session_info_seqnum; + session->global->expiration_time = gensec_expire_time(session->gensec); + + if ((in_previous_session_id != 0) && + (session->global->session_wire_id != + in_previous_session_id)) + { + struct tevent_context *ev; + struct tevent_req *subreq; + bool ok; + + ev = event_context_init(talloc_tos()); + if (ev == NULL) { + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; + } + + subreq = smb2srv_session_close_previous_send(smb2req, ev, + session, + in_previous_session_id); + if (subreq == NULL) { + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; + } + + ok = tevent_req_poll_ntstatus(subreq, ev, &status); + if (!ok) { + TALLOC_FREE(subreq); + TALLOC_FREE(session); + return status; + } + + status = smb2srv_session_close_previous_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(session); + return status; + } + } + + status = smbXsrv_session_update(session); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("smb2: Failed to update session for vuid=%d - %s\n", + session->compat->vuid, nt_errstr(status))); + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; + } /* * we attach the session to the request * so that the response can be signed */ smb2req->session = session; - if (session->do_signing) { + if (!guest) { smb2req->do_signing = true; } global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); - status = NT_STATUS_OK; - - /* wrap that up in a nice GSS-API wrapping */ - ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep, - TOK_ID_KRB_AP_REP); - - secblob_out = spnego_gen_auth_response( - talloc_tos(), - &ap_rep_wrapped, - status, - mechOID); - - *out_security_buffer = data_blob_talloc(smb2req, - secblob_out.data, - secblob_out.length); - if (secblob_out.data && out_security_buffer->data == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - data_blob_free(&ap_rep); - data_blob_free(&ap_rep_wrapped); - data_blob_free(&ticket); - data_blob_free(&session_key); - data_blob_free(&secblob_out); - *out_session_id = session->vuid; + *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; - - fail: - - data_blob_free(&ap_rep); - data_blob_free(&ap_rep_wrapped); - data_blob_free(&ticket); - data_blob_free(&session_key); - data_blob_free(&secblob_out); - - ap_rep_wrapped = data_blob_null; - secblob_out = spnego_gen_auth_response( - talloc_tos(), - &ap_rep_wrapped, - status, - mechOID); - - *out_security_buffer = data_blob_talloc(smb2req, - secblob_out.data, - secblob_out.length); - data_blob_free(&secblob_out); - return status; } -#endif -static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session, +static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, - uint8_t in_security_mode, - DATA_BLOB in_security_buffer, uint16_t *out_session_flags, - DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { - DATA_BLOB secblob_in = data_blob_null; - DATA_BLOB chal_out = data_blob_null; - char *kerb_mech = NULL; NTSTATUS status; + struct smbXsrv_session *x = session; + struct auth_session_info *session_info; + struct smbXsrv_connection *conn = session->connection; - /* Ensure we have no old NTLM state around. */ - TALLOC_FREE(session->auth_ntlmssp_state); - - status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer, - &secblob_in, &kerb_mech); + status = gensec_session_info(session->gensec, + session->global, + &session_info); if (!NT_STATUS_IS_OK(status)) { - goto out; - } - -#ifdef HAVE_KRB5 - if (kerb_mech && ((lp_security()==SEC_ADS) || - USE_KERBEROS_KEYTAB) ) { - status = smbd_smb2_session_setup_krb5(session, - smb2req, - in_security_mode, - &secblob_in, - kerb_mech, - out_session_flags, - out_security_buffer, - out_session_id); - - goto out; - } -#endif - - if (kerb_mech) { - /* The mechtoken is a krb5 ticket, but - * we need to fall back to NTLM. */ - - DEBUG(3,("smb2: Got krb5 ticket in SPNEGO " - "but set to downgrade to NTLMSSP\n")); - - status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - /* Fall back to NTLMSSP. */ - status = auth_ntlmssp_start(session->sconn->remote_address, - &session->auth_ntlmssp_state); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - secblob_in, - &chal_out); - } - - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - goto out; - } - - *out_security_buffer = spnego_gen_auth_response(smb2req, - &chal_out, - status, - OID_NTLMSSP); - if (out_security_buffer->data == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - *out_session_id = session->vuid; - - out: - - data_blob_free(&secblob_in); - data_blob_free(&chal_out); - TALLOC_FREE(kerb_mech); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - TALLOC_FREE(session->auth_ntlmssp_state); TALLOC_FREE(session); - } - return status; -} - -static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session, - struct smbd_smb2_request *smb2req, - uint8_t in_security_mode, - DATA_BLOB in_security_buffer, - uint16_t *out_session_flags, - uint64_t *out_session_id) -{ - fstring tmp; - - if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || - lp_server_signing() == Required) { - session->do_signing = true; - } - - if (security_session_user_level(session->session_info, NULL) < SECURITY_USER) { - /* we map anonymous to guest internally */ - *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; - *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; - /* force no signing */ - session->do_signing = false; + return status; } - session->session_key = session->session_info->session_key; - - session->compat_vuser = talloc_zero(session, user_struct); - if (session->compat_vuser == NULL) { - TALLOC_FREE(session->auth_ntlmssp_state); + data_blob_clear_free(&session_info->session_key); + session_info->session_key = data_blob_dup_talloc(session_info, + x->global->application_key); + if (session_info->session_key.data == NULL) { TALLOC_FREE(session); return NT_STATUS_NO_MEMORY; } - session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state; - session->compat_vuser->homes_snum = -1; - session->compat_vuser->session_info = session->session_info; - session->compat_vuser->session_keystr = NULL; - session->compat_vuser->vuid = session->vuid; - DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser); - /* This is a potentially untrusted username */ - alpha_strcpy(tmp, - auth_ntlmssp_get_username(session->auth_ntlmssp_state), - ". _-$", - sizeof(tmp)); - session->session_info->unix_info->sanitized_username = talloc_strdup( - session->session_info, tmp); + session->compat->session_info = session_info; + session->compat->vuid = session->global->session_wire_id; - if (security_session_user_level(session->session_info, NULL) >= SECURITY_USER) { - session->compat_vuser->homes_snum = - register_homes_share(session->session_info->unix_info->unix_name); - } + session->compat->homes_snum = + register_homes_share(session_info->unix_info->unix_name); - if (!session_claim(session->sconn, session->compat_vuser)) { - DEBUG(1, ("smb2: Failed to claim session " - "for vuid=%d\n", - session->compat_vuser->vuid)); - TALLOC_FREE(session->auth_ntlmssp_state); + set_current_user_info(session_info->unix_info->sanitized_username, + session_info->unix_info->unix_name, + session_info->info->domain_name); + + reload_services(smb2req->sconn, conn_snum_used, true); + + session->status = NT_STATUS_OK; + TALLOC_FREE(session->global->auth_session_info); + session->global->auth_session_info = session->session_info; + session->global->auth_session_info_seqnum += 1; + session->global->channels[0].auth_session_info_seqnum = + session->global->auth_session_info_seqnum; + session->global->expiration_time = gensec_expire_time(session->gensec); + + status = smbXsrv_session_update(session); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("smb2: Failed to update session for vuid=%d - %s\n", + session->compat->vuid, nt_errstr(status))); TALLOC_FREE(session); return NT_STATUS_LOGON_FAILURE; } - - session->status = NT_STATUS_OK; + conn_clear_vuid_caches(conn->sconn, session->compat->vuid); /* * we attach the session to the request * so that the response can be signed */ smb2req->session = session; - if (session->do_signing) { - smb2req->do_signing = true; - } + smb2req->do_signing = true; global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); - *out_session_id = session->vuid; + *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; } -static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session, - struct smbd_smb2_request *smb2req, - uint8_t in_security_mode, - DATA_BLOB in_security_buffer, - uint16_t *out_session_flags, - DATA_BLOB *out_security_buffer, - uint64_t *out_session_id) +static NTSTATUS smbd_smb2_auth_generic(struct smbXsrv_session *session, + struct smbd_smb2_request *smb2req, + uint8_t in_security_mode, + uint64_t in_previous_session_id, + DATA_BLOB in_security_buffer, + uint16_t *out_session_flags, + DATA_BLOB *out_security_buffer, + uint64_t *out_session_id) { - DATA_BLOB auth = data_blob_null; - DATA_BLOB auth_out = data_blob_null; NTSTATUS status; - if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) { - TALLOC_FREE(session); - return NT_STATUS_LOGON_FAILURE; - } - - if (auth.data[0] == ASN1_APPLICATION(0)) { - /* Might be a second negTokenTarg packet */ - DATA_BLOB secblob_in = data_blob_null; - char *kerb_mech = NULL; + *out_security_buffer = data_blob_null; - status = parse_spnego_mechanisms(talloc_tos(), - in_security_buffer, - &secblob_in, &kerb_mech); + if (session->gensec == NULL) { + status = auth_generic_prepare(session, + session->connection->remote_address, + &session->gensec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return status; } -#ifdef HAVE_KRB5 - if (kerb_mech && ((lp_security()==SEC_ADS) || - USE_KERBEROS_KEYTAB) ) { - status = smbd_smb2_session_setup_krb5(session, - smb2req, - in_security_mode, - &secblob_in, - kerb_mech, - out_session_flags, - out_security_buffer, - out_session_id); - - data_blob_free(&secblob_in); - TALLOC_FREE(kerb_mech); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - } - return status; - } -#endif - - /* Can't blunder into NTLMSSP auth if we have - * a krb5 ticket. */ - - if (kerb_mech) { - DEBUG(3,("smb2: network " - "misconfiguration, client sent us a " - "krb5 ticket and kerberos security " - "not enabled\n")); - TALLOC_FREE(session); - data_blob_free(&secblob_in); - TALLOC_FREE(kerb_mech); - return NT_STATUS_LOGON_FAILURE; - } + gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY); + gensec_want_feature(session->gensec, GENSEC_FEATURE_UNIX_TOKEN); - data_blob_free(&secblob_in); - } - - if (session->auth_ntlmssp_state == NULL) { - status = auth_ntlmssp_start(session->sconn->remote_address, - &session->auth_ntlmssp_state); + status = gensec_start_mech_by_oid(session->gensec, + GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { - data_blob_free(&auth); TALLOC_FREE(session); return status; } } - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - auth, - &auth_out); - /* If status is NT_STATUS_OK then we need to get the token. - * Map to guest is now internal to auth_ntlmssp */ - if (NT_STATUS_IS_OK(status)) { - status = auth_ntlmssp_steal_session_info(session, - session->auth_ntlmssp_state, - &session->session_info); - } - - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - TALLOC_FREE(session->auth_ntlmssp_state); - data_blob_free(&auth); + become_root(); + status = gensec_update(session->gensec, + smb2req, NULL, + in_security_buffer, + out_security_buffer); + unbecome_root(); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && + !NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); - return status; + return nt_status_squash(status); } - data_blob_free(&auth); - - *out_security_buffer = spnego_gen_auth_response(smb2req, - &auth_out, status, NULL); - - if (out_security_buffer->data == NULL) { - TALLOC_FREE(session->auth_ntlmssp_state); - TALLOC_FREE(session); - return NT_STATUS_NO_MEMORY; + if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + *out_session_id = session->global->session_wire_id; + return status; } - *out_session_id = session->vuid; - - if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - return NT_STATUS_MORE_PROCESSING_REQUIRED; + if (session->global->auth_session_info != NULL) { + return smbd_smb2_reauth_generic_return(session, + smb2req, + out_session_flags, + out_session_id); } - /* We're done - claim the session. */ - return smbd_smb2_common_ntlmssp_auth_return(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags, - out_session_id); + return smbd_smb2_auth_generic_return(session, + smb2req, + in_security_mode, + in_previous_session_id, + in_security_buffer, + out_session_flags, + out_session_id); } -static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session, - struct smbd_smb2_request *smb2req, +static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req, + uint64_t in_session_id, + uint8_t in_flags, uint8_t in_security_mode, + uint64_t in_previous_session_id, DATA_BLOB in_security_buffer, uint16_t *out_session_flags, DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { + struct smbXsrv_session *session; NTSTATUS status; - DATA_BLOB secblob_out = data_blob_null; + NTTIME now = timeval_to_nttime(&req->request_time); - if (session->auth_ntlmssp_state == NULL) { - status = auth_ntlmssp_start(session->sconn->remote_address, - &session->auth_ntlmssp_state); + *out_session_flags = 0; + *out_session_id = 0; + + if (in_session_id == 0) { + /* create a new session */ + status = smbXsrv_session_create(smb2req->sconn->conn, + now, &session); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); + return status; + } + } else { + status = smb2srv_session_lookup(smb2req->sconn->conn, + in_session_id, now, + &session); + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { + status = NT_STATUS_OK; + } + if (NT_STATUS_IS_OK(status)) { + session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + TALLOC_FREE(session->gensec); + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { return status; } } - /* RAW NTLMSSP */ - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - in_security_buffer, - &secblob_out); + return smbd_smb2_auth_generic(session, + smb2req, + in_security_mode, + in_previous_session_id, + in_security_buffer, + out_session_flags, + out_security_buffer, + out_session_id); +} - if (NT_STATUS_IS_OK(status) || - NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - *out_security_buffer = data_blob_talloc(smb2req, - secblob_out.data, - secblob_out.length); - if (secblob_out.data && out_security_buffer->data == NULL) { - TALLOC_FREE(session->auth_ntlmssp_state); - TALLOC_FREE(session); - return NT_STATUS_NO_MEMORY; - } - } +struct smbd_smb2_session_setup_state { + struct tevent_context *ev; + struct smbd_smb2_request *smb2req; + uint64_t in_session_id; + uint8_t in_flags; + uint8_t in_security_mode; + uint64_t in_previous_session_id; + DATA_BLOB in_security_buffer; + uint16_t out_session_flags; + DATA_BLOB out_security_buffer; + uint64_t out_session_id; +}; - if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - *out_session_id = session->vuid; - return status; - } +static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbd_smb2_request *smb2req, + uint64_t in_session_id, + uint8_t in_flags, + uint8_t in_security_mode, + uint64_t in_previous_session_id, + DATA_BLOB in_security_buffer) +{ + struct tevent_req *req; + struct smbd_smb2_session_setup_state *state; + NTSTATUS status; - status = auth_ntlmssp_steal_session_info(session, - session->auth_ntlmssp_state, - &session->session_info); + req = tevent_req_create(mem_ctx, &state, + struct smbd_smb2_session_setup_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->smb2req = smb2req; + state->in_session_id = in_session_id; + state->in_flags = in_flags; + state->in_security_mode = in_security_mode; + state->in_previous_session_id = in_previous_session_id; + state->in_security_buffer = in_security_buffer; - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session->auth_ntlmssp_state); - TALLOC_FREE(session); - return status; + status = smbd_smb2_session_setup(smb2req, + in_session_id, + in_flags, + in_security_mode, + in_previous_session_id, + in_security_buffer, + &state->out_session_flags, + &state->out_security_buffer, + &state->out_session_id); + if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || + NT_STATUS_IS_OK(status)) + { + talloc_steal(state, state->out_security_buffer.data); + } + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } - *out_session_id = session->vuid; - return smbd_smb2_common_ntlmssp_auth_return(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags, - out_session_id); + tevent_req_done(req); + return tevent_req_post(req, ev); } -static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req, - uint64_t in_session_id, - uint8_t in_security_mode, - DATA_BLOB in_security_buffer, +static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req, uint16_t *out_session_flags, + TALLOC_CTX *mem_ctx, DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { - struct smbd_smb2_session *session; - - *out_session_flags = 0; - *out_session_id = 0; - - if (in_session_id == 0) { - int id; - - /* create a new session */ - session = talloc_zero(smb2req->sconn, struct smbd_smb2_session); - if (session == NULL) { - return NT_STATUS_NO_MEMORY; - } - session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; - id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree, - session, - smb2req->sconn->smb2.sessions.limit); - if (id == -1) { - return NT_STATUS_INSUFFICIENT_RESOURCES; - } - session->vuid = id; + struct smbd_smb2_session_setup_state *state = + tevent_req_data(req, + struct smbd_smb2_session_setup_state); + NTSTATUS status; - session->tcons.idtree = idr_init(session); - if (session->tcons.idtree == NULL) { - return NT_STATUS_NO_MEMORY; + if (tevent_req_is_nterror(req, &status)) { + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_received(req); + return status; } - session->tcons.limit = 0x0000FFFE; - session->tcons.list = NULL; - - DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session, - struct smbd_smb2_session *); - session->sconn = smb2req->sconn; - talloc_set_destructor(session, smbd_smb2_session_destructor); } else { - void *p; + status = NT_STATUS_OK; + } - /* lookup an existing session */ - p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id); - if (p == NULL) { - return NT_STATUS_USER_SESSION_DELETED; - } - session = talloc_get_type_abort(p, struct smbd_smb2_session); - } - - if (NT_STATUS_IS_OK(session->status)) { - return NT_STATUS_REQUEST_NOT_ACCEPTED; - } - - 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.data[0] == ASN1_CONTEXT(1)) { - return smbd_smb2_spnego_auth(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags, - out_security_buffer, - out_session_id); - } else if (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); - } - - /* Unknown packet type. */ - DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n", - (unsigned int)in_security_buffer.data[0] )); - TALLOC_FREE(session->auth_ntlmssp_state); - TALLOC_FREE(session); - return NT_STATUS_LOGON_FAILURE; + *out_session_flags = state->out_session_flags; + *out_security_buffer = state->out_security_buffer; + *out_session_id = state->out_session_id; + + talloc_steal(mem_ctx, out_security_buffer->data); + tevent_req_received(req); + return status; } NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) { - const uint8_t *inbody; - int i = req->current_idx; + NTSTATUS status; DATA_BLOB outbody; - size_t expected_body_size = 0x04; - size_t body_size; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } + struct connection_struct *conn, *next_conn; - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); + status = smbd_smb2_request_verify_sizes(req, 0x04); + if (!NT_STATUS_IS_OK(status)) { + return smbd_smb2_request_error(req, status); } /* * TODO: cancel all outstanding requests on the session - * and delete all tree connections. */ - smbd_smb2_session_destructor(req->session); + file_close_user(req->sconn, req->session->compat->vuid); + + for (conn=req->sconn->connections; conn; conn=next_conn) { + struct smbXsrv_tcon *tcon; + + next_conn = conn->next; + tcon = conn->tcon; + + if (conn->vuid != req->session->compat->vuid) { + continue; + } + + set_current_service(conn, 0, True); + close_cnum(conn, conn->vuid); + + /* for now tcon is NULL for SMB1 */ + TALLOC_FREE(tcon); + } + + invalidate_vuid(req->sconn, req->session->compat->vuid); + req->session->compat = NULL; + + req->session->status = NT_STATUS_USER_SESSION_DELETED; + /* * we may need to sign the response, so we need to keep * the session until the response is sent to the wire.