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 <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>
    
    Autobuild-User(master): Jeremy Allison <j...@samba.org>
    Autobuild-Date(master): Thu Feb 10 19:11:33 UTC 2022 on sn-devel-184

commit e91b59c4dfb2b35661dbecbc5769584109e23571
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit e751c6237b750adb4cb59df4a42bb9f39354e7e4
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 5f1ceead7094aefc6ad1f209468e9ea8f009716c
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 93fe9c83145d31ea11a9cd25049ac527ad4a000d
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 1fbd9877fead466a17d697c143cd370c0b27f610
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 61f57ba24ee2e54abf224118f93bd0ccda44ec41
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit d1341d666af12965b4318f89b1d0e1e8769e861e
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit f5bc73a2ad97647f76143f7962c964f45aa6b1a0
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 363ac7533895fda786f56c4fe8346128753f38a5
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 244c5a7d31c3a37082b320680f2b71108d77bbd4
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 2293ca5b572178404273856f8d8989a5ee7de80c
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 9966b5e233ef2ff0368ba5860c824c7cd6420415
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 1c1734974fcf1d060bc6bcdbe1858cba1b7e5a73
Author: Volker Lendecke <v...@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 <v...@samba.org>
    Reviewed-by: Jeremy Allison <j...@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

Reply via email to