smbXsrv_session: add a smbXsrv_session_disconnect_xconn() helper
authorStefan Metzmacher <metze@samba.org>
Fri, 4 Oct 2019 10:11:00 +0000 (12:11 +0200)
committerGünther Deschner <gd@samba.org>
Fri, 15 May 2020 09:04:36 +0000 (09:04 +0000)
This removes the connection references from the session channel
array for each session that's used on the connection.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
source3/smbd/globals.h
source3/smbd/smbXsrv_session.c

index 2d40f0802604e1c0be07559ba3280e6b499fbf15..d3b6ac2ffe6561703a8e3b2b476731254aebb80f 100644 (file)
@@ -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,
index 1ebed144afdb47b2cee0af0d8caf141c626bc77e..8eaa9fdcbab7670ca2e61013fd3037bf66b700a8 100644 (file)
@@ -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)
 {
        /*