[SCM] Samba Shared Repository - branch v4-15-test updated

Jule Anger janger at samba.org
Tue Aug 23 07:35:01 UTC 2022


The branch, v4-15-test has been updated
       via  f6bb11dbaac lib:replace: Only include <sys/mount.h> on non-Linux systems
       via  907e4ce03ab s3: smbd: Plumb close_type parameter through close_file_in_loop(), file_close_conn()
       via  4c436dfe8cc s3: smbd: Add "enum file_close_type close_type" parameter to file_close_conn().
       via  6cd04ec396c s3: smbd: Add "enum file_close_type close_type" parameter to close_cnum().
       via  659dfb93c2a s3/smbd: Use after free when iterating smbd_server_connection->connections
       via  6b54bb8abea s3/smbd: Use after free when iterating smbd_server_connection->connections
       via  89110595b44 s3:smbd: only clear LEASE_READ if there's no read lease is left
       via  ec1ad34f288 s4:torture/smb2: add smb2.lease.v[1,2]_bug_15148
       via  93febc222bf s3:smbd: share_mode_flags_set() takes SMB2_LEASE_* values
       via  bb66bbfa4e7 libcli/smb: Set error status if 'iov' pointer is NULL
       via  6b711620fe4 libcli/smb: Ensure we call tevent_req_nterror() on failure
      from  94bdda617e0 s3/util/py_net.c: fix samba-tool domain join&leave segfault

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-15-test


- Log -----------------------------------------------------------------
commit f6bb11dbaacaa03ca1991e7b1aa11b6699c15b84
Author: Andreas Schneider <asn at samba.org>
Date:   Tue Aug 2 07:55:46 2022 +0200

    lib:replace: Only include <sys/mount.h> on non-Linux systems
    
    Details at:
    https://sourceware.org/glibc/wiki/Release/2.36#Usage_of_.3Clinux.2Fmount.h.3E_and_.3Csys.2Fmount.h.3E
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15132
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 766151bf5b7ef95ae4c8c98b8994e5c21c5bbec0)
    
    Autobuild-User(v4-15-test): Jule Anger <janger at samba.org>
    Autobuild-Date(v4-15-test): Tue Aug 23 07:34:22 UTC 2022 on sn-devel-184

commit 907e4ce03ab6809dd00d984c78ff1c006d925f97
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Aug 17 11:43:47 2022 -0700

    s3: smbd: Plumb close_type parameter through close_file_in_loop(), file_close_conn()
    
    Allows close_file_in_loop() to differentiate between SHUTDOWN_CLOSE
    (previously it only used this close type) and ERROR_CLOSE - called
    on error from smbXsrv_tcon_disconnect() in the error path. In that
    case we want to close the fd, but not run any delete-on-close actions.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15128
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reivewed-by: Noel Power <npower at samba.org>
    
    Autobuild-User(master): Noel Power <npower at samba.org>
    Autobuild-Date(master): Thu Aug 18 14:10:18 UTC 2022 on sn-devel-184
    
    (cherry picked from commit cf5f7b1489930f6d64c3e3512f116ccf286d4605)
    [npower at samba.org Adjusted for 4.15 only file_close_conn needs to
         differentiate between SHUTDOWN_CLOSE & ERROR_CLOSE]

commit 4c436dfe8cca162f086bd49f4032bdd3eb77553b
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Aug 17 11:39:36 2022 -0700

    s3: smbd: Add "enum file_close_type close_type" parameter to file_close_conn().
    
    Not yet used.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15128
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Noel Power <npower at samba.org>
    (cherry picked from commit 7005a6354df5522d9f665fb30052c458dfc93124)
    [npower at samba.org Adjusted for 4.15 filename change
             smb2-service.c -> service.c]

commit 6cd04ec396cf101fb86c1cc2c17f5547d2e2e154
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Aug 17 11:35:29 2022 -0700

    s3: smbd: Add "enum file_close_type close_type" parameter to close_cnum().
    
    Not yet used, but needed so we can differentiate between
    SHUTDOWN_CLOSE and ERROR_CLOSE in smbXsrv_tcon_disconnect()
    if we fail to chdir. In that case we want to close the fd,
    but not run any delete-on-close actions.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15128
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Noel Power <npower at samba.org>
    (cherry picked from commit 9203d17106c0e55a30813ff1ed76869c7581a343)
    [npower at samba.org Adjusted for 4.15 filename change
             smb2-service.c -> service.c]

commit 659dfb93c2acbd038aa5465abae89cc12e394ad4
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Jul 22 16:28:03 2022 +0100

    s3/smbd: Use after free when iterating smbd_server_connection->connections
    
    Change conn_free() to just use a destructor. We now
    catch any other places where we may have forgetten to
    call conn_free() - it's implicit on talloc_free(conn).
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15128
    
    Based on code from Noel Power <noel.power at suse.com>.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Noel Power <npower at samba.org>
    
    Autobuild-User(master): Noel Power <npower at samba.org>
    Autobuild-Date(master): Wed Aug 17 09:54:06 UTC 2022 on sn-devel-184
    
    (cherry picked from commit f92bacbe216d2d74ea3ccf3fe0df5c1cc9860996)

commit 6b54bb8abead164487d6c061f729ac3dc25580b9
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Aug 16 13:51:27 2022 -0700

    s3/smbd: Use after free when iterating smbd_server_connection->connections
    
    In SMB2 smbd_smb2_tree_connect() we create a new conn struct
    inside make_connection_smb2() then move the ownership to tcon using:
    
            tcon->compat = talloc_move(tcon, &compat_conn);
    
    so the lifetime of tcon->compat is tied directly to tcon.
    
    Inside smbXsrv_tcon_disconnect() we have:
    
     908                 ok = chdir_current_service(tcon->compat);
     909                 if (!ok) {
     910                         status = NT_STATUS_INTERNAL_ERROR;
     911                         DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
     912                                   "chdir_current_service() failed: %s\n",
     913                                   tcon->global->tcon_global_id,
     914                                   tcon->global->share_name,
     915                                   nt_errstr(status)));
     916                         tcon->compat = NULL;
     917                         return status;
     918                 }
     919
     920                 close_cnum(tcon->compat, vuid);
     921                 tcon->compat = NULL;
    
    If chdir_current_service(tcon->compat) fails, we return status without ever having
    called close_cnum(tcon->compat, vuid), leaving the conn pointer left in the linked
    list sconn->connections.
    
    The caller frees tcon and (by ownership) tcon->compat, still leaving the
    freed tcon->compat pointer on the sconn->connections linked list.
    
    When deadtime_fn() fires and walks the sconn->connections list it
    indirects this freed pointer. We must call close_cnum() on error also.
    
    Valgrind trace from Noel Power <noel.power at suse.com> is:
    
    ==6432== Invalid read of size 8
    ==6432==    at 0x52CED3A: conn_lastused_update (conn_idle.c:38)
    ==6432==    by 0x52CEDB1: conn_idle_all (conn_idle.c:54)
    ==6432==    by 0x5329971: deadtime_fn (smb2_process.c:1566)
    ==6432==    by 0x5DA2339: smbd_idle_event_handler (util_event.c:45)
    ==6432==    by 0x685F2F8: tevent_common_invoke_timer_handler (tevent_timed.c:376)
    
    ==6432==  Address 0x19074b88 is 232 bytes inside a block of size 328 free'd
    ==6432==    at 0x4C3451B: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==6432==    by 0x5B38521: _tc_free_internal (talloc.c:1222)
    ==6432==    by 0x5B39463: _tc_free_children_internal (talloc.c:1669)
    ==6432==    by 0x5B38404: _tc_free_internal (talloc.c:1184)
    ==6432==    by 0x5B39463: _tc_free_children_internal (talloc.c:1669)
    ==6432==    by 0x5B38404: _tc_free_internal (talloc.c:1184)
    ==6432==    by 0x5B39463: _tc_free_children_internal (talloc.c:1669)
    ==6432==    by 0x5B38404: _tc_free_internal (talloc.c:1184)
    ==6432==    by 0x5B39463: _tc_free_children_internal (talloc.c:1669)
    ==6432==    by 0x5B38404: _tc_free_internal (talloc.c:1184)
    ==6432==    by 0x5B385C5: _talloc_free_internal (talloc.c:1248)
    ==6432==    by 0x5B3988D: _talloc_free (talloc.c:1792)
    ==6432==    by 0x5349B22: smbd_smb2_flush_send_queue (smb2_server.c:4828)
    
    ==6432==  Block was alloc'd at
    ==6432==    at 0x4C332EF: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==6432==    by 0x5B378D9: __talloc_with_prefix (talloc.c:783)
    ==6432==    by 0x5B37A73: __talloc (talloc.c:825)
    ==6432==    by 0x5B37E0C: _talloc_named_const (talloc.c:982)
    ==6432==    by 0x5B3A8ED: _talloc_zero (talloc.c:2421)
    ==6432==    by 0x539873A: conn_new (conn.c:70)
    ==6432==    by 0x532D692: make_connection_smb2 (smb2_service.c:909)
    ==6432==    by 0x5352B5E: smbd_smb2_tree_connect (smb2_tcon.c:344)
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15128
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Noel Power <npower at samba.org>
    (cherry picked from commit 0bdfb5a5e60df214c088df0782c4a1bcc2a4944a)

commit 89110595b447729f1d0afa40aa011976943c1186
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Aug 15 22:45:17 2022 +0200

    s3:smbd: only clear LEASE_READ if there's no read lease is left
    
    If contend_level2_oplocks_begin_default() skips break it's
    own lease, we should not clear SHARE_MODE_LEASE_READ
    in share_mode_data->flags.
    
    Otherwise that lease won't see any lease break notifications
    for writes from other clients (file handles not using the same lease
    key).
    
    So we need to count the number existing read leases (including
    the one with the same lease key) in order to know it's
    safe to clear SMB2_LEASE_READ/SHARE_MODE_LEASE_READ.
    
    Otherwise the next run (likely from another client)
    will get the wrong result from file_has_read_lease().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15148
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Thu Aug 18 19:41:33 UTC 2022 on sn-devel-184
    
    (cherry picked from commit 96e2a82760ea06a89b7387b5cd3e864732afded3)

commit ec1ad34f288526fb965dff14d49b6fccedd2140c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Aug 17 17:07:08 2022 +0200

    s4:torture/smb2: add smb2.lease.v[1,2]_bug_15148
    
    This demonstrates the bug that happens with a
    write to a file handle holding an R lease,
    while there are other openers without any lease.
    
    When one of the other openers writes to the file,
    the R lease of the only lease holder isn't broken to NONE.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15148
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 9e5ff607eb1b9c45c8836d3cff9d51b418740b87)

commit 93febc222bf56f4df7d8a2ca760785620c1abe4c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Aug 15 10:49:13 2022 +0200

    s3:smbd: share_mode_flags_set() takes SMB2_LEASE_* values
    
    We currently only ever pass SMB2_LEASE_READ and both
    have the same value of 0x1, so for now it's only cosmetic,
    but that will change soon.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15148
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 7592aad4d7a84d0ac66a156a22af3ad77803e55c)

commit bb66bbfa4e74a1360307666f714f32fb77050f92
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Mon Aug 22 16:56:46 2022 +1200

    libcli/smb: Set error status if 'iov' pointer is NULL
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15152
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Mon Aug 22 09:03:29 UTC 2022 on sn-devel-184
    
    (cherry picked from commit 75e03ea021afa66842b6e0dea21072b1b8026d58)

commit 6b711620fe47166fa8bd6e135cce7d5b066beb5f
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Mon Aug 22 15:50:02 2022 +1200

    libcli/smb: Ensure we call tevent_req_nterror() on failure
    
    Commit 3594c3ae202688fd8aae5f7f5e20464cb23feea9 added a NULL check for
    'inhdr', but it meant we didn't always call tevent_req_nterror() when we
    should.
    
    Now we handle connection errors. We now also set an error status if the
    NULL check fails.
    
    I noticed this when an ECONNRESET error from a server refusing SMB1
    wasn't handled, and the client subsequently hung in epoll_wait().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15152
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 40d4912d841e6bcd7cd37810ef101d5f89268ee7)

-----------------------------------------------------------------------

Summary of changes:
 lib/replace/system/filesys.h |   4 +-
 lib/replace/wscript          |   3 +
 libcli/smb/smbXcli_base.c    |  12 ++-
 source3/smbd/conn.c          |  36 +++++---
 source3/smbd/files.c         |   4 +-
 source3/smbd/open.c          |   2 +-
 source3/smbd/oplock.c        |  13 +--
 source3/smbd/proto.h         |   6 +-
 source3/smbd/service.c       |   6 +-
 source3/smbd/smbXsrv_tcon.c  |  11 ++-
 source4/torture/smb2/lease.c | 208 +++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 277 insertions(+), 28 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/replace/system/filesys.h b/lib/replace/system/filesys.h
index 034e5d5886c..bb9482c69af 100644
--- a/lib/replace/system/filesys.h
+++ b/lib/replace/system/filesys.h
@@ -36,7 +36,8 @@
 #include <sys/param.h>
 #endif
 
-#ifdef HAVE_SYS_MOUNT_H
+/* This include is required on UNIX (*BSD, AIX, ...) for statfs() */
+#if !defined(LINUX) && defined(HAVE_SYS_MOUNT_H)
 #include <sys/mount.h>
 #endif
 
@@ -44,6 +45,7 @@
 #include <mntent.h>
 #endif
 
+/* This include is required on Linux for statfs() */
 #ifdef HAVE_SYS_VFS_H
 #include <sys/vfs.h>
 #endif
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 782ac5bd550..87e2010f52b 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -31,6 +31,9 @@ def configure(conf):
 
     conf.env.standalone_replace = conf.IN_LAUNCH_DIR()
 
+    if sys.platform.rfind('linux') > -1:
+        conf.DEFINE('LINUX', '1')
+
     conf.DEFINE('BOOL_DEFINED', 1)
     conf.DEFINE('HAVE_LIBREPLACE', 1)
     conf.DEFINE('LIBREPLACE_NETWORK_CHECKS', 1)
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 7579fa1c378..5d5b5ac45fd 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -4469,7 +4469,11 @@ static void smbXcli_negprot_smb1_done(struct tevent_req *subreq)
 				  NULL, /* pinbuf */
 				  expected, ARRAY_SIZE(expected));
 	TALLOC_FREE(subreq);
-	if (inhdr == NULL || tevent_req_nterror(req, status)) {
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	if (inhdr == NULL) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
 		return;
 	}
 
@@ -5009,7 +5013,11 @@ static void smbXcli_negprot_smb2_done(struct tevent_req *subreq)
 
 	status = smb2cli_req_recv(subreq, state, &iov,
 				  expected, ARRAY_SIZE(expected));
-	if (tevent_req_nterror(req, status) || iov == NULL) {
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	if (iov == NULL) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
 		return;
 	}
 
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index 044242d5697..776d7af4c12 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -24,6 +24,25 @@
 #include "smbd/globals.h"
 #include "lib/util/bitmap.h"
 
+static void conn_free_internal(connection_struct *conn);
+
+/****************************************************************************
+ * Remove a conn struct from conn->sconn->connections
+ * if not already done.
+****************************************************************************/
+
+static int conn_struct_destructor(connection_struct *conn)
+{
+        if (conn->sconn != NULL) {
+		DLIST_REMOVE(conn->sconn->connections, conn);
+		SMB_ASSERT(conn->sconn->num_connections > 0);
+		conn->sconn->num_connections--;
+		conn->sconn = NULL;
+	}
+	conn_free_internal(conn);
+	return 0;
+}
+
 /****************************************************************************
  Return the number of open connections.
 ****************************************************************************/
@@ -115,6 +134,11 @@ connection_struct *conn_new(struct smbd_server_connection *sconn)
 	DLIST_ADD(sconn->connections, conn);
 	sconn->num_connections++;
 
+	/*
+	 * Catches the case where someone forgets to call
+	 * conn_free().
+	 */
+	talloc_set_destructor(conn, conn_struct_destructor);
 	return conn;
 }
 
@@ -212,7 +236,6 @@ static void conn_free_internal(connection_struct *conn)
 	free_namearray(conn->aio_write_behind_list);
 
 	ZERO_STRUCTP(conn);
-	talloc_destroy(conn);
 }
 
 /****************************************************************************
@@ -221,16 +244,7 @@ static void conn_free_internal(connection_struct *conn)
 
 void conn_free(connection_struct *conn)
 {
-	if (conn->sconn == NULL) {
-		conn_free_internal(conn);
-		return;
-	}
-
-	DLIST_REMOVE(conn->sconn->connections, conn);
-	SMB_ASSERT(conn->sconn->num_connections > 0);
-	conn->sconn->num_connections--;
-
-	conn_free_internal(conn);
+	TALLOC_FREE(conn);
 }
 
 /*
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 196c0008e31..3f90c2e247e 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -755,7 +755,7 @@ NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
  Close all open files for a connection.
 ****************************************************************************/
 
-void file_close_conn(connection_struct *conn)
+void file_close_conn(connection_struct *conn, enum file_close_type close_type)
 {
 	files_struct *fsp, *next;
 
@@ -770,7 +770,7 @@ void file_close_conn(connection_struct *conn)
 			 */
 			fsp->op->global->durable = false;
 		}
-		close_file(NULL, fsp, SHUTDOWN_CLOSE);
+		close_file(NULL, fsp, close_type);
 	}
 }
 
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 4b64dd11e87..3ab1b92e3fd 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -2730,7 +2730,7 @@ grant:
 	if (granted & SMB2_LEASE_READ) {
 		uint32_t acc, sh, ls;
 		share_mode_flags_get(lck, &acc, &sh, &ls);
-		ls |= SHARE_MODE_LEASE_READ;
+		ls |= SMB2_LEASE_READ;
 		share_mode_flags_set(lck, acc, sh, ls, NULL);
 	}
 
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index d02872a610f..7dc944c10c1 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -1175,7 +1175,7 @@ struct break_to_none_state {
 	struct file_id id;
 	struct smb2_lease_key lease_key;
 	struct GUID client_guid;
-	size_t num_broken;
+	size_t num_read_leases;
 };
 
 static bool do_break_lease_to_none(struct share_mode_entry *e,
@@ -1209,6 +1209,8 @@ static bool do_break_lease_to_none(struct share_mode_entry *e,
 		return false;
 	}
 
+	state->num_read_leases += 1;
+
 	our_own = smb2_lease_equal(&state->client_guid,
 				   &state->lease_key,
 				   &e->client_guid,
@@ -1224,8 +1226,6 @@ static bool do_break_lease_to_none(struct share_mode_entry *e,
 
 	send_break_to_none(state->sconn->msg_ctx, &state->id, e);
 
-	state->num_broken += 1;
-
 	return false;
 }
 
@@ -1259,11 +1259,12 @@ static bool do_break_oplock_to_none(struct share_mode_entry *e,
 		return false;
 	}
 
+	state->num_read_leases += 1;
+
 	/* Paranoia .... */
 	SMB_ASSERT(!EXCLUSIVE_OPLOCK_TYPE(e->op_type));
 
 	send_break_to_none(state->sconn->msg_ctx, &state->id, e);
-	state->num_broken += 1;
 
 	return false;
 }
@@ -1337,14 +1338,14 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 		DBG_WARNING("share_mode_forall_entries failed\n");
 	}
 
-	if (state.num_broken == 0) {
+	if (state.num_read_leases == 0) {
 		/*
 		 * Lazy update here. It might be that the read lease
 		 * has gone in the meantime.
 		 */
 		uint32_t acc, sh, ls;
 		share_mode_flags_get(lck, &acc, &sh, &ls);
-		ls &= ~SHARE_MODE_LEASE_READ;
+		ls &= ~SMB2_LEASE_READ;
 		share_mode_flags_set(lck, acc, sh, ls, NULL);
 	}
 
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 46d3f2e5156..d937d3d9615 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -397,7 +397,7 @@ void fsp_set_gen_id(files_struct *fsp);
 NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
 		  files_struct **result);
 NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req);
-void file_close_conn(connection_struct *conn);
+void file_close_conn(connection_struct *conn, enum file_close_type close_type);
 bool file_init_global(void);
 bool file_init(struct smbd_server_connection *sconn);
 void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid);
@@ -1127,7 +1127,9 @@ connection_struct *make_connection(struct smb_request *req,
 				   const char *service_in,
 				   const char *pdev, uint64_t vuid,
 				   NTSTATUS *status);
-void close_cnum(connection_struct *conn, uint64_t vuid);
+void close_cnum(connection_struct *conn,
+		uint64_t vuid,
+		enum file_close_type close_type);
 
 /* The following definitions come from smbd/session.c  */
 struct sessionid;
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index ef7c14d92d0..d4dc81bf986 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -1111,14 +1111,16 @@ connection_struct *make_connection(struct smb_request *req,
  Close a cnum.
 ****************************************************************************/
 
-void close_cnum(connection_struct *conn, uint64_t vuid)
+void close_cnum(connection_struct *conn,
+		uint64_t vuid,
+		enum file_close_type close_type)
 {
 	char rootpath[2] = { '/', '\0'};
 	struct smb_filename root_fname = { .base_name = rootpath };
 	const struct loadparm_substitution *lp_sub =
 		loadparm_s3_global_substitution();
 
-	file_close_conn(conn);
+	file_close_conn(conn, close_type);
 
 	change_to_root_user();
 
diff --git a/source3/smbd/smbXsrv_tcon.c b/source3/smbd/smbXsrv_tcon.c
index 6b105522855..8707082edd6 100644
--- a/source3/smbd/smbXsrv_tcon.c
+++ b/source3/smbd/smbXsrv_tcon.c
@@ -913,11 +913,20 @@ NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
 				  tcon->global->tcon_global_id,
 				  tcon->global->share_name,
 				  nt_errstr(status)));
+			/*
+			 * We must call close_cnum() on
+			 * error, as the caller is going
+			 * to free tcon and tcon->compat
+			 * so we must ensure tcon->compat is
+			 * removed from the linked list
+			 * conn->sconn->connections.
+			 */
+			close_cnum(tcon->compat, vuid, ERROR_CLOSE);
 			tcon->compat = NULL;
 			return status;
 		}
 
-		close_cnum(tcon->compat, vuid);
+		close_cnum(tcon->compat, vuid, SHUTDOWN_CLOSE);
 		tcon->compat = NULL;
 	}
 
diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c
index 43b418c5acf..a2c354dc02a 100644
--- a/source4/torture/smb2/lease.c
+++ b/source4/torture/smb2/lease.c
@@ -4556,6 +4556,210 @@ done:
 	return ret;
 }
 
+static bool test_lease_v1_bug_15148(struct torture_context *tctx,
+				    struct smb2_tree *tree)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_create io1;
+	struct smb2_create io2;
+	struct smb2_lease ls1;
+	struct smb2_lease ls2;
+	struct smb2_handle h1 = {{0}};
+	struct smb2_handle h2 = {{0}};
+	struct smb2_write w;
+	NTSTATUS status;
+	const char *fname = "lease_v1_bug_15148.dat";
+	bool ret = true;
+	uint32_t caps;
+
+	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+	if (!(caps & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	tree->session->transport->lease.handler = torture_lease_handler;
+	tree->session->transport->lease.private_data = tree;
+	tree->session->transport->oplock.handler = torture_oplock_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	smb2_util_unlink(tree, fname);
+
+	torture_reset_lease_break_info(tctx, &lease_break_info);
+
+	/* Grab R lease over connection 1a */
+	smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
+	status = smb2_create(tree, mem_ctx, &io1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h1 = io1.out.file.handle;
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_LEASE(&io1, "R", true, LEASE1, 0);
+
+	CHECK_NO_BREAK(tctx);
+
+	/* Contend with LEASE2. */
+	smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
+	status = smb2_create(tree, mem_ctx, &io2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h2 = io2.out.file.handle;
+	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_LEASE(&io2, "R", true, LEASE2, 0);
+
+	CHECK_NO_BREAK(tctx);
+
+	ZERO_STRUCT(w);
+	w.in.file.handle = h1;
+	w.in.offset      = 0;
+	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
+	memset(w.in.data.data, 'o', w.in.data.length);
+	status = smb2_write(tree, &w);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	ls2.lease_epoch += 1;
+	CHECK_BREAK_INFO("R", "", LEASE2);
+
+	torture_reset_lease_break_info(tctx, &lease_break_info);
+
+	ZERO_STRUCT(w);
+	w.in.file.handle = h1;
+	w.in.offset      = 0;
+	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
+	memset(w.in.data.data, 'O', w.in.data.length);
+	status = smb2_write(tree, &w);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	CHECK_NO_BREAK(tctx);
+
+	ZERO_STRUCT(w);
+	w.in.file.handle = h2;
+	w.in.offset      = 0;
+	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
+	memset(w.in.data.data, 'o', w.in.data.length);
+	status = smb2_write(tree, &w);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	ls1.lease_epoch += 1;
+	CHECK_BREAK_INFO("R", "", LEASE1);
+
+ done:
+	smb2_util_close(tree, h1);
+	smb2_util_close(tree, h2);
+
+	smb2_util_unlink(tree, fname);
+
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+static bool test_lease_v2_bug_15148(struct torture_context *tctx,
+				    struct smb2_tree *tree)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_create io1;
+	struct smb2_create io2;
+	struct smb2_lease ls1;
+	struct smb2_lease ls2;
+	struct smb2_handle h1 = {{0}};
+	struct smb2_handle h2 = {{0}};
+	struct smb2_write w;
+	NTSTATUS status;
+	const char *fname = "lease_v2_bug_15148.dat";
+	bool ret = true;
+	uint32_t caps;
+	enum protocol_types protocol;
+
+	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+	if (!(caps & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+	if (protocol < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "v2 leases are not supported");
+	}
+
+	tree->session->transport->lease.handler = torture_lease_handler;
+	tree->session->transport->lease.private_data = tree;
+	tree->session->transport->oplock.handler = torture_oplock_handler;
+	tree->session->transport->oplock.private_data = tree;
+
+	smb2_util_unlink(tree, fname);
+
+	torture_reset_lease_break_info(tctx, &lease_break_info);
+
+	/* Grab R lease over connection 1a */
+	smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
+			     smb2_util_lease_state("R"), 0x4711);
+	status = smb2_create(tree, mem_ctx, &io1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h1 = io1.out.file.handle;
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	ls1.lease_epoch += 1;
+	CHECK_LEASE_V2(&io1, "R", true, LEASE1,
+		       0, 0, ls1.lease_epoch);
+
+	CHECK_NO_BREAK(tctx);
+
+	/* Contend with LEASE2. */
+	smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
+			     smb2_util_lease_state("R"), 0x11);
+	status = smb2_create(tree, mem_ctx, &io2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h2 = io2.out.file.handle;
+	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	ls2.lease_epoch += 1;
+	CHECK_LEASE_V2(&io2, "R", true, LEASE2,
+		       0, 0, ls2.lease_epoch);
+
+	CHECK_NO_BREAK(tctx);
+
+	ZERO_STRUCT(w);
+	w.in.file.handle = h1;
+	w.in.offset      = 0;
+	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
+	memset(w.in.data.data, 'o', w.in.data.length);
+	status = smb2_write(tree, &w);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	ls2.lease_epoch += 1;
+	CHECK_BREAK_INFO_V2(tree->session->transport,
+			    "R", "", LEASE2, ls2.lease_epoch);
+
+	torture_reset_lease_break_info(tctx, &lease_break_info);
+
+	ZERO_STRUCT(w);
+	w.in.file.handle = h1;
+	w.in.offset      = 0;
+	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
+	memset(w.in.data.data, 'O', w.in.data.length);
+	status = smb2_write(tree, &w);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	CHECK_NO_BREAK(tctx);
+
+	ZERO_STRUCT(w);
+	w.in.file.handle = h2;
+	w.in.offset      = 0;
+	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
+	memset(w.in.data.data, 'o', w.in.data.length);
+	status = smb2_write(tree, &w);
+	CHECK_STATUS(status, NT_STATUS_OK);


-- 
Samba Shared Repository



More information about the samba-cvs mailing list