s3: smbd: Fix logic in rmdir_internals() to cope with dangling symlinks.
authorJeremy Allison <jra@samba.org>
Mon, 25 Oct 2021 19:32:29 +0000 (12:32 -0700)
committerRalph Boehme <slow@samba.org>
Fri, 29 Oct 2021 14:02:34 +0000 (14:02 +0000)
Still need to add the same logic in can_delete_directory_fsp()
before we can delete the knownfail.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14879

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/smbd/close.c

index 882a7bbbeb3df258d6be35544311582d8a88aa70..eae276b2e9c5d21211389023b2e34a31123fd655 100644 (file)
@@ -1100,15 +1100,61 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
                        goto err;
                }
 
-               /*
-                * is_visible_fsp() always returns true
-                * for the symlink/MSDFS case.
-                */
                if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
+                       /* Could it be an msdfs link ? */
+                       if (lp_host_msdfs() &&
+                           lp_msdfs_root(SNUM(conn))) {
+                               struct smb_filename *smb_atname;
+                               smb_atname = synthetic_smb_fname(talloc_tos(),
+                                                       dname,
+                                                       NULL,
+                                                       &smb_dname_full->st,
+                                                       fsp->fsp_name->twrp,
+                                                       fsp->fsp_name->flags);
+                               if (smb_atname == NULL) {
+                                       TALLOC_FREE(talloced);
+                                       TALLOC_FREE(fullname);
+                                       TALLOC_FREE(smb_dname_full);
+                                       errno = ENOMEM;
+                                       goto err;
+                               }
+                               if (is_msdfs_link(fsp, smb_atname)) {
+                                       TALLOC_FREE(talloced);
+                                       TALLOC_FREE(fullname);
+                                       TALLOC_FREE(smb_dname_full);
+                                       TALLOC_FREE(smb_atname);
+                                       DBG_DEBUG("got msdfs link name %s "
+                                               "- can't delete directory %s\n",
+                                               dname,
+                                               fsp_str_dbg(fsp));
+                                       errno = ENOTEMPTY;
+                                       goto err;
+                               }
+                               TALLOC_FREE(smb_atname);
+                       }
+
+                       /* Not a DFS link - could it be a dangling symlink ? */
+                       ret = SMB_VFS_STAT(conn, smb_dname_full);
+                       if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
+                               /*
+                                * Dangling symlink.
+                                * Allow delete as "delete veto files = yes"
+                                */
+                               TALLOC_FREE(talloced);
+                               TALLOC_FREE(fullname);
+                               TALLOC_FREE(smb_dname_full);
+                               continue;
+                       }
+
+                       DBG_DEBUG("got symlink name %s - "
+                               "can't delete directory %s\n",
+                               dname,
+                               fsp_str_dbg(fsp));
                        TALLOC_FREE(talloced);
                        TALLOC_FREE(fullname);
                        TALLOC_FREE(smb_dname_full);
-                       continue;
+                       errno = ENOTEMPTY;
+                       goto err;
                }
 
                /* Not a symlink, get a pathref. */