X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Fsmb2_sesssetup.c;h=bf7001938a57abe3c004d32f50511a1537092985;hb=f91aec92ec9418dc2521bb68e5c3635c4fc9a304;hp=4e31952f207a4ab1ddf329105104c2e102485faf;hpb=2deff342b949ef7f91134115aa77c4051e2a4c33;p=metze%2Fsamba%2Fwip.git diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 4e31952f207a..bf7001938a57 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -20,57 +20,64 @@ */ #include "includes.h" +#include "smbd/smbd.h" #include "smbd/globals.h" #include "../libcli/smb/smb_common.h" -#include "../libcli/auth/spnego.h" -#include "ntlmssp.h" - -static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req, +#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 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); } @@ -78,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; @@ -102,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); @@ -117,461 +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; - } - - /* 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_session_setup_krb5(struct smbd_smb2_session *session, - struct smbd_smb2_request *smb2req, - const DATA_BLOB *psecblob_in, - const char *kerb_mech, - uint16_t *out_session_flags, - DATA_BLOB *out_security_buffer, - uint64_t *out_session_id) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS smbd_smb2_spnego_negotiate(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, + 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 secblob_in = data_blob_null; - DATA_BLOB chal_out = data_blob_null; - DATA_BLOB secblob_out = data_blob_null; - char *kerb_mech = NULL; NTSTATUS status; + 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; - /* Ensure we have no old NTLM state around. */ - auth_ntlmssp_end(&session->auth_ntlmssp_state); + if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || + lp_server_signing() == SMB_SIGNING_REQUIRED) { + x->global->signing_required = true; + } - status = parse_spnego_mechanisms(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; + 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, - &secblob_in, - kerb_mech, - out_session_flags, - out_security_buffer, - out_session_id); + 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; + } - goto out; + 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; } -#endif - status = auth_ntlmssp_start(&session->auth_ntlmssp_state); - if (!NT_STATUS_IS_OK(status)) { - goto out; + 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"); + + 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; } - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - secblob_in, - &chal_out); + 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"); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - goto out; + 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); - secblob_out = spnego_gen_auth_response(&chal_out, - status, - OID_NTLMSSP); - *out_security_buffer = data_blob_talloc(smb2req, - secblob_out.data, - secblob_out.length); - if (out_security_buffer->data == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + 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; } - *out_session_id = session->vuid; - out: + 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; + } - data_blob_free(&secblob_in); - data_blob_free(&secblob_out); - data_blob_free(&chal_out); - SAFE_FREE(kerb_mech); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, - NT_STATUS_MORE_PROCESSING_REQUIRED)) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); + session->compat = talloc_zero(session, user_struct); + if (session->compat == NULL) { TALLOC_FREE(session); + return NT_STATUS_NO_MEMORY; } - return status; -} + 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++; -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) -{ - if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || - lp_server_signing() == Required) { - session->do_signing = true; + 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->auth_ntlmssp_state->server_info->guest) { - /* 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; - } - - session->server_info = session->auth_ntlmssp_state->server_info; - data_blob_free(&session->server_info->user_session_key); - session->server_info->user_session_key = - data_blob_talloc( - session->server_info, - session->auth_ntlmssp_state->ntlmssp_state->session_key.data, - session->auth_ntlmssp_state->ntlmssp_state->session_key.length); - if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) { - if (session->server_info->user_session_key.data == NULL) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); + if (!session_claim(smb2req->sconn, session->compat)) { + DEBUG(1, ("smb2: Failed to claim session " + "for vuid=%d\n", + 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 NT_STATUS_NO_MEMORY; + return status; } } - session->session_key = session->server_info->user_session_key; - session->compat_vuser = talloc_zero(session, user_struct); - if (session->compat_vuser == NULL) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); + 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_NO_MEMORY; + return NT_STATUS_LOGON_FAILURE; } - session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state; - session->compat_vuser->homes_snum = -1; - session->compat_vuser->server_info = session->server_info; - session->compat_vuser->session_keystr = NULL; - session->compat_vuser->vuid = session->vuid; - DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser); - - session->status = NT_STATUS_OK; /* * 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); + + *out_session_id = session->global->session_wire_id; + return NT_STATUS_OK; } -static NTSTATUS smbd_smb2_spnego_auth(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 auth = data_blob_null; - DATA_BLOB auth_out = data_blob_null; - DATA_BLOB secblob_out = data_blob_null; NTSTATUS status; + struct smbXsrv_session *x = session; + struct auth_session_info *session_info; + struct smbXsrv_connection *conn = session->connection; - if (!spnego_parse_auth(in_security_buffer, &auth)) { + status = gensec_session_info(session->gensec, + session->global, + &session_info); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); - return NT_STATUS_LOGON_FAILURE; + return status; } - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - auth, - &auth_out); - if (!NT_STATUS_IS_OK(status)) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); - data_blob_free(&auth); + 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 status; + return NT_STATUS_NO_MEMORY; } - data_blob_free(&auth); + 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); - secblob_out = spnego_gen_auth_response(&auth_out, - status, NULL); + 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_talloc(smb2req, - secblob_out.data, - secblob_out.length); - if (out_security_buffer->data == NULL) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); + 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_NO_MEMORY; + return NT_STATUS_LOGON_FAILURE; } - *out_session_id = session->vuid; + 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 smbd_smb2_common_ntlmssp_auth_return(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags); + return NT_STATUS_OK; } -static NTSTATUS smbd_smb2_raw_ntlmssp_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) { NTSTATUS status; - DATA_BLOB secblob_out = data_blob_null; - if (session->auth_ntlmssp_state == NULL) { - status = auth_ntlmssp_start(&session->auth_ntlmssp_state); + *out_security_buffer = data_blob_null; + + 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; } - } - /* RAW NTLMSSP */ - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - in_security_buffer, - &secblob_out); + gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY); + gensec_want_feature(session->gensec, GENSEC_FEATURE_UNIX_TOKEN); - 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 (out_security_buffer->data == NULL) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); + status = gensec_start_mech_by_oid(session->gensec, + GENSEC_OID_SPNEGO); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); - return NT_STATUS_NO_MEMORY; + return status; } } + 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 nt_status_squash(status); + } + if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - *out_session_id = session->vuid; + *out_session_id = session->global->session_wire_id; return status; } - if (!NT_STATUS_IS_OK(status)) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); - TALLOC_FREE(session); - return status; + + if (session->global->auth_session_info != NULL) { + return smbd_smb2_reauth_generic_return(session, + smb2req, + out_session_flags, + out_session_id); } - *out_session_id = session->vuid; - return smbd_smb2_common_ntlmssp_auth_return(session, - smb2req, - in_security_mode, - in_security_buffer, - out_session_flags); + 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_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 smbd_smb2_session *session; + struct smbXsrv_session *session; + NTSTATUS status; + NTTIME now = timeval_to_nttime(&req->request_time); *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; + status = smbXsrv_session_create(smb2req->sconn->conn, + now, &session); + if (!NT_STATUS_IS_OK(status)) { + return status; } - 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; + } 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; } - session->vuid = id; - - session->tcons.idtree = idr_init(session); - if (session->tcons.idtree == NULL) { - return NT_STATUS_NO_MEMORY; + if (NT_STATUS_IS_OK(status)) { + session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + TALLOC_FREE(session->gensec); } - 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; - - /* 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 (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + return status; } - 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_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] )); - auth_ntlmssp_end(&session->auth_ntlmssp_state); - TALLOC_FREE(session); - return NT_STATUS_LOGON_FAILURE; + } + + 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); } -NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *outhdr; - int i = req->current_idx; +struct smbd_smb2_session_setup_state { + struct tevent_context *ev; + struct smbd_smb2_request *smb2req; uint64_t in_session_id; - void *p; - struct smbd_smb2_session *session; - bool chained_fixup = false; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; + 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; +}; - in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID); +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; - if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) { - if (req->async) { - /* - * async request - fill in session_id from - * already setup request out.vector[].iov_base. - */ - outhdr = (const uint8_t *)req->out.vector[i].iov_base; - in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID); - } else if (i > 2) { - /* - * Chained request - fill in session_id from - * the previous request out.vector[].iov_base. - */ - outhdr = (const uint8_t *)req->out.vector[i-3].iov_base; - in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID); - chained_fixup = true; - } + 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; - /* lookup an existing session */ - p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id); - if (p == NULL) { - return NT_STATUS_USER_SESSION_DELETED; + 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); } - session = talloc_get_type_abort(p, struct smbd_smb2_session); - - if (!NT_STATUS_IS_OK(session->status)) { - return NT_STATUS_ACCESS_DENIED; + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); } - set_current_user_info(session->server_info->sanitized_username, - session->server_info->unix_name, - pdb_get_domain(session->server_info->sam_account)); + tevent_req_done(req); + return tevent_req_post(req, ev); +} - req->session = session; +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; - if (chained_fixup) { - /* Fix up our own outhdr. */ - outhdr = (const uint8_t *)req->out.vector[i].iov_base; - SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id); + if (tevent_req_is_nterror(req, &status)) { + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_received(req); + return status; + } + } else { + status = NT_STATUS_OK; } - return NT_STATUS_OK; + + *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; + struct connection_struct *conn, *next_conn; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - 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.