1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

s3: smbd: Fix rmdir_internals() to do an early return if lp_delete_veto_files() is not set.

Fix the comments to match what the code actually does. The
exit at the end of the scan directory loop if we find a client
visible filename is a change in behavior, but the previous
behavior (not exist on visible filename, but delete it) was
a bug and in non-tested code. Now it's testd.

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>
(cherry picked from commit a37d16e7c5)
(backported from commit e00fe095e8)
[pfilipen@redhat.com: rmdir_internals() got refactored in 4.15]
This commit is contained in:
Jeremy Allison 2021-10-25 12:21:37 -07:00 committed by Jule Anger
parent 3d4761cf04
commit 66d688cea2

View File

@ -938,8 +938,11 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
{
connection_struct *conn = fsp->conn;
struct smb_filename *smb_dname = fsp->fsp_name;
const struct loadparm_substitution *lp_sub =
loadparm_s3_global_substitution();
SMB_STRUCT_STAT st;
const char *dname = NULL;
char *talloced = NULL;
long dirpos = 0;
struct smb_Dir *dir_hnd = NULL;
int ret;
SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
@ -974,144 +977,150 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
return NT_STATUS_OK;
}
if(((errno == ENOTEMPTY)||(errno == EEXIST)) && *lp_veto_files(talloc_tos(), lp_sub, SNUM(conn))) {
/*
* Check to see if the only thing in this directory are
* vetoed files/directories. If so then delete them and
* retry. If we fail to delete any of them (and we *don't*
* do a recursive delete) then fail the rmdir.
*/
SMB_STRUCT_STAT st;
const char *dname = NULL;
char *talloced = NULL;
long dirpos = 0;
struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
smb_dname, NULL,
0);
if(dir_hnd == NULL) {
errno = ENOTEMPTY;
goto err;
}
while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
&talloced)) != NULL) {
if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
TALLOC_FREE(talloced);
continue;
}
if (!is_visible_file(conn,
dir_hnd,
dname,
&st,
false)) {
TALLOC_FREE(talloced);
continue;
}
if(!IS_VETO_PATH(conn, dname)) {
TALLOC_FREE(dir_hnd);
TALLOC_FREE(talloced);
errno = ENOTEMPTY;
goto err;
}
TALLOC_FREE(talloced);
}
/* We only have veto files/directories.
* Are we allowed to delete them ? */
if(!lp_delete_veto_files(SNUM(conn))) {
TALLOC_FREE(dir_hnd);
errno = ENOTEMPTY;
goto err;
}
/* Do a recursive delete. */
RewindDir(dir_hnd,&dirpos);
while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
&talloced)) != NULL) {
struct smb_filename *smb_dname_full = NULL;
char *fullname = NULL;
bool do_break = true;
if (ISDOT(dname) || ISDOTDOT(dname)) {
TALLOC_FREE(talloced);
continue;
}
if (!is_visible_file(conn,
dir_hnd,
dname,
&st,
false)) {
TALLOC_FREE(talloced);
continue;
}
fullname = talloc_asprintf(ctx,
"%s/%s",
smb_dname->base_name,
dname);
if(!fullname) {
errno = ENOMEM;
goto err_break;
}
smb_dname_full = synthetic_smb_fname(talloc_tos(),
fullname,
NULL,
NULL,
smb_dname->twrp,
smb_dname->flags);
if (smb_dname_full == NULL) {
errno = ENOMEM;
goto err_break;
}
if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
goto err_break;
}
if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
int retval;
if(!recursive_rmdir(ctx, conn,
smb_dname_full)) {
goto err_break;
}
retval = SMB_VFS_UNLINKAT(conn,
conn->cwd_fsp,
smb_dname_full,
AT_REMOVEDIR);
if(retval != 0) {
goto err_break;
}
} else {
int retval = SMB_VFS_UNLINKAT(conn,
conn->cwd_fsp,
smb_dname_full,
0);
if(retval != 0) {
goto err_break;
}
}
/* Successful iteration. */
do_break = false;
err_break:
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(talloced);
if (do_break)
break;
}
TALLOC_FREE(dir_hnd);
/* Retry the rmdir */
ret = SMB_VFS_UNLINKAT(conn,
conn->cwd_fsp,
smb_dname,
AT_REMOVEDIR);
if (!((errno == ENOTEMPTY) || (errno == EEXIST))) {
DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
"%s\n", smb_fname_str_dbg(smb_dname),
strerror(errno)));
return map_nt_error_from_unix(errno);
}
/*
* Here we know the initial directory unlink failed with
* ENOTEMPTY or EEXIST so we know there are objects within.
* If we don't have permission to delete files non
* visible to the client just fail the directory delete.
*/
if (!lp_delete_veto_files(SNUM(conn))) {
errno = ENOTEMPTY;
goto err;
}
/*
* Check to see if the only thing in this directory are
* files non-visible to the client. If not, fail the delete.
*/
dir_hnd = OpenDir(talloc_tos(), conn, smb_dname, NULL, 0);
if (dir_hnd == NULL) {
errno = ENOTEMPTY;
goto err;
}
while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
TALLOC_FREE(talloced);
continue;
}
if (!is_visible_file(conn,
dir_hnd,
dname,
&st,
false)) {
TALLOC_FREE(talloced);
continue;
}
if(!IS_VETO_PATH(conn, dname)) {
/*
* We found a client visible name.
* We cannot delete this directory.
*/
DBG_DEBUG("got name %s - "
"can't delete directory %s\n",
dname,
fsp_str_dbg(fsp));
TALLOC_FREE(dir_hnd);
TALLOC_FREE(talloced);
errno = ENOTEMPTY;
goto err;
}
TALLOC_FREE(talloced);
}
/* Do a recursive delete. */
RewindDir(dir_hnd,&dirpos);
while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
struct smb_filename *smb_dname_full = NULL;
char *fullname = NULL;
bool do_break = true;
if (ISDOT(dname) || ISDOTDOT(dname)) {
TALLOC_FREE(talloced);
continue;
}
if (!is_visible_file(conn,
dir_hnd,
dname,
&st,
false)) {
TALLOC_FREE(talloced);
continue;
}
fullname = talloc_asprintf(ctx,
"%s/%s",
smb_dname->base_name,
dname);
if (fullname == NULL) {
errno = ENOMEM;
goto err_break;
}
smb_dname_full = synthetic_smb_fname(talloc_tos(),
fullname,
NULL,
NULL,
smb_dname->twrp,
smb_dname->flags);
if (smb_dname_full == NULL) {
errno = ENOMEM;
goto err_break;
}
if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
goto err_break;
}
if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
int retval;
if(!recursive_rmdir(ctx, conn,
smb_dname_full)) {
goto err_break;
}
retval = SMB_VFS_UNLINKAT(conn,
conn->cwd_fsp,
smb_dname_full,
AT_REMOVEDIR);
if(retval != 0) {
goto err_break;
}
} else {
int retval = SMB_VFS_UNLINKAT(conn,
conn->cwd_fsp,
smb_dname_full,
0);
if(retval != 0) {
goto err_break;
}
}
/* Successful iteration. */
do_break = false;
err_break:
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(talloced);
if (do_break)
break;
}
TALLOC_FREE(dir_hnd);
/* Retry the rmdir */
ret = SMB_VFS_UNLINKAT(conn,
conn->cwd_fsp,
smb_dname,
AT_REMOVEDIR);
err:
if (ret != 0) {