[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Thu Feb 10 19:12:01 UTC 2022


The branch, master has been updated
       via  434e6d4b4b4 smbd: Only file_free() a self-created fsp in create_file_unixpath()
       via  e91b59c4dfb smbd: Introduce close_file_smb()
       via  e751c6237b7 smbd: Factor out fsp_unbind_smb() from file_free()
       via  5f1ceead709 torture: Add a test to show that full_audit uses a ptr after free
       via  93fe9c83145 smbd: Simplify the flow in close_file_free()
       via  1fbd9877fea smbd: No base fsps to close_file_free() from file_close_user()
       via  61f57ba24ee smbd: Factor out close_file_in_loop() from file_close_conn_fn()
       via  d1341d666af smbd: No base fsps to close_file_free() from file_close_conn()
       via  f5bc73a2ad9 smbd: NULL out "fsp" in close_file()
       via  363ac753389 smbd: Call file_free() just once in close_file()
       via  244c5a7d31c smbd: Move the call to file_free() out of close_fake_file()
       via  2293ca5b572 smbd: Move the call to file_free() out of close_normal_file()
       via  9966b5e233e smbd: Move the call to file_free() out of close_directory()
       via  1c1734974fc smbd: Slightly simplify create_file_unixpath()
      from  cd06574b528 s3:winbind: Reduce the level and improve a couple of debug messages

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 434e6d4b4b45757878642d229d26d146792a3878
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Feb 3 17:17:07 2022 +0100

    smbd: Only file_free() a self-created fsp in create_file_unixpath()
    
    This fixes a use-after-free in smb_full_audit_create_file() when
    calling SMB_VFS_CREATE_FILE with fsp->fsp_name as smb_fname.
    
    create_file_unixpath() has this comment:
    
     * This is really subtle. If someone passes in an smb_fname
     * where smb_fname actually is taken from fsp->fsp_name, then
     * the lifetime of these objects is meant to be the same.
    
    so it seems legitimate to call CREATE_FILE this way.
    
    When CREATE_FILE runs into an error, create_file_unixpath() does a
    file_free, which also takes fsp->fsp_name with
    it. smb_full_audit_create_file() wants to log the failure including
    the smb_fname after NEXT_CREATE_FILE has exited, but this will then
    use the already free'ed data.
    
    Fix by only doing the file_free() on an fsp that
    create_file_unixpath() created itself.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Thu Feb 10 19:11:33 UTC 2022 on sn-devel-184

commit e91b59c4dfb2b35661dbecbc5769584109e23571
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 9 18:03:33 2022 +0100

    smbd: Introduce close_file_smb()
    
    This does almost everything that close_file_free() does, but it leaves
    the fsp around.
    
    A normal close_file() now calls fsp_unbind_smb() twice. Functionally
    this is not a problem, fsp_unbind_smb() is idempotent. The only
    potential performance penalty might come from the loops in
    remove_smb2_chained_fsp(), but those only are potentially large with
    deeply queued smb2 requests. If that turns out to be a problem, we'll
    cope with it later. The alternative would be to split up file_free()
    into even more routines and make it more difficult to figure out which
    of the "rundown/unbind/free" routines to call in any particular
    situation.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit e751c6237b750adb4cb59df4a42bb9f39354e7e4
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 9 17:23:03 2022 +0100

    smbd: Factor out fsp_unbind_smb() from file_free()
    
    For example, remove our entry from smbXsrv_open_global.tdb
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 5f1ceead7094aefc6ad1f209468e9ea8f009716c
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Feb 3 15:25:11 2022 +0100

    torture: Add a test to show that full_audit uses a ptr after free
    
    Run vfstest with this vfstest.cmd under valgrind and you'll see what
    happens. Exact explanation a few patches further down...
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 93fe9c83145d31ea11a9cd25049ac527ad4a000d
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 2 12:42:08 2022 +0100

    smbd: Simplify the flow in close_file_free()
    
    We are no longer called on base_fsp's in SHUTDOWN_CLOSE. That
    simplifies the logic in the common case, we now have a linear flow for
    the very often-called close_file()
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 1fbd9877fead466a17d697c143cd370c0b27f610
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 2 08:58:15 2022 +0100

    smbd: No base fsps to close_file_free() from file_close_user()
    
    Same logic as the change for file_close_conn()
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 61f57ba24ee2e54abf224118f93bd0ccda44ec41
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 2 12:27:50 2022 +0100

    smbd: Factor out close_file_in_loop() from file_close_conn_fn()
    
    To be reused in file_close_user(). Deliberately a separate commit to
    make the previous commit easier to understand.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit d1341d666af12965b4318f89b1d0e1e8769e861e
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 2 08:58:15 2022 +0100

    smbd: No base fsps to close_file_free() from file_close_conn()
    
    close_file_free() needs to handle base fsps specially. This can be
    simplified a lot if we pass the the open files a second time in case
    we encountered base_fsps that we could not immediately delete.
    
    file_close_conn() is not our hot code path, and also we don't expect
    many thousand open files that we need to walk a second time.
    
    A subsequent patch will simplify close_file_free(), the complicated
    logic is now in files.c, where it IMHO belongs because
    file_set_base_fsp() are here as well.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit f5bc73a2ad97647f76143f7962c964f45aa6b1a0
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Feb 1 17:47:29 2022 +0100

    smbd: NULL out "fsp" in close_file()
    
    Quite a few places already had this in the caller, but not all. Rename
    close_file() to close_file_free() appropriately. We'll factor out
    close_file_smb() doing only parts of close_file_free() later.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 363ac7533895fda786f56c4fe8346128753f38a5
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Feb 1 17:21:24 2022 +0100

    smbd: Call file_free() just once in close_file()
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 244c5a7d31c3a37082b320680f2b71108d77bbd4
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Feb 1 17:19:54 2022 +0100

    smbd: Move the call to file_free() out of close_fake_file()
    
    Centralize calling file_free(), but leave close_fake_file() in for API
    symmetry reasons.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 2293ca5b572178404273856f8d8989a5ee7de80c
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Feb 1 17:17:36 2022 +0100

    smbd: Move the call to file_free() out of close_normal_file()
    
    Call file_free() just once
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 9966b5e233ef2ff0368ba5860c824c7cd6420415
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Feb 1 17:14:34 2022 +0100

    smbd: Move the call to file_free() out of close_directory()
    
    Call file_free() just once
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 1c1734974fcf1d060bc6bcdbe1858cba1b7e5a73
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Feb 9 10:02:46 2022 +0100

    smbd: Slightly simplify create_file_unixpath()
    
    Avoid the "needs_fsp_unlink" variable, describe the talloc hierarchy a
    bit differently in the comments.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

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

Summary of changes:
 source3/lib/adouble.c                              |  20 +--
 source3/modules/vfs_fruit.c                        |  12 +-
 source3/modules/vfs_worm.c                         |   2 +-
 source3/printing/nt_printing.c                     |  10 +-
 source3/rpc_server/srvsvc/srv_srvsvc_nt.c          |   4 +-
 source3/script/tests/full_audit_segfault/run.sh    |  23 ++++
 .../script/tests/full_audit_segfault/vfstest.cmd   |   3 +
 source3/selftest/tests.py                          |   8 ++
 source3/smbd/close.c                               | 104 ++++++--------
 source3/smbd/dir.c                                 |   9 +-
 source3/smbd/fake_file.c                           |   4 +-
 source3/smbd/files.c                               | 150 +++++++++++++++++----
 source3/smbd/nttrans.c                             |   6 +-
 source3/smbd/open.c                                |  75 +++++------
 source3/smbd/proto.h                               |   9 +-
 source3/smbd/reply.c                               |  62 ++++-----
 source3/smbd/smb2_close.c                          |   2 +-
 source3/smbd/smb2_create.c                         |   3 +-
 source3/smbd/trans2.c                              |  48 +++----
 source3/torture/cmd_vfs.c                          |  85 ++++++++++++
 source3/utils/net_vfs.c                            |   7 +-
 21 files changed, 415 insertions(+), 231 deletions(-)
 create mode 100755 source3/script/tests/full_audit_segfault/run.sh
 create mode 100644 source3/script/tests/full_audit_segfault/vfstest.cmd


Changeset truncated at 500 lines:

diff --git a/source3/lib/adouble.c b/source3/lib/adouble.c
index 37fb686f17b..aa78007dadd 100644
--- a/source3/lib/adouble.c
+++ b/source3/lib/adouble.c
@@ -1254,13 +1254,13 @@ static bool ad_convert_xattr(vfs_handle_struct *handle,
 		if (nwritten == -1) {
 			DBG_ERR("SMB_VFS_PWRITE failed\n");
 			saved_errno = errno;
-			close_file(NULL, fsp, ERROR_CLOSE);
+			close_file_free(NULL, &fsp, ERROR_CLOSE);
 			errno = saved_errno;
 			ok = false;
 			goto fail;
 		}
 
-		status = close_file(NULL, fsp, NORMAL_CLOSE);
+		status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 		if (!NT_STATUS_IS_OK(status)) {
 			ok = false;
 			goto fail;
@@ -1395,12 +1395,12 @@ static bool ad_convert_finderinfo(vfs_handle_struct *handle,
 	if (nwritten == -1) {
 		DBG_ERR("SMB_VFS_PWRITE failed\n");
 		saved_errno = errno;
-		close_file(NULL, fsp, ERROR_CLOSE);
+		close_file_free(NULL, &fsp, ERROR_CLOSE);
 		errno = saved_errno;
 		return false;
 	}
 
-	status = close_file(NULL, fsp, NORMAL_CLOSE);
+	status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	if (!NT_STATUS_IS_OK(status)) {
 		return false;
 	}
@@ -1652,7 +1652,7 @@ static bool ad_unconvert_open_ad(TALLOC_CTX *mem_ctx,
 		if (ret != 0) {
 			DBG_ERR("SMB_VFS_FCHOWN [%s] failed: %s\n",
 				fsp_str_dbg(fsp), nt_errstr(status));
-			close_file(NULL, fsp, NORMAL_CLOSE);
+			close_file_free(NULL, &fsp, NORMAL_CLOSE);
 			return false;
 		}
 	}
@@ -1710,14 +1710,14 @@ static bool ad_unconvert_get_streams(struct vfs_handle_struct *handle,
 				num_streams,
 				streams);
 	if (!NT_STATUS_IS_OK(status)) {
-		close_file(NULL, fsp, NORMAL_CLOSE);
+		close_file_free(NULL, &fsp, NORMAL_CLOSE);
 		DBG_ERR("streaminfo on [%s] failed: %s\n",
 			smb_fname_str_dbg(smb_fname),
 			nt_errstr(status));
 		return false;
 	}
 
-	status = close_file(NULL, fsp, NORMAL_CLOSE);
+	status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	if (!NT_STATUS_IS_OK(status)) {
 		DBG_ERR("close_file [%s] failed: %s\n",
 			smb_fname_str_dbg(smb_fname),
@@ -1975,7 +1975,7 @@ static bool ad_collect_one_stream(struct vfs_handle_struct *handle,
 out:
 	TALLOC_FREE(sname);
 	if (fsp != NULL) {
-		status = close_file(NULL, fsp, NORMAL_CLOSE);
+		status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_ERR("close_file [%s] failed: %s\n",
 				smb_fname_str_dbg(smb_fname),
@@ -2117,9 +2117,9 @@ bool ad_unconvert(TALLOC_CTX *mem_ctx,
 
 out:
 	if (fsp != NULL) {
-		status = close_file(NULL, fsp, NORMAL_CLOSE);
+		status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 		if (!NT_STATUS_IS_OK(status)) {
-			DBG_ERR("close_file [%s] failed: %s\n",
+			DBG_ERR("close_file_free() [%s] failed: %s\n",
 				smb_fname_str_dbg(smb_fname),
 				nt_errstr(status));
 			ok = false;
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index d6aa7e3644e..303df41258e 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -1002,7 +1002,7 @@ static bool readdir_attr_meta_finderi_stream(
 
 fail:
 	if (fsp != NULL) {
-		close_file(NULL, fsp, NORMAL_CLOSE);
+		close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	}
 
 	return ok;
@@ -4247,8 +4247,8 @@ fail:
 	DEBUG(10, ("fruit_create_file: %s\n", nt_errstr(status)));
 
 	if (fsp) {
-		close_file(req, fsp, ERROR_CLOSE);
-		*result = fsp = NULL;
+		close_file_free(req, &fsp, ERROR_CLOSE);
+		*result = NULL;
 	}
 
 	return status;
@@ -4993,8 +4993,7 @@ static bool fruit_get_bandsize(vfs_handle_struct *handle,
 
 	}
 
-	status = close_file(NULL, fsp, NORMAL_CLOSE);
-	fsp = NULL;
+	status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	if (!NT_STATUS_IS_OK(status)) {
 		DBG_ERR("close_file failed: %s\n", nt_errstr(status));
 		ok = false;
@@ -5028,11 +5027,10 @@ static bool fruit_get_bandsize(vfs_handle_struct *handle,
 
 out:
 	if (fsp != NULL) {
-		status = close_file(NULL, fsp, NORMAL_CLOSE);
+		status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_ERR("close_file failed: %s\n", nt_errstr(status));
 		}
-		fsp = NULL;
 	}
 	TALLOC_FREE(plist);
 	TALLOC_FREE(smb_fname);
diff --git a/source3/modules/vfs_worm.c b/source3/modules/vfs_worm.c
index 3ae1f9f39e6..76762e0a84f 100644
--- a/source3/modules/vfs_worm.c
+++ b/source3/modules/vfs_worm.c
@@ -75,7 +75,7 @@ static NTSTATUS vfs_worm_create_file(vfs_handle_struct *handle,
 	 * Access via MAXIMUM_ALLOWED_ACCESS?
 	 */
 	if (readonly && ((*result)->access_mask & write_access_flags)) {
-		close_file(req, *result, NORMAL_CLOSE);
+		close_file_free(req, result, NORMAL_CLOSE);
 		return NT_STATUS_ACCESS_DENIED;
 	}
 	return NT_STATUS_OK;
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index a47afda4a84..1e35e017fb2 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -874,8 +874,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 			    (long)old_create_time));
 	}
 
-	close_file(NULL, fsp, NORMAL_CLOSE);
-	fsp = NULL;
+	close_file_free(NULL, &fsp, NORMAL_CLOSE);
 
 	/* Get file version info (if available) for new file */
 	status = driver_unix_convert(conn, new_file, &smb_fname);
@@ -935,8 +934,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 			    (long)new_create_time));
 	}
 
-	close_file(NULL, fsp, NORMAL_CLOSE);
-	fsp = NULL;
+	close_file_free(NULL, &fsp, NORMAL_CLOSE);
 
 	if (use_version && (new_major != old_major || new_minor != old_minor)) {
 		/* Compare versions and choose the larger version number */
@@ -969,7 +967,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 
  error_exit:
 	if(fsp)
-		close_file(NULL, fsp, NORMAL_CLOSE);
+		close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	ret = -1;
  done:
 	TALLOC_FREE(smb_fname);
@@ -1177,7 +1175,7 @@ static uint32_t get_correct_cversion(const struct auth_session_info *session_inf
 	unbecome_user_without_service();
  error_free_conn:
 	if (fsp != NULL) {
-		close_file(NULL, fsp, NORMAL_CLOSE);
+		close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	}
 	if (!W_ERROR_IS_OK(*perr)) {
 		cversion = -1;
diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
index 770e5d368a8..ea296eaa6ab 100644
--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
@@ -2539,7 +2539,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p,
 error_exit:
 
 	if (fsp) {
-		close_file(NULL, fsp, NORMAL_CLOSE);
+		close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	}
 
 	TALLOC_FREE(frame);
@@ -2659,7 +2659,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p,
 error_exit:
 
 	if (fsp) {
-		close_file(NULL, fsp, NORMAL_CLOSE);
+		close_file_free(NULL, &fsp, NORMAL_CLOSE);
 	}
 
 	TALLOC_FREE(frame);
diff --git a/source3/script/tests/full_audit_segfault/run.sh b/source3/script/tests/full_audit_segfault/run.sh
new file mode 100755
index 00000000000..752b27125c8
--- /dev/null
+++ b/source3/script/tests/full_audit_segfault/run.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+if [ $# -lt 1 ]; then
+cat <<EOF
+Usage: run.sh VFSTEST
+EOF
+exit 1;
+fi
+
+TALLOC_FILL_FREE=0; export TALLOC_FILL_FREE
+
+TESTBASE="$(dirname $0)"
+VFSTEST="$VALGRIND $1"; shift 1;
+ADDARGS="$*"
+
+incdir=`dirname $0`/../../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+failed=0
+
+testit "vfstest" "$VFSTEST" -f "$TESTBASE/vfstest.cmd" "$ADDARGS" ||
+    failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source3/script/tests/full_audit_segfault/vfstest.cmd b/source3/script/tests/full_audit_segfault/vfstest.cmd
new file mode 100644
index 00000000000..84e93e2b157
--- /dev/null
+++ b/source3/script/tests/full_audit_segfault/vfstest.cmd
@@ -0,0 +1,3 @@
+load full_audit
+connect
+create_file .
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 08c8d48ddd5..cab64969491 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -359,6 +359,14 @@ plantestsuite("samba.vfstest.stream_depot", "nt4_dc:local", [os.path.join(samba3
 plantestsuite("samba.vfstest.xattr-tdb-1", "nt4_dc:local", [os.path.join(samba3srcdir, "script/tests/xattr-tdb-1/run.sh"), binpath("vfstest"), "$PREFIX", configuration])
 plantestsuite("samba.vfstest.acl", "nt4_dc:local", [os.path.join(samba3srcdir, "script/tests/vfstest-acl/run.sh"), binpath("vfstest"), "$PREFIX", configuration])
 plantestsuite("samba.vfstest.catia", "nt4_dc:local", [os.path.join(samba3srcdir, "script/tests/vfstest-catia/run.sh"), binpath("vfstest"), "$PREFIX", configuration])
+plantestsuite(
+    "samba.vfstest.full_audit_segfault",
+    "nt4_dc:local",
+    [os.path.join(samba3srcdir,
+                  "script/tests/full_audit_segfault/run.sh"),
+     binpath("vfstest"),
+     "$PREFIX",
+     configuration])
 
 plantestsuite("samba3.blackbox.smbclient_basic.NT1", "nt4_dc_schannel", [os.path.join(samba3srcdir, "script/tests/test_smbclient_basic.sh"), '$SERVER', '$SERVER_IP', '$DC_USERNAME', '$DC_PASSWORD', smbclient3, configuration, "-mNT1"])
 plantestsuite("samba3.blackbox.smbclient_basic.NT1", "nt4_dc_smb1", [os.path.join(samba3srcdir, "script/tests/test_smbclient_basic.sh"), '$SERVER', '$SERVER_IP', '$DC_USERNAME', '$DC_PASSWORD', smbclient3, configuration, "-mNT1"])
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index 8abd3fb3861..206515202e0 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -782,7 +782,6 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
 		DEBUG(10, ("%s disconnected durable handle for file %s\n",
 			   conn->session_info->unix_info->unix_name,
 			   fsp_str_dbg(fsp)));
-		file_free(req, fsp);
 		return NT_STATUS_OK;
 	}
 
@@ -833,7 +832,6 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
 		conn->num_files_open - 1,
 		nt_errstr(status) ));
 
-	file_free(req, fsp);
 	return status;
 }
 /****************************************************************************
@@ -1379,7 +1377,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 	if (lck == NULL) {
 		DEBUG(0, ("close_directory: Could not get share mode lock for "
 			  "%s\n", fsp_str_dbg(fsp)));
-		file_free(req, fsp);
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
@@ -1429,7 +1426,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 			if (!NT_STATUS_IS_OK(status)) {
 				DEBUG(5, ("delete_all_streams failed: %s\n",
 					  nt_errstr(status)));
-				file_free(req, fsp);
 				/* unbecome user. */
 				pop_sec_ctx();
 				return status;
@@ -1472,11 +1468,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 			  strerror(errno)));
 	}
 
-	/*
-	 * Do the code common to files and directories.
-	 */
-	file_free(req, fsp);
-
 	if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
 		status = status1;
 	}
@@ -1484,15 +1475,14 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
 }
 
 /****************************************************************************
- Close a files_struct.
+ Rundown all SMB-related dependencies of a files struct
 ****************************************************************************/
   
-NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
-		    enum file_close_type close_type)
+NTSTATUS close_file_smb(struct smb_request *req,
+			struct files_struct *fsp,
+			enum file_close_type close_type)
 {
 	NTSTATUS status;
-	struct files_struct *base_fsp = fsp->base_fsp;
-	bool close_base_fsp = false;
 
 	/*
 	 * This fsp can never be an internal dirfsp. They must
@@ -1500,44 +1490,10 @@ NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
 	 */
 	SMB_ASSERT(!fsp->fsp_flags.is_dirfsp);
 
-	if (fsp->stream_fsp != NULL) {
-		/*
-		 * fsp is the base for a stream.
-		 *
-		 * We're called with SHUTDOWN_CLOSE from files.c which walks the
-		 * complete list of files.
-		 *
-		 * We need to wait until the stream is closed.
-		 */
-		SMB_ASSERT(close_type == SHUTDOWN_CLOSE);
-		return NT_STATUS_OK;
-	}
-
-	if (base_fsp != NULL) {
-		/*
-		 * We need to remove the link in order to
-		 * recurse for the base fsp below.
-		 */
-		SMB_ASSERT(base_fsp->base_fsp == NULL);
-		SMB_ASSERT(base_fsp->stream_fsp == fsp);
-		base_fsp->stream_fsp = NULL;
-
-		if (close_type == SHUTDOWN_CLOSE) {
-			/*
-			 * We're called with SHUTDOWN_CLOSE from files.c
-			 * which walks the complete list of files.
-			 *
-			 * We may need to defer the SHUTDOWN_CLOSE
-			 * if it's the next in the linked list.
-			 *
-			 * So we only close if the base is *not* the
-			 * next in the list.
-			 */
-			close_base_fsp = (fsp->next != base_fsp);
-		} else {
-			close_base_fsp = true;
-		}
-	}
+	/*
+	 * Never call directly on a base fsp
+	 */
+	SMB_ASSERT(fsp->stream_fsp == NULL);
 
 	if (fsp->fake_file_handle != NULL) {
 		status = close_fake_file(req, fsp);
@@ -1545,7 +1501,6 @@ NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
 		/* FIXME: return spool errors */
 		print_spool_end(fsp, close_type);
 		fd_close(fsp);
-		file_free(req, fsp);
 		status = NT_STATUS_OK;
 	} else if (!fsp->fsp_flags.is_fsa) {
 		if (close_type == NORMAL_CLOSE) {
@@ -1558,7 +1513,6 @@ NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
 		}
 		SMB_ASSERT(close_type != NORMAL_CLOSE);
 		fd_close(fsp);
-		file_free(req, fsp);
 		status = NT_STATUS_OK;
 	} else if (fsp->fsp_flags.is_directory) {
 		status = close_directory(req, fsp, close_type);
@@ -1566,21 +1520,43 @@ NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
 		status = close_normal_file(req, fsp, close_type);
 	}
 
-	if (close_base_fsp) {
+	if (fsp->base_fsp != NULL) {
+		/*
+		 * fsp was a stream, its base_fsp can't be a stream
+		 * as well
+		 */
+		SMB_ASSERT(fsp->base_fsp->base_fsp == NULL);
+
+		/*
+		 * There's a 1:1 relationship between fsp and a base_fsp
+		 */
+		SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
 
 		/*
-		 * fsp was a stream, the base fsp can't be a stream as well
-		 *
-		 * For SHUTDOWN_CLOSE this is not possible here
-		 * (if the base_fsp was the next in the linked list), because
-		 * SHUTDOWN_CLOSE only happens from files.c which walks the
-		 * complete list of files. If we mess with more than one fsp
-		 * those loops will become confused.
+		 * Make base_fsp look standalone now
 		 */
+		fsp->base_fsp->stream_fsp = NULL;
 
-		close_file(req, base_fsp, close_type);
+		close_file_free(req, &fsp->base_fsp, close_type);
 	}
 
+	fsp_unbind_smb(req, fsp);
+
+	return status;
+}
+
+NTSTATUS close_file_free(struct smb_request *req,
+			 struct files_struct **_fsp,
+			 enum file_close_type close_type)
+{
+	struct files_struct *fsp = *_fsp;
+	NTSTATUS status;
+
+	status = close_file_smb(req, fsp, close_type);
+
+	file_free(req, fsp);
+        *_fsp = NULL;
+
 	return status;
 }
 
@@ -1619,5 +1595,5 @@ void msg_close_file(struct messaging_context *msg_ctx,
 		DEBUG(10,("msg_close_file: failed to find file.\n"));
 		return;
 	}
-	close_file(NULL, fsp, NORMAL_CLOSE);
+	close_file_free(NULL, &fsp, NORMAL_CLOSE);
 }
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 8e5ce66c961..581ce5202ed 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -185,9 +185,12 @@ void dptr_closecnum(connection_struct *conn)
 	for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
 		next = dptr->next;
 		if (dptr->conn == conn) {
-			files_struct *fsp = dptr->dir_hnd->fsp;
-			close_file(NULL, fsp, NORMAL_CLOSE);
-			fsp = NULL;
+			/*
+			 * Need to make a copy, "dptr" will be gone
+			 * after close_file_free() returns
+			 */
+			struct files_struct *fsp = dptr->dir_hnd->fsp;
+			close_file_free(NULL, &fsp, NORMAL_CLOSE);
 		}
 	}
 }
diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c
index 92ea14a76da..5d669bfe8e5 100644
--- a/source3/smbd/fake_file.c
+++ b/source3/smbd/fake_file.c
@@ -206,6 +206,8 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn,
 
 NTSTATUS close_fake_file(struct smb_request *req, files_struct *fsp)
 {
-	file_free(req, fsp);
+	/*
+	 * Nothing to do, fake files don't hold any resources
+	 */
 	return NT_STATUS_OK;
 }
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 4113779f963..3fc1992ce4d 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -759,26 +759,97 @@ NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
+static bool close_file_in_loop(struct files_struct *fsp)
+{


-- 
Samba Shared Repository



More information about the samba-cvs mailing list