xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 1b83305cfc332b1e19ad6a194b73b2975e6bf79a)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * SMB Node State Machine
30  * ----------------------
31  *
32  *    +----------------------------+	 T0
33  *    |  SMB_NODE_STATE_AVAILABLE  |<----------- Creation/Allocation
34  *    +----------------------------+
35  *		    |
36  *		    | T1
37  *		    |
38  *		    v
39  *    +-----------------------------+    T2
40  *    |  SMB_NODE_STATE_DESTROYING  |----------> Deletion/Free
41  *    +-----------------------------+
42  *
43  * Transition T0
44  *
45  *    This transition occurs in smb_node_lookup(). If the node looked for is
46  *    not found in the has table a new node is created. The reference count is
47  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
48  *
49  * Transition T1
50  *
51  *    This transition occurs in smb_node_release(). If the reference count
52  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
53  *    reference count will be given out for that node.
54  *
55  * Transition T2
56  *
57  *    This transition occurs in smb_node_release(). The structure is deleted.
58  *
59  * Comments
60  * --------
61  *
62  *    The reason the smb node has 2 states is the following synchronization
63  *    rule:
64  *
65  *    There's a mutex embedded in the node used to protect its fields and
66  *    there's a lock embedded in the bucket of the hash table the node belongs
67  *    to. To increment or to decrement the reference count the mutex must be
68  *    entered. To insert the node into the bucket and to remove it from the
69  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
70  *    lock) have to be entered, the lock has always to be entered first then
71  *    the mutex. This prevents a deadlock between smb_node_lookup() and
72  *    smb_node_release() from occurring. However, in smb_node_release() when the
73  *    reference count drops to zero and triggers the deletion of the node, the
74  *    mutex has to be released before entering the lock of the bucket (to
75  *    remove the node). This creates a window during which the node that is
76  *    about to be freed could be given out by smb_node_lookup(). To close that
77  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
78  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
79  *    state will indicate that the node should be treated as non existent (of
80  *    course the state of the node should be tested/updated under the
81  *    protection of the mutex).
82  */
83 #include <smbsrv/smb_incl.h>
84 #include <smbsrv/smb_fsops.h>
85 #include <sys/pathname.h>
86 #include <sys/sdt.h>
87 #include <sys/nbmlock.h>
88 
89 uint32_t smb_is_executable(char *path);
90 static void smb_node_delete_on_close(smb_node_t *node);
91 
92 uint32_t	smb_node_hit = 0;
93 uint32_t	smb_node_miss = 0;
94 uint32_t	smb_node_alloc = 0;
95 uint32_t	smb_node_free = 0;
96 
97 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
98     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
99     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
100     ASSERT((_dir_)->dir_snode != (_node_));
101 
102 /*
103  * smb_node_lookup()
104  *
105  * NOTE: This routine should only be called by the file system interface layer,
106  * and not by SMB.
107  *
108  * smb_node_lookup() is called upon successful lookup, mkdir, and create
109  * (for both non-streams and streams).  In each of these cases, a held vnode is
110  * passed into this routine.  If an smb_node already exists for this vnode,
111  * the vp is released.  Otherwise, a new smb_node will be created and the
112  * reference will be held until the refcnt on the node goes to 0 (see
113  * smb_node_release()).
114  *
115  * A reference is taken on the smb_node whether found in the hash table
116  * or newly created.
117  *
118  * If an smb_node needs to be created, a reference is also taken on the
119  * dir_snode (if passed in).
120  *
121  * See smb_node_release() for details on the release of these references.
122  */
123 
124 /*ARGSUSED*/
125 smb_node_t *
126 smb_node_lookup(
127     struct smb_request	*sr,
128     struct open_param	*op,
129     cred_t		*cred,
130     vnode_t		*vp,
131     char		*od_name,
132     smb_node_t		*dir_snode,
133     smb_node_t		*unnamed_node,
134     smb_attr_t		*attr)
135 {
136 	smb_llist_t		*node_hdr;
137 	smb_node_t		*node;
138 	uint32_t		hashkey = 0;
139 	fs_desc_t		fsd;
140 	int			error;
141 	krw_t			lock_mode;
142 	vnode_t			*unnamed_vp = NULL;
143 
144 	/*
145 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
146 	 * because the node may not yet exist.  We also do not want to call
147 	 * it with the list lock held.
148 	 */
149 
150 	if (unnamed_node)
151 		unnamed_vp = unnamed_node->vp;
152 
153 	/*
154 	 * This getattr is performed on behalf of the server
155 	 * that's why kcred is used not the user's cred
156 	 */
157 	attr->sa_mask = SMB_AT_ALL;
158 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
159 	if (error)
160 		return (NULL);
161 
162 	if (sr) {
163 		if (sr->tid_tree) {
164 			/*
165 			 * The fsd for a file is that of the tree, even
166 			 * if the file resides in a different mountpoint
167 			 * under the share.
168 			 */
169 			fsd = sr->tid_tree->t_fsd;
170 		} else {
171 			/*
172 			 * This should be getting executed only for the
173 			 * tree's root smb_node.
174 			 */
175 			fsd = vp->v_vfsp->vfs_fsid;
176 		}
177 	} else {
178 		fsd = vp->v_vfsp->vfs_fsid;
179 	}
180 
181 	hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid;
182 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
183 	node_hdr = &smb_info.node_hash_table[(hashkey & SMBND_HASH_MASK)];
184 	lock_mode = RW_READER;
185 
186 	smb_llist_enter(node_hdr, lock_mode);
187 	for (;;) {
188 		node = list_head(&node_hdr->ll_list);
189 		while (node) {
190 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
191 			ASSERT(node->n_hash_bucket == node_hdr);
192 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
193 				smb_rwx_xenter(&node->n_lock);
194 				DTRACE_PROBE1(smb_node_lookup_hit,
195 				    smb_node_t *, node);
196 				switch (node->n_state) {
197 				case SMB_NODE_STATE_AVAILABLE:
198 					/* The node was found. */
199 					node->n_refcnt++;
200 					if ((node->dir_snode == NULL) &&
201 					    (dir_snode != NULL) &&
202 					    (strcmp(od_name, "..") != 0) &&
203 					    (strcmp(od_name, ".") != 0)) {
204 						VALIDATE_DIR_NODE(dir_snode,
205 						    node);
206 						node->dir_snode = dir_snode;
207 						smb_node_ref(dir_snode);
208 					}
209 					node->attr = *attr;
210 					node->n_size = attr->sa_vattr.va_size;
211 
212 					smb_audit_node(node);
213 					smb_rwx_xexit(&node->n_lock);
214 					smb_llist_exit(node_hdr);
215 					VN_RELE(vp);
216 					return (node);
217 
218 				case SMB_NODE_STATE_DESTROYING:
219 					/*
220 					 * Although the node exists it is about
221 					 * to be destroyed. We act as it hasn't
222 					 * been found.
223 					 */
224 					smb_rwx_xexit(&node->n_lock);
225 					break;
226 				default:
227 					/*
228 					 * Although the node exists it is in an
229 					 * unknown state. We act as it hasn't
230 					 * been found.
231 					 */
232 					ASSERT(0);
233 					smb_rwx_xexit(&node->n_lock);
234 					break;
235 				}
236 			}
237 			node = smb_llist_next(node_hdr, node);
238 		}
239 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
240 			lock_mode = RW_WRITER;
241 			continue;
242 		}
243 		break;
244 	}
245 	node = kmem_cache_alloc(smb_info.si_cache_node, KM_SLEEP);
246 	smb_node_alloc++;
247 
248 	bzero(node, sizeof (smb_node_t));
249 
250 	node->n_state = SMB_NODE_STATE_AVAILABLE;
251 	node->n_hash_bucket = node_hdr;
252 
253 	if (fsd_chkcap(&fsd, FSOLF_READONLY) > 0) {
254 		node->flags |= NODE_READ_ONLY;
255 	}
256 
257 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
258 	    offsetof(smb_ofile_t, f_nnd));
259 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
260 	    offsetof(smb_lock_t, l_lnd));
261 	node->n_hashkey = hashkey;
262 	node->n_refcnt = 1;
263 
264 	if (sr) {
265 		node->n_orig_session_id = sr->session->s_kid;
266 		node->n_orig_uid = crgetuid(sr->user_cr);
267 	}
268 
269 	node->vp = vp;
270 
271 	ASSERT(od_name);
272 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
273 	if (strcmp(od_name, XATTR_DIR) == 0)
274 		node->flags |= NODE_XATTR_DIR;
275 	node->tree_fsd = fsd;
276 
277 	if (op)
278 		node->flags |= smb_is_executable(op->fqi.last_comp);
279 
280 	if (dir_snode) {
281 		smb_node_ref(dir_snode);
282 		node->dir_snode = dir_snode;
283 		ASSERT(dir_snode->dir_snode != node);
284 		ASSERT((dir_snode->vp->v_xattrdir) ||
285 		    (dir_snode->vp->v_type == VDIR));
286 	}
287 
288 	if (unnamed_node) {
289 		smb_node_ref(unnamed_node);
290 		node->unnamed_stream_node = unnamed_node;
291 	}
292 
293 	node->attr = *attr;
294 	node->flags |= NODE_FLAGS_ATTR_VALID;
295 	node->n_size = node->attr.sa_vattr.va_size;
296 
297 	smb_rwx_init(&node->n_lock);
298 	node->n_magic = SMB_NODE_MAGIC;
299 	smb_audit_buf_node_create(node);
300 
301 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
302 	smb_audit_node(node);
303 	smb_llist_insert_head(node_hdr, node);
304 	smb_llist_exit(node_hdr);
305 	return (node);
306 }
307 
308 /*
309  * smb_stream_node_lookup()
310  *
311  * Note: stream_name (the name that will be stored in the "od_name" field
312  * of a stream's smb_node) is the same as the on-disk name for the stream
313  * except that it does not have SMB_STREAM_PREFIX prepended.
314  */
315 
316 smb_node_t *
317 smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
318     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
319 {
320 	smb_node_t	*xattrdir_node;
321 	smb_node_t	*snode;
322 	smb_attr_t	tmp_attr;
323 
324 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
325 	    fnode, NULL, &tmp_attr);
326 
327 	if (xattrdir_node == NULL)
328 		return (NULL);
329 
330 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
331 	    fnode, ret_attr);
332 
333 	/*
334 	 * The following VN_HOLD is necessary because the caller will VN_RELE
335 	 * xattrdirvp in the case of an error.  (xattrdir_node has the original
336 	 * hold on the vnode, which the smb_node_release() call below will
337 	 * release.)
338 	 */
339 	if (snode == NULL) {
340 		VN_HOLD(xattrdirvp);
341 	}
342 	(void) smb_node_release(xattrdir_node);
343 	return (snode);
344 }
345 
346 
347 /*
348  * This function should be called whenever a reference is needed on an
349  * smb_node pointer.  The copy of an smb_node pointer from one non-local
350  * data structure to another requires a reference to be taken on the smb_node
351  * (unless the usage is localized).  Each data structure deallocation routine
352  * will call smb_node_release() on its smb_node pointers.
353  *
354  * In general, an smb_node pointer residing in a structure should never be
355  * stale.  A node pointer may be NULL, however, and care should be taken
356  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
357  * Care also needs to be taken with respect to racing deallocations of a
358  * structure.
359  */
360 
361 void
362 smb_node_ref(smb_node_t *node)
363 {
364 	ASSERT(node);
365 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
366 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
367 
368 	smb_rwx_xenter(&node->n_lock);
369 	node->n_refcnt++;
370 	ASSERT(node->n_refcnt);
371 	DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
372 	smb_audit_node(node);
373 	smb_rwx_xexit(&node->n_lock);
374 }
375 
376 /*
377  * smb_node_lookup() takes a hold on an smb_node, whether found in the
378  * hash table or newly created.  This hold is expected to be released
379  * in the following manner.
380  *
381  * smb_node_lookup() takes an address of an smb_node pointer.  This should
382  * be getting passed down via a lookup (whether path name or component), mkdir,
383  * create.  If the original smb_node pointer resides in a data structure, then
384  * the deallocation routine for the data structure is responsible for calling
385  * smb_node_release() on the smb_node pointer.  Alternatively,
386  * smb_node_release() can be called as soon as the smb_node pointer is no longer
387  * needed.  In this case, callers are responsible for setting an embedded
388  * pointer to NULL if it is known that the last reference is being released.
389  *
390  * If the passed-in address of the smb_node pointer belongs to a local variable,
391  * then the caller with the local variable should call smb_node_release()
392  * directly.
393  *
394  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
395  * as smb_node_lookup() takes a hold on dir_snode.
396  */
397 
398 void
399 smb_node_release(smb_node_t *node)
400 {
401 	ASSERT(node);
402 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
403 
404 	smb_rwx_xenter(&node->n_lock);
405 	ASSERT(node->n_refcnt);
406 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
407 	if (--node->n_refcnt == 0) {
408 		switch (node->n_state) {
409 
410 		case SMB_NODE_STATE_AVAILABLE:
411 			node->n_state = SMB_NODE_STATE_DESTROYING;
412 			smb_rwx_xexit(&node->n_lock);
413 
414 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
415 			smb_llist_remove(node->n_hash_bucket, node);
416 			smb_llist_exit(node->n_hash_bucket);
417 
418 			/*
419 			 * Check if the file was deleted
420 			 */
421 			smb_node_delete_on_close(node);
422 			node->n_magic = (uint32_t)~SMB_NODE_MAGIC;
423 
424 			/* These lists should be empty. */
425 			smb_llist_destructor(&node->n_ofile_list);
426 			smb_llist_destructor(&node->n_lock_list);
427 
428 			if (node->dir_snode) {
429 				ASSERT(node->dir_snode->n_magic ==
430 				    SMB_NODE_MAGIC);
431 				smb_node_release(node->dir_snode);
432 			}
433 
434 			if (node->unnamed_stream_node) {
435 				ASSERT(node->unnamed_stream_node->n_magic ==
436 				    SMB_NODE_MAGIC);
437 				smb_node_release(node->unnamed_stream_node);
438 			}
439 
440 			ASSERT(node->vp);
441 			VN_RELE(node->vp);
442 
443 			smb_audit_buf_node_destroy(node);
444 			smb_rwx_destroy(&node->n_lock);
445 			kmem_cache_free(smb_info.si_cache_node, node);
446 			++smb_node_free;
447 			return;
448 
449 		default:
450 			ASSERT(0);
451 			break;
452 		}
453 	}
454 	smb_audit_node(node);
455 	smb_rwx_xexit(&node->n_lock);
456 }
457 
458 static void
459 smb_node_delete_on_close(smb_node_t *node)
460 {
461 	smb_node_t	*d_snode;
462 	int		rc = 0;
463 
464 	d_snode = node->dir_snode;
465 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
466 
467 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
468 		ASSERT(node->od_name != NULL);
469 		if (node->attr.sa_vattr.va_type == VDIR)
470 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
471 			    d_snode, node->od_name, 1);
472 		else
473 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
474 			    d_snode, node->od_name, 1);
475 		smb_cred_rele(node->delete_on_close_cred);
476 	}
477 	if (rc != 0)
478 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
479 		    node->od_name, rc);
480 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
481 }
482 
483 /*
484  * smb_node_rename()
485  *
486  */
487 int
488 smb_node_rename(
489     smb_node_t	*from_dir_snode,
490     smb_node_t	*ret_snode,
491     smb_node_t	*to_dir_snode,
492     char	*to_name)
493 {
494 	ASSERT(from_dir_snode);
495 	ASSERT(to_dir_snode);
496 	ASSERT(ret_snode);
497 	ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
498 	ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
499 	ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC);
500 	ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
501 	ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
502 	ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE);
503 
504 	smb_node_ref(to_dir_snode);
505 	smb_rwx_xenter(&ret_snode->n_lock);
506 	ret_snode->dir_snode = to_dir_snode;
507 	smb_rwx_xexit(&ret_snode->n_lock);
508 	ASSERT(to_dir_snode->dir_snode != ret_snode);
509 	ASSERT((to_dir_snode->vp->v_xattrdir) ||
510 	    (to_dir_snode->vp->v_type == VDIR));
511 	smb_node_release(from_dir_snode);
512 
513 	(void) strcpy(ret_snode->od_name, to_name);
514 
515 	/*
516 	 * XXX Need to update attributes?
517 	 */
518 
519 	return (0);
520 }
521 
522 int
523 smb_node_root_init()
524 {
525 	smb_attr_t va;
526 
527 	/*
528 	 * Take an explicit hold on rootdir.  This goes with the
529 	 * corresponding release in smb_node_root_fini()/smb_node_release().
530 	 */
531 
532 	VN_HOLD(rootdir);
533 
534 	if ((smb_info.si_root_smb_node = smb_node_lookup(NULL, NULL, kcred,
535 	    rootdir, ROOTVOL, NULL, NULL, &va)) == NULL)
536 		return (-1);
537 	else
538 		return (0);
539 }
540 
541 void
542 smb_node_root_fini()
543 {
544 	if (smb_info.si_root_smb_node) {
545 		smb_node_release(smb_info.si_root_smb_node);
546 		smb_info.si_root_smb_node = NULL;
547 	}
548 }
549 
550 /*
551  * smb_node_get_size
552  */
553 uint64_t
554 smb_node_get_size(
555     smb_node_t		*node,
556     smb_attr_t		*attr)
557 {
558 	uint64_t	size;
559 
560 	if (attr->sa_vattr.va_type == VDIR)
561 		return (0);
562 
563 	smb_rwx_xenter(&node->n_lock);
564 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
565 		size = node->n_size;
566 	else
567 		size = attr->sa_vattr.va_size;
568 	smb_rwx_xexit(&node->n_lock);
569 	return (size);
570 }
571 
572 static int
573 timeval_cmp(timestruc_t *a, timestruc_t *b)
574 {
575 	if (a->tv_sec < b->tv_sec)
576 		return (-1);
577 	if (a->tv_sec > b->tv_sec)
578 		return (1);
579 	/* Seconds are equal compare tv_nsec */
580 	if (a->tv_nsec < b->tv_nsec)
581 		return (-1);
582 	return (a->tv_nsec > b->tv_nsec);
583 }
584 
585 /*
586  * smb_node_set_time
587  *
588  * This function will update the time stored in the node and
589  * set the appropriate flags. If there is nothing to update
590  * or the node is readonly, the function would return without
591  * any updates. The update is only in the node level and the
592  * attribute in the file system will be updated when client
593  * close the file.
594  */
595 void
596 smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
597     struct timestruc *mtime, struct timestruc *atime,
598     struct timestruc *ctime, unsigned int what)
599 {
600 	smb_rwx_xenter(&node->n_lock);
601 	if (node->flags & NODE_READ_ONLY || what == 0) {
602 		smb_rwx_xexit(&node->n_lock);
603 		return;
604 	}
605 
606 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
607 	    (what & SMB_AT_MTIME && mtime == 0) ||
608 	    (what & SMB_AT_ATIME && atime == 0) ||
609 	    (what & SMB_AT_CTIME && ctime == 0)) {
610 		smb_rwx_xexit(&node->n_lock);
611 		return;
612 	}
613 
614 	if ((what & SMB_AT_CRTIME) &&
615 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
616 	    crtime) != 0) {
617 		node->what |= SMB_AT_CRTIME;
618 		node->attr.sa_crtime = *((timestruc_t *)crtime);
619 	}
620 
621 	if ((what & SMB_AT_MTIME) &&
622 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
623 	    mtime) != 0) {
624 		node->what |= SMB_AT_MTIME;
625 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
626 	}
627 
628 	if ((what & SMB_AT_ATIME) &&
629 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
630 	    atime) != 0) {
631 			node->what |= SMB_AT_ATIME;
632 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
633 	}
634 
635 	/*
636 	 * The ctime handling is trickier. It has three scenarios.
637 	 * 1. Only ctime need to be set and it is the same as the ctime
638 	 *    stored in the node. (update not necessary)
639 	 * 2. The ctime is the same as the ctime stored in the node but
640 	 *    is not the only time need to be set. (update required)
641 	 * 3. The ctime need to be set and is not the same as the ctime
642 	 *    stored in the node. (update required)
643 	 * Unlike other time setting, the ctime needs to be set even when
644 	 * it is the same as the ctime in the node if there are other time
645 	 * needs to be set (#2). This will ensure the ctime not being
646 	 * updated when other times are being updated in the file system.
647 	 *
648 	 * Retained file rules:
649 	 *
650 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
651 	 *    request will be rejected by filesystem
652 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
653 	 *    any request for changing ctime on these files should have
654 	 *    been already rejected
655 	 */
656 	node->what |= SMB_AT_CTIME;
657 	if (what & SMB_AT_CTIME) {
658 		if ((what == SMB_AT_CTIME) &&
659 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
660 		    ctime) == 0) {
661 			node->what &= ~SMB_AT_CTIME;
662 		} else {
663 			gethrestime(&node->attr.sa_vattr.va_ctime);
664 		}
665 	} else {
666 		gethrestime(&node->attr.sa_vattr.va_ctime);
667 	}
668 	smb_rwx_xexit(&node->n_lock);
669 }
670 
671 
672 timestruc_t *
673 smb_node_get_crtime(smb_node_t *node)
674 {
675 	return ((timestruc_t *)&node->attr.sa_crtime);
676 }
677 
678 timestruc_t *
679 smb_node_get_atime(smb_node_t *node)
680 {
681 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
682 }
683 
684 timestruc_t *
685 smb_node_get_ctime(smb_node_t *node)
686 {
687 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
688 }
689 
690 timestruc_t *
691 smb_node_get_mtime(smb_node_t *node)
692 {
693 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
694 }
695 
696 /*
697  * smb_node_set_dosattr
698  *
699  * Parse the specified DOS attributes and, if they have been modified,
700  * update the node cache. This call should be followed by a
701  * smb_sync_fsattr() call to write the attribute changes to filesystem.
702  */
703 void
704 smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr)
705 {
706 	unsigned int mode;  /* New mode */
707 
708 	mode = 0;
709 
710 	/* Handle the archive bit */
711 	if (dos_attr & SMB_FA_ARCHIVE)
712 		mode |= FILE_ATTRIBUTE_ARCHIVE;
713 
714 	/* Handle the readonly bit */
715 	if (dos_attr & SMB_FA_READONLY)
716 		mode |= FILE_ATTRIBUTE_READONLY;
717 
718 	/* Handle the hidden bit */
719 	if (dos_attr & SMB_FA_HIDDEN)
720 		mode |= FILE_ATTRIBUTE_HIDDEN;
721 
722 	/* Handle the system bit */
723 	if (dos_attr & SMB_FA_SYSTEM)
724 		mode |= FILE_ATTRIBUTE_SYSTEM;
725 
726 	smb_rwx_xenter(&node->n_lock);
727 	if (node->attr.sa_dosattr != mode) {
728 		node->attr.sa_dosattr = mode;
729 		node->what |= SMB_AT_DOSATTR;
730 	}
731 	smb_rwx_xexit(&node->n_lock);
732 }
733 
734 /*
735  * smb_node_get_dosattr
736  *
737  * This function will get dos attribute using the node.
738  */
739 uint32_t
740 smb_node_get_dosattr(smb_node_t *node)
741 {
742 	return (smb_mode_to_dos_attributes(&node->attr));
743 }
744 
745 int
746 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
747 {
748 	int	rc = -1;
749 
750 	smb_rwx_xenter(&node->n_lock);
751 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
752 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
753 		crhold(cr);
754 		node->delete_on_close_cred = cr;
755 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
756 		rc = 0;
757 	}
758 	smb_rwx_xexit(&node->n_lock);
759 	return (rc);
760 }
761 
762 void
763 smb_node_reset_delete_on_close(smb_node_t *node)
764 {
765 	smb_rwx_xenter(&node->n_lock);
766 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
767 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
768 		crfree(node->delete_on_close_cred);
769 		node->delete_on_close_cred = NULL;
770 	}
771 	smb_rwx_xexit(&node->n_lock);
772 }
773 
774 /*
775  * smb_node_share_check
776  *
777  * check file sharing rules for current open request
778  * against all existing opens for a file.
779  *
780  * Returns NT_STATUS_SHARING_VIOLATION if there is any
781  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
782  */
783 uint32_t
784 smb_node_open_check(struct smb_node *node, cred_t *cr,
785     uint32_t desired_access, uint32_t share_access)
786 {
787 	smb_ofile_t *of;
788 	uint32_t status;
789 
790 	ASSERT(node);
791 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
792 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
793 
794 	smb_llist_enter(&node->n_ofile_list, RW_READER);
795 	of = smb_llist_head(&node->n_ofile_list);
796 	while (of) {
797 		status = smb_node_share_check(node, cr, desired_access,
798 		    share_access, of);
799 		if (status == NT_STATUS_SHARING_VIOLATION) {
800 			smb_llist_exit(&node->n_ofile_list);
801 			return (status);
802 		}
803 		of = smb_llist_next(&node->n_ofile_list, of);
804 	}
805 	smb_llist_exit(&node->n_ofile_list);
806 
807 	return (NT_STATUS_SUCCESS);
808 }
809 
810 /*
811  * smb_open_share_check
812  *
813  * check file sharing rules for current open request
814  * against the given existing open.
815  *
816  * Returns NT_STATUS_SHARING_VIOLATION if there is any
817  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
818  */
819 uint32_t
820 smb_node_share_check(
821     struct smb_node *node,
822     cred_t *cr,
823     uint32_t desired_access,
824     uint32_t share_access,
825     smb_ofile_t *of)
826 {
827 	/*
828 	 * It appears that share modes are not relevant to
829 	 * directories, but this check will remain as it is not
830 	 * clear whether it was originally put here for a reason.
831 	 */
832 	if (node->attr.sa_vattr.va_type == VDIR) {
833 		if (SMB_DENY_RW(of->f_share_access) &&
834 		    (node->n_orig_uid != crgetuid(cr))) {
835 			return (NT_STATUS_SHARING_VIOLATION);
836 		}
837 
838 		return (NT_STATUS_SUCCESS);
839 	}
840 
841 	/* if it's just meta data */
842 	if ((of->f_granted_access & FILE_DATA_ALL) == 0)
843 		return (NT_STATUS_SUCCESS);
844 
845 	/*
846 	 * Check requested share access against the
847 	 * open granted (desired) access
848 	 */
849 	if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE))
850 		return (NT_STATUS_SHARING_VIOLATION);
851 
852 	if (SMB_DENY_READ(share_access) &&
853 	    (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE)))
854 		return (NT_STATUS_SHARING_VIOLATION);
855 
856 	if (SMB_DENY_WRITE(share_access) &&
857 	    (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
858 		return (NT_STATUS_SHARING_VIOLATION);
859 
860 	/* check requested desired access against the open share access */
861 	if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE))
862 		return (NT_STATUS_SHARING_VIOLATION);
863 
864 	if (SMB_DENY_READ(of->f_share_access) &&
865 	    (desired_access & (FILE_READ_DATA | FILE_EXECUTE)))
866 		return (NT_STATUS_SHARING_VIOLATION);
867 
868 	if (SMB_DENY_WRITE(of->f_share_access) &&
869 	    (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
870 		return (NT_STATUS_SHARING_VIOLATION);
871 
872 	return (NT_STATUS_SUCCESS);
873 }
874 
875 /*
876  * smb_rename_share_check
877  *
878  * An open file can be renamed if
879  *
880  *  1. isn't opened for data writing or deleting
881  *
882  *  2. Opened with "Deny Delete" share mode
883  *         But not opened for data reading or executing
884  *         (opened for accessing meta data)
885  */
886 
887 DWORD
888 smb_node_rename_check(struct smb_node *node)
889 {
890 	struct smb_ofile *open;
891 
892 	ASSERT(node);
893 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
894 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
895 
896 	/*
897 	 * Intra-CIFS check
898 	 */
899 
900 	smb_llist_enter(&node->n_ofile_list, RW_READER);
901 	open = smb_llist_head(&node->n_ofile_list);
902 	while (open) {
903 		if (open->f_granted_access &
904 		    (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) {
905 			smb_llist_exit(&node->n_ofile_list);
906 			return (NT_STATUS_SHARING_VIOLATION);
907 		}
908 
909 		if ((open->f_share_access & FILE_SHARE_DELETE) == 0) {
910 			if (open->f_granted_access &
911 			    (FILE_READ_DATA | FILE_EXECUTE)) {
912 				smb_llist_exit(&node->n_ofile_list);
913 				return (NT_STATUS_SHARING_VIOLATION);
914 			}
915 		}
916 		open = smb_llist_next(&node->n_ofile_list, open);
917 	}
918 	smb_llist_exit(&node->n_ofile_list);
919 
920 	/*
921 	 * system-wide share check
922 	 */
923 
924 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
925 		return (NT_STATUS_SHARING_VIOLATION);
926 	else
927 		return (NT_STATUS_SUCCESS);
928 }
929 
930 /*
931  * smb_node_delete_check
932  *
933  * An open file can be deleted only if opened for
934  * accessing meta data. Share modes aren't important
935  * in this case.
936  *
937  * NOTE: there is another mechanism for deleting an
938  * open file that NT clients usually use.
939  * That's setting "Delete on close" flag for an open
940  * file.  In this way the file will be deleted after
941  * last close. This flag can be set by SmbTrans2SetFileInfo
942  * with FILE_DISPOSITION_INFO information level.
943  * For setting this flag, the file should be opened by
944  * DELETE access in the FID that is passed in the Trans2
945  * request.
946  */
947 DWORD
948 smb_node_delete_check(smb_node_t *node)
949 {
950 	smb_ofile_t *file;
951 
952 	ASSERT(node);
953 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
954 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
955 
956 	if (node->attr.sa_vattr.va_type == VDIR)
957 		return (NT_STATUS_SUCCESS);
958 
959 	/*
960 	 * intra-CIFS check
961 	 */
962 
963 	smb_llist_enter(&node->n_ofile_list, RW_READER);
964 	file = smb_llist_head(&node->n_ofile_list);
965 	while (file) {
966 		ASSERT(file->f_magic == SMB_OFILE_MAGIC);
967 		if (file->f_granted_access &
968 		    (FILE_READ_DATA |
969 		    FILE_WRITE_DATA |
970 		    FILE_APPEND_DATA |
971 		    FILE_EXECUTE |
972 		    DELETE)) {
973 			smb_llist_exit(&node->n_ofile_list);
974 			return (NT_STATUS_SHARING_VIOLATION);
975 		}
976 		file = smb_llist_next(&node->n_ofile_list, file);
977 	}
978 	smb_llist_exit(&node->n_ofile_list);
979 
980 	/*
981 	 * system-wide share check
982 	 */
983 
984 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
985 		return (NT_STATUS_SHARING_VIOLATION);
986 	else
987 		return (NT_STATUS_SUCCESS);
988 }
989 
990 /*
991  * smb_node_start_crit()
992  *
993  * Enter critical region for share reservations.
994  * See comments above smb_fsop_shrlock().
995  */
996 
997 void
998 smb_node_start_crit(smb_node_t *node, krw_t mode)
999 {
1000 	rw_enter(&node->n_share_lock, mode);
1001 	nbl_start_crit(node->vp, mode);
1002 }
1003 
1004 /*
1005  * smb_node_end_crit()
1006  *
1007  * Exit critical region for share reservations.
1008  */
1009 
1010 void
1011 smb_node_end_crit(smb_node_t *node)
1012 {
1013 	nbl_end_crit(node->vp);
1014 	rw_exit(&node->n_share_lock);
1015 }
1016 
1017 int
1018 smb_node_in_crit(smb_node_t *node)
1019 {
1020 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock));
1021 }
1022