1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <sys/synch.h>
  27 #include <smbsrv/smb_kproto.h>
  28 #include <smbsrv/smb_fsops.h>
  29 #include <sys/nbmlock.h>
  30 
  31 /*
  32  * NT_RENAME InformationLevels:
  33  *
  34  * SMB_NT_RENAME_MOVE_CLUSTER_INFO      Server returns invalid parameter.
  35  * SMB_NT_RENAME_SET_LINK_INFO          Create a hard link to a file.
  36  * SMB_NT_RENAME_RENAME_FILE            In-place rename of a file.
  37  * SMB_NT_RENAME_MOVE_FILE              Move (rename) a file.
  38  */
  39 #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102
  40 #define SMB_NT_RENAME_SET_LINK_INFO     0x0103
  41 #define SMB_NT_RENAME_RENAME_FILE       0x0104
  42 #define SMB_NT_RENAME_MOVE_FILE         0x0105
  43 
  44 /*
  45  * smb_com_rename
  46  *
  47  * Rename a file. Files OldFileName must exist and NewFileName must not.
  48  * Both pathnames must be relative to the Tid specified in the request.
  49  * Open files may be renamed.
  50  *
  51  * Multiple files may be renamed in response to a single request as Rename
  52  * File supports wildcards in the file name (last component of the path).
  53  * NOTE: we don't support rename with wildcards.
  54  *
  55  * SearchAttributes indicates the attributes that the target file(s) must
  56  * have. If SearchAttributes is zero then only normal files are renamed.
  57  * If the system file or hidden attributes are specified then the rename
  58  * is inclusive - both the specified type(s) of files and normal files are
  59  * renamed.
  60  */
  61 smb_sdrc_t
  62 smb_pre_rename(smb_request_t *sr)
  63 {
  64         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
  65         smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
  66         int rc;
  67 
  68         if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) {
  69                 rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path,
  70                     &dst_fqi->fq_path.pn_path);
  71 
  72                 dst_fqi->fq_sattr = 0;
  73         }
  74 
  75         DTRACE_SMB_1(op__Rename__start, smb_request_t *, sr); /* arg.dirop */
  76 
  77         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  78 }
  79 
  80 void
  81 smb_post_rename(smb_request_t *sr)
  82 {
  83         DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr);
  84 }
  85 
  86 smb_sdrc_t
  87 smb_com_rename(smb_request_t *sr)
  88 {
  89         smb_fqi_t       *src_fqi = &sr->arg.dirop.fqi;
  90         smb_fqi_t       *dst_fqi = &sr->arg.dirop.dst_fqi;
  91         smb_pathname_t  *src_pn = &src_fqi->fq_path;
  92         smb_pathname_t  *dst_pn = &dst_fqi->fq_path;
  93         uint32_t        status;
  94 
  95         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
  96                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
  97                     ERRDOS, ERROR_ACCESS_DENIED);
  98                 return (SDRC_ERROR);
  99         }
 100 
 101         smb_pathname_init(sr, src_pn, src_pn->pn_path);
 102         smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
 103         if (!smb_pathname_validate(sr, src_pn) ||
 104             !smb_pathname_validate(sr, dst_pn)) {
 105                 return (SDRC_ERROR);
 106         }
 107 
 108         status = smb_common_rename(sr, src_fqi, dst_fqi);
 109         if (status != 0) {
 110                 smbsr_error(sr, status, 0, 0);
 111                 return (SDRC_ERROR);
 112         }
 113 
 114         (void) smbsr_encode_empty_result(sr);
 115         return (SDRC_SUCCESS);
 116 }
 117 
 118 /*
 119  * smb_com_nt_rename
 120  *
 121  * Rename a file. Files OldFileName must exist and NewFileName must not.
 122  * Both pathnames must be relative to the Tid specified in the request.
 123  * Open files may be renamed.
 124  *
 125  * SearchAttributes indicates the attributes that the target file(s) must
 126  * have. If SearchAttributes is zero then only normal files are renamed.
 127  * If the system file or hidden attributes are specified then the rename
 128  * is inclusive - both the specified type(s) of files and normal files are
 129  * renamed.
 130  */
 131 smb_sdrc_t
 132 smb_pre_nt_rename(smb_request_t *sr)
 133 {
 134         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
 135         smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
 136         uint32_t clusters;
 137         int rc;
 138 
 139         rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr,
 140             &sr->arg.dirop.info_level, &clusters);
 141         if (rc == 0) {
 142                 rc = smbsr_decode_data(sr, "%SS", sr,
 143                     &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path);
 144 
 145                 dst_fqi->fq_sattr = 0;
 146         }
 147 
 148         DTRACE_SMB_1(op__NtRename__start, smb_request_t *, sr); /* arg.dirop */
 149 
 150         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 151 }
 152 
 153 void
 154 smb_post_nt_rename(smb_request_t *sr)
 155 {
 156         DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr);
 157 }
 158 
 159 smb_sdrc_t
 160 smb_com_nt_rename(smb_request_t *sr)
 161 {
 162         smb_fqi_t       *src_fqi = &sr->arg.dirop.fqi;
 163         smb_fqi_t       *dst_fqi = &sr->arg.dirop.dst_fqi;
 164         smb_pathname_t  *src_pn = &src_fqi->fq_path;
 165         smb_pathname_t  *dst_pn = &dst_fqi->fq_path;
 166         uint32_t        status;
 167 
 168         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 169                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 170                     ERRDOS, ERROR_ACCESS_DENIED);
 171                 return (SDRC_ERROR);
 172         }
 173 
 174         smb_pathname_init(sr, src_pn, src_pn->pn_path);
 175         smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
 176         if (!smb_pathname_validate(sr, src_pn) ||
 177             !smb_pathname_validate(sr, dst_pn)) {
 178                 return (SDRC_ERROR);
 179         }
 180 
 181         if (smb_contains_wildcards(src_pn->pn_path)) {
 182                 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
 183                     ERRDOS, ERROR_BAD_PATHNAME);
 184                 return (SDRC_ERROR);
 185         }
 186 
 187         switch (sr->arg.dirop.info_level) {
 188         case SMB_NT_RENAME_SET_LINK_INFO:
 189                 status = smb_make_link(sr, src_fqi, dst_fqi);
 190                 break;
 191         case SMB_NT_RENAME_RENAME_FILE:
 192         case SMB_NT_RENAME_MOVE_FILE:
 193                 status = smb_common_rename(sr, src_fqi, dst_fqi);
 194                 break;
 195         case SMB_NT_RENAME_MOVE_CLUSTER_INFO:
 196                 status = NT_STATUS_INVALID_PARAMETER;
 197                 break;
 198         default:
 199                 status = NT_STATUS_ACCESS_DENIED;
 200                 break;
 201         }
 202 
 203         if (status != 0) {
 204                 smbsr_error(sr, status, 0, 0);
 205                 return (SDRC_ERROR);
 206         }
 207 
 208         (void) smbsr_encode_empty_result(sr);
 209         return (SDRC_SUCCESS);
 210 }
 211 
 212 /*
 213  * smb_nt_transact_rename
 214  *
 215  * Windows servers return SUCCESS without renaming file.
 216  * The only check required is to check that the handle (fid) is valid.
 217  */
 218 smb_sdrc_t
 219 smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa)
 220 {
 221         if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0)
 222                 return (SDRC_ERROR);
 223 
 224         smbsr_lookup_file(sr);
 225         if (sr->fid_ofile == NULL) {
 226                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 227                 return (SDRC_ERROR);
 228         }
 229         smbsr_release_file(sr);
 230 
 231         return (SDRC_SUCCESS);
 232 }