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