Skip to content

Commit

Permalink
s3/smbd: fix handling of delete-on-close on directories
Browse files Browse the repository at this point in the history
This implements a check to test the delete-on-close flag of a directory
for requests to create files in this directory.

Windows server implement this check, Samba doesn't as it has performance
implications.

This commit implements the check and a new option to control it. By
default the check is skipped, setting "check parent directory delete on
close = yes" enables it.

Signed-off-by: Ralph Boehme <[email protected]>
Reviewed-by: Jeremy Allison <[email protected]>

Autobuild-User(master): Ralph Böhme <[email protected]>
Autobuild-Date(master): Sat Feb  3 23:42:16 CET 2018 on sn-devel-144
  • Loading branch information
slowfranklin committed Feb 3, 2018
1 parent 4c857e0 commit 84f07a8
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 3 deletions.
13 changes: 13 additions & 0 deletions docs-xml/smbdotconf/tuning/checkparentdirectorydeleteonclose.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<samba:parameter name="check parent directory delete on close"
context="S"
type="boolean"
xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
<description>
<para>A Windows SMB server prevents the client from creating files in a
directory that has the delete-on-close flag set. By default Samba doesn't
perform this check as this check is a quite expensive operation in Samba.
</para>
</description>

<value type="default">no</value>
</samba:parameter>
2 changes: 2 additions & 0 deletions lib/param/loadparm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)

lpcfg_do_global_parameter(lp_ctx, "prefork children", "1");

lpcfg_do_global_parameter(lp_ctx, "check parent directory delete on close", "no");

for (i = 0; parm_table[i].label; i++) {
if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
lp_ctx->flags[i] |= FLAG_DEFAULT;
Expand Down
2 changes: 0 additions & 2 deletions selftest/knownfail.d/samba3.base.delete

This file was deleted.

1 change: 1 addition & 0 deletions selftest/target/Samba3.pm
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ sub setup_nt4_dc($$)
rpc_daemon:lsasd = fork
rpc_daemon:fssd = fork
fss: sequence timeout = 1
check parent directory delete on close = yes
";

my $vars = $self->provision($path, "SAMBA-TEST",
Expand Down
1 change: 1 addition & 0 deletions selftest/target/Samba4.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,7 @@ sub provision_ad_dc($$$$$$)
smbd:writetimeupdatedelay = 500000
create mask = 755
dos filemode = yes
check parent directory delete on close = yes
dcerpc endpoint servers = -winreg -srvsvc
Expand Down
1 change: 1 addition & 0 deletions source3/param/loadparm.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ static const struct loadparm_service _sDefault =
.smb_encrypt = SMB_SIGNING_DEFAULT,
.kernel_share_modes = true,
.durable_handles = true,
.check_parent_directory_delete_on_close = false,
.param_opt = NULL,
.dummy = ""
};
Expand Down
45 changes: 44 additions & 1 deletion source3/smbd/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ NTSTATUS check_parent_access(struct connection_struct *conn,
struct security_descriptor *parent_sd = NULL;
uint32_t access_granted = 0;
struct smb_filename *parent_smb_fname = NULL;
struct share_mode_lock *lck = NULL;
struct file_id id = {0};
uint32_t name_hash;
bool delete_on_close_set;
int ret;

if (!parent_dirname(talloc_tos(),
smb_fname->base_name,
Expand Down Expand Up @@ -320,7 +325,45 @@ NTSTATUS check_parent_access(struct connection_struct *conn,
return status;
}

return NT_STATUS_OK;
if (!(access_mask & (SEC_DIR_ADD_FILE | SEC_DIR_ADD_SUBDIR))) {
return NT_STATUS_OK;
}
if (!lp_check_parent_directory_delete_on_close(SNUM(conn))) {
return NT_STATUS_OK;
}

/* Check if the directory has delete-on-close set */
ret = SMB_VFS_STAT(conn, parent_smb_fname);
if (ret != 0) {
status = map_nt_error_from_unix(errno);
goto out;
}

id = SMB_VFS_FILE_ID_CREATE(conn, &parent_smb_fname->st);

status = file_name_hash(conn, parent_smb_fname->base_name, &name_hash);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}

lck = get_existing_share_mode_lock(talloc_tos(), id);
if (lck == NULL) {
status = NT_STATUS_OK;
goto out;
}

delete_on_close_set = is_delete_on_close_set(lck, name_hash);
if (delete_on_close_set) {
status = NT_STATUS_DELETE_PENDING;
goto out;
}

status = NT_STATUS_OK;

out:
TALLOC_FREE(lck);
TALLOC_FREE(parent_smb_fname);
return status;
}

/****************************************************************************
Expand Down

0 comments on commit 84f07a8

Please sign in to comment.