From a90ac47d88d08dfd396e956f9e24d9fcc0de3c5d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 4 Oct 2019 12:11:00 +0200 Subject: [PATCH] smbXsrv_session: add a smbXsrv_session_disconnect_xconn() helper This removes the connection references from the session channel array for each session that's used on the connection. Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner --- source3/smbd/globals.h | 1 + source3/smbd/smbXsrv_session.c | 122 +++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 2d40f080260..d3b6ac2ffe6 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -553,6 +553,7 @@ NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session, struct smbXsrv_connection *conn, NTTIME now, struct smbXsrv_channel_global0 **_c); +NTSTATUS smbXsrv_session_disconnect_xconn(struct smbXsrv_connection *xconn); NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session); struct smbXsrv_channel_global0; NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session, diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c index 1ebed144afd..8eaa9fdcbab 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -1909,6 +1909,128 @@ static int smbXsrv_session_local_traverse_cb(struct db_record *local_rec, return state->caller_cb(session, state->caller_data); } +struct smbXsrv_session_disconnect_xconn_state { + struct smbXsrv_connection *xconn; + NTSTATUS first_status; + int errors; +}; + +static int smbXsrv_session_disconnect_xconn_callback(struct db_record *local_rec, + void *private_data); + +NTSTATUS smbXsrv_session_disconnect_xconn(struct smbXsrv_connection *xconn) +{ + struct smbXsrv_client *client = xconn->client; + struct smbXsrv_session_table *table = client->session_table; + struct smbXsrv_session_disconnect_xconn_state state; + NTSTATUS status; + int count = 0; + + if (table == NULL) { + DBG_ERR("empty session_table, nothing to do.\n"); + return NT_STATUS_OK; + } + + ZERO_STRUCT(state); + state.xconn = xconn; + + status = dbwrap_traverse(table->local.db_ctx, + smbXsrv_session_disconnect_xconn_callback, + &state, &count); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("dbwrap_traverse() failed: %s\n", + nt_errstr(status)); + return status; + } + + if (!NT_STATUS_IS_OK(state.first_status)) { + DBG_ERR("count[%d] errors[%d] first[%s]\n", + count, state.errors, + nt_errstr(state.first_status)); + return state.first_status; + } + + return NT_STATUS_OK; +} + +static int smbXsrv_session_disconnect_xconn_callback(struct db_record *local_rec, + void *private_data) +{ + struct smbXsrv_session_disconnect_xconn_state *state = + (struct smbXsrv_session_disconnect_xconn_state *)private_data; + TDB_DATA val; + void *ptr = NULL; + struct smbXsrv_session *session = NULL; + struct smbXsrv_session_auth0 *a = NULL; + struct smbXsrv_channel_global0 *c = NULL; + NTSTATUS status; + bool need_update = false; + + val = dbwrap_record_get_value(local_rec); + if (val.dsize != sizeof(ptr)) { + status = NT_STATUS_INTERNAL_ERROR; + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + return 0; + } + + memcpy(&ptr, val.dptr, val.dsize); + session = talloc_get_type_abort(ptr, struct smbXsrv_session); + + session->db_rec = local_rec; + + status = smbXsrv_session_find_auth(session, state->xconn, 0, &a); + if (!NT_STATUS_IS_OK(status)) { + a = NULL; + } + status = smbXsrv_session_find_channel(session, state->xconn, &c); + if (!NT_STATUS_IS_OK(status)) { + c = NULL; + } + if (session->global->num_channels <= 1) { + /* + * The last channel is treated different + */ + c = NULL; + } + + if (a != NULL) { + smbXsrv_session_auth0_destructor(a); + a->connection = NULL; + need_update = true; + } + + if (c != NULL) { + struct smbXsrv_session_global0 *global = session->global; + ptrdiff_t n; + + n = (c - global->channels); + if (n >= global->num_channels || n < 0) { + status = NT_STATUS_INTERNAL_ERROR; + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + return 0; + } + ARRAY_DEL_ELEMENT(global->channels, n, global->num_channels); + global->num_channels--; + need_update = true; + } + + if (need_update) { + status = smbXsrv_session_update(session); + if (NT_STATUS_IS_OK(state->first_status)) { + state->first_status = status; + } + state->errors++; + } + + return 0; +} + NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn) { /* -- 2.34.1