X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Fsmb2_sesssetup.c;h=53552929677ec9c6aaeca4e2532d5dfac54532f0;hb=d4bce355a;hp=1a6f7697ffff4d2ca12d4aad879848919697461c;hpb=3383ebbe7edaf902a511bd3be964d7ae56b62610;p=samba.git diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 1a6f7697fff..53552929677 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -27,33 +27,38 @@ #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; 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 = data_blob_null; NTSTATUS status; + struct tevent_req *subreq; status = smbd_smb2_request_verify_sizes(smb2req, 0x19); if (!NT_STATUS_IS_OK(status)) { @@ -62,8 +67,15 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req) inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base; inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base; + 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 + smb2req->in.vector[i+1].iov_len)) { return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); @@ -73,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; @@ -97,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); @@ -112,89 +165,146 @@ 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; - } - - /* first free all tcons */ - while (session->tcons.list) { - talloc_free(session->tcons.list); + 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; } - - 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; } -static NTSTATUS smbd_smb2_auth_generic_return(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, - DATA_BLOB in_security_buffer, + struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { + NTSTATUS status; bool guest = false; + uint8_t session_key[16]; + struct smbXsrv_session *x = session; + struct smbXsrv_connection *conn = session->connection; if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || lp_server_signing() == SMB_SIGNING_REQUIRED) { - session->do_signing = true; + x->global->signing_required = true; } - if (security_session_user_level(session->session_info, NULL) < SECURITY_USER) { + 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 */ - session->do_signing = false; + x->global->signing_required = false; guest = true; } - session->session_key = session->session_info->session_key; + ZERO_STRUCT(session_key); + memcpy(session_key, session_info->session_key.data, + MIN(session_info->session_key.length, sizeof(session_key))); + + 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; + } + + 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"); - session->compat_vuser = talloc_zero(session, user_struct); - if (session->compat_vuser == NULL) { + smb2_key_derivation(session_key, sizeof(session_key), + label.data, label.length, + context.data, context.length, + x->global->signing_key.data); + } + + 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; } - session->compat_vuser->gensec_security = session->gensec_security; - 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); - 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 (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); + + 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; } - if (!session_claim(session->sconn, session->compat_vuser)) { + 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 = talloc_zero(session, struct user_struct); + if (session->compat == NULL) { + TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; + } + session->compat->session = session; + 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_info, NULL) >= SECURITY_USER) { + session->compat->homes_snum = + register_homes_share(session_info->unix_info->unix_name); + } + + if (!session_claim(smb2req->sconn, session->compat)) { DEBUG(1, ("smb2: Failed to claim session " - "for vuid=%d\n", - session->compat_vuser->vuid)); + "for vuid=%llu\n", + (unsigned long long)session->compat->vuid)); TALLOC_FREE(session); return NT_STATUS_LOGON_FAILURE; } - set_current_user_info(session->session_info->unix_info->sanitized_username, - session->session_info->unix_info->unix_name, - session->session_info->info->domain_name); + 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_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=%llu - %s\n", + (unsigned long long)session->compat->vuid, + nt_errstr(status))); + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; + } /* * we attach the session to the request @@ -207,143 +317,360 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbd_smb2_session *session, 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_auth_generic(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_reauth_generic_return(struct smbXsrv_session *session, + struct smbd_smb2_request *smb2req, + struct auth_session_info *session_info, + uint16_t *out_session_flags, + uint64_t *out_session_id) { NTSTATUS status; + struct smbXsrv_session *x = session; + struct smbXsrv_connection *conn = session->connection; + + 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->session_info = session_info; + session->compat->vuid = session->global->session_wire_id; + + session->compat->homes_snum = + register_homes_share(session_info->unix_info->unix_name); + + set_current_user_info(session_info->unix_info->sanitized_username, + session_info->unix_info->unix_name, + session_info->info->domain_name); - *out_security_buffer = data_blob_null; + reload_services(smb2req->sconn, conn_snum_used, true); - if (session->gensec_security == NULL) { - status = auth_generic_prepare(session, session->sconn->remote_address, - &session->gensec_security); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - return status; + session->status = NT_STATUS_OK; + TALLOC_FREE(session->global->auth_session_info); + session->global->auth_session_info = 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=%llu - %s\n", + (unsigned long long)session->compat->vuid, + nt_errstr(status))); + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; + } + + 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; + smb2req->do_signing = true; + + global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); + + *out_session_id = session->global->session_wire_id; + + return NT_STATUS_OK; +} + +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; + struct smbXsrv_session *session; + struct auth_session_info *session_info; + uint16_t out_session_flags; + DATA_BLOB out_security_buffer; + uint64_t out_session_id; +}; + +static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) +{ + /* + * if state->session is not NULL, + * we remove the session on failure + */ + TALLOC_FREE(state->session); + return 0; +} + +static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq); +static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq); + +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; + NTTIME now = timeval_to_nttime(&smb2req->request_time); + struct tevent_req *subreq; + + 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 (in_flags & SMB2_SESSION_FLAG_BINDING) { + if (smb2req->sconn->conn->protocol < PROTOCOL_SMB2_22) { + tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); + return tevent_req_post(req, ev); } - gensec_want_feature(session->gensec_security, GENSEC_FEATURE_SESSION_KEY); - gensec_want_feature(session->gensec_security, GENSEC_FEATURE_UNIX_TOKEN); + /* + * We do not support multi channel. + */ + tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); + return tevent_req_post(req, ev); + } + + talloc_set_destructor(state, smbd_smb2_session_setup_state_destructor); + + if (state->in_session_id == 0) { + /* create a new session */ + status = smbXsrv_session_create(state->smb2req->sconn->conn, + now, &state->session); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + } else { + status = smb2srv_session_lookup(state->smb2req->sconn->conn, + state->in_session_id, now, + &state->session); + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { + status = NT_STATUS_OK; + } + if (NT_STATUS_IS_OK(status)) { + state->session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + TALLOC_FREE(state->session->gensec); + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } - if (session->sconn->use_gensec_hook) { - status = gensec_start_mech_by_oid(session->gensec_security, GENSEC_OID_SPNEGO); - } else { - status = gensec_start_mech_by_oid(session->gensec_security, GENSEC_OID_NTLMSSP); + if (state->session->gensec == NULL) { + status = auth_generic_prepare(state->session, + state->session->connection->remote_address, + &state->session->gensec); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - return status; + + gensec_want_feature(state->session->gensec, GENSEC_FEATURE_SESSION_KEY); + gensec_want_feature(state->session->gensec, GENSEC_FEATURE_UNIX_TOKEN); + + status = gensec_start_mech_by_oid(state->session->gensec, + GENSEC_OID_SPNEGO); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } } become_root(); - status = gensec_update(session->gensec_security, - smb2req, NULL, - in_security_buffer, - out_security_buffer); + subreq = gensec_update_send(state, state->ev, + state->session->gensec, + state->in_security_buffer); unbecome_root(); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, smbd_smb2_session_setup_gensec_done, req); + + return req; +} + +static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smbd_smb2_session_setup_state *state = + tevent_req_data(req, + struct smbd_smb2_session_setup_state); + NTSTATUS status; + + become_root(); + status = gensec_update_recv(subreq, state, + &state->out_security_buffer); + unbecome_root(); + TALLOC_FREE(subreq); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - return nt_status_squash(status); + tevent_req_nterror(req, status); + return; } if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - *out_session_id = session->vuid; - return status; + state->out_session_id = state->session->global->session_wire_id; + /* we want to keep the session */ + state->session = NULL; + tevent_req_nterror(req, status); + return; } - status = gensec_session_info(session->gensec_security, - session, - &session->session_info); + status = gensec_session_info(state->session->gensec, + state->session->global, + &state->session_info); + if (tevent_req_nterror(req, status)) { + return; + } - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - return status; + if ((state->in_previous_session_id != 0) && + (state->session->global->session_wire_id != + state->in_previous_session_id)) + { + subreq = smb2srv_session_close_previous_send(state, state->ev, + state->session->connection, + state->session_info, + state->in_previous_session_id, + state->session->global->session_wire_id); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, + smbd_smb2_session_setup_previous_done, + req); + return; + } + + if (state->session->global->auth_session_info != NULL) { + status = smbd_smb2_reauth_generic_return(state->session, + state->smb2req, + state->session_info, + &state->out_session_flags, + &state->out_session_id); + if (tevent_req_nterror(req, status)) { + return; + } + /* we want to keep the session */ + state->session = NULL; + tevent_req_done(req); + return; + } + + status = smbd_smb2_auth_generic_return(state->session, + state->smb2req, + state->in_security_mode, + state->session_info, + &state->out_session_flags, + &state->out_session_id); + if (tevent_req_nterror(req, status)) { + return; } - *out_session_id = session->vuid; - return smbd_smb2_auth_generic_return(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags, - out_session_id); + /* we want to keep the session */ + state->session = NULL; + tevent_req_done(req); + return; } -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, - uint16_t *out_session_flags, - DATA_BLOB *out_security_buffer, - uint64_t *out_session_id) +static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq) { - struct smbd_smb2_session *session; - - *out_session_flags = 0; - *out_session_id = 0; + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smbd_smb2_session_setup_state *state = + tevent_req_data(req, + struct smbd_smb2_session_setup_state); + NTSTATUS status; - if (in_session_id == 0) { - int id; + status = smb2srv_session_close_previous_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } - /* 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; + if (state->session->global->auth_session_info != NULL) { + status = smbd_smb2_reauth_generic_return(state->session, + state->smb2req, + state->session_info, + &state->out_session_flags, + &state->out_session_id); + if (tevent_req_nterror(req, status)) { + return; } - session->vuid = id; + /* we want to keep the session */ + state->session = NULL; + tevent_req_done(req); + return; + } - session->tcons.idtree = idr_init(session); - if (session->tcons.idtree == NULL) { - return NT_STATUS_NO_MEMORY; - } - session->tcons.limit = 0x0000FFFE; - session->tcons.list = NULL; + status = smbd_smb2_auth_generic_return(state->session, + state->smb2req, + state->in_security_mode, + state->session_info, + &state->out_session_flags, + &state->out_session_id); + if (tevent_req_nterror(req, status)) { + return; + } - 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; + /* we want to keep the session */ + state->session = NULL; + tevent_req_done(req); + return; +} + +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_setup_state *state = + tevent_req_data(req, + struct smbd_smb2_session_setup_state); + NTSTATUS status; - /* lookup an existing session */ - p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id); - if (p == NULL) { - return NT_STATUS_USER_SESSION_DELETED; + if (tevent_req_is_nterror(req, &status)) { + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_received(req); + return nt_status_squash(status); } - session = talloc_get_type_abort(p, struct smbd_smb2_session); + } else { + status = NT_STATUS_OK; } - if (NT_STATUS_IS_OK(session->status)) { - return NT_STATUS_REQUEST_NOT_ACCEPTED; - } + *out_session_flags = state->out_session_flags; + *out_security_buffer = state->out_security_buffer; + *out_session_id = state->out_session_id; - return smbd_smb2_auth_generic(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags, - out_security_buffer, - 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) @@ -358,9 +685,19 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) /* * TODO: cancel all outstanding requests on the session - * and delete all tree connections. */ - smbd_smb2_session_destructor(req->session); + status = smbXsrv_session_logoff(req->session); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("smbd_smb2_request_process_logoff: " + "smbXsrv_session_logoff() failed: %s\n", + nt_errstr(status))); + /* + * If we hit this case, there is something completely + * wrong, so we better disconnect the transport connection. + */ + return status; + } + /* * we may need to sign the response, so we need to keep * the session until the response is sent to the wire.