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