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