diff --git a/source3/smbd/close.c b/source3/smbd/close.c index be7b6159b64..2fcd5ada27f 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -962,8 +962,6 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp) struct smb_filename *smb_dname = fsp->fsp_name; struct smb_filename *parent_fname = NULL; struct smb_filename *at_fname = NULL; - const struct loadparm_substitution *lp_sub = - loadparm_s3_global_substitution(); SMB_STRUCT_STAT st; const char *dname = NULL; char *talloced = NULL; @@ -1023,8 +1021,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp) return NT_STATUS_OK; } - if (!((errno == ENOTEMPTY) || (errno == EEXIST)) || - !*lp_veto_files(talloc_tos(), lp_sub, SNUM(conn))) + if (!(errno == ENOTEMPTY) || (errno == EEXIST)) { DEBUG(3,("rmdir_internals: couldn't remove directory %s : " "%s\n", smb_fname_str_dbg(smb_dname), @@ -1099,10 +1096,51 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp) * for the symlink/MSDFS case. */ if (S_ISLNK(smb_dname_full->st.st_ex_mode)) { + /* Could be an msdfs link. */ + struct smb_filename *smb_relname; + smb_relname = synthetic_smb_fname(talloc_tos(), + dname, + NULL, + &smb_dname_full->st, + fsp->fsp_name->twrp, + fsp->fsp_name->flags); + if (smb_relname == NULL) { + TALLOC_FREE(talloced); + TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + errno = ENOMEM; + goto err; + } + if (is_msdfs_link(fsp, smb_relname)) { + TALLOC_FREE(talloced); + TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + TALLOC_FREE(smb_relname); + DBG_DEBUG("got msdfs link name %s - can't " + "delete\n", + dname); + errno = ENOTEMPTY; + goto err; + } + TALLOC_FREE(smb_relname); + + /* Is it a dangling smylink ? */ + ret = SMB_VFS_STAT(conn, smb_dname_full); + if (ret == -1 && (errno == ENOENT || errno == ELOOP)) { + /* Yes, allow delete. */ + TALLOC_FREE(talloced); + TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + continue; + } + /* Valid (non-dangling) symlink. No delete allowed. */ TALLOC_FREE(talloced); TALLOC_FREE(fullname); TALLOC_FREE(smb_dname_full); - continue; + DBG_DEBUG("got name %s - can't delete\n", + dname); + errno = ENOTEMPTY; + goto err; } /* Not a symlink, get a pathref. */ @@ -1134,6 +1172,9 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp) TALLOC_FREE(fullname); TALLOC_FREE(smb_dname_full); TALLOC_FREE(direntry_fname); + DBG_DEBUG("got name %s - can't delete\n", dname); + errno = ENOTEMPTY; + goto err; } /* We only have veto files/directories. @@ -1264,7 +1305,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp) /* Retry the rmdir */ ret = SMB_VFS_UNLINKAT(conn, - dirfsp, + parent_fname->fsp, at_fname, AT_REMOVEDIR); diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 174f07b1159..582062b25d2 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -1928,6 +1928,44 @@ NTSTATUS can_delete_directory_fsp(files_struct *fsp) */ if (S_ISLNK(smb_dname_full->st.st_ex_mode)) { + /* Could be an msdfs link. */ + struct smb_filename *smb_dname; + smb_dname = synthetic_smb_fname(talloc_tos(), + dname, + NULL, + NULL, + fsp->fsp_name->twrp, + fsp->fsp_name->flags); + if (smb_dname == NULL) { + TALLOC_FREE(talloced); + TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + status = NT_STATUS_NO_MEMORY; + break; + } + if (is_msdfs_link(fsp, smb_dname)) { + TALLOC_FREE(talloced); + TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + TALLOC_FREE(smb_dname); + DBG_DEBUG("got msdfs link name %s - can't " + "delete\n", + dname); + status = NT_STATUS_DIRECTORY_NOT_EMPTY; + break; + } + TALLOC_FREE(smb_dname); + + /* Is it a dangling smylink ? */ + ret = SMB_VFS_STAT(conn, smb_dname_full); + if (ret == -1 && (errno == ENOENT || errno == ELOOP)) { + /* Yes, allow delete. */ + TALLOC_FREE(talloced); + TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + continue; + } + /* Valid (non-dangling) symlink. No delete allowed. */ TALLOC_FREE(talloced); TALLOC_FREE(fullname); TALLOC_FREE(smb_dname_full);