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