xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision b62fa64bd1b93f15d05f01b9f01842071f059a30)
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 2020 Tintri by DDN, Inc. All rights reserved.
24  * Copyright 2022-2023 RackTop Systems, Inc.
25  */
26 /*
27  * SMB Node State Machine
28  * ----------------------
29  *
30  *
31  *		    +----------- Creation/Allocation
32  *		    |
33  *		    | T0
34  *		    |
35  *		    v
36  *    +----------------------------+
37  *    |  SMB_NODE_STATE_AVAILABLE  |
38  *    +----------------------------+
39  *		    |
40  *		    | T1
41  *		    |
42  *		    v
43  *    +-----------------------------+
44  *    |  SMB_NODE_STATE_DESTROYING  |
45  *    +-----------------------------+
46  *		    |
47  *		    |
48  *		    | T2
49  *		    |
50  *		    +----------> Deletion/Free
51  *
52  * Transition T0
53  *
54  *    This transition occurs in smb_node_lookup(). If the node looked for is
55  *    not found in the has table a new node is created. The reference count is
56  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
57  *
58  * Transition T1
59  *
60  *    This transition occurs in smb_node_release(). If the reference count
61  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
62  *    reference count will be given out for that node.
63  *
64  * Transition T2
65  *
66  *    This transition occurs in smb_node_release(). The structure is deleted.
67  *
68  * Comments
69  * --------
70  *
71  *    The reason the smb node has 2 states is the following synchronization
72  *    rule:
73  *
74  *    There's a mutex embedded in the node used to protect its fields and
75  *    there's a lock embedded in the bucket of the hash table the node belongs
76  *    to. To increment or to decrement the reference count the mutex must be
77  *    entered. To insert the node into the bucket and to remove it from the
78  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
79  *    lock) have to be entered, the lock has always to be entered first then
80  *    the mutex. This prevents a deadlock between smb_node_lookup() and
81  *    smb_node_release() from occurring. However, in smb_node_release() when the
82  *    reference count drops to zero and triggers the deletion of the node, the
83  *    mutex has to be released before entering the lock of the bucket (to
84  *    remove the node). This creates a window during which the node that is
85  *    about to be freed could be given out by smb_node_lookup(). To close that
86  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
87  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
88  *    state will indicate that the node should be treated as non existent (of
89  *    course the state of the node should be tested/updated under the
90  *    protection of the mutex).
91  */
92 #include <smbsrv/smb2_kproto.h>
93 #include <smbsrv/smb_fsops.h>
94 #include <smbsrv/smb_kstat.h>
95 #include <sys/ddi.h>
96 #include <sys/extdirent.h>
97 #include <sys/pathname.h>
98 #include <sys/sdt.h>
99 #include <sys/nbmlock.h>
100 #include <fs/fs_reparse.h>
101 
102 /* Todo: move this to sys/time.h */
103 #ifndef	timespeccmp
104 #define	timespeccmp(tvp, uvp, cmp)				\
105 	(((tvp)->tv_sec == (uvp)->tv_sec) ?			\
106 	((tvp)->tv_nsec cmp (uvp)->tv_nsec) :			\
107 	((tvp)->tv_sec cmp (uvp)->tv_sec))
108 #endif
109 
110 uint32_t smb_is_executable(char *);
111 static void smb_node_create_audit_buf(smb_node_t *, int);
112 static void smb_node_destroy_audit_buf(smb_node_t *);
113 static void smb_node_audit(smb_node_t *);
114 static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
115 static void smb_node_free(smb_node_t *);
116 static int smb_node_constructor(void *, void *, int);
117 static void smb_node_destructor(void *, void *);
118 static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
119 
120 static void smb_node_init_reparse(smb_node_t *, smb_attr_t *);
121 static void smb_node_init_system(smb_node_t *);
122 
123 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
124     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
125     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
126     ASSERT((_dir_)->n_dnode != (_node_));
127 
128 /* round sz to DEV_BSIZE block */
129 #define	SMB_ALLOCSZ(sz)	(((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
130 
131 static kmem_cache_t	*smb_node_cache = NULL;
132 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
133 static smb_node_t	*smb_root_node;
134 
135 /*
136  * smb_node_init
137  *
138  * Initialization of the SMB node layer.
139  *
140  * This function is not multi-thread safe. The caller must make sure only one
141  * thread makes the call.
142  */
143 void
smb_node_init(void)144 smb_node_init(void)
145 {
146 	smb_attr_t	attr;
147 	smb_llist_t	*node_hdr;
148 	smb_node_t	*node;
149 	uint32_t	hashkey;
150 	int		i;
151 
152 	if (smb_node_cache != NULL)
153 		return;
154 
155 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
156 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
157 	    NULL, NULL, NULL, 0);
158 
159 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
160 		smb_llist_constructor(&smb_node_hash_table[i],
161 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
162 	}
163 
164 	/*
165 	 * The node cache is shared by all zones, so the smb_root_node
166 	 * must represent the real (global zone) rootdir.
167 	 * Note intentional use of kcred here.
168 	 */
169 	attr.sa_mask = SMB_AT_ALL;
170 	VERIFY0(smb_vop_getattr(rootdir, NULL, &attr, 0, kcred));
171 	node_hdr = smb_node_get_hash(&rootdir->v_vfsp->vfs_fsid, &attr,
172 	    &hashkey);
173 	node = smb_node_alloc("/", rootdir, node_hdr, hashkey);
174 	smb_llist_enter(node_hdr, RW_WRITER);
175 	smb_llist_insert_head(node_hdr, node);
176 	smb_llist_exit(node_hdr);
177 	smb_root_node = node;	/* smb_node_release in smb_node_fini */
178 }
179 
180 /*
181  * smb_node_fini
182  *
183  * This function is not multi-thread safe. The caller must make sure only one
184  * thread makes the call.
185  */
186 void
smb_node_fini(void)187 smb_node_fini(void)
188 {
189 	int	i;
190 
191 	if (smb_root_node != NULL) {
192 		smb_node_release(smb_root_node);
193 		smb_root_node = NULL;
194 	}
195 
196 	if (smb_node_cache == NULL)
197 		return;
198 
199 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
200 		smb_llist_t	*bucket;
201 		smb_node_t	*node;
202 
203 		/*
204 		 * The SMB node hash table should be empty at this point.
205 		 * If the hash table is not empty, clean it up.
206 		 *
207 		 * The reason why SMB nodes might remain in this table is
208 		 * generally forgotten references somewhere, perhaps on
209 		 * open files, etc.  Those are defects.
210 		 */
211 		bucket = &smb_node_hash_table[i];
212 		node = smb_llist_head(bucket);
213 		while (node != NULL) {
214 #ifdef DEBUG
215 			cmn_err(CE_NOTE, "leaked node: 0x%p %s",
216 			    (void *)node, node->od_name);
217 			cmn_err(CE_NOTE, "...bucket: 0x%p", bucket);
218 			debug_enter("leaked_node");
219 #endif
220 			smb_llist_remove(bucket, node);
221 			node = smb_llist_head(bucket);
222 		}
223 	}
224 
225 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
226 		smb_llist_destructor(&smb_node_hash_table[i]);
227 	}
228 	kmem_cache_destroy(smb_node_cache);
229 	smb_node_cache = NULL;
230 }
231 
232 /*
233  * smb_node_lookup()
234  *
235  * NOTE: This routine should only be called by the file system interface layer,
236  * and not by SMB.
237  *
238  * smb_node_lookup() is called upon successful lookup, mkdir, and create
239  * (for both non-streams and streams).  In each of these cases, a held vnode is
240  * passed into this routine.  If a new smb_node is created it will take its
241  * own hold on the vnode.  The caller's hold therefore still belongs to, and
242  * should be released by, the caller.
243  *
244  * A reference is taken on the smb_node whether found in the hash table
245  * or newly created.
246  *
247  * If an smb_node needs to be created, a reference is also taken on the
248  * dnode (if passed in).
249  *
250  * See smb_node_release() for details on the release of these references.
251  */
252 
253 /*ARGSUSED*/
254 smb_node_t *
smb_node_lookup(struct smb_request * sr,struct open_param * op,cred_t * cred,vnode_t * vp,char * od_name,smb_node_t * dnode,smb_node_t * unode)255 smb_node_lookup(
256     struct smb_request	*sr,
257     struct open_param	*op,
258     cred_t		*cred,
259     vnode_t		*vp,
260     char		*od_name,
261     smb_node_t		*dnode,
262     smb_node_t		*unode)
263 {
264 	smb_llist_t		*node_hdr;
265 	smb_node_t		*node;
266 	smb_attr_t		attr;
267 	uint32_t		hashkey = 0;
268 	fsid_t			fsid;
269 	int			error;
270 	krw_t			lock_mode;
271 	vnode_t			*unnamed_vp = NULL;
272 
273 	/*
274 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
275 	 * because the node may not yet exist.  We also do not want to call
276 	 * it with the list lock held.
277 	 */
278 
279 	if (unode)
280 		unnamed_vp = unode->vp;
281 
282 	/*
283 	 * This getattr is performed on behalf of the server
284 	 * that's why kcred is used not the user's cred
285 	 */
286 	attr.sa_mask = SMB_AT_ALL;
287 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, zone_kcred());
288 	if (error)
289 		return (NULL);
290 
291 	if (sr && sr->tid_tree) {
292 		/*
293 		 * The fsid for a file is that of the tree, even
294 		 * if the file resides in a different mountpoint
295 		 * under the share.
296 		 */
297 		fsid = SMB_TREE_FSID(sr->tid_tree);
298 	} else {
299 		/*
300 		 * This should be getting executed only for the
301 		 * tree root smb_node.
302 		 */
303 		fsid = vp->v_vfsp->vfs_fsid;
304 	}
305 
306 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
307 	lock_mode = RW_READER;
308 
309 	smb_llist_enter(node_hdr, lock_mode);
310 	for (;;) {
311 		node = list_head(&node_hdr->ll_list);
312 		while (node) {
313 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
314 			ASSERT(node->n_hash_bucket == node_hdr);
315 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
316 				mutex_enter(&node->n_mutex);
317 				DTRACE_PROBE1(smb_node_lookup_hit,
318 				    smb_node_t *, node);
319 				switch (node->n_state) {
320 				case SMB_NODE_STATE_AVAILABLE:
321 					/* The node was found. */
322 					node->n_refcnt++;
323 					if ((node->n_dnode == NULL) &&
324 					    (dnode != NULL) &&
325 					    (node != dnode) &&
326 					    (strcmp(od_name, "..") != 0) &&
327 					    (strcmp(od_name, ".") != 0)) {
328 						VALIDATE_DIR_NODE(dnode, node);
329 						node->n_dnode = dnode;
330 						smb_node_ref(dnode);
331 					}
332 
333 					smb_node_audit(node);
334 					mutex_exit(&node->n_mutex);
335 					smb_llist_exit(node_hdr);
336 					return (node);
337 
338 				case SMB_NODE_STATE_DESTROYING:
339 					/*
340 					 * Although the node exists it is about
341 					 * to be destroyed. We act as it hasn't
342 					 * been found.
343 					 */
344 					mutex_exit(&node->n_mutex);
345 					break;
346 				default:
347 					/*
348 					 * Although the node exists it is in an
349 					 * unknown state. We act as it hasn't
350 					 * been found.
351 					 */
352 					ASSERT(0);
353 					mutex_exit(&node->n_mutex);
354 					break;
355 				}
356 			}
357 			node = smb_llist_next(node_hdr, node);
358 		}
359 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
360 			lock_mode = RW_WRITER;
361 			continue;
362 		}
363 		break;
364 	}
365 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
366 	smb_node_init_reparse(node, &attr);
367 
368 	if (op)
369 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
370 
371 	if (dnode) {
372 		smb_node_ref(dnode);
373 		node->n_dnode = dnode;
374 		ASSERT(dnode->n_dnode != node);
375 		ASSERT((dnode->vp->v_xattrdir) ||
376 		    (dnode->vp->v_type == VDIR));
377 	}
378 
379 	if (unode) {
380 		smb_node_ref(unode);
381 		node->n_unode = unode;
382 	}
383 
384 	smb_node_init_system(node);
385 
386 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
387 	smb_node_audit(node);
388 	smb_llist_insert_head(node_hdr, node);
389 	smb_llist_exit(node_hdr);
390 	return (node);
391 }
392 
393 /*
394  * smb_stream_node_lookup()
395  *
396  * Note: stream_name (the name that will be stored in the "od_name" field
397  * of a stream's smb_node) is the same as the on-disk name for the stream
398  * except that it does not have SMB_STREAM_PREFIX prepended.
399  */
400 
401 smb_node_t *
smb_stream_node_lookup(smb_request_t * sr,cred_t * cr,smb_node_t * fnode,vnode_t * xattrdirvp,vnode_t * vp,char * stream_name)402 smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
403     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
404 {
405 	smb_node_t	*xattrdir_node;
406 	smb_node_t	*snode;
407 
408 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
409 	    fnode, NULL);
410 
411 	if (xattrdir_node == NULL)
412 		return (NULL);
413 
414 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
415 	    fnode);
416 
417 	(void) smb_node_release(xattrdir_node);
418 	return (snode);
419 }
420 
421 
422 /*
423  * This function should be called whenever a reference is needed on an
424  * smb_node pointer.  The copy of an smb_node pointer from one non-local
425  * data structure to another requires a reference to be taken on the smb_node
426  * (unless the usage is localized).  Each data structure deallocation routine
427  * will call smb_node_release() on its smb_node pointers.
428  *
429  * In general, an smb_node pointer residing in a structure should never be
430  * stale.  A node pointer may be NULL, however, and care should be taken
431  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
432  * Care also needs to be taken with respect to racing deallocations of a
433  * structure.
434  */
435 void
smb_node_ref(smb_node_t * node)436 smb_node_ref(smb_node_t *node)
437 {
438 	SMB_NODE_VALID(node);
439 
440 	mutex_enter(&node->n_mutex);
441 	switch (node->n_state) {
442 	case SMB_NODE_STATE_AVAILABLE:
443 		node->n_refcnt++;
444 		ASSERT(node->n_refcnt);
445 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
446 		smb_node_audit(node);
447 		break;
448 	default:
449 		SMB_PANIC();
450 	}
451 	mutex_exit(&node->n_mutex);
452 }
453 
454 /*
455  * smb_node_lookup() takes a hold on an smb_node, whether found in the
456  * hash table or newly created.  This hold is expected to be released
457  * in the following manner.
458  *
459  * smb_node_lookup() takes an address of an smb_node pointer.  This should
460  * be getting passed down via a lookup (whether path name or component), mkdir,
461  * create.  If the original smb_node pointer resides in a data structure, then
462  * the deallocation routine for the data structure is responsible for calling
463  * smb_node_release() on the smb_node pointer.  Alternatively,
464  * smb_node_release() can be called as soon as the smb_node pointer is no longer
465  * needed.  In this case, callers are responsible for setting an embedded
466  * pointer to NULL if it is known that the last reference is being released.
467  *
468  * If the passed-in address of the smb_node pointer belongs to a local variable,
469  * then the caller with the local variable should call smb_node_release()
470  * directly.
471  *
472  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
473  * as smb_node_lookup() takes a hold on dnode.
474  */
475 void
smb_node_release(smb_node_t * node)476 smb_node_release(smb_node_t *node)
477 {
478 	SMB_NODE_VALID(node);
479 
480 	mutex_enter(&node->n_mutex);
481 	ASSERT(node->n_refcnt);
482 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
483 	if (--node->n_refcnt == 0) {
484 		switch (node->n_state) {
485 
486 		case SMB_NODE_STATE_AVAILABLE:
487 			node->n_state = SMB_NODE_STATE_DESTROYING;
488 
489 			/*
490 			 * While we still hold n_mutex,
491 			 * make sure FEM hooks are gone.
492 			 */
493 			if (node->n_fcn_count > 0) {
494 				DTRACE_PROBE1(fem__fcn__dangles,
495 				    smb_node_t *, node);
496 				node->n_fcn_count = 0;
497 				(void) smb_fem_fcn_uninstall(node);
498 			}
499 
500 			mutex_exit(&node->n_mutex);
501 
502 			/*
503 			 * Out of caution, make sure FEM hooks
504 			 * used by oplocks are also gone.
505 			 */
506 			mutex_enter(&node->n_oplock.ol_mutex);
507 			ASSERT(node->n_oplock.ol_fem == B_FALSE);
508 			if (node->n_oplock.ol_fem == B_TRUE) {
509 				smb_fem_oplock_uninstall(node);
510 				node->n_oplock.ol_fem = B_FALSE;
511 			}
512 			mutex_exit(&node->n_oplock.ol_mutex);
513 
514 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
515 			smb_llist_remove(node->n_hash_bucket, node);
516 			smb_llist_exit(node->n_hash_bucket);
517 
518 			/*
519 			 * Check if the file was deleted
520 			 */
521 			if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
522 				smb_node_delete_on_close(node);
523 			}
524 
525 			if (node->n_dnode) {
526 				ASSERT(node->n_dnode->n_magic ==
527 				    SMB_NODE_MAGIC);
528 				smb_node_release(node->n_dnode);
529 			}
530 
531 			if (node->n_unode) {
532 				ASSERT(node->n_unode->n_magic ==
533 				    SMB_NODE_MAGIC);
534 				smb_node_release(node->n_unode);
535 			}
536 
537 			smb_node_free(node);
538 			return;
539 
540 		default:
541 			SMB_PANIC();
542 		}
543 	}
544 	smb_node_audit(node);
545 	mutex_exit(&node->n_mutex);
546 }
547 
548 void
smb_node_delete_on_close(smb_node_t * node)549 smb_node_delete_on_close(smb_node_t *node)
550 {
551 	smb_node_t	*d_snode;
552 	int		rc = 0;
553 	uint32_t	flags = 0;
554 
555 	d_snode = node->n_dnode;
556 
557 	ASSERT((node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0);
558 
559 	node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
560 	node->flags |= NODE_FLAGS_DELETE_COMMITTED;
561 	flags = node->n_delete_on_close_flags;
562 	ASSERT(node->od_name != NULL);
563 
564 	if (smb_node_is_dir(node))
565 		rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
566 		    d_snode, node->od_name, flags);
567 	else
568 		rc = smb_fsop_remove(0, node->delete_on_close_cred,
569 		    d_snode, node->od_name, flags);
570 	crfree(node->delete_on_close_cred);
571 	node->delete_on_close_cred = NULL;
572 
573 	if (rc != 0)
574 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
575 		    node->od_name, rc);
576 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
577 }
578 
579 /*
580  * smb_node_rename()
581  *
582  */
583 void
smb_node_rename(smb_node_t * from_dnode,smb_node_t * ret_node,smb_node_t * to_dnode,char * to_name)584 smb_node_rename(
585     smb_node_t	*from_dnode,
586     smb_node_t	*ret_node,
587     smb_node_t	*to_dnode,
588     char	*to_name)
589 {
590 	SMB_NODE_VALID(from_dnode);
591 	SMB_NODE_VALID(to_dnode);
592 	SMB_NODE_VALID(ret_node);
593 
594 	smb_node_ref(to_dnode);
595 	mutex_enter(&ret_node->n_mutex);
596 	switch (ret_node->n_state) {
597 	case SMB_NODE_STATE_AVAILABLE:
598 		ret_node->n_dnode = to_dnode;
599 		mutex_exit(&ret_node->n_mutex);
600 		ASSERT(to_dnode->n_dnode != ret_node);
601 		ASSERT((to_dnode->vp->v_xattrdir) ||
602 		    (to_dnode->vp->v_type == VDIR));
603 		smb_node_release(from_dnode);
604 		(void) strcpy(ret_node->od_name, to_name);
605 		/*
606 		 * XXX Need to update attributes?
607 		 */
608 		break;
609 	default:
610 		SMB_PANIC();
611 	}
612 }
613 
614 /*
615  * Find/create an SMB node for the root of this zone and store it
616  * in *svrootp.  Also create nodes leading to this directory.
617  */
618 int
smb_node_root_init(smb_server_t * sv,smb_node_t ** svrootp)619 smb_node_root_init(smb_server_t *sv, smb_node_t **svrootp)
620 {
621 	zone_t		*zone = curzone;
622 	int		error;
623 
624 	ASSERT(zone->zone_id == sv->sv_zid);
625 	if (smb_root_node == NULL)
626 		return (ENOENT);
627 
628 	/*
629 	 * We're getting smb nodes below the zone root here,
630 	 * so need to use kcred, not zone_kcred().
631 	 */
632 	error = smb_pathname(NULL, zone->zone_rootpath, 0,
633 	    smb_root_node, smb_root_node, NULL, svrootp, kcred, NULL);
634 
635 	return (error);
636 }
637 
638 /*
639  * Helper function for smb_node_set_delete_on_close(). Assumes node is a dir.
640  * Return 0 if this is an empty dir. Otherwise return a NT_STATUS code.
641  * Unfortunately, to find out if a directory is empty, we have to read it
642  * and check for anything other than "." or ".." in the readdir buf.
643  */
644 static uint32_t
smb_rmdir_possible(smb_node_t * n)645 smb_rmdir_possible(smb_node_t *n)
646 {
647 	ASSERT(n->vp->v_type == VDIR);
648 	char *buf;
649 	char *bufptr;
650 	struct dirent64	*dp;
651 	uint32_t status = NT_STATUS_SUCCESS;
652 	int bsize = SMB_ODIR_BUFSIZE;
653 	int eof = 0;
654 
655 	buf = kmem_alloc(SMB_ODIR_BUFSIZE, KM_SLEEP);
656 
657 	/* Flags zero: no edirent, no ABE wanted here */
658 	if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, 0, zone_kcred())) {
659 		status = NT_STATUS_INTERNAL_ERROR;
660 		goto out;
661 	}
662 
663 	bufptr = buf;
664 	while (bsize > 0) {
665 		/* LINTED pointer alignment */
666 		dp = (struct dirent64 *)bufptr;
667 
668 		bufptr += dp->d_reclen;
669 		bsize  -= dp->d_reclen;
670 		if (bsize < 0) {
671 			/* partial record */
672 			status = NT_STATUS_DIRECTORY_NOT_EMPTY;
673 			break;
674 		}
675 
676 		if (strcmp(dp->d_name, ".") != 0 &&
677 		    strcmp(dp->d_name, "..") != 0) {
678 			status = NT_STATUS_DIRECTORY_NOT_EMPTY;
679 			break;
680 		}
681 	}
682 
683 out:
684 	kmem_free(buf, SMB_ODIR_BUFSIZE);
685 	return (status);
686 }
687 
688 /*
689  * When DeleteOnClose is set on an smb_node, the common open code will
690  * reject subsequent open requests for the file. Observation of Windows
691  * 2000 indicates that subsequent opens should be allowed (assuming
692  * there would be no sharing violation) until the file is closed using
693  * the fid on which the DeleteOnClose was requested.
694  *
695  * If there are multiple opens with delete-on-close create options,
696  * whichever the first file handle is closed will trigger the node to be
697  * marked as delete-on-close. The credentials of that ofile will be used
698  * as the delete-on-close credentials of the node.
699  *
700  * Note that "read-only" tests have already happened before this call.
701  */
702 uint32_t
smb_node_set_delete_on_close(smb_node_t * node,cred_t * cr,uint32_t flags)703 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
704 {
705 	uint32_t status;
706 
707 	/*
708 	 * If the directory is not empty we should fail setting del-on-close
709 	 * with STATUS_DIRECTORY_NOT_EMPTY. see MS's
710 	 * "File System Behavior Overview" doc section 4.3.2
711 	 */
712 	if (smb_node_is_dir(node)) {
713 		status = smb_rmdir_possible(node);
714 		if (status != 0) {
715 			return (status);
716 		}
717 	}
718 
719 	/* Dataset roots can't be deleted, so don't set DOC */
720 	if ((node->flags & NODE_FLAGS_VFSROOT) != 0) {
721 		return (NT_STATUS_CANNOT_DELETE);
722 	}
723 
724 	mutex_enter(&node->n_mutex);
725 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
726 		/* It was already marked.  We're done. */
727 		mutex_exit(&node->n_mutex);
728 		return (NT_STATUS_SUCCESS);
729 	}
730 
731 	crhold(cr);
732 	node->delete_on_close_cred = cr;
733 	node->n_delete_on_close_flags = flags;
734 	node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
735 	mutex_exit(&node->n_mutex);
736 
737 	/*
738 	 * Tell any change notify calls to close their handles
739 	 * and get out of the way.  FILE_ACTION_DELETE_PENDING
740 	 * is a special, internal-only action for this purpose.
741 	 */
742 	smb_node_notify_change(node, FILE_ACTION_DELETE_PENDING, NULL);
743 
744 	return (NT_STATUS_SUCCESS);
745 }
746 
747 void
smb_node_reset_delete_on_close(smb_node_t * node)748 smb_node_reset_delete_on_close(smb_node_t *node)
749 {
750 	mutex_enter(&node->n_mutex);
751 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
752 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
753 		crfree(node->delete_on_close_cred);
754 		node->delete_on_close_cred = NULL;
755 		node->n_delete_on_close_flags = 0;
756 	}
757 	mutex_exit(&node->n_mutex);
758 }
759 
760 /*
761  * smb_node_open_check
762  *
763  * check file sharing rules for current open request
764  * against all existing opens for a file.
765  *
766  * Returns NT_STATUS_SHARING_VIOLATION if there is any
767  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
768  */
769 uint32_t
smb_node_open_check(smb_node_t * node,uint32_t desired_access,uint32_t share_access)770 smb_node_open_check(smb_node_t *node, uint32_t desired_access,
771     uint32_t share_access)
772 {
773 	smb_ofile_t *of;
774 	uint32_t status;
775 
776 	SMB_NODE_VALID(node);
777 
778 	smb_llist_enter(&node->n_ofile_list, RW_READER);
779 	of = smb_llist_head(&node->n_ofile_list);
780 	while (of) {
781 		status = smb_ofile_open_check(of, desired_access, share_access);
782 
783 		switch (status) {
784 		case NT_STATUS_INVALID_HANDLE:
785 		case NT_STATUS_SUCCESS:
786 			of = smb_llist_next(&node->n_ofile_list, of);
787 			break;
788 		default:
789 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
790 			DTRACE_PROBE3(conflict3,
791 			    smb_ofile_t *, of,
792 			    uint32_t, desired_access,
793 			    uint32_t, share_access);
794 			smb_llist_exit(&node->n_ofile_list);
795 			return (status);
796 		}
797 	}
798 
799 	smb_llist_exit(&node->n_ofile_list);
800 	return (NT_STATUS_SUCCESS);
801 }
802 
803 uint32_t
smb_node_rename_check(smb_node_t * node)804 smb_node_rename_check(smb_node_t *node)
805 {
806 	smb_ofile_t	*of;
807 	uint32_t	status;
808 
809 	SMB_NODE_VALID(node);
810 
811 	/*
812 	 * Intra-CIFS check
813 	 */
814 	smb_llist_enter(&node->n_ofile_list, RW_READER);
815 	of = smb_llist_head(&node->n_ofile_list);
816 	while (of) {
817 		status = smb_ofile_rename_check(of);
818 
819 		switch (status) {
820 		case NT_STATUS_INVALID_HANDLE:
821 		case NT_STATUS_SUCCESS:
822 			of = smb_llist_next(&node->n_ofile_list, of);
823 			break;
824 		default:
825 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
826 			DTRACE_PROBE1(conflict1, smb_ofile_t *, of);
827 			smb_llist_exit(&node->n_ofile_list);
828 			return (status);
829 		}
830 	}
831 	smb_llist_exit(&node->n_ofile_list);
832 	return (NT_STATUS_SUCCESS);
833 }
834 
835 uint32_t
smb_node_delete_check(smb_node_t * node)836 smb_node_delete_check(smb_node_t *node)
837 {
838 	smb_ofile_t	*of;
839 	uint32_t	status;
840 
841 	SMB_NODE_VALID(node);
842 
843 	if (smb_node_is_dir(node))
844 		return (NT_STATUS_SUCCESS);
845 
846 	if (smb_node_is_reparse(node))
847 		return (NT_STATUS_ACCESS_DENIED);
848 
849 	/*
850 	 * intra-CIFS check
851 	 */
852 	smb_llist_enter(&node->n_ofile_list, RW_READER);
853 	of = smb_llist_head(&node->n_ofile_list);
854 	while (of) {
855 		status = smb_ofile_delete_check(of);
856 
857 		switch (status) {
858 		case NT_STATUS_INVALID_HANDLE:
859 		case NT_STATUS_SUCCESS:
860 			of = smb_llist_next(&node->n_ofile_list, of);
861 			break;
862 		default:
863 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
864 			DTRACE_PROBE1(conflict1, smb_ofile_t *, of);
865 			smb_llist_exit(&node->n_ofile_list);
866 			return (status);
867 		}
868 	}
869 	smb_llist_exit(&node->n_ofile_list);
870 	return (NT_STATUS_SUCCESS);
871 }
872 
873 /*
874  * smb_node_share_check
875  *
876  * Returns: TRUE    - ofiles have non-zero share access
877  *          B_FALSE - ofile with share access NONE.
878  */
879 boolean_t
smb_node_share_check(smb_node_t * node)880 smb_node_share_check(smb_node_t *node)
881 {
882 	smb_ofile_t	*of;
883 	boolean_t	status = B_TRUE;
884 
885 	SMB_NODE_VALID(node);
886 
887 	smb_llist_enter(&node->n_ofile_list, RW_READER);
888 	of = smb_llist_head(&node->n_ofile_list);
889 	if (of)
890 		status = smb_ofile_share_check(of);
891 	smb_llist_exit(&node->n_ofile_list);
892 
893 	return (status);
894 }
895 
896 /*
897  * SMB Change Notification
898  */
899 
900 void
smb_node_fcn_subscribe(smb_node_t * node)901 smb_node_fcn_subscribe(smb_node_t *node)
902 {
903 
904 	mutex_enter(&node->n_mutex);
905 	if (node->n_fcn_count == 0)
906 		(void) smb_fem_fcn_install(node);
907 	node->n_fcn_count++;
908 	mutex_exit(&node->n_mutex);
909 }
910 
911 void
smb_node_fcn_unsubscribe(smb_node_t * node)912 smb_node_fcn_unsubscribe(smb_node_t *node)
913 {
914 
915 	mutex_enter(&node->n_mutex);
916 	node->n_fcn_count--;
917 	if (node->n_fcn_count == 0) {
918 		VERIFY0(smb_fem_fcn_uninstall(node));
919 	}
920 	mutex_exit(&node->n_mutex);
921 }
922 
923 void
smb_node_notify_change(smb_node_t * node,uint_t action,const char * name)924 smb_node_notify_change(smb_node_t *node, uint_t action, const char *name)
925 {
926 	smb_ofile_t	*of;
927 
928 	SMB_NODE_VALID(node);
929 
930 	smb_llist_enter(&node->n_ofile_list, RW_READER);
931 	of = smb_llist_head(&node->n_ofile_list);
932 	while (of) {
933 		/*
934 		 * We'd rather deliver events only to ofiles that have
935 		 * subscribed.  There's no explicit synchronization with
936 		 * where this flag is set, but other actions cause this
937 		 * value to reach visibility soon enough for events to
938 		 * start arriving by the time we need them to start.
939 		 * Once nc_subscribed is set, it stays set for the
940 		 * life of the ofile.
941 		 */
942 		if (of->f_notify.nc_subscribed)
943 			smb_notify_ofile(of, action, name);
944 		of = smb_llist_next(&node->n_ofile_list, of);
945 	}
946 	smb_llist_exit(&node->n_ofile_list);
947 
948 	/*
949 	 * After changes that add or remove a name,
950 	 * we know the directory attributes changed,
951 	 * and we can tell the immediate parent.
952 	 */
953 	switch (action) {
954 	case FILE_ACTION_ADDED:
955 	case FILE_ACTION_REMOVED:
956 	case FILE_ACTION_RENAMED_NEW_NAME:
957 		/*
958 		 * Note: FILE_ACTION_RENAMED_OLD_NAME is intentionally
959 		 * omitted, because it's always followed by another
960 		 * event with FILE_ACTION_RENAMED_NEW_NAME posted to
961 		 * the same directory, and we only need/want one.
962 		 */
963 		if (node->n_dnode != NULL) {
964 			smb_node_notify_change(node->n_dnode,
965 			    FILE_ACTION_MODIFIED, node->od_name);
966 		}
967 		break;
968 	}
969 
970 	/*
971 	 * If we wanted to support recursive notify events
972 	 * (where a notify call on some directory receives
973 	 * events from all objects below that directory),
974 	 * we might deliver _SUBDIR_CHANGED to all our
975 	 * parents, grandparents etc, here.  However, we
976 	 * don't currently subscribe to changes on all the
977 	 * child (and grandchild) objects that would be
978 	 * needed to make that work. It's prohibitively
979 	 * expensive to do that, and support for recursive
980 	 * notify is optional anyway, so don't bother.
981 	 */
982 }
983 
984 /*
985  * Change notify modified differs for stream vs regular file.
986  * Changes to a stream give a notification on the "unnamed" node,
987  * which is the parent object of the stream.
988  */
989 void
smb_node_notify_modified(smb_node_t * node)990 smb_node_notify_modified(smb_node_t *node)
991 {
992 	smb_node_t *u_node;
993 
994 	u_node = SMB_IS_STREAM(node);
995 	if (u_node != NULL) {
996 		/* This is a named stream */
997 		if (u_node->n_dnode != NULL) {
998 			smb_node_notify_change(u_node->n_dnode,
999 			    FILE_ACTION_MODIFIED_STREAM, u_node->od_name);
1000 		}
1001 	} else {
1002 		/* regular file or directory */
1003 		if (node->n_dnode != NULL) {
1004 			smb_node_notify_change(node->n_dnode,
1005 			    FILE_ACTION_MODIFIED, node->od_name);
1006 		}
1007 	}
1008 }
1009 
1010 /*
1011  * smb_node_start_crit()
1012  *
1013  * Enter critical region for share reservations.
1014  * See comments above smb_fsop_shrlock().
1015  */
1016 void
smb_node_start_crit(smb_node_t * node,krw_t mode)1017 smb_node_start_crit(smb_node_t *node, krw_t mode)
1018 {
1019 	rw_enter(&node->n_lock, mode);
1020 	nbl_start_crit(node->vp, mode);
1021 }
1022 
1023 /*
1024  * smb_node_end_crit()
1025  *
1026  * Exit critical region for share reservations.
1027  */
1028 void
smb_node_end_crit(smb_node_t * node)1029 smb_node_end_crit(smb_node_t *node)
1030 {
1031 	nbl_end_crit(node->vp);
1032 	rw_exit(&node->n_lock);
1033 }
1034 
1035 int
smb_node_in_crit(smb_node_t * node)1036 smb_node_in_crit(smb_node_t *node)
1037 {
1038 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
1039 }
1040 
1041 void
smb_node_rdlock(smb_node_t * node)1042 smb_node_rdlock(smb_node_t *node)
1043 {
1044 	rw_enter(&node->n_lock, RW_READER);
1045 }
1046 
1047 void
smb_node_wrlock(smb_node_t * node)1048 smb_node_wrlock(smb_node_t *node)
1049 {
1050 	rw_enter(&node->n_lock, RW_WRITER);
1051 }
1052 
1053 void
smb_node_unlock(smb_node_t * node)1054 smb_node_unlock(smb_node_t *node)
1055 {
1056 	rw_exit(&node->n_lock);
1057 }
1058 
1059 void
smb_node_add_ofile(smb_node_t * node,smb_ofile_t * of)1060 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
1061 {
1062 	SMB_NODE_VALID(node);
1063 
1064 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
1065 	smb_llist_insert_tail(&node->n_ofile_list, of);
1066 	smb_llist_exit(&node->n_ofile_list);
1067 }
1068 
1069 void
smb_node_rem_ofile(smb_node_t * node,smb_ofile_t * of)1070 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
1071 {
1072 	SMB_NODE_VALID(node);
1073 
1074 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
1075 	smb_llist_remove(&node->n_ofile_list, of);
1076 	smb_llist_exit(&node->n_ofile_list);
1077 }
1078 
1079 /*
1080  * smb_node_inc_open_ofiles
1081  */
1082 void
smb_node_inc_open_ofiles(smb_node_t * node)1083 smb_node_inc_open_ofiles(smb_node_t *node)
1084 {
1085 	SMB_NODE_VALID(node);
1086 	atomic_inc_32(&node->n_open_count);
1087 }
1088 
1089 /*
1090  * smb_node_dec_open_ofiles
1091  * returns new value
1092  */
1093 uint32_t
smb_node_dec_open_ofiles(smb_node_t * node)1094 smb_node_dec_open_ofiles(smb_node_t *node)
1095 {
1096 	SMB_NODE_VALID(node);
1097 	return (atomic_dec_32_nv(&node->n_open_count));
1098 }
1099 
1100 /*
1101  * smb_node_inc_opening_count
1102  */
1103 void
smb_node_inc_opening_count(smb_node_t * node)1104 smb_node_inc_opening_count(smb_node_t *node)
1105 {
1106 	SMB_NODE_VALID(node);
1107 	atomic_inc_32(&node->n_opening_count);
1108 }
1109 
1110 /*
1111  * smb_node_dec_opening_count
1112  */
1113 void
smb_node_dec_opening_count(smb_node_t * node)1114 smb_node_dec_opening_count(smb_node_t *node)
1115 {
1116 	SMB_NODE_VALID(node);
1117 	atomic_dec_32(&node->n_opening_count);
1118 }
1119 
1120 /*
1121  * smb_node_getmntpath
1122  */
1123 int
smb_node_getmntpath(smb_node_t * node,char * buf,uint32_t buflen)1124 smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
1125 {
1126 	vnode_t *vp, *root_vp;
1127 	vfs_t *vfsp;
1128 	int err;
1129 
1130 	ASSERT(node);
1131 	ASSERT(node->vp);
1132 	ASSERT(node->vp->v_vfsp);
1133 
1134 	vp = node->vp;
1135 	vfsp = vp->v_vfsp;
1136 
1137 	if (VFS_ROOT(vfsp, &root_vp))
1138 		return (ENOENT);
1139 
1140 	VN_HOLD(vp);
1141 
1142 	/* NULL is passed in as we want to start at "/" */
1143 	err = vnodetopath(NULL, root_vp, buf, buflen, zone_kcred());
1144 
1145 	VN_RELE(vp);
1146 	VN_RELE(root_vp);
1147 	return (err);
1148 }
1149 
1150 /*
1151  * smb_node_getshrpath
1152  *
1153  * Determine the absolute pathname of 'node' within the share (tree).
1154  * For example if the node represents file "test1.txt" in directory
1155  * "dir1" the pathname would be: \dir1\test1.txt
1156  */
1157 int
smb_node_getshrpath(smb_node_t * node,smb_tree_t * tree,char * buf,uint32_t buflen)1158 smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
1159     char *buf, uint32_t buflen)
1160 {
1161 	int rc;
1162 
1163 	ASSERT(node);
1164 	ASSERT(tree);
1165 	ASSERT(tree->t_snode);
1166 
1167 	rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
1168 	(void) strsubst(buf, '/', '\\');
1169 	return (rc);
1170 }
1171 
1172 /*
1173  * smb_node_getpath
1174  *
1175  * Determine the absolute pathname of 'node' from 'rootvp'.
1176  *
1177  * Using vnodetopath is only reliable for directory nodes (due to
1178  * its reliance on the DNLC for non-directory nodes). Thus, if node
1179  * represents a file, construct the pathname for the parent dnode
1180  * and append filename.
1181  * If node represents a named stream, construct the pathname for the
1182  * associated unnamed stream and append the stream name.
1183  *
1184  * The pathname returned in buf will be '/' separated.
1185  */
1186 int
smb_node_getpath(smb_node_t * node,vnode_t * rootvp,char * buf,uint32_t buflen)1187 smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
1188 {
1189 	int rc;
1190 	vnode_t *vp;
1191 	smb_node_t *unode, *dnode;
1192 	cred_t *kcr = zone_kcred();
1193 
1194 	unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
1195 	dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
1196 
1197 	/* find path to directory node */
1198 	vp = dnode->vp;
1199 	VN_HOLD(vp);
1200 	if (rootvp) {
1201 		VN_HOLD(rootvp);
1202 		rc = vnodetopath(rootvp, vp, buf, buflen, kcr);
1203 		VN_RELE(rootvp);
1204 	} else {
1205 		rc = vnodetopath(NULL, vp, buf, buflen, kcr);
1206 	}
1207 	VN_RELE(vp);
1208 
1209 	if (rc != 0)
1210 		return (rc);
1211 
1212 	/* append filename if necessary */
1213 	if (!smb_node_is_dir(unode)) {
1214 		if (buf[strlen(buf) - 1] != '/')
1215 			(void) strlcat(buf, "/", buflen);
1216 		(void) strlcat(buf, unode->od_name, buflen);
1217 	}
1218 
1219 	/* append named stream name if necessary */
1220 	if (SMB_IS_STREAM(node))
1221 		(void) strlcat(buf, node->od_name, buflen);
1222 
1223 	return (rc);
1224 }
1225 
1226 /*
1227  * smb_node_alloc
1228  */
1229 static smb_node_t *
smb_node_alloc(char * od_name,vnode_t * vp,smb_llist_t * bucket,uint32_t hashkey)1230 smb_node_alloc(
1231     char	*od_name,
1232     vnode_t	*vp,
1233     smb_llist_t	*bucket,
1234     uint32_t	hashkey)
1235 {
1236 	smb_node_t	*node;
1237 
1238 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
1239 
1240 	if (node->n_audit_buf != NULL)
1241 		node->n_audit_buf->anb_index = 0;
1242 
1243 	node->flags = 0;
1244 	VN_HOLD(vp);
1245 	node->vp = vp;
1246 	node->n_refcnt = 1;
1247 	node->n_hash_bucket = bucket;
1248 	node->n_hashkey = hashkey;
1249 	node->n_open_count = 0;
1250 	node->n_allocsz = 0;
1251 	node->n_dnode = NULL;
1252 	node->n_unode = NULL;
1253 	node->delete_on_close_cred = NULL;
1254 	node->n_delete_on_close_flags = 0;
1255 	node->n_oplock.ol_fem = B_FALSE;
1256 
1257 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
1258 	if (strcmp(od_name, XATTR_DIR) == 0)
1259 		node->flags |= NODE_XATTR_DIR;
1260 
1261 	if ((vp->v_flag & VROOT) != 0)
1262 		node->flags |= NODE_FLAGS_VFSROOT;
1263 
1264 	node->n_state = SMB_NODE_STATE_AVAILABLE;
1265 	node->n_magic = SMB_NODE_MAGIC;
1266 
1267 	return (node);
1268 }
1269 
1270 /*
1271  * smb_node_free
1272  */
1273 static void
smb_node_free(smb_node_t * node)1274 smb_node_free(smb_node_t *node)
1275 {
1276 	SMB_NODE_VALID(node);
1277 
1278 	node->n_magic = 0;
1279 	VERIFY(!list_link_active(&node->n_lnd));
1280 	VERIFY(node->n_lock_list.ll_count == 0);
1281 	VERIFY(node->n_wlock_list.ll_count == 0);
1282 	VERIFY(node->n_ofile_list.ll_count == 0);
1283 	VERIFY(node->n_oplock.ol_fem == B_FALSE);
1284 	VERIFY(MUTEX_NOT_HELD(&node->n_mutex));
1285 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
1286 	VN_RELE(node->vp);
1287 	kmem_cache_free(smb_node_cache, node);
1288 }
1289 
1290 /*
1291  * smb_node_constructor
1292  */
1293 static int
smb_node_constructor(void * buf,void * un,int kmflags)1294 smb_node_constructor(void *buf, void *un, int kmflags)
1295 {
1296 	_NOTE(ARGUNUSED(kmflags, un))
1297 
1298 	smb_node_t	*node = (smb_node_t *)buf;
1299 
1300 	bzero(node, sizeof (smb_node_t));
1301 
1302 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1303 	    offsetof(smb_ofile_t, f_node_lnd));
1304 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1305 	    offsetof(smb_lock_t, l_lnd));
1306 	smb_llist_constructor(&node->n_wlock_list, sizeof (smb_lock_t),
1307 	    offsetof(smb_lock_t, l_lnd));
1308 	mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
1309 	cv_init(&node->n_oplock.WaitingOpenCV, NULL, CV_DEFAULT, NULL);
1310 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1311 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1312 	smb_node_create_audit_buf(node, kmflags);
1313 	return (0);
1314 }
1315 
1316 /*
1317  * smb_node_destructor
1318  */
1319 static void
smb_node_destructor(void * buf,void * un)1320 smb_node_destructor(void *buf, void *un)
1321 {
1322 	_NOTE(ARGUNUSED(un))
1323 
1324 	smb_node_t	*node = (smb_node_t *)buf;
1325 
1326 	smb_node_destroy_audit_buf(node);
1327 	mutex_destroy(&node->n_mutex);
1328 	rw_destroy(&node->n_lock);
1329 	cv_destroy(&node->n_oplock.WaitingOpenCV);
1330 	mutex_destroy(&node->n_oplock.ol_mutex);
1331 	smb_llist_destructor(&node->n_lock_list);
1332 	smb_llist_destructor(&node->n_wlock_list);
1333 	smb_llist_destructor(&node->n_ofile_list);
1334 }
1335 
1336 /*
1337  * smb_node_create_audit_buf
1338  */
1339 static void
smb_node_create_audit_buf(smb_node_t * node,int kmflags)1340 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1341 {
1342 	smb_audit_buf_node_t	*abn;
1343 
1344 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1345 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1346 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1347 		node->n_audit_buf = abn;
1348 	}
1349 }
1350 
1351 /*
1352  * smb_node_destroy_audit_buf
1353  */
1354 static void
smb_node_destroy_audit_buf(smb_node_t * node)1355 smb_node_destroy_audit_buf(smb_node_t *node)
1356 {
1357 	if (node->n_audit_buf != NULL) {
1358 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1359 		node->n_audit_buf = NULL;
1360 	}
1361 }
1362 
1363 /*
1364  * smb_node_audit
1365  *
1366  * This function saves the calling stack in the audit buffer of the node passed
1367  * in.
1368  */
1369 static void
smb_node_audit(smb_node_t * node)1370 smb_node_audit(smb_node_t *node)
1371 {
1372 #ifdef	_KERNEL
1373 	smb_audit_buf_node_t	*abn;
1374 	smb_audit_record_node_t	*anr;
1375 
1376 	if (node->n_audit_buf) {
1377 		abn = node->n_audit_buf;
1378 		anr = abn->anb_records;
1379 		anr += abn->anb_index;
1380 		abn->anb_index++;
1381 		abn->anb_index &= abn->anb_max_index;
1382 		anr->anr_refcnt = node->n_refcnt;
1383 		anr->anr_depth = getpcstack(anr->anr_stack,
1384 		    SMB_AUDIT_STACK_DEPTH);
1385 	}
1386 #else	/* _KERNEL */
1387 	_NOTE(ARGUNUSED(node))
1388 #endif	/* _KERNEL */
1389 }
1390 
1391 static smb_llist_t *
smb_node_get_hash(fsid_t * fsid,smb_attr_t * attr,uint32_t * phashkey)1392 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1393 {
1394 	uint32_t	hashkey;
1395 
1396 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1397 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1398 	*phashkey = hashkey;
1399 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1400 }
1401 
1402 boolean_t
smb_node_is_file(smb_node_t * node)1403 smb_node_is_file(smb_node_t *node)
1404 {
1405 	SMB_NODE_VALID(node);
1406 	return (node->vp->v_type == VREG);
1407 }
1408 
1409 boolean_t
smb_node_is_dir(smb_node_t * node)1410 smb_node_is_dir(smb_node_t *node)
1411 {
1412 	SMB_NODE_VALID(node);
1413 	return ((node->vp->v_type == VDIR) ||
1414 	    (node->flags & NODE_FLAGS_DFSLINK));
1415 }
1416 
1417 boolean_t
smb_node_is_symlink(smb_node_t * node)1418 smb_node_is_symlink(smb_node_t *node)
1419 {
1420 	SMB_NODE_VALID(node);
1421 	return ((node->vp->v_type == VLNK) &&
1422 	    ((node->flags & NODE_FLAGS_REPARSE) == 0));
1423 }
1424 
1425 boolean_t
smb_node_is_dfslink(smb_node_t * node)1426 smb_node_is_dfslink(smb_node_t *node)
1427 {
1428 	SMB_NODE_VALID(node);
1429 	return ((node->vp->v_type == VLNK) &&
1430 	    (node->flags & NODE_FLAGS_DFSLINK));
1431 }
1432 
1433 boolean_t
smb_node_is_reparse(smb_node_t * node)1434 smb_node_is_reparse(smb_node_t *node)
1435 {
1436 	SMB_NODE_VALID(node);
1437 	return ((node->vp->v_type == VLNK) &&
1438 	    (node->flags & NODE_FLAGS_REPARSE));
1439 }
1440 
1441 boolean_t
smb_node_is_vfsroot(smb_node_t * node)1442 smb_node_is_vfsroot(smb_node_t *node)
1443 {
1444 	SMB_NODE_VALID(node);
1445 	return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
1446 }
1447 
1448 boolean_t
smb_node_is_system(smb_node_t * node)1449 smb_node_is_system(smb_node_t *node)
1450 {
1451 	SMB_NODE_VALID(node);
1452 	return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
1453 }
1454 
1455 /*
1456  * smb_node_file_is_readonly
1457  *
1458  * Checks if the file (which node represents) is marked readonly
1459  * in the filesystem.  Note that there may be handles open with
1460  * modify rights, and those continue to allow access even after
1461  * the DOS read-only flag has been set in the file system.
1462  */
1463 boolean_t
smb_node_file_is_readonly(smb_node_t * node)1464 smb_node_file_is_readonly(smb_node_t *node)
1465 {
1466 	smb_attr_t attr;
1467 
1468 	if (node == NULL)
1469 		return (B_FALSE);	/* pipes */
1470 
1471 	bzero(&attr, sizeof (smb_attr_t));
1472 	attr.sa_mask = SMB_AT_DOSATTR;
1473 	(void) smb_fsop_getattr(NULL, zone_kcred(), node, &attr);
1474 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1475 }
1476 
1477 /*
1478  * smb_node_setattr
1479  *
1480  * The sr may be NULL, for example when closing an ofile.
1481  * The ofile may be NULL, for example when a client request
1482  * specifies the file by pathname.
1483  *
1484  * Returns: errno
1485  *
1486  * Timestamps
1487  *
1488  * Windows and Unix have different models for timestamp updates.
1489  * [MS-FSA 2.1.5.14 Server Requests Setting of File Information]
1490  *
1491  * An open "handle" in Windows can control whether and when
1492  * any timestamp updates happen for that handle.  For example,
1493  * timestamps set via some handle are no longer updated by I/O
1494  * operations on that handle.  In Unix we don't really have any
1495  * way to avoid the timestamp updates that the file system does.
1496  * Therefore, we need to make some compromises, and simulate the
1497  * more important parts of the Windows file system semantics.
1498  *
1499  * For example, when an SMB client sets file times, set those
1500  * times in the file system (so the change will be visible to
1501  * other clients, at least until they change again) but we also
1502  * make those times "sticky" in our open handle, and reapply
1503  * those times when the handle is closed.  That reapply on close
1504  * simulates the Windows behavior where the timestamp updates
1505  * would be discontinued after they were set.  These "sticky"
1506  * attributes are returned in any query on the handle where
1507  * they are stored.
1508  *
1509  * The client can also turn on or off these "sticky" times using
1510  * the special NT time values -1 or -2, as described in:
1511  *	[MS-FSCC] Section 2.4.7, the paragraphs describing:
1512  *	CreationTime, LastAccessTime, LastWriteTime, ChangeTime
1513  * and the Windows behavior notes in those descriptions.
1514  * To summarize all the "special" NT time values:
1515  *	 0: no change (caller handles this case)
1516  *	-1: pause time updates (current value becomes "sticky")
1517  *	-2: resume time updates (discontiue "sticky" behavior)
1518  *
1519  * Other than the above, the file system layer takes care of the
1520  * normal time stamp updates, such as updating the mtime after a
1521  * write, and ctime after an attribute change.
1522  *
1523  * File allocation size is also simulated, and not persistent.
1524  * When the file allocation size is set it is first rounded up
1525  * to block size. If the file size is smaller than the allocation
1526  * size the file is truncated by setting the filesize to allocsz.
1527  */
1528 int
smb_node_setattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)1529 smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1530     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1531 {
1532 	smb_attr_t cur_attr;
1533 	uint_t times_set = 0;
1534 	uint_t times_clr = 0;
1535 	int rc;
1536 
1537 	SMB_NODE_VALID(node);
1538 
1539 	/* set attributes specified in attr */
1540 	if (attr->sa_mask == 0)
1541 		return (0);  /* nothing to do (caller bug?) */
1542 
1543 	/*
1544 	 * Allocation size and EOF position interact.
1545 	 * We don't persistently store the allocation size
1546 	 * but make it look like we do while there are opens.
1547 	 * Note: We update the caller's attr in the cases
1548 	 * where they're setting only one of allocsz|size.
1549 	 */
1550 	switch (attr->sa_mask & (SMB_AT_ALLOCSZ | SMB_AT_SIZE)) {
1551 
1552 	case SMB_AT_ALLOCSZ:
1553 		/*
1554 		 * Setting the allocation size but not EOF position.
1555 		 * Get the current EOF in cur_attr and (if necessary)
1556 		 * truncate to the (rounded up) allocation size.
1557 		 * Using kcred here because if we don't have access,
1558 		 * we want to fail at setattr below and not here.
1559 		 */
1560 		bzero(&cur_attr, sizeof (smb_attr_t));
1561 		cur_attr.sa_mask = SMB_AT_SIZE;
1562 		rc = smb_fsop_getattr(NULL, zone_kcred(), node, &cur_attr);
1563 		if (rc != 0)
1564 			return (rc);
1565 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
1566 		if (cur_attr.sa_vattr.va_size > attr->sa_allocsz) {
1567 			/* truncate the file to allocsz */
1568 			attr->sa_vattr.va_size = attr->sa_allocsz;
1569 			attr->sa_mask |= SMB_AT_SIZE;
1570 		}
1571 		break;
1572 
1573 	case SMB_AT_SIZE:
1574 		/*
1575 		 * Setting the EOF position but not allocation size.
1576 		 * If the new EOF position would be greater than
1577 		 * the allocation size, increase the latter.
1578 		 */
1579 		if (node->n_allocsz < attr->sa_vattr.va_size) {
1580 			attr->sa_mask |= SMB_AT_ALLOCSZ;
1581 			attr->sa_allocsz =
1582 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1583 		}
1584 		break;
1585 
1586 	case SMB_AT_ALLOCSZ | SMB_AT_SIZE:
1587 		/*
1588 		 * Setting both.  Increase alloc size if needed.
1589 		 */
1590 		if (attr->sa_allocsz < attr->sa_vattr.va_size)
1591 			attr->sa_allocsz =
1592 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1593 		break;
1594 
1595 	default:
1596 		break;
1597 	}
1598 
1599 	/*
1600 	 * When setting times, -1 and -2 are "special" (see above).
1601 	 * Keep track of -2 values and just clear mask.
1602 	 * Replace -1 values with current time.
1603 	 *
1604 	 * Note that NT times -1, -2 have been converted to
1605 	 * smb_nttime_m1, smb_nttime_m2, respectively.
1606 	 */
1607 	times_set = attr->sa_mask & SMB_AT_TIMES;
1608 	if (times_set != 0) {
1609 		bzero(&cur_attr, sizeof (smb_attr_t));
1610 		cur_attr.sa_mask = SMB_AT_TIMES;
1611 		rc = smb_fsop_getattr(NULL, zone_kcred(), node, &cur_attr);
1612 		if (rc != 0)
1613 			return (rc);
1614 
1615 		/* Easiest to get these right with a macro. */
1616 #define	FIX_TIME(FIELD, MASK)				\
1617 		if (timespeccmp(&attr->FIELD, &smb_nttime_m2, ==)) { \
1618 			times_clr |= MASK;		\
1619 			times_set &= ~MASK;		\
1620 		}					\
1621 		if (timespeccmp(&attr->FIELD, &smb_nttime_m1, ==)) \
1622 			attr->FIELD = cur_attr.FIELD	/* no ; */
1623 
1624 		if (times_set & SMB_AT_ATIME) {
1625 			FIX_TIME(sa_vattr.va_atime, SMB_AT_ATIME);
1626 		}
1627 		if (times_set & SMB_AT_MTIME) {
1628 			FIX_TIME(sa_vattr.va_mtime, SMB_AT_MTIME);
1629 		}
1630 		if (times_set & SMB_AT_CTIME) {
1631 			FIX_TIME(sa_vattr.va_ctime, SMB_AT_CTIME);
1632 		}
1633 		if (times_set & SMB_AT_CRTIME) {
1634 			FIX_TIME(sa_crtime, SMB_AT_CRTIME);
1635 		}
1636 #undef	FIX_TIME
1637 
1638 		/* Clear mask for -2 fields. */
1639 		attr->sa_mask &= ~times_clr;
1640 	}
1641 
1642 	/*
1643 	 * When operating on an open file, some settable attributes
1644 	 * become "sticky" in the open file object until close, or until
1645 	 * a set-time with value -2 (see above re. timestamps)
1646 	 *
1647 	 * Save the pending attributes.  We've handled -2 and -1 above,
1648 	 * and cleared the -2 cases from the times_set mask.
1649 	 */
1650 	if (of != NULL && (times_set != 0 || times_clr != 0)) {
1651 		smb_attr_t *pa;
1652 
1653 		SMB_OFILE_VALID(of);
1654 		mutex_enter(&of->f_mutex);
1655 		pa = &of->f_pending_attr;
1656 
1657 		pa->sa_mask |= times_set;
1658 		pa->sa_mask &= ~times_clr;
1659 
1660 		if (times_set & SMB_AT_ATIME)
1661 			pa->sa_vattr.va_atime = attr->sa_vattr.va_atime;
1662 		if (times_set & SMB_AT_MTIME)
1663 			pa->sa_vattr.va_mtime = attr->sa_vattr.va_mtime;
1664 		if (times_set & SMB_AT_CTIME)
1665 			pa->sa_vattr.va_ctime = attr->sa_vattr.va_ctime;
1666 		if (times_set & SMB_AT_CRTIME)
1667 			pa->sa_crtime = attr->sa_crtime;
1668 
1669 		mutex_exit(&of->f_mutex);
1670 
1671 		/*
1672 		 * The f_pending_attr times are reapplied in
1673 		 * smb_ofile_close().
1674 		 */
1675 
1676 		/*
1677 		 * If this change is coming directly from a client
1678 		 * (sr != NULL) and it's a persistent handle, save
1679 		 * the "sticky times" in the handle.
1680 		 */
1681 		if (sr != NULL && of->dh_persist) {
1682 			smb2_dh_update_times(sr, of, attr);
1683 		}
1684 	}
1685 
1686 	if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0) {
1687 		mutex_enter(&node->n_mutex);
1688 		/*
1689 		 * Simulate n_allocsz persistence only while
1690 		 * there are opens.  See smb_node_getattr
1691 		 */
1692 		if (node->n_open_count != 0)
1693 			node->n_allocsz = attr->sa_allocsz;
1694 		mutex_exit(&node->n_mutex);
1695 	}
1696 
1697 	rc = smb_fsop_setattr(sr, cr, node, attr);
1698 
1699 	/*
1700 	 * Only generate change notify events for client requests.
1701 	 * Internal operations use sr=NULL
1702 	 */
1703 	if (rc == 0 && sr != NULL)
1704 		smb_node_notify_modified(node);
1705 
1706 	return (rc);
1707 }
1708 
1709 /*
1710  * smb_node_getattr
1711  *
1712  * Get attributes from the file system and apply any smb-specific
1713  * overrides for size, dos attributes and timestamps
1714  *
1715  * Returns: errno
1716  */
1717 int
smb_node_getattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)1718 smb_node_getattr(smb_request_t *sr, smb_node_t *node, cred_t *cr,
1719     smb_ofile_t *of, smb_attr_t *attr)
1720 {
1721 	int rc;
1722 	uint_t want_mask, pend_mask;
1723 	boolean_t isdir;
1724 
1725 	SMB_NODE_VALID(node);
1726 
1727 	rc = smb_fsop_getattr(sr, cr, node, attr);
1728 	if (rc != 0)
1729 		return (rc);
1730 
1731 	isdir = smb_node_is_dir(node);
1732 
1733 	mutex_enter(&node->n_mutex);
1734 
1735 	/*
1736 	 * Fix-up sa_allocsz, for which we simulate persistence
1737 	 * while there are open files. (See smb_node_setattr)
1738 	 *
1739 	 * The value in node->n_allocsz is the value last set via
1740 	 * smb_node_setattr.  It's possible that writes may have
1741 	 * increased the file size beyond n_allocsz, in which case
1742 	 * the sa_vattr.va_size, sa_allocsz from smb_fsop_getattr
1743 	 * will be greater than n_allocsz, so this returns the
1744 	 * greater of n_allocsz and sa_allocsz.
1745 	 */
1746 	if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0 &&
1747 	    node->n_open_count > 0 && !isdir &&
1748 	    attr->sa_allocsz < node->n_allocsz) {
1749 		attr->sa_allocsz = node->n_allocsz;
1750 	}
1751 
1752 	mutex_exit(&node->n_mutex);
1753 
1754 	/*
1755 	 * getattr with an ofile gets any "pending" times that
1756 	 * might have been previously set via this ofile.
1757 	 * This is what makes these times "sticky".
1758 	 */
1759 	want_mask = attr->sa_mask & SMB_AT_TIMES;
1760 	if (of != NULL && want_mask != 0) {
1761 		smb_attr_t *pa;
1762 
1763 		SMB_OFILE_VALID(of);
1764 		mutex_enter(&of->f_mutex);
1765 		pa = &of->f_pending_attr;
1766 
1767 		pend_mask = pa->sa_mask;
1768 
1769 		if (want_mask & pend_mask & SMB_AT_ATIME)
1770 			attr->sa_vattr.va_atime =
1771 			    pa->sa_vattr.va_atime;
1772 		if (want_mask & pend_mask & SMB_AT_MTIME)
1773 			attr->sa_vattr.va_mtime =
1774 			    pa->sa_vattr.va_mtime;
1775 		if (want_mask & pend_mask & SMB_AT_CTIME)
1776 			attr->sa_vattr.va_ctime =
1777 			    pa->sa_vattr.va_ctime;
1778 		if (want_mask & pend_mask & SMB_AT_CRTIME)
1779 			attr->sa_crtime =
1780 			    pa->sa_crtime;
1781 
1782 		mutex_exit(&of->f_mutex);
1783 	}
1784 
1785 
1786 	return (0);
1787 }
1788 
1789 
1790 #ifndef	_KERNEL
1791 extern int reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl);
1792 #endif	/* _KERNEL */
1793 
1794 /*
1795  * Check to see if the node represents a reparse point.
1796  * If yes, whether the reparse point contains a DFS link.
1797  */
1798 static void
smb_node_init_reparse(smb_node_t * node,smb_attr_t * attr)1799 smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
1800 {
1801 	nvlist_t *nvl;
1802 	nvpair_t *rec;
1803 	char *rec_type;
1804 
1805 	if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
1806 		return;
1807 
1808 	if ((nvl = reparse_init()) == NULL)
1809 		return;
1810 
1811 	if (reparse_vnode_parse(node->vp, nvl) != 0) {
1812 		reparse_free(nvl);
1813 		return;
1814 	}
1815 
1816 	node->flags |= NODE_FLAGS_REPARSE;
1817 
1818 	rec = nvlist_next_nvpair(nvl, NULL);
1819 	while (rec != NULL) {
1820 		rec_type = nvpair_name(rec);
1821 		if ((rec_type != NULL) &&
1822 		    (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
1823 			node->flags |= NODE_FLAGS_DFSLINK;
1824 			break;
1825 		}
1826 		rec = nvlist_next_nvpair(nvl, rec);
1827 	}
1828 
1829 	reparse_free(nvl);
1830 }
1831 
1832 /*
1833  * smb_node_init_system
1834  *
1835  * If the node represents a special system file set NODE_FLAG_SYSTEM.
1836  * System files:
1837  * - any node whose parent dnode has NODE_FLAG_SYSTEM set
1838  * - any node whose associated unnamed stream node (unode) has
1839  *   NODE_FLAG_SYSTEM set
1840  * - .$EXTEND at root of share (quota management)
1841  */
1842 static void
smb_node_init_system(smb_node_t * node)1843 smb_node_init_system(smb_node_t *node)
1844 {
1845 	smb_node_t *dnode = node->n_dnode;
1846 	smb_node_t *unode = node->n_unode;
1847 
1848 	if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
1849 		node->flags |= NODE_FLAGS_SYSTEM;
1850 		return;
1851 	}
1852 
1853 	if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
1854 		node->flags |= NODE_FLAGS_SYSTEM;
1855 		return;
1856 	}
1857 
1858 	if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
1859 	    (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
1860 		node->flags |= NODE_FLAGS_SYSTEM;
1861 	}
1862 }
1863