Skip to content

Commit

Permalink
NAS-115969 / 22.02 / Permit case-insensitive renames
Browse files Browse the repository at this point in the history
Add additional logic in source3/smbd/reply.c for case where
destination file exists, i.e. stat(2) for file does not fail
with ENOENT. In this case, compare inode numbers of the two
files and if they're identical, allow vfs_renameat() to proceed.

This in turn passes the rename operation through the VFS stack
to a module that moves file through intermediate one.

During testing of this, it was discovered that vfs_fset_nt_acl()
was failing in vfs_ixnas with EINVAL. This was due to
improper initialization of ids and tag for non-special ACEs.

Additional cleanup of temporary FSP structs was added to
vfs_zfs_core as well.
  • Loading branch information
anodos325 committed Apr 29, 2022
1 parent f7a0e4d commit 378853f
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
9 changes: 6 additions & 3 deletions source3/modules/vfs_ixnas.c
Expand Up @@ -328,8 +328,8 @@ static bool smbace2bsdentry(acl_t bsdacl, SMB_ACE4PROP_T *aceprop)
acl_entry_t new_entry;
acl_perm_t permset = 0;
acl_entry_type_t type = 0;
acl_flag_t flags;
uid_t id;
acl_flag_t flags = 0;
uid_t id = ACL_UNDEFINED_ID;
acl_tag_t tag;
int i;

Expand Down Expand Up @@ -373,7 +373,9 @@ static bool smbace2bsdentry(acl_t bsdacl, SMB_ACE4PROP_T *aceprop)
smb_panic("Unsupported special id.");
}
} else {
tag = ACL_GROUP ? aceprop->aceFlags & SMB_ACE4_IDENTIFIER_GROUP : ACL_USER;
tag = aceprop->aceFlags & SMB_ACE4_IDENTIFIER_GROUP ?
ACL_GROUP : ACL_USER;
id = aceprop->who.id;
}

new_entry->ae_perm = permset;
Expand Down Expand Up @@ -553,6 +555,7 @@ static bool ixnas_process_smbacl(vfs_handle_struct *handle,

hidden_entry->ae_perm = 0;
hidden_entry->ae_entry_type = ACL_ENTRY_TYPE_ALLOW;
hidden_entry->ae_flags = ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT;
hidden_entry->ae_tag = ACL_EVERYONE;
hidden_entry->ae_id = ACL_UNDEFINED_ID;
}
Expand Down
6 changes: 6 additions & 0 deletions source3/modules/vfs_zfs_core.c
Expand Up @@ -326,6 +326,7 @@ static bool get_synthetic_fsp(vfs_handle_struct *handle,
DBG_ERR("Failed to open %s, mode: 0o%o: %s\n",
smb_fname_str_dbg(tmp_fname), unix_mode,
strerror(errno));
file_free(NULL, tmp_fsp);
return false;
}
tmp_fsp->fsp_flags.is_directory = true;
Expand Down Expand Up @@ -373,13 +374,18 @@ static bool zfs_inherit_acls(vfs_handle_struct *handle,

ok = get_synthetic_fsp(handle, ds->mountpoint + root_len, &c_fsp);
if (!ok) {
fd_close(pathref);
file_free(NULL, pathref);
return false;
}

error = SMB_VFS_STAT(handle->conn, c_fsp->fsp_name);
if (error) {
DBG_ERR("%s: stat() failed: %s\n", fsp_str_dbg(c_fsp), strerror(errno));
fd_close(c_fsp);
file_free(NULL, c_fsp);
fd_close(pathref);
file_free(NULL, pathref);
return false;
}

Expand Down
20 changes: 17 additions & 3 deletions source3/smbd/reply.c
Expand Up @@ -7126,7 +7126,9 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
NTSTATUS status = NT_STATUS_OK;
struct share_mode_lock *lck = NULL;
uint32_t access_mask = SEC_DIR_ADD_FILE;
bool dst_exists, old_is_stream, new_is_stream;
bool dst_exists, old_is_stream, new_is_stream, is_same_fileid;
struct file_id fileid_src;
struct file_id fileid_dst;
int ret;

status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
Expand Down Expand Up @@ -7283,7 +7285,19 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,

dst_exists = vfs_stat(conn, smb_fname_dst) == 0;

if(!replace_if_exists && dst_exists) {
/*
* Some filesystems are case-insensitive, but case-preserving
* Compare fileid in this situation to determine whether the
* source and destination are the same file. If this is the
* case, then bypass these checks and hand off to VFS_RENAME
* and hope that a VFS module is enabled that has special
* handling for this situation.
*/
fileid_src = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
fileid_dst = vfs_file_id_from_sbuf(conn, &smb_fname_dst->st);
is_same_fileid = file_id_equal(&fileid_src, &fileid_dst);

if(!replace_if_exists && dst_exists && !is_same_fileid) {
DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
"%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
smb_fname_str_dbg(smb_fname_dst)));
Expand All @@ -7301,7 +7315,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
}

if (dst_exists) {
if (dst_exists && !is_same_fileid) {
struct file_id fileid = vfs_file_id_from_sbuf(conn,
&smb_fname_dst->st);
files_struct *dst_fsp = file_find_di_first(conn->sconn,
Expand Down

0 comments on commit 378853f

Please sign in to comment.