smbXsrv_session: smbXsrv_session_remove_channel() should also remove the last channel
authorStefan Metzmacher <metze@samba.org>
Wed, 24 Feb 2021 16:44:12 +0000 (17:44 +0100)
committerJeremy Allison <jra@samba.org>
Mon, 29 Mar 2021 19:36:37 +0000 (19:36 +0000)
There's nothing special regarding the last channel,
as the smb2.session.bind2 test demonstrates.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14449

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail.d/smb2.session [deleted file]
source3/smbd/smbXsrv_session.c

diff --git a/selftest/knownfail.d/smb2.session b/selftest/knownfail.d/smb2.session
deleted file mode 100644 (file)
index e6520ff..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.smb2.session.*.bind2
index 734b2edfe2e8ac9e80768a8b00133bd6baaec78e..457505655293b148cb3a28bf33ada22007360b9a 100644 (file)
@@ -1219,6 +1219,9 @@ static int smbXsrv_session_destructor(struct smbXsrv_session *session)
 {
        NTSTATUS status;
 
+       DBG_DEBUG("destructing session(%llu)\n",
+                 (unsigned long long)session->global->session_wire_id);
+
        status = smbXsrv_session_clear_and_logoff(session);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0, ("smbXsrv_session_destructor: "
@@ -1556,6 +1559,8 @@ NTSTATUS smbXsrv_session_create_auth(struct smbXsrv_session *session,
        return NT_STATUS_OK;
 }
 
+static void smbXsrv_session_remove_channel_done(struct tevent_req *subreq);
+
 NTSTATUS smbXsrv_session_remove_channel(struct smbXsrv_session *session,
                                        struct smbXsrv_connection *xconn)
 {
@@ -1572,12 +1577,6 @@ NTSTATUS smbXsrv_session_remove_channel(struct smbXsrv_session *session,
        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);
@@ -1595,6 +1594,30 @@ NTSTATUS smbXsrv_session_remove_channel(struct smbXsrv_session *session,
                }
                ARRAY_DEL_ELEMENT(global->channels, n, global->num_channels);
                global->num_channels--;
+               if (global->num_channels == 0) {
+                       struct smbXsrv_client *client = session->client;
+                       struct tevent_req *subreq = NULL;
+
+                       /*
+                        * This is garanteed to set
+                        * session->status = NT_STATUS_USER_SESSION_DELETED
+                        * even if NULL is returned.
+                        */
+                       subreq = smb2srv_session_shutdown_send(session,
+                                                              client->raw_ev_ctx,
+                                                              session,
+                                                              NULL);
+                       if (subreq == NULL) {
+                               status = NT_STATUS_NO_MEMORY;
+                               DBG_ERR("smb2srv_session_shutdown_send(%llu) failed: %s\n",
+                                       (unsigned long long)session->global->session_wire_id,
+                                       nt_errstr(status));
+                               return status;
+                       }
+                       tevent_req_set_callback(subreq,
+                                               smbXsrv_session_remove_channel_done,
+                                               session);
+               }
                need_update = true;
        }
 
@@ -1605,6 +1628,31 @@ NTSTATUS smbXsrv_session_remove_channel(struct smbXsrv_session *session,
        return smbXsrv_session_update(session);
 }
 
+static void smbXsrv_session_remove_channel_done(struct tevent_req *subreq)
+{
+       struct smbXsrv_session *session =
+               tevent_req_callback_data(subreq,
+               struct smbXsrv_session);
+       NTSTATUS status;
+
+       status = smb2srv_session_shutdown_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("smb2srv_session_shutdown_recv(%llu) failed: %s\n",
+                       (unsigned long long)session->global->session_wire_id,
+                       nt_errstr(status));
+       }
+
+       status = smbXsrv_session_logoff(session);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("smbXsrv_session_logoff(%llu) failed: %s\n",
+                       (unsigned long long)session->global->session_wire_id,
+                       nt_errstr(status));
+       }
+
+       TALLOC_FREE(session);
+}
+
 struct smb2srv_session_shutdown_state {
        struct tevent_queue *wait_queue;
 };