From 02d206ee64d8b08d40204a948b696bf0b4156c5b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Mar 2012 15:01:27 +0100 Subject: [PATCH] s3:smb2_sesssetup: make use of the smbXsrv_session infrastructure We still have smbd_smb2_session as primary structure, but that will went away once we got rid of smbd_smb2_tcon. metze --- source3/smbd/globals.h | 14 ++-- source3/smbd/process.c | 9 +++ source3/smbd/smb2_server.c | 60 ++++++++++------- source3/smbd/smb2_sesssetup.c | 118 +++++++++++++++++++++++++--------- 4 files changed, 138 insertions(+), 63 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index aaea100a65ef..9eadc99c0e24 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -494,8 +494,8 @@ struct smbd_smb2_session { uint64_t vuid; struct gensec_security *gensec_security; struct auth_session_info *session_info; - DATA_BLOB session_key; - bool do_signing; + + struct smbXsrv_session *smbXsrv; struct user_struct *compat_vuser; @@ -532,6 +532,8 @@ struct user_struct { struct auth_session_info *session_info; struct gensec_security *gensec_security; + + struct smbXsrv_session0 *session; }; struct smbd_server_connection { @@ -672,14 +674,6 @@ struct smbd_server_connection { struct tstream_context *stream; bool negprot_2ff; struct { - /* an id tree used to allocate vuids */ - /* this holds info on session vuids that are already - * validated for this VC */ - struct idr_context *idtree; - - /* this is the limit of vuid values for this connection */ - uint64_t limit; - struct smbd_smb2_session *list; } sessions; struct { diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 77c4804a38af..e25fbc77c161 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -3157,9 +3157,18 @@ static void smbd_id_cache_kill(struct messaging_context *msg_ctx, NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn, enum protocol_types protocol) { + NTSTATUS status; + set_Protocol(protocol); conn->protocol = protocol; + if (protocol >= PROTOCOL_SMB2_02) { + status = smb2srv_session_table_init(conn); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + return NT_STATUS_OK; } diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 5d30aa48900f..f49c05cd5683 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -108,11 +108,6 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn) return NT_STATUS_NO_MEMORY; } - sconn->smb2.sessions.idtree = idr_init(sconn); - if (sconn->smb2.sessions.idtree == NULL) { - return NT_STATUS_NO_MEMORY; - } - sconn->smb2.sessions.limit = 0x0000FFFE; sconn->smb2.sessions.list = NULL; sconn->smb2.seqnum_low = 0; sconn->smb2.credits_granted = 0; @@ -816,9 +811,13 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request /* Re-sign if needed. */ if (nreq->do_signing) { NTSTATUS status; - status = smb2_signing_sign_pdu(nreq->session->session_key, - get_Protocol(), - &nreq->out.vector[i], 3); + struct smbXsrv_session *x = nreq->session->smbXsrv; + struct smbXsrv_connection *conn = x->connection; + DATA_BLOB signing_key = x->global->channels[0].signing_key; + + status = smb2_signing_sign_pdu(signing_key, + conn->protocol, + &nreq->out.vector[i], 3); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1101,10 +1100,13 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, if (req->do_signing) { NTSTATUS status; + struct smbXsrv_session *x = req->session->smbXsrv; + struct smbXsrv_connection *conn = x->connection; + DATA_BLOB signing_key = x->global->channels[0].signing_key; - status = smb2_signing_sign_pdu(req->session->session_key, - get_Protocol(), - &state->vector[1], 2); + status = smb2_signing_sign_pdu(signing_key, + conn->protocol, + &state->vector[1], 2); if (!NT_STATUS_IS_OK(status)) { smbd_server_connection_terminate(req->sconn, nt_errstr(status)); @@ -1247,8 +1249,10 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) int i = req->current_idx; uint32_t in_flags; uint64_t in_session_id; - void *p; struct smbd_smb2_session *session; + struct smbXsrv_session *smbXsrv; + NTSTATUS status; + NTTIME now = timeval_to_nttime(&req->request_time); req->session = NULL; req->tcon = NULL; @@ -1263,12 +1267,13 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) } /* 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 = smb2srv_session_lookup(req->sconn->conn, + in_session_id, now, + &smbXsrv); + if (!NT_STATUS_IS_OK(status)) { + return status; } - session = talloc_get_type_abort(p, struct smbd_smb2_session); - + session = smbXsrv->smb2sess; if (!NT_STATUS_IS_OK(session->status)) { return NT_STATUS_ACCESS_DENIED; } @@ -1388,6 +1393,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) NTSTATUS session_status; uint32_t allowed_flags; NTSTATUS return_value; + struct smbXsrv_session *x = NULL; inhdr = (const uint8_t *)req->in.vector[i].iov_base; @@ -1439,23 +1445,29 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) * we defer the check of the session_status */ session_status = smbd_smb2_request_check_session(req); + if (req->session) { + x = req->session->smbXsrv; + } req->do_signing = false; if (flags & SMB2_HDR_FLAG_SIGNED) { + struct smbXsrv_connection *conn = x->connection; + DATA_BLOB signing_key = x->global->channels[0].signing_key; + if (!NT_STATUS_IS_OK(session_status)) { return smbd_smb2_request_error(req, session_status); } req->do_signing = true; - status = smb2_signing_check_pdu(req->session->session_key, - get_Protocol(), + status = smb2_signing_check_pdu(signing_key, + conn->protocol, &req->in.vector[i], 3); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } } else if (opcode == SMB2_OP_CANCEL) { /* Cancel requests are allowed to skip the signing */ - } else if (req->session && req->session->do_signing) { + } else if (x && x->global->signing_required) { return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED); } @@ -1937,8 +1949,12 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) if (req->do_signing) { NTSTATUS status; - status = smb2_signing_sign_pdu(req->session->session_key, - get_Protocol(), + struct smbXsrv_session *x = req->session->smbXsrv; + struct smbXsrv_connection *conn = x->connection; + DATA_BLOB signing_key = x->global->channels[0].signing_key; + + status = smb2_signing_sign_pdu(signing_key, + conn->protocol, &req->out.vector[i], 3); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index 36084a4df684..bc13ffbf722b 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -187,7 +187,6 @@ static int smbd_smb2_session_destructor(struct smbd_smb2_session *session) 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); @@ -195,6 +194,9 @@ static int smbd_smb2_session_destructor(struct smbd_smb2_session *session) session->status = NT_STATUS_USER_SESSION_DELETED; session->sconn = NULL; + session->smbXsrv->compat = NULL; + TALLOC_FREE(session->smbXsrv); + return 0; } @@ -206,11 +208,14 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbd_smb2_session *session, 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->smbXsrv; 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) { @@ -218,11 +223,39 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbd_smb2_session *session, *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->session_info->session_key.data, + MIN(session->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; + } + + 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; + } + + 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; + } session->compat_vuser = talloc_zero(session, struct user_struct); if (session->compat_vuser == NULL) { @@ -256,6 +289,21 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbd_smb2_session *session, reload_services(smb2req->sconn, conn_snum_used, true); + session->smbXsrv->status = NT_STATUS_OK; + session->smbXsrv->global->auth_session_info = session->session_info; + session->smbXsrv->global->auth_session_info_seqnum += 1; + session->smbXsrv->global->channels[0].auth_session_info_seqnum = + session->smbXsrv->global->auth_session_info_seqnum; + + status = smbXsrv_session_update(session->smbXsrv); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", + (unsigned long long)session->compat_vuser->vuid, + nt_errstr(status))); + TALLOC_FREE(session); + return NT_STATUS_LOGON_FAILURE; + } + session->status = NT_STATUS_OK; /* @@ -351,55 +399,63 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req, DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { - struct smbd_smb2_session *session; + struct smbd_smb2_session *smb2sess; + struct smbXsrv_session *session; + NTSTATUS status; + NTTIME now = timeval_to_nttime(&smb2req->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) { + smb2sess = talloc_zero(smb2req->sconn, struct smbd_smb2_session); + if (smb2sess == 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; + + status = smbXsrv_session_create(smb2req->sconn->conn, + now, &session); + if (!NT_STATUS_IS_OK(status)) { + return status; } - session->vuid = id; + smb2sess->smbXsrv = session; + session->smb2sess = smb2sess; + talloc_set_destructor(smb2sess, smbd_smb2_session_destructor); - session->tcons.idtree = idr_init(session); - if (session->tcons.idtree == NULL) { + smb2sess->status = NT_STATUS_MORE_PROCESSING_REQUIRED; + smb2sess->vuid = session->global->session_wire_id; + + smb2sess->tcons.idtree = idr_init(smb2sess); + if (smb2sess->tcons.idtree == NULL) { return NT_STATUS_NO_MEMORY; } - session->tcons.limit = 0x0000FFFE; - session->tcons.list = NULL; + smb2sess->tcons.limit = 0x0000FFFE; + smb2sess->tcons.list = NULL; - DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session, + DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, smb2sess, struct smbd_smb2_session *); - session->sconn = smb2req->sconn; - talloc_set_destructor(session, smbd_smb2_session_destructor); + smb2sess->sconn = smb2req->sconn; } else { - void *p; + status = smb2srv_session_lookup(smb2req->sconn->conn, + in_session_id, now, + &session); + if (NT_STATUS_IS_OK(status)) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - /* lookup an existing session */ - p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id); - if (p == NULL) { - return NT_STATUS_USER_SESSION_DELETED; + return status; } - session = talloc_get_type_abort(p, struct smbd_smb2_session); + + smb2sess = session->smb2sess; } - if (NT_STATUS_IS_OK(session->status)) { + if (NT_STATUS_IS_OK(smb2sess->status)) { return NT_STATUS_REQUEST_NOT_ACCEPTED; } - return smbd_smb2_auth_generic(session, + return smbd_smb2_auth_generic(smb2sess, smb2req, in_security_mode, in_previous_session_id, -- 2.34.1