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