The branch, master has been updated
       via  95e1998a4a8 tests: Check symlinks are readable as reparse points
       via  34be8ef5962 smbd: Return NT_STATUS_STOPPED_ON_SYMLINK
       via  cc0ed15fecc smbd: Always init symlink_err in 
filename_convert_dirfsp_nosymlink()
       via  239df72787f smbd: Create the proper error blob for 
STOPPED_ON_SYMLINK
       via  2065778b5cd smbd: Prepare smbd_smb2_create_recv() to return a 
symlink error
       via  647b711e4e1 tests: Fix test_symlinkerror_absolute_inshare
       via  63d877342a2 tests: Reparse point dirs are shown as 
REPARSE_POINT|DIRECTORY
       via  70f424657f0 tests: Reparse point files are shown as 
FILE_ATTRIBUTE_REPARSE_POINT
       via  ed239d3f297 smbd: Allow a symlink as lcomp when asking for 
REPARSE_POINT
       via  0d8b71f0b6c smbd: Fix the turning an absolute symlink into a 
relative one
       via  259517d7aec smbd: Set fsp->fsp_flags.posix_open in 
openat_pathref_fsp_lcomp()
       via  4a46c6a8827 smbd: Allow symlinks to be read via GET_REPARSE_POINT
       via  c87269f528a smbd: Prepare fdos_mode() for handling symlinks in smb2
       via  61259bf9aab libsmb: Retry the open with OPEN_REPARSE_POINT on 
IO_REPARSE_TAG_NOT_HANDLED
       via  079d95da0bb smbd: Make filename_convert_dirfsp_nosymlink() public
       via  76f51569061 smbd: Revert "smbd: Simplify filename_convert_dirfsp()"
       via  ec64f81df92 smbd: Pass "create_options" to 
filename_create_ucf_flags()
      from  fee31b6cb2b ctdb-common: Map ENOENT for a missing event script to 
ENOEXEC

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


- Log -----------------------------------------------------------------
commit 95e1998a4a853287563b6eb84a3ca4a18d9fe271
Author: Volker Lendecke <v...@samba.org>
Date:   Wed May 17 10:54:49 2023 +0200

    tests: Check symlinks are readable as reparse points
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>
    
    Autobuild-User(master): Ralph Böhme <s...@samba.org>
    Autobuild-Date(master): Fri Nov 22 11:05:33 UTC 2024 on atb-devel-224

commit 34be8ef596291686e35e90e00c4da99de6cd55f3
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Nov 20 12:56:33 2024 +0100

    smbd: Return NT_STATUS_STOPPED_ON_SYMLINK
    
    Do this for "follow symlinks = now" and smb2 unix extensions
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit cc0ed15feccfed8748619d0ee309f12dbe4f77e0
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Nov 20 12:54:05 2024 +0100

    smbd: Always init symlink_err in filename_convert_dirfsp_nosymlink()
    
    Make sure that we don't leave symlink_err in the caller
    uninitialized.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 239df72787f4680b39d2f2a4a0d5be9feb34ad6d
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Nov 20 11:13:12 2024 +0100

    smbd: Create the proper error blob for STOPPED_ON_SYMLINK
    
    Unused so far, our lowerlevel routines so far never return
    NT_STATUS_STOPPED_ON_SYMLINK. Also see the NULL passed as
    "symlink_reparse", this will change soon. Separate patch for easier
    review.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 2065778b5cdcfa20b5a667f5bdc551c22393ce90
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Nov 20 13:18:25 2024 +0100

    smbd: Prepare smbd_smb2_create_recv() to return a symlink error
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 647b711e4e11c70a16be542be34e3c4b999664e0
Author: Volker Lendecke <v...@samba.org>
Date:   Tue May 16 17:32:28 2023 +0200

    tests: Fix test_symlinkerror_absolute_inshare
    
    This tests converting an absolute into a relative target. Reflect that
    in the flags expected from the STOPPED_ON_SYMLINK error response.
    
    As of this patch it's still knownfail, so irrelevant. But soon this test 
will
    succeed.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 63d877342a2772eab9ad9f601fe9554cbdc6a329
Author: Volker Lendecke <v...@samba.org>
Date:   Mon Jan 9 18:30:05 2023 +0100

    tests: Reparse point dirs are shown as REPARSE_POINT|DIRECTORY
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 70f424657f0b846ed51ae55287e3a715e086534d
Author: Volker Lendecke <v...@samba.org>
Date:   Mon Jan 9 18:24:23 2023 +0100

    tests: Reparse point files are shown as FILE_ATTRIBUTE_REPARSE_POINT
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit ed239d3f297b6ea4dc64ed9818ebc6ca2720753e
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Nov 20 12:02:54 2024 +0100

    smbd: Allow a symlink as lcomp when asking for REPARSE_POINT
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 0d8b71f0b6c953d031caff0c37a309646dc57c57
Author: Volker Lendecke <v...@samba.org>
Date:   Sun Feb 4 11:45:22 2024 +0100

    smbd: Fix the turning an absolute symlink into a relative one
    
    If dirfsp is the share root, we end up with a "/." at the end of
    subdir_path. subdir_of() does not cover that case. fsp_fullbasepath()
    takes care of that case and also avoids a talloc.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 259517d7aec73280b7e02f3695f826561e76f82f
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Jan 31 19:48:48 2024 +0100

    smbd: Set fsp->fsp_flags.posix_open in openat_pathref_fsp_lcomp()
    
    Not sure why this wasn't caught as a bug yet...
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 4a46c6a88273ea765b142299d6cf33d5ec93588a
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Dec 21 16:42:12 2022 +0100

    smbd: Allow symlinks to be read via GET_REPARSE_POINT
    
    ... to be used soon
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit c87269f528ae7758ed8b5a793d724596ab35a697
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Nov 19 15:35:58 2024 +0100

    smbd: Prepare fdos_mode() for handling symlinks in smb2
    
    We should show all special files as NORMAL|REPARSE_POINT, except
    symlinks for SMB1 Posix Extensions. IFREG and IFDIR are handled via
    our xattr mechanisms.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 61259bf9aabfa1d207b3d4bfeac0860f54f5cd4d
Author: Volker Lendecke <v...@samba.org>
Date:   Wed May 3 16:44:34 2023 +0200

    libsmb: Retry the open with OPEN_REPARSE_POINT on IO_REPARSE_TAG_NOT_HANDLED
    
    If we get that error message, we want to look at the reparse point as
    such. This does not affect normal files, but soon we will need it in
    our tests.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 079d95da0bb190c9b26fde46aef53eacd3eff72e
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Dec 16 16:35:00 2022 +0100

    smbd: Make filename_convert_dirfsp_nosymlink() public
    
    To be used directly in smb2_create.c
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit 76f5156906139559d4414fe9bf1b4938780000c5
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Nov 19 11:48:12 2024 +0100

    smbd: Revert "smbd: Simplify filename_convert_dirfsp()"
    
    This reverts commit bd30c9c128c203c3ed4b123b651862a9953f6cf2.
    
    While this does indeed slightly simplify code, it simplifies too much: Soon 
we
    will need filename_convert_dirfsp_nosymlink raw without looking at
    UCF_LCOMP_LNK_OK. So in hindsight this went too far.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

commit ec64f81df92355e0e48cd774f4bc54192b0f0074
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Feb 2 21:16:46 2024 +0100

    smbd: Pass "create_options" to filename_create_ucf_flags()
    
    OPEN_REPARSE_POINT will trigger symlinks not being followed but
    returned, even if we have "follow symlinks = yes". Prepare for setting
    UCF_LCOMP_LNK_OK for this case in a central place.
    
    Signed-off-by: Volker Lendecke <v...@samba.org>
    Reviewed-by: Ralph Boehme <s...@samba.org>

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

Summary of changes:
 python/samba/tests/reparsepoints.py       |  13 ++
 python/samba/tests/smb2symlink.py         |  43 +++--
 selftest/knownfail.d/symlink              |   4 -
 source3/include/proto.h                   |  12 ++
 source3/libsmb/cli_smb2_fnum.c            |  78 +++++++-
 source3/modules/util_reparse.c            |  44 +++++
 source3/script/tests/test_smbclient_s3.sh |  10 +-
 source3/smbd/dosmode.c                    |  26 ++-
 source3/smbd/filename.c                   |  59 +++---
 source3/smbd/files.c                      |  15 +-
 source3/smbd/open.c                       |  34 ++--
 source3/smbd/proto.h                      |   4 +-
 source3/smbd/smb1_nttrans.c               |   8 +-
 source3/smbd/smb1_reply.c                 |  16 +-
 source3/smbd/smb2_create.c                | 286 ++++++++++++++++++++++++++++--
 15 files changed, 537 insertions(+), 115 deletions(-)
 delete mode 100644 selftest/knownfail.d/symlink


Changeset truncated at 500 lines:

diff --git a/python/samba/tests/reparsepoints.py 
b/python/samba/tests/reparsepoints.py
index a8d506d48d6..40d7de3f63b 100644
--- a/python/samba/tests/reparsepoints.py
+++ b/python/samba/tests/reparsepoints.py
@@ -198,6 +198,10 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
         conn.close(fd)
 
         dirents = conn.list("", filename)
+        self.assertEqual(
+            dirents[0]["attrib"],
+            libsmb.FILE_ATTRIBUTE_REPARSE_POINT|
+            libsmb.FILE_ATTRIBUTE_ARCHIVE)
         self.assertEqual(
             dirents[0]["reparse_tag"],
             libsmb.IO_REPARSE_TAG_SYMLINK)
@@ -247,6 +251,15 @@ class ReparsePoints(samba.tests.libsmb.LibsmbTests):
         conn.delete_on_close(dir_fd, 1)
         conn.close(dir_fd)
 
+        dirents = conn.list("", dirname)
+        self.assertEqual(
+            dirents[0]["attrib"],
+            libsmb.FILE_ATTRIBUTE_REPARSE_POINT|
+            libsmb.FILE_ATTRIBUTE_DIRECTORY)
+        self.assertEqual(dirents[0]["reparse_tag"], 0x80000025)
+
+        self.clean_file(conn, dirname)
+
     # Only empty directories can carry reparse points
 
     def test_create_reparse_nonempty_directory(self):
diff --git a/python/samba/tests/smb2symlink.py 
b/python/samba/tests/smb2symlink.py
index a2b34aee639..f9cd4a23cd6 100644
--- a/python/samba/tests/smb2symlink.py
+++ b/python/samba/tests/smb2symlink.py
@@ -55,13 +55,19 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
             self.creds)
         return (smb1, smb2)
 
-    def create_symlink(self, conn, target, symlink):
-        self.clean_file(conn, symlink)
-        if (conn.protocol() < libsmb.PROTOCOL_SMB2_02 and conn.have_posix()):
-            conn.smb1_symlink(target, symlink)
+    def create_symlink(self, conn1, conn2, target, symlink,
+                       expect_tgt=None):
+
+        if expect_tgt is None:
+            expect_tgt = target
+
+        self.clean_file(conn1, symlink)
+        if (conn1.protocol() < libsmb.PROTOCOL_SMB2_02 and
+            conn1.have_posix()):
+            conn1.smb1_symlink(target, symlink)
         else:
             flags = 0 if target[0]=='/' else 1
-            syml = conn.create(
+            syml = conn1.create(
                 symlink,
                 DesiredAccess=sec.SEC_FILE_READ_ATTRIBUTE|
                 sec.SEC_FILE_WRITE_ATTRIBUTE|
@@ -70,8 +76,19 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
                 CreateDisposition=libsmb.FILE_OPEN_IF,
                 CreateOptions=libsmb.FILE_OPEN_REPARSE_POINT)
             b = reparse_symlink.symlink_put(target, target, 0, 1)
-            conn.fsctl(syml, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
-            conn.close(syml)
+            conn1.fsctl(syml, libsmb.FSCTL_SET_REPARSE_POINT, b, 0)
+            conn1.close(syml)
+
+        fd = conn2.create(symlink,
+                          DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE,
+                          CreateOptions=libsmb.FILE_OPEN_REPARSE_POINT,
+                          CreateDisposition=libsmb.FILE_OPEN)
+        blob = conn2.fsctl(fd, libsmb.FSCTL_GET_REPARSE_POINT, b'', 1024)
+        conn2.close(fd)
+
+        (tag,(subst,_,_,_)) = reparse_symlink.get(blob)
+        self.assertEqual(tag, "IO_REPARSE_TAG_SYMLINK")
+        self.assertEqual(expect_tgt, subst)
 
     def assert_symlink_exception(self, e, expect):
         self.assertEqual(e.args[0], ntstatus.NT_STATUS_STOPPED_ON_SYMLINK)
@@ -91,7 +108,7 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
         target="foo"
         suffix="bar"
 
-        self.create_symlink(smb1, target, symlink)
+        self.create_symlink(smb1, smb2, target, symlink);
 
         with self.assertRaises(NTSTATUSError) as e:
             fd = smb2.create_ex(f'{symlink}\\{suffix}')
@@ -111,7 +128,7 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
         symlink="syml"
         target="foo"
 
-        self.create_symlink(smb1, target, symlink)
+        self.create_symlink(smb1, smb2, target, symlink);
 
         with self.assertRaises(NTSTATUSError) as e:
             fd = smb2.create_ex(f'{symlink}')
@@ -135,7 +152,7 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
 
         for target in ["/etc", "//foo/bar", "/"]:
 
-            self.create_symlink(smb1, target, symlink)
+            self.create_symlink(smb1, smb2, target, symlink)
 
             with self.assertRaises(NTSTATUSError) as e:
                 fd = smb2.create_ex(f'{symlink}')
@@ -159,7 +176,7 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
         rel_dest="dst"
         target=f'{shareroot}/{rel_dest}'
 
-        self.create_symlink(smb1, target, symlink)
+        self.create_symlink(smb1, smb2, target, symlink, rel_dest)
 
         with self.assertRaises(NTSTATUSError) as e:
             fd = smb2.create_ex(f'{symlink}')
@@ -169,7 +186,7 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
             { 'unparsed_path_length' : 0,
               'substitute_name' : rel_dest,
               'print_name' : rel_dest,
-              'flags' : 0 })
+              'flags' : 1 })
 
         self.clean_file(smb1, symlink)
 
@@ -199,7 +216,7 @@ class Smb2SymlinkTests(samba.tests.libsmb.LibsmbTests):
         smb1.mkdir("sub")
         self.addCleanup(self.clean_file, smb1, "sub")
 
-        self.create_symlink(smb1, f'{localpath}/sub1', "sub/lnk")
+        self.create_symlink(smb1, smb2, f'{localpath}/sub1', "sub/lnk")
         self.addCleanup(self.clean_file, smb1, "sub/lnk")
 
         smb1.mkdir("sub1")
diff --git a/selftest/knownfail.d/symlink b/selftest/knownfail.d/symlink
deleted file mode 100644
index 64135666aec..00000000000
--- a/selftest/knownfail.d/symlink
+++ /dev/null
@@ -1,4 +0,0 @@
-^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_directory
-^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_file
-^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_absolute_outside_share
-^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_absolute_inshare
diff --git a/source3/include/proto.h b/source3/include/proto.h
index ee28afa6a56..8b446fa9f9e 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -713,6 +713,18 @@ NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
                                  const char *target,
                                  size_t unparsed,
                                  char **_relative);
+struct reparse_data_buffer;
+NTSTATUS
+filename_convert_dirfsp_nosymlink(TALLOC_CTX *mem_ctx,
+                                 connection_struct *conn,
+                                 struct files_struct *basedir,
+                                 const char *name_in,
+                                 uint32_t ucf_flags,
+                                 NTTIME twrp,
+                                 struct files_struct **_dirfsp,
+                                 struct smb_filename **_smb_fname,
+                                 struct smb_filename **_smb_fname_rel,
+                                 struct reparse_data_buffer **_symlink_err);
 NTSTATUS filename_convert_dirfsp_rel(TALLOC_CTX *mem_ctx,
                                     connection_struct *conn,
                                     struct files_struct *basedir,
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 95b4385bc9f..f9a82089709 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -204,7 +204,16 @@ static char *smb2_dfs_share_path(TALLOC_CTX *ctx,
 ***************************************************************/
 
 struct cli_smb2_create_fnum_state {
+       struct tevent_context *ev;
        struct cli_state *cli;
+       char *fname;
+       struct cli_smb2_create_flags create_flags;
+       uint32_t impersonation_level;
+       uint32_t desired_access;
+       uint32_t file_attributes;
+       uint32_t share_access;
+       uint32_t create_disposition;
+       uint32_t create_options;
        struct smb2_create_blobs in_cblobs;
        struct smb2_create_blobs out_cblobs;
        struct smb_create_returns cr;
@@ -243,17 +252,25 @@ struct tevent_req *cli_smb2_create_fnum_send(
        if (req == NULL) {
                return NULL;
        }
+       state->ev = ev;
        state->cli = cli;
+       state->create_flags = create_flags;
+       state->impersonation_level = impersonation_level;
+       state->desired_access = desired_access;
+       state->file_attributes = file_attributes;
+       state->share_access = share_access;
+       state->create_disposition = create_disposition;
+
+       if (cli->backup_intent) {
+               create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
+       }
+       state->create_options = create_options;
 
        fname = talloc_strdup(state, fname_in);
        if (tevent_req_nomem(fname, req)) {
                return tevent_req_post(req, ev);
        }
 
-       if (cli->backup_intent) {
-               create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
-       }
-
        if (cli->smb2.client_smb311_posix) {
                uint8_t modebuf[4] = {
                        0,
@@ -316,15 +333,21 @@ struct tevent_req *cli_smb2_create_fnum_send(
 
        /* Or end in a '\' */
        if (fname_len > 0 && fname[fname_len-1] == '\\') {
-               fname[fname_len-1] = '\0';
+               fname_len -= 1;
        }
 
-       subreq = smb2cli_create_send(state, ev,
+       state->fname = talloc_strndup(state, fname, fname_len);
+       if (tevent_req_nomem(state->fname, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = smb2cli_create_send(state,
+                                    ev,
                                     cli->conn,
                                     cli->timeout,
                                     cli->smb2.session,
                                     cli->smb2.tcon,
-                                    fname,
+                                    state->fname,
                                     flags_to_smb2_oplock(create_flags),
                                     impersonation_level,
                                     desired_access,
@@ -352,6 +375,7 @@ static void cli_smb2_create_fnum_done(struct tevent_req 
*subreq)
                req, struct cli_smb2_create_fnum_state);
        uint64_t fid_persistent, fid_volatile;
        struct smb2_create_blob *posix = NULL;
+       struct cli_state *cli = state->cli;
        NTSTATUS status;
 
        status = smb2cli_create_recv(subreq,
@@ -362,6 +386,46 @@ static void cli_smb2_create_fnum_done(struct tevent_req 
*subreq)
                                     &state->out_cblobs,
                                     &state->symlink);
        TALLOC_FREE(subreq);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
+
+               if (state->create_options & FILE_OPEN_REPARSE_POINT) {
+                       /*
+                        * Should not happen, but you never know...
+                        */
+                       tevent_req_nterror(
+                               req, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED);
+                       return;
+               }
+
+               state->create_options |= FILE_OPEN_REPARSE_POINT;
+
+               subreq = smb2cli_create_send(state,
+                                            state->ev,
+                                            cli->conn,
+                                            cli->timeout,
+                                            cli->smb2.session,
+                                            cli->smb2.tcon,
+                                            state->fname,
+                                            flags_to_smb2_oplock(
+                                                    state->create_flags),
+                                            state->impersonation_level,
+                                            state->desired_access,
+                                            state->file_attributes,
+                                            state->share_access,
+                                            state->create_disposition,
+                                            state->create_options,
+                                            &state->in_cblobs);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+               tevent_req_set_callback(subreq,
+                                       cli_smb2_create_fnum_done,
+                                       req);
+               state->subreq = subreq;
+               return;
+       }
+
        if (tevent_req_nterror(req, status)) {
                return;
        }
diff --git a/source3/modules/util_reparse.c b/source3/modules/util_reparse.c
index 2694410be4f..60373d7fd4e 100644
--- a/source3/modules/util_reparse.c
+++ b/source3/modules/util_reparse.c
@@ -154,6 +154,45 @@ static NTSTATUS fsctl_get_reparse_point_dev(struct 
files_struct *fsp,
                fsp, &reparse_data, ctx, _out_data, max_out_len, _out_len);
 }
 
+static NTSTATUS fsctl_get_reparse_point_lnk(struct files_struct *fsp,
+                                           TALLOC_CTX *mem_ctx,
+                                           uint8_t **_out_data,
+                                           uint32_t max_out_len,
+                                           uint32_t *_out_len)
+{
+       struct reparse_data_buffer *reparse = NULL;
+       struct smb_filename *parent_fname = NULL;
+       struct smb_filename *base_name = NULL;
+       NTSTATUS status;
+
+       status = parent_pathref(talloc_tos(),
+                               fsp->conn->cwd_fsp,
+                               fsp->fsp_name,
+                               &parent_fname,
+                               &base_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("parent_pathref(%s) failed: %s\n",
+                         fsp_str_dbg(fsp),
+                         nt_errstr(status));
+               return status;
+       }
+
+       status = read_symlink_reparse(talloc_tos(),
+                                     parent_fname->fsp,
+                                     base_name,
+                                     &reparse);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("read_symlink_reparse failed: %s\n",
+                         nt_errstr(status));
+               return status;
+       }
+
+       status = fsctl_get_reparse_point_int(
+               fsp, reparse, mem_ctx, _out_data, max_out_len, _out_len);
+       TALLOC_FREE(reparse);
+       return status;
+}
+
 NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
                                 TALLOC_CTX *mem_ctx,
                                 uint32_t *_reparse_tag,
@@ -212,6 +251,11 @@ NTSTATUS fsctl_get_reparse_point(struct files_struct *fsp,
                        max_out_len,
                        &out_len);
                break;
+       case S_IFLNK:
+               DBG_DEBUG("%s is a symlink\n", fsp_str_dbg(fsp));
+               status = fsctl_get_reparse_point_lnk(
+                       fsp, mem_ctx, &out_data, max_out_len, &out_len);
+               break;
        default:
                break;
        }
diff --git a/source3/script/tests/test_smbclient_s3.sh 
b/source3/script/tests/test_smbclient_s3.sh
index cbff5026ee7..35a283a8546 100755
--- a/source3/script/tests/test_smbclient_s3.sh
+++ b/source3/script/tests/test_smbclient_s3.sh
@@ -1343,11 +1343,17 @@ EOF
                return 1
        fi
 
-       echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND'
+       if [ "$PROTOCOL" = "SMB3" ]; then
+           expected_error="NT_STATUS_STOPPED_ON_SYMLINK"
+       else
+           expected_error="NT_STATUS_OBJECT_NAME_NOT_FOUND"
+       fi
+
+       echo "$out" | grep "$expected_error"
        ret=$?
        if [ $ret -ne 0 ]; then
                echo "$out"
-               echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND 
getting \\nosymlinks\\source"
+               echo "failed - should get ${expected_error} getting 
\\nosymlinks\\source"
                return 1
        fi
 
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index f39f8a7d15b..0de348883e4 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -721,16 +721,28 @@ uint32_t fdos_mode(struct files_struct *fsp)
        }
 
        switch (fsp->fsp_name->st.st_ex_mode & S_IFMT) {
-       case S_IFLNK:
-               return FILE_ATTRIBUTE_NORMAL;
+       case S_IFREG:
+       case S_IFDIR:
                break;
-       case S_IFIFO:
-       case S_IFSOCK:
-       case S_IFBLK:
-       case S_IFCHR:
-               return FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_REPARSE_POINT;
+       case S_IFLNK:
+               if (fsp->fsp_flags.posix_open &&
+                   !conn_using_smb2(fsp->conn->sconn)) {
+                       /*
+                        * SMB1 posix doesn't like the reparse point flag
+                        */
+                       result = FILE_ATTRIBUTE_NORMAL;
+               } else {
+                       /*
+                        * Everybody else wants to see symlinks as
+                        * reparse points
+                        */
+                       result = FILE_ATTRIBUTE_NORMAL |
+                                FILE_ATTRIBUTE_REPARSE_POINT;
+               }
+
                break;
        default:
+               return FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_REPARSE_POINT;
                break;
        }
 
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 0c2e365c239..554df2fd1f8 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -41,11 +41,7 @@ uint32_t ucf_flags_from_smb_request(struct smb_request *req)
        }
 
        if (req->posix_pathnames) {
-               ucf_flags |= UCF_POSIX_PATHNAMES;
-
-               if (!conn_using_smb2(req->sconn)) {
-                       ucf_flags |= UCF_LCOMP_LNK_OK;
-               }
+               ucf_flags |= (UCF_POSIX_PATHNAMES|UCF_LCOMP_LNK_OK);
        }
        if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
                ucf_flags |= UCF_DFS_PATHNAME;
@@ -57,7 +53,9 @@ uint32_t ucf_flags_from_smb_request(struct smb_request *req)
        return ucf_flags;
 }
 
-uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t 
create_disposition)
+uint32_t filename_create_ucf_flags(struct smb_request *req,
+                                  uint32_t create_disposition,
+                                  uint32_t create_options)
 {
        uint32_t ucf_flags = 0;
 
@@ -75,6 +73,10 @@ uint32_t filename_create_ucf_flags(struct smb_request *req, 
uint32_t create_disp
                break;
        }
 
+       if (create_options & FILE_OPEN_REPARSE_POINT) {
+               ucf_flags |= UCF_LCOMP_LNK_OK;
+       }
+
        return ucf_flags;
 }
 
@@ -664,17 +666,17 @@ fail:
  * Split up name_in as sent by the client into a directory pathref fsp
  * and a relative smb_filename.
  */
-static NTSTATUS filename_convert_dirfsp_nosymlink(
-       TALLOC_CTX *mem_ctx,
-       connection_struct *conn,
-       struct files_struct *basedir,
-       const char *name_in,
-       uint32_t ucf_flags,
-       NTTIME twrp,
-       struct files_struct **_dirfsp,
-       struct smb_filename **_smb_fname,
-       struct smb_filename **_smb_fname_rel,
-       struct reparse_data_buffer **_symlink_err)
+NTSTATUS
+filename_convert_dirfsp_nosymlink(TALLOC_CTX *mem_ctx,
+                                 connection_struct *conn,
+                                 struct files_struct *basedir,
+                                 const char *name_in,
+                                 uint32_t ucf_flags,
+                                 NTTIME twrp,
+                                 struct files_struct **_dirfsp,
+                                 struct smb_filename **_smb_fname,
+                                 struct smb_filename **_smb_fname_rel,
+                                 struct reparse_data_buffer **_symlink_err)
 {
        struct smb_filename *smb_dirname = NULL;
        struct smb_filename *smb_fname_rel = NULL;
@@ -802,8 +804,6 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
                        }
 
                        lnk->unparsed_path_length = unparsed;
-                       *_symlink_err = symlink_err;
-


-- 
Samba Shared Repository

Reply via email to