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_2(op__Rename__start, smb_request_t *, sr,
  76             struct dirop *, &sr->arg.dirop);
  77 
  78         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  79 }
  80 
  81 void
  82 smb_post_rename(smb_request_t *sr)
  83 {
  84         DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr);
  85 }
  86 
  87 smb_sdrc_t
  88 smb_com_rename(smb_request_t *sr)
  89 {
  90         smb_fqi_t       *src_fqi = &sr->arg.dirop.fqi;
  91         smb_fqi_t       *dst_fqi = &sr->arg.dirop.dst_fqi;
  92         smb_pathname_t  *src_pn = &src_fqi->fq_path;
  93         smb_pathname_t  *dst_pn = &dst_fqi->fq_path;
  94         uint32_t        status;
  95 
  96         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
  97                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
  98                     ERRDOS, ERROR_ACCESS_DENIED);
  99                 return (SDRC_ERROR);
 100         }
 101 
 102         smb_pathname_init(sr, src_pn, src_pn->pn_path);
 103         smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
 104         if (!smb_pathname_validate(sr, src_pn) ||
 105             !smb_pathname_validate(sr, dst_pn)) {
 106                 return (SDRC_ERROR);
 107         }
 108 
 109         status = smb_common_rename(sr, src_fqi, dst_fqi);
 110         if (status != 0) {
 111                 smbsr_error(sr, status, 0, 0);
 112                 return (SDRC_ERROR);
 113         }
 114 
 115         (void) smbsr_encode_empty_result(sr);
 116         return (SDRC_SUCCESS);
 117 }
 118 
 119 /*
 120  * smb_com_nt_rename
 121  *
 122  * Rename a file. Files OldFileName must exist and NewFileName must not.
 123  * Both pathnames must be relative to the Tid specified in the request.
 124  * Open files may be renamed.
 125  *
 126  * SearchAttributes indicates the attributes that the target file(s) must
 127  * have. If SearchAttributes is zero then only normal files are renamed.
 128  * If the system file or hidden attributes are specified then the rename
 129  * is inclusive - both the specified type(s) of files and normal files are
 130  * renamed.
 131  */
 132 smb_sdrc_t
 133 smb_pre_nt_rename(smb_request_t *sr)
 134 {
 135         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
 136         smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
 137         uint32_t clusters;
 138         int rc;
 139 
 140         rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr,
 141             &sr->arg.dirop.info_level, &clusters);
 142         if (rc == 0) {
 143                 rc = smbsr_decode_data(sr, "%SS", sr,
 144                     &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path);
 145 
 146                 dst_fqi->fq_sattr = 0;
 147         }
 148 
 149         DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr,
 150             struct dirop *, &sr->arg.dirop);
 151 
 152         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 153 }
 154 
 155 void
 156 smb_post_nt_rename(smb_request_t *sr)
 157 {
 158         DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr);
 159 }
 160 
 161 smb_sdrc_t
 162 smb_com_nt_rename(smb_request_t *sr)
 163 {
 164         smb_fqi_t       *src_fqi = &sr->arg.dirop.fqi;
 165         smb_fqi_t       *dst_fqi = &sr->arg.dirop.dst_fqi;
 166         smb_pathname_t  *src_pn = &src_fqi->fq_path;
 167         smb_pathname_t  *dst_pn = &dst_fqi->fq_path;
 168         uint32_t        status;
 169 
 170         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 171                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 172                     ERRDOS, ERROR_ACCESS_DENIED);
 173                 return (SDRC_ERROR);
 174         }
 175 
 176         smb_pathname_init(sr, src_pn, src_pn->pn_path);
 177         smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
 178         if (!smb_pathname_validate(sr, src_pn) ||
 179             !smb_pathname_validate(sr, dst_pn)) {
 180                 return (SDRC_ERROR);
 181         }
 182 
 183         if (smb_contains_wildcards(src_pn->pn_path)) {
 184                 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
 185                     ERRDOS, ERROR_BAD_PATHNAME);
 186                 return (SDRC_ERROR);
 187         }
 188 
 189         switch (sr->arg.dirop.info_level) {
 190         case SMB_NT_RENAME_SET_LINK_INFO:
 191                 status = smb_make_link(sr, src_fqi, dst_fqi);
 192                 break;
 193         case SMB_NT_RENAME_RENAME_FILE:
 194         case SMB_NT_RENAME_MOVE_FILE:
 195                 status = smb_common_rename(sr, src_fqi, dst_fqi);
 196                 break;
 197         case SMB_NT_RENAME_MOVE_CLUSTER_INFO:
 198                 status = NT_STATUS_INVALID_PARAMETER;
 199                 break;
 200         default:
 201                 status = NT_STATUS_ACCESS_DENIED;
 202                 break;
 203         }
 204 
 205         if (status != 0) {
 206                 smbsr_error(sr, status, 0, 0);
 207                 return (SDRC_ERROR);
 208         }
 209 
 210         (void) smbsr_encode_empty_result(sr);
 211         return (SDRC_SUCCESS);
 212 }
 213 
 214 /*
 215  * smb_nt_transact_rename
 216  *
 217  * Windows servers return SUCCESS without renaming file.
 218  * The only check required is to check that the handle (fid) is valid.
 219  */
 220 smb_sdrc_t
 221 smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa)
 222 {
 223         if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0)
 224                 return (SDRC_ERROR);
 225 
 226         smbsr_lookup_file(sr);
 227         if (sr->fid_ofile == NULL) {
 228                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 229                 return (SDRC_ERROR);
 230         }
 231         smbsr_release_file(sr);
 232 
 233         return (SDRC_SUCCESS);
 234 }