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