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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <smbsrv/smb_kproto.h>
27 #include <smbsrv/smbinfo.h>
28 #include <smbsrv/smb_fsops.h>
29
30 /*
31 * The create directory message is sent to create a new directory. The
32 * appropriate Tid and additional pathname are passed. The directory must
33 * not exist for it to be created.
34 *
35 * Client Request Description
36 * ================================== =================================
37 * UCHAR WordCount; Count of parameter words = 0
38 * USHORT ByteCount; Count of data bytes; min = 2
39 * UCHAR BufferFormat; 0x04
40 * STRING DirectoryName[]; Directory name
41 *
42 * Servers require clients to have at least create permission for the
43 * subtree containing the directory in order to create a new directory.
44 * The creator's access rights to the new directory are be determined by
45 * local policy on the server.
46 *
47 * Server Response Description
48 * ================================== =================================
49 * UCHAR WordCount; Count of parameter words = 0
50 * USHORT ByteCount; Count of data bytes = 0
51 */
52 smb_sdrc_t
smb_pre_create_directory(smb_request_t * sr)53 smb_pre_create_directory(smb_request_t *sr)
54 {
55 int rc;
56
57 rc = smbsr_decode_data(sr, "%S", sr,
58 &sr->arg.dirop.fqi.fq_path.pn_path);
59
60 DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr,
61 struct dirop *, &sr->arg.dirop);
62
63 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
64 }
65
66 void
smb_post_create_directory(smb_request_t * sr)67 smb_post_create_directory(smb_request_t *sr)
68 {
69 DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr);
70 }
71
72 smb_sdrc_t
smb_com_create_directory(smb_request_t * sr)73 smb_com_create_directory(smb_request_t *sr)
74 {
75 int rc = 0;
76 smb_pathname_t *pn = &sr->arg.dirop.fqi.fq_path;
77
78 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
79 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
80 ERRDOS, ERROR_ACCESS_DENIED);
81 return (SDRC_ERROR);
82 }
83
84 smb_pathname_init(sr, pn, pn->pn_path);
85 if (!smb_pathname_validate(sr, pn) ||
86 !smb_validate_dirname(sr, pn)) {
87 return (SDRC_ERROR);
88 }
89
90 if ((rc = smb_common_create_directory(sr)) != 0) {
91 smbsr_errno(sr, rc);
92 return (SDRC_ERROR);
93 }
94
95 rc = smbsr_encode_empty_result(sr);
96 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
97 }
98
99 /*
100 * smb_common_create_directory
101 *
102 * Currently called from:
103 * smb_com_create_directory
104 * smb_com_trans2_create_directory
105 *
106 * Returns errno values.
107 */
108 int
smb_common_create_directory(smb_request_t * sr)109 smb_common_create_directory(smb_request_t *sr)
110 {
111 int rc;
112 smb_attr_t new_attr;
113 smb_fqi_t *fqi;
114 smb_node_t *tnode;
115
116 fqi = &sr->arg.dirop.fqi;
117 tnode = sr->tid_tree->t_snode;
118
119 rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
120 tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
121 if (rc != 0)
122 return (rc);
123
124 if (smb_is_invalid_filename(fqi->fq_last_comp)) {
125 smb_node_release(fqi->fq_dnode);
126 return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
127 }
128
129 /* lookup node - to ensure that it does NOT exist */
130 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
131 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
132 if (rc == 0) {
133 smb_node_release(fqi->fq_dnode);
134 smb_node_release(fqi->fq_fnode);
135 return (EEXIST);
136 }
137 if (rc != ENOENT) {
138 smb_node_release(fqi->fq_dnode);
139 return (rc);
140 }
141
142 rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
143 FILE_ADD_SUBDIRECTORY);
144 if (rc != NT_STATUS_SUCCESS) {
145 smb_node_release(fqi->fq_dnode);
146 return (EACCES);
147 }
148
149 /*
150 * Explicitly set sa_dosattr, otherwise the file system may
151 * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for
152 * compatibility with windows servers, should not be set.
153 */
154 bzero(&new_attr, sizeof (new_attr));
155 new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
156 new_attr.sa_vattr.va_type = VDIR;
157 new_attr.sa_vattr.va_mode = 0777;
158 new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
159
160 rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
161 &new_attr, &fqi->fq_fnode);
162 if (rc != 0) {
163 smb_node_release(fqi->fq_dnode);
164 return (rc);
165 }
166
167 sr->arg.open.create_options = FILE_DIRECTORY_FILE;
168
169 smb_node_release(fqi->fq_dnode);
170 smb_node_release(fqi->fq_fnode);
171 return (0);
172 }
173
174 /*
175 * The delete directory message is sent to delete an empty directory. The
176 * appropriate Tid and additional pathname are passed. The directory must
177 * be empty for it to be deleted.
178 *
179 * NT supports a hidden permission known as File Delete Child (FDC). If
180 * the user has FullControl access to a directory, the user is permitted
181 * to delete any object in the directory regardless of the permissions
182 * on the object.
183 *
184 * Client Request Description
185 * ================================== =================================
186 * UCHAR WordCount; Count of parameter words = 0
187 * USHORT ByteCount; Count of data bytes; min = 2
188 * UCHAR BufferFormat; 0x04
189 * STRING DirectoryName[]; Directory name
190 *
191 * The directory to be deleted cannot be the root of the share specified
192 * by Tid.
193 *
194 * Server Response Description
195 * ================================== =================================
196 * UCHAR WordCount; Count of parameter words = 0
197 * USHORT ByteCount; Count of data bytes = 0
198 */
199 smb_sdrc_t
smb_pre_delete_directory(smb_request_t * sr)200 smb_pre_delete_directory(smb_request_t *sr)
201 {
202 int rc;
203
204 rc = smbsr_decode_data(sr, "%S", sr,
205 &sr->arg.dirop.fqi.fq_path.pn_path);
206
207 DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr,
208 struct dirop *, &sr->arg.dirop);
209
210 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
211 }
212
213 void
smb_post_delete_directory(smb_request_t * sr)214 smb_post_delete_directory(smb_request_t *sr)
215 {
216 DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr);
217 }
218
219 smb_sdrc_t
smb_com_delete_directory(smb_request_t * sr)220 smb_com_delete_directory(smb_request_t *sr)
221 {
222 int rc;
223 uint32_t flags = 0;
224 smb_fqi_t *fqi;
225 smb_node_t *tnode;
226
227 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
228 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
229 ERRDOS, ERROR_ACCESS_DENIED);
230 return (SDRC_ERROR);
231 }
232
233 fqi = &sr->arg.dirop.fqi;
234 tnode = sr->tid_tree->t_snode;
235
236 smb_pathname_init(sr, &fqi->fq_path, fqi->fq_path.pn_path);
237 if (!smb_pathname_validate(sr, &fqi->fq_path) ||
238 !smb_validate_dirname(sr, &fqi->fq_path)) {
239 return (SDRC_ERROR);
240 }
241
242 rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
243 tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
244
245 if (rc != 0) {
246 smbsr_errno(sr, rc);
247 return (SDRC_ERROR);
248 }
249
250 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
251 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
252 if (rc != 0) {
253 if (rc == ENOENT)
254 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
255 ERRDOS, ERROR_FILE_NOT_FOUND);
256 else
257 smbsr_errno(sr, rc);
258 smb_node_release(fqi->fq_dnode);
259 return (SDRC_ERROR);
260 }
261
262 /*
263 * Delete should fail if this is the root of a share
264 * or a DFS link
265 */
266 if ((fqi->fq_fnode == tnode) || smb_node_is_dfslink(fqi->fq_fnode)) {
267 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
268 ERRDOS, ERROR_ACCESS_DENIED);
269 smb_node_release(fqi->fq_dnode);
270 smb_node_release(fqi->fq_fnode);
271 return (SDRC_ERROR);
272 }
273
274 if (!smb_node_is_dir(fqi->fq_fnode)) {
275 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
276 ERRDOS, ERROR_PATH_NOT_FOUND);
277 smb_node_release(fqi->fq_dnode);
278 smb_node_release(fqi->fq_fnode);
279 return (SDRC_ERROR);
280 }
281
282 rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
283 if (rc != 0) {
284 smbsr_errno(sr, rc);
285 smb_node_release(fqi->fq_dnode);
286 smb_node_release(fqi->fq_fnode);
287 return (SDRC_ERROR);
288 }
289
290 if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
291 (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
292 != NT_STATUS_SUCCESS)) {
293 smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
294 ERRDOS, ERROR_ACCESS_DENIED);
295 smb_node_release(fqi->fq_dnode);
296 smb_node_release(fqi->fq_fnode);
297 return (SDRC_ERROR);
298 }
299
300 if (SMB_TREE_SUPPORTS_CATIA(sr))
301 flags |= SMB_CATIA;
302
303 rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
304 fqi->fq_fnode->od_name, flags);
305
306 smb_node_release(fqi->fq_fnode);
307 smb_node_release(fqi->fq_dnode);
308
309 if (rc != 0) {
310 if (rc == EEXIST)
311 smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
312 ERRDOS, ERROR_DIR_NOT_EMPTY);
313 else
314 smbsr_errno(sr, rc);
315 return (SDRC_ERROR);
316 }
317
318 rc = smbsr_encode_empty_result(sr);
319 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
320 }
321
322 /*
323 * This SMB is used to verify that a path exists and is a directory. No
324 * error is returned if the given path exists and the client has read
325 * access to it. Client machines which maintain a concept of a "working
326 * directory" will find this useful to verify the validity of a "change
327 * working directory" command. Note that the servers do NOT have a concept
328 * of working directory for a particular client. The client must always
329 * supply full pathnames relative to the Tid in the SMB header.
330 *
331 * Client Request Description
332 * ================================== =================================
333 *
334 * UCHAR WordCount; Count of parameter words = 0
335 * USHORT ByteCount; Count of data bytes; min = 2
336 * UCHAR BufferFormat; 0x04
337 * STRING DirectoryPath[]; Directory path
338 *
339 * Server Response Description
340 * ================================== =================================
341 *
342 * UCHAR WordCount; Count of parameter words = 0
343 * USHORT ByteCount; Count of data bytes = 0
344 *
345 * DOS clients, in particular, depend on ERRbadpath if the directory is
346 * not found.
347 */
348 smb_sdrc_t
smb_pre_check_directory(smb_request_t * sr)349 smb_pre_check_directory(smb_request_t *sr)
350 {
351 int rc;
352
353 rc = smbsr_decode_data(sr, "%S", sr,
354 &sr->arg.dirop.fqi.fq_path.pn_path);
355
356 DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr,
357 struct dirop *, &sr->arg.dirop);
358
359 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
360 }
361
362 void
smb_post_check_directory(smb_request_t * sr)363 smb_post_check_directory(smb_request_t *sr)
364 {
365 DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
366 }
367
368 smb_sdrc_t
smb_com_check_directory(smb_request_t * sr)369 smb_com_check_directory(smb_request_t *sr)
370 {
371 int rc;
372 smb_fqi_t *fqi;
373 smb_node_t *tnode;
374 smb_node_t *node;
375 char *path;
376 smb_pathname_t *pn;
377
378 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
379 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
380 ERROR_ACCESS_DENIED);
381 return (SDRC_ERROR);
382 }
383
384 fqi = &sr->arg.dirop.fqi;
385 pn = &fqi->fq_path;
386
387 if (pn->pn_path[0] == '\0') {
388 rc = smbsr_encode_empty_result(sr);
389 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
390 }
391
392 smb_pathname_init(sr, pn, pn->pn_path);
393 if (!smb_pathname_validate(sr, pn) ||
394 !smb_validate_dirname(sr, pn)) {
395 return (SDRC_ERROR);
396 }
397
398 path = pn->pn_path;
399 tnode = sr->tid_tree->t_snode;
400
401 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
402 &fqi->fq_dnode, fqi->fq_last_comp);
403 if (rc != 0) {
404 smbsr_errno(sr, rc);
405 return (SDRC_ERROR);
406 }
407
408 rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
409 tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
410 smb_node_release(fqi->fq_dnode);
411 if (rc != 0) {
412 if (rc == ENOENT)
413 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
414 ERRDOS, ERROR_PATH_NOT_FOUND);
415 else
416 smbsr_errno(sr, rc);
417 return (SDRC_ERROR);
418 }
419
420 node = fqi->fq_fnode;
421 if (!smb_node_is_dir(node)) {
422 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
423 ERRDOS, ERROR_PATH_NOT_FOUND);
424 smb_node_release(node);
425 return (SDRC_ERROR);
426 }
427
428 if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
429 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
430 smb_node_release(node);
431 return (SDRC_ERROR);
432 }
433
434 rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE);
435
436 smb_node_release(node);
437
438 if (rc != 0) {
439 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
440 ERRDOS, ERROR_ACCESS_DENIED);
441 return (SDRC_ERROR);
442 }
443
444 rc = smbsr_encode_empty_result(sr);
445 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
446 }
447