/****************************************************************************
Reply to a file copy.
+
+ From MS-CIFS.
+
+ This command was introduced in the LAN Manager 1.0 dialect
+ It was rendered obsolete in the NT LAN Manager dialect.
+ This command was used to perform server-side file copies, but
+ is no longer used. Clients SHOULD
+ NOT send requests using this command code.
+ Servers receiving requests with this command code
+ SHOULD return STATUS_NOT_IMPLEMENTED (ERRDOS/ERRbadfunc).
****************************************************************************/
void reply_copy(struct smb_request *req)
{
- connection_struct *conn = req->conn;
- struct smb_filename *smb_fname_src = NULL;
- struct smb_filename *smb_fname_src_dir = NULL;
- struct smb_filename *smb_fname_dst = NULL;
- char *fname_src = NULL;
- char *fname_dst = NULL;
- char *fname_src_mask = NULL;
- char *fname_src_dir = NULL;
- const char *p;
- int count=0;
- int error = ERRnoaccess;
- int tid2;
- int ofun;
- int flags;
- bool target_is_directory=False;
- bool source_has_wild = False;
- bool dest_has_wild = False;
- NTSTATUS status;
- uint32_t ucf_flags_src = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
- ucf_flags_from_smb_request(req);
- uint32_t ucf_flags_dst = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
- ucf_flags_from_smb_request(req);
- bool posix_pathnames = req->posix_pathnames;
- TALLOC_CTX *ctx = talloc_tos();
-
START_PROFILE(SMBcopy);
-
- if (req->wct < 3) {
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- goto out;
- }
-
- tid2 = SVAL(req->vwv+0, 0);
- ofun = SVAL(req->vwv+1, 0);
- flags = SVAL(req->vwv+2, 0);
-
- p = (const char *)req->buf;
- p += srvstr_get_path_req(ctx, req, &fname_src, p, STR_TERMINATE,
- &status);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- }
- p += srvstr_get_path_req(ctx, req, &fname_dst, p, STR_TERMINATE,
- &status);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- }
-
- DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
-
- if (tid2 != conn->cnum) {
- /* can't currently handle inter share copies XXXX */
- DEBUG(3,("Rejecting inter-share copy\n"));
- reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
- goto out;
- }
-
- status = filename_convert(ctx, conn,
- fname_src,
- ucf_flags_src,
- 0,
- &smb_fname_src);
- if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
- reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
- ERRSRV, ERRbadpath);
- goto out;
- }
- reply_nterror(req, status);
- goto out;
- }
-
- status = filename_convert(ctx, conn,
- fname_dst,
- ucf_flags_dst,
- 0,
- &smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
- reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
- ERRSRV, ERRbadpath);
- goto out;
- }
- reply_nterror(req, status);
- goto out;
- }
-
- target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
-
- if ((flags&1) && target_is_directory) {
- reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
- goto out;
- }
-
- if ((flags&2) && !target_is_directory) {
- reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
- goto out;
- }
-
- if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
- /* wants a tree copy! XXXX */
- DEBUG(3,("Rejecting tree copy\n"));
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- goto out;
- }
-
- /* Split up the directory from the filename/mask. */
- status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
- &fname_src_dir, &fname_src_mask);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
-
- if (!posix_pathnames) {
- char *orig_src_lcomp = NULL;
- char *orig_dst_lcomp = NULL;
- /*
- * Check the wildcard mask *before*
- * unmangling. As mangling is done
- * for names that can't be returned
- * to Windows the unmangled name may
- * contain Windows wildcard characters.
- */
- orig_src_lcomp = get_original_lcomp(ctx,
- conn,
- fname_src,
- ucf_flags_src);
- if (orig_src_lcomp == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
- orig_dst_lcomp = get_original_lcomp(ctx,
- conn,
- fname_dst,
- ucf_flags_dst);
- if (orig_dst_lcomp == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
- source_has_wild = ms_has_wild(orig_src_lcomp);
- dest_has_wild = ms_has_wild(orig_dst_lcomp);
- TALLOC_FREE(orig_src_lcomp);
- TALLOC_FREE(orig_dst_lcomp);
- }
-
- /*
- * We should only check the mangled cache
- * here if unix_convert failed. This means
- * that the path in 'mask' doesn't exist
- * on the file system and so we need to look
- * for a possible mangle. This patch from
- * Tine Smukavec <valentin.smukavec@hermes.si>.
- */
- if (!VALID_STAT(smb_fname_src->st) &&
- !posix_pathnames &&
- mangle_is_mangled(fname_src_mask, conn->params)) {
- char *new_mask = NULL;
- mangle_lookup_name_from_8_3(ctx, fname_src_mask,
- &new_mask, conn->params);
-
- /* Use demangled name if one was successfully found. */
- if (new_mask) {
- TALLOC_FREE(fname_src_mask);
- fname_src_mask = new_mask;
- }
- }
-
- if (!source_has_wild) {
-
- /*
- * Only one file needs to be copied. Append the mask back onto
- * the directory.
- */
- TALLOC_FREE(smb_fname_src->base_name);
- if (ISDOT(fname_src_dir)) {
- /* Ensure we use canonical names on open. */
- smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
- "%s",
- fname_src_mask);
- } else {
- smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
- "%s/%s",
- fname_src_dir,
- fname_src_mask);
- }
- if (!smb_fname_src->base_name) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
-
- if (dest_has_wild) {
- char *fname_dst_mod = NULL;
- if (!resolve_wildcards(smb_fname_dst,
- smb_fname_src->base_name,
- smb_fname_dst->base_name,
- &fname_dst_mod)) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
- TALLOC_FREE(smb_fname_dst->base_name);
- smb_fname_dst->base_name = fname_dst_mod;
- }
-
- status = check_name(conn, smb_fname_src);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- }
-
- status = check_name(conn, smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- }
-
- status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
- ofun, count, target_is_directory);
-
- if(!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- } else {
- count++;
- }
- } else {
- struct smb_Dir *dir_hnd = NULL;
- const char *dname = NULL;
- char *talloced = NULL;
- long offset = 0;
-
- /*
- * There is a wildcard that requires us to actually read the
- * src dir and copy each file matching the mask to the dst.
- * Right now streams won't be copied, but this could
- * presumably be added with a nested loop for reach dir entry.
- */
- SMB_ASSERT(!smb_fname_src->stream_name);
- SMB_ASSERT(!smb_fname_dst->stream_name);
-
- smb_fname_src->stream_name = NULL;
- smb_fname_dst->stream_name = NULL;
-
- if (strequal(fname_src_mask,"????????.???")) {
- TALLOC_FREE(fname_src_mask);
- fname_src_mask = talloc_strdup(ctx, "*");
- if (!fname_src_mask) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
- }
-
- smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
- fname_src_dir,
- NULL,
- NULL,
- smb_fname_src->twrp,
- smb_fname_src->flags);
- if (smb_fname_src_dir == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
-
- status = check_name(conn, smb_fname_src_dir);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
- goto out;
- }
-
- dir_hnd = OpenDir(ctx,
- conn,
- smb_fname_src_dir,
- fname_src_mask,
- 0);
- if (dir_hnd == NULL) {
- status = map_nt_error_from_unix(errno);
- reply_nterror(req, status);
- goto out;
- }
-
- error = ERRbadfile;
-
- /* Iterate over the src dir copying each entry to the dst. */
- while ((dname = ReadDirName(dir_hnd, &offset,
- &smb_fname_src->st, &talloced))) {
- char *destname = NULL;
-
- if (ISDOT(dname) || ISDOTDOT(dname)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- if (IS_VETO_PATH(conn, dname)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- if(!mask_match(dname, fname_src_mask,
- posix_pathnames ?
- true : conn->case_sensitive)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- error = ERRnoaccess;
-
- /* Get the src smb_fname struct setup. */
- TALLOC_FREE(smb_fname_src->base_name);
- if (ISDOT(fname_src_dir)) {
- /* Ensure we use canonical names on open. */
- smb_fname_src->base_name =
- talloc_asprintf(smb_fname_src, "%s",
- dname);
- } else {
- smb_fname_src->base_name =
- talloc_asprintf(smb_fname_src, "%s/%s",
- fname_src_dir, dname);
- }
-
- if (!smb_fname_src->base_name) {
- TALLOC_FREE(dir_hnd);
- TALLOC_FREE(talloced);
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
-
- if (!resolve_wildcards(ctx, smb_fname_src->base_name,
- smb_fname_dst->base_name,
- &destname)) {
- TALLOC_FREE(talloced);
- continue;
- }
- if (!destname) {
- TALLOC_FREE(dir_hnd);
- TALLOC_FREE(talloced);
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
-
- TALLOC_FREE(smb_fname_dst->base_name);
- smb_fname_dst->base_name = destname;
-
- ZERO_STRUCT(smb_fname_src->st);
- vfs_stat(conn, smb_fname_src);
-
- status = openat_pathref_fsp(conn->cwd_fsp,
- smb_fname_src);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_INFO("openat_pathref_fsp [%s] failed: %s\n",
- smb_fname_str_dbg(smb_fname_src),
- nt_errstr(status));
- break;
- }
-
- if (!is_visible_fsp(smb_fname_src->fsp)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- status = check_name(conn, smb_fname_src);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(dir_hnd);
- TALLOC_FREE(talloced);
- reply_nterror(req, status);
- goto out;
- }
-
- status = check_name(conn, smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(dir_hnd);
- TALLOC_FREE(talloced);
- reply_nterror(req, status);
- goto out;
- }
-
- DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
- smb_fname_src->base_name,
- smb_fname_dst->base_name));
-
- status = copy_file(ctx, conn, smb_fname_src,
- smb_fname_dst, ofun, count,
- target_is_directory);
- if (NT_STATUS_IS_OK(status)) {
- count++;
- }
-
- TALLOC_FREE(talloced);
- }
- TALLOC_FREE(dir_hnd);
- }
-
- if (count == 0) {
- reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
- goto out;
- }
-
- reply_outbuf(req, 1, 0);
- SSVAL(req->outbuf,smb_vwv0,count);
- out:
- TALLOC_FREE(smb_fname_src);
- TALLOC_FREE(smb_fname_src_dir);
- TALLOC_FREE(smb_fname_dst);
- TALLOC_FREE(fname_src);
- TALLOC_FREE(fname_dst);
- TALLOC_FREE(fname_src_mask);
- TALLOC_FREE(fname_src_dir);
-
+ reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
END_PROFILE(SMBcopy);
return;
}