From 17e04761cbc570468536a4dae3e817f7c876dc94 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 11 Mar 2022 12:06:38 -0700 Subject: [PATCH] smbd: Move copy_internals to smb2_nttrans.c Signed-off-by: David Mulder Reviewed-by: Jeremy Allison --- source3/smbd/nttrans.c | 177 ------------------------------------ source3/smbd/proto.h | 12 +-- source3/smbd/smb2_nttrans.c | 177 ++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 183 deletions(-) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index bce77a41e0d..7d9a94a6317 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1386,183 +1386,6 @@ void reply_ntcancel(struct smb_request *req) return; } -/**************************************************************************** - Copy a file. -****************************************************************************/ - -NTSTATUS copy_internals(TALLOC_CTX *ctx, - connection_struct *conn, - struct smb_request *req, - struct smb_filename *smb_fname_src, - struct smb_filename *smb_fname_dst, - uint32_t attrs) -{ - files_struct *fsp1,*fsp2; - uint32_t fattr; - int info; - off_t ret=-1; - NTSTATUS status = NT_STATUS_OK; - struct smb_filename *parent = NULL; - struct smb_filename *pathref = NULL; - - if (!CAN_WRITE(conn)) { - status = NT_STATUS_MEDIA_WRITE_PROTECTED; - goto out; - } - - /* Source must already exist. */ - if (!VALID_STAT(smb_fname_src->st)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - goto out; - } - - /* Ensure attributes match. */ - fattr = fdos_mode(smb_fname_src->fsp); - if ((fattr & ~attrs) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) { - status = NT_STATUS_NO_SUCH_FILE; - goto out; - } - - /* Disallow if dst file already exists. */ - if (VALID_STAT(smb_fname_dst->st)) { - status = NT_STATUS_OBJECT_NAME_COLLISION; - goto out; - } - - /* No links from a directory. */ - if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { - status = NT_STATUS_FILE_IS_A_DIRECTORY; - goto out; - } - - DEBUG(10,("copy_internals: doing file copy %s to %s\n", - smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); - - status = SMB_VFS_CREATE_FILE( - conn, /* conn */ - req, /* req */ - smb_fname_src, /* fname */ - FILE_READ_DATA|FILE_READ_ATTRIBUTES| - FILE_READ_EA, /* access_mask */ - (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ - FILE_SHARE_DELETE), - FILE_OPEN, /* create_disposition*/ - 0, /* create_options */ - FILE_ATTRIBUTE_NORMAL, /* file_attributes */ - NO_OPLOCK, /* oplock_request */ - NULL, /* lease */ - 0, /* allocation_size */ - 0, /* private_flags */ - NULL, /* sd */ - NULL, /* ea_list */ - &fsp1, /* result */ - &info, /* pinfo */ - NULL, NULL); /* create context */ - - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = SMB_VFS_CREATE_FILE( - conn, /* conn */ - req, /* req */ - smb_fname_dst, /* fname */ - FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES| - FILE_WRITE_EA, /* access_mask */ - (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ - FILE_SHARE_DELETE), - FILE_CREATE, /* create_disposition*/ - 0, /* create_options */ - fattr, /* file_attributes */ - NO_OPLOCK, /* oplock_request */ - NULL, /* lease */ - 0, /* allocation_size */ - 0, /* private_flags */ - NULL, /* sd */ - NULL, /* ea_list */ - &fsp2, /* result */ - &info, /* pinfo */ - NULL, NULL); /* create context */ - - if (!NT_STATUS_IS_OK(status)) { - close_file_free(NULL, &fsp1, ERROR_CLOSE); - goto out; - } - - if (smb_fname_src->st.st_ex_size) { - ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size); - } - - /* - * As we are opening fsp1 read-only we only expect - * an error on close on fsp2 if we are out of space. - * Thus we don't look at the error return from the - * close of fsp1. - */ - close_file_free(NULL, &fsp1, NORMAL_CLOSE); - - /* Ensure the modtime is set correctly on the destination file. */ - set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime); - - status = close_file_free(NULL, &fsp2, NORMAL_CLOSE); - if (!NT_STATUS_IS_OK(status)) { - DBG_WARNING("close_file_free() failed: %s\n", - nt_errstr(status)); - /* - * We can't do much but leak the fsp - */ - goto out; - } - - /* Grrr. We have to do this as open_file_ntcreate adds FILE_ATTRIBUTE_ARCHIVE when it - creates the file. This isn't the correct thing to do in the copy - case. JRA */ - - status = SMB_VFS_PARENT_PATHNAME(conn, - talloc_tos(), - smb_fname_dst, - &parent, - NULL); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (smb_fname_dst->fsp == NULL) { - status = synthetic_pathref(parent, - conn->cwd_fsp, - smb_fname_dst->base_name, - smb_fname_dst->stream_name, - NULL, - smb_fname_dst->twrp, - smb_fname_dst->flags, - &pathref); - - /* should we handle NT_STATUS_OBJECT_NAME_NOT_FOUND specially here ???? */ - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(parent); - goto out; - } - file_set_dosmode(conn, pathref, fattr, parent, false); - smb_fname_dst->st.st_ex_mode = pathref->st.st_ex_mode; - } else { - file_set_dosmode(conn, smb_fname_dst, fattr, parent, false); - } - TALLOC_FREE(parent); - - if (ret < (off_t)smb_fname_src->st.st_ex_size) { - status = NT_STATUS_DISK_FULL; - goto out; - } - out: - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", - nt_errstr(status), smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); - } - - return status; -} - /**************************************************************************** Reply to a NT rename request. ****************************************************************************/ diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 29525f2a736..0b21dc2f42f 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -685,12 +685,6 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, uint32_t max_data_count, uint8_t **ppmarshalled_sd, size_t *psd_size); -NTSTATUS copy_internals(TALLOC_CTX *ctx, - connection_struct *conn, - struct smb_request *req, - struct smb_filename *smb_fname_src, - struct smb_filename *smb_fname_dst, - uint32_t attrs); #ifdef HAVE_SYS_QUOTAS struct smb2_query_quota_info; @@ -714,6 +708,12 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd, uint32_t security_info_sent); NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len, uint32_t security_info_sent); +NTSTATUS copy_internals(TALLOC_CTX *ctx, + connection_struct *conn, + struct smb_request *req, + struct smb_filename *smb_fname_src, + struct smb_filename *smb_fname_dst, + uint32_t attrs); /* The following definitions come from smbd/open.c */ diff --git a/source3/smbd/smb2_nttrans.c b/source3/smbd/smb2_nttrans.c index 932dec76233..1b650d06960 100644 --- a/source3/smbd/smb2_nttrans.c +++ b/source3/smbd/smb2_nttrans.c @@ -189,3 +189,180 @@ NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len, return set_sd(fsp, psd, security_info_sent); } + +/**************************************************************************** + Copy a file. +****************************************************************************/ + +NTSTATUS copy_internals(TALLOC_CTX *ctx, + connection_struct *conn, + struct smb_request *req, + struct smb_filename *smb_fname_src, + struct smb_filename *smb_fname_dst, + uint32_t attrs) +{ + files_struct *fsp1,*fsp2; + uint32_t fattr; + int info; + off_t ret=-1; + NTSTATUS status = NT_STATUS_OK; + struct smb_filename *parent = NULL; + struct smb_filename *pathref = NULL; + + if (!CAN_WRITE(conn)) { + status = NT_STATUS_MEDIA_WRITE_PROTECTED; + goto out; + } + + /* Source must already exist. */ + if (!VALID_STAT(smb_fname_src->st)) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto out; + } + + /* Ensure attributes match. */ + fattr = fdos_mode(smb_fname_src->fsp); + if ((fattr & ~attrs) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) { + status = NT_STATUS_NO_SUCH_FILE; + goto out; + } + + /* Disallow if dst file already exists. */ + if (VALID_STAT(smb_fname_dst->st)) { + status = NT_STATUS_OBJECT_NAME_COLLISION; + goto out; + } + + /* No links from a directory. */ + if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto out; + } + + DEBUG(10,("copy_internals: doing file copy %s to %s\n", + smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); + + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + smb_fname_src, /* fname */ + FILE_READ_DATA|FILE_READ_ATTRIBUTES| + FILE_READ_EA, /* access_mask */ + (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ + FILE_SHARE_DELETE), + FILE_OPEN, /* create_disposition*/ + 0, /* create_options */ + FILE_ATTRIBUTE_NORMAL, /* file_attributes */ + NO_OPLOCK, /* oplock_request */ + NULL, /* lease */ + 0, /* allocation_size */ + 0, /* private_flags */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp1, /* result */ + &info, /* pinfo */ + NULL, NULL); /* create context */ + + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + smb_fname_dst, /* fname */ + FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES| + FILE_WRITE_EA, /* access_mask */ + (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ + FILE_SHARE_DELETE), + FILE_CREATE, /* create_disposition*/ + 0, /* create_options */ + fattr, /* file_attributes */ + NO_OPLOCK, /* oplock_request */ + NULL, /* lease */ + 0, /* allocation_size */ + 0, /* private_flags */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp2, /* result */ + &info, /* pinfo */ + NULL, NULL); /* create context */ + + if (!NT_STATUS_IS_OK(status)) { + close_file_free(NULL, &fsp1, ERROR_CLOSE); + goto out; + } + + if (smb_fname_src->st.st_ex_size) { + ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size); + } + + /* + * As we are opening fsp1 read-only we only expect + * an error on close on fsp2 if we are out of space. + * Thus we don't look at the error return from the + * close of fsp1. + */ + close_file_free(NULL, &fsp1, NORMAL_CLOSE); + + /* Ensure the modtime is set correctly on the destination file. */ + set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime); + + status = close_file_free(NULL, &fsp2, NORMAL_CLOSE); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("close_file_free() failed: %s\n", + nt_errstr(status)); + /* + * We can't do much but leak the fsp + */ + goto out; + } + + /* Grrr. We have to do this as open_file_ntcreate adds FILE_ATTRIBUTE_ARCHIVE when it + creates the file. This isn't the correct thing to do in the copy + case. JRA */ + + status = SMB_VFS_PARENT_PATHNAME(conn, + talloc_tos(), + smb_fname_dst, + &parent, + NULL); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (smb_fname_dst->fsp == NULL) { + status = synthetic_pathref(parent, + conn->cwd_fsp, + smb_fname_dst->base_name, + smb_fname_dst->stream_name, + NULL, + smb_fname_dst->twrp, + smb_fname_dst->flags, + &pathref); + + /* should we handle NT_STATUS_OBJECT_NAME_NOT_FOUND specially here ???? */ + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(parent); + goto out; + } + file_set_dosmode(conn, pathref, fattr, parent, false); + smb_fname_dst->st.st_ex_mode = pathref->st.st_ex_mode; + } else { + file_set_dosmode(conn, smb_fname_dst, fattr, parent, false); + } + TALLOC_FREE(parent); + + if (ret < (off_t)smb_fname_src->st.st_ex_size) { + status = NT_STATUS_DISK_FULL; + goto out; + } + out: + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", + nt_errstr(status), smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); + } + + return status; +}