]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: don't return NT_STATUS_STOPPED_ON_SYMLINK in openat_pathref_fsp()
authorRalph Boehme <slow@samba.org>
Tue, 2 Feb 2021 10:18:54 +0000 (11:18 +0100)
committerRalph Boehme <slow@samba.org>
Fri, 5 Feb 2021 06:22:35 +0000 (06:22 +0000)
NT_STATUS_STOPPED_ON_SYMLINK is returned when trying to open a symlink, most
callers are not interested in this.

Some callers that would want to know whether openat_pathref_fsp() failed
specifically on a symlink are setup_close_full_information(),
smbd_dirptr_get_entry(), unlink_internals() and filename_convert_internal(), so
we fix those callers to handle the symlink case themselves.

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/dir.c
source3/smbd/filename.c
source3/smbd/files.c
source3/smbd/reply.c
source3/smbd/smb2_close.c

index d7b1363205ccb49444f0a00f64162e5f9a191428..9d5244e3c4e51a707adac0c54efd86839e36b052 100644 (file)
@@ -936,44 +936,25 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
                 */
                status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname);
                if (!NT_STATUS_IS_OK(status) &&
-                   !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
-                   !NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
+                   !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
                {
                        TALLOC_FREE(atname);
                        TALLOC_FREE(dname);
                        TALLOC_FREE(fname);
                        TALLOC_FREE(smb_fname);
                        continue;
-               } else if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+               } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
                        if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) {
-                               TALLOC_FREE(atname);
-                               TALLOC_FREE(dname);
-                               TALLOC_FREE(fname);
-                               TALLOC_FREE(smb_fname);
-                               continue;
+                               check_dfs_symlink = true;
                        }
                        /*
-                        * It's a symlink, disable getting dosmode in the
-                        * mode_fn() and prime the mode as
-                        * FILE_ATTRIBUTE_NORMAL.
+                        * Check if it's a symlink. We only want to return this
+                        * if it's a DFS symlink or in POSIX mode. Disable
+                        * getting dosmode in the mode_fn() and prime the mode
+                        * as FILE_ATTRIBUTE_NORMAL.
                         */
                        mode = FILE_ATTRIBUTE_NORMAL;
                        get_dosmode = false;
-               } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-                       if (atname->flags & SMB_FILENAME_POSIX_PATH) {
-                               TALLOC_FREE(atname);
-                               TALLOC_FREE(dname);
-                               TALLOC_FREE(fname);
-                               TALLOC_FREE(smb_fname);
-                               continue;
-                       }
-                       /*
-                        * Likely a dangling symlink. We only want to return
-                        * this if it's a DFS symlink, so we need to check for
-                        * that. Set get_dosmode to skip getting dosmode.
-                        */
-                       get_dosmode = false;
-                       check_dfs_symlink = true;
                }
 
                status = move_smb_fname_fsp_link(smb_fname, atname);
index 184a293f2055d7f180e7598bddb6bb6441672e9c..9035c7e82c72cba90dfd55db319508d0cb3fc481 100644 (file)
@@ -1982,14 +1982,9 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
        }
 
        status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
                /*
-                * Don't leak NT_STATUS_STOPPED_ON_SYMLINK into the callers:
-                * it's a special SMB2 error that needs an extended SMB2 error
-                * response. We don't support that for SMB2 and it doesn't exist
-                * at all in SMB1.
-                *
-                * So we deal with symlinks here as we do in
+                * We deal with symlinks here as we do in
                 * SMB_VFS_CREATE_FILE(): return success for POSIX clients with
                 * the notable difference that there will be no fsp in
                 * smb_fname->fsp.
@@ -1997,10 +1992,10 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
                 * For Windows (non POSIX) clients fail with
                 * NT_STATUS_OBJECT_NAME_NOT_FOUND.
                 */
-               if (ucf_flags & UCF_POSIX_PATHNAMES) {
+               if (smb_fname->flags & SMB_FILENAME_POSIX_PATH &&
+                   S_ISLNK(smb_fname->st.st_ex_mode))
+               {
                        status = NT_STATUS_OK;
-               } else {
-                       status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                }
        }
        if (!NT_STATUS_IS_OK(status)) {
index e3e02e5dad1cf965978c9237b0114ab3b1c5e674..83ccb332bf478e2fd74ffa9a0858b53948ad5b4a 100644 (file)
@@ -456,7 +456,7 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
        }
 
        if (S_ISLNK(smb_fname->st.st_ex_mode)) {
-               return NT_STATUS_STOPPED_ON_SYMLINK;
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
        status = fsp_new(conn, conn, &fsp);
@@ -503,7 +503,8 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
        status = fd_openat(dirfsp, smb_fname, fsp, open_flags, 0);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ||
-                   NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND))
+                   NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
+                   NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
                {
                        /*
                         * streams_xattr return NT_STATUS_NOT_FOUND for
@@ -515,6 +516,10 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
                         *
                         * NT_STATUS_OBJECT_NAME_NOT_FOUND is the simple
                         * ENOENT case.
+                        *
+                        * NT_STATUS_STOPPED_ON_SYMLINK is returned when trying
+                        * to open a symlink, our callers are not interested in
+                        * this.
                         */
                        status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                }
index a09e11e84937a46379fe547dc10a0afe32bbfed2..c9820df2bb5417f9b6ea61ed2a55cf845e509ea8 100644 (file)
@@ -3468,9 +3468,13 @@ NTSTATUS unlink_internals(connection_struct *conn,
                        }
 
                        status = openat_pathref_fsp(conn->cwd_fsp, f);
-                       if (!NT_STATUS_IS_OK(status) &&
-                           !NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+                           (f->flags & SMB_FILENAME_POSIX_PATH) &&
+                           S_ISLNK(f->st.st_ex_mode))
                        {
+                               status = NT_STATUS_OK;
+                       }
+                       if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                TALLOC_FREE(frame);
                                TALLOC_FREE(talloced);
index 229b41cd91c3d002a1792cb4d4fa7a712f79d57c..5948ba95a5df1c7346e9316cb2ff2331d44e8b5a 100644 (file)
@@ -167,7 +167,10 @@ static void setup_close_full_information(connection_struct *conn,
        int ret;
 
        status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+           (smb_fname->flags & SMB_FILENAME_POSIX_PATH) &&
+           S_ISLNK(smb_fname->st.st_ex_mode))
+       {
                status = NT_STATUS_OK;
        }
        if (!NT_STATUS_IS_OK(status)) {