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