xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision e2f4f3dab373b605b62ac175115f264a5c417eb6)
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 }
235