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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * SMB Node State Machine 30 * ---------------------- 31 * 32 * +----------------------------+ T0 33 * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation 34 * +----------------------------+ 35 * | 36 * | T1 37 * | 38 * v 39 * +-----------------------------+ T2 40 * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free 41 * +-----------------------------+ 42 * 43 * Transition T0 44 * 45 * This transition occurs in smb_node_lookup(). If the node looked for is 46 * not found in the has table a new node is created. The reference count is 47 * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 48 * 49 * Transition T1 50 * 51 * This transition occurs in smb_node_release(). If the reference count 52 * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 53 * reference count will be given out for that node. 54 * 55 * Transition T2 56 * 57 * This transition occurs in smb_node_release(). The structure is deleted. 58 * 59 * Comments 60 * -------- 61 * 62 * The reason the smb node has 2 states is the following synchronization 63 * rule: 64 * 65 * There's a mutex embedded in the node used to protect its fields and 66 * there's a lock embedded in the bucket of the hash table the node belongs 67 * to. To increment or to decrement the reference count the mutex must be 68 * entered. To insert the node into the bucket and to remove it from the 69 * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 70 * lock) have to be entered, the lock has always to be entered first then 71 * the mutex. This prevents a deadlock between smb_node_lookup() and 72 * smb_node_release() from occurring. However, in smb_node_release() when the 73 * reference count drops to zero and triggers the deletion of the node, the 74 * mutex has to be released before entering the lock of the bucket (to 75 * remove the node). This creates a window during which the node that is 76 * about to be freed could be given out by smb_node_lookup(). To close that 77 * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 78 * releasing the mutex. That way, even if smb_node_lookup() finds it, the 79 * state will indicate that the node should be treated as non existent (of 80 * course the state of the node should be tested/updated under the 81 * protection of the mutex). 82 */ 83 #include <smbsrv/smb_incl.h> 84 #include <smbsrv/smb_fsops.h> 85 #include <sys/pathname.h> 86 #include <sys/sdt.h> 87 #include <sys/nbmlock.h> 88 89 uint32_t smb_is_executable(char *path); 90 static void smb_node_delete_on_close(smb_node_t *node); 91 92 #define VALIDATE_DIR_NODE(_dir_, _node_) \ 93 ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 94 ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 95 ASSERT((_dir_)->dir_snode != (_node_)); 96 97 static boolean_t smb_node_initialized = B_FALSE; 98 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 99 100 /* 101 * smb_node_init 102 * 103 * Initialization of the SMB node layer. 104 * 105 * This function is not multi-thread safe. The caller must make sure only one 106 * thread makes the call. 107 */ 108 int 109 smb_node_init(void) 110 { 111 int i; 112 113 if (smb_node_initialized) 114 return (0); 115 116 for (i = 0; i <= SMBND_HASH_MASK; i++) { 117 smb_llist_constructor(&smb_node_hash_table[i], 118 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 119 } 120 smb_node_initialized = B_TRUE; 121 return (0); 122 } 123 124 /* 125 * smb_node_fini 126 * 127 * This function is not multi-thread safe. The caller must make sure only one 128 * thread makes the call. 129 */ 130 void 131 smb_node_fini(void) 132 { 133 int i; 134 135 if (!smb_node_initialized) 136 return; 137 138 #ifdef DEBUG 139 for (i = 0; i <= SMBND_HASH_MASK; i++) { 140 smb_node_t *node; 141 142 /* 143 * The following sequence is just intended for sanity check. 144 * This will have to be modified when the code goes into 145 * production. 146 * 147 * The SMB node hash table should be emtpy at this point. If the 148 * hash table is not empty a panic will be triggered. 149 * 150 * The reason why SMB nodes are still remaining in the hash 151 * table is problably due to a mismatch between calls to 152 * smb_node_lookup() and smb_node_release(). You must track that 153 * down. 154 */ 155 node = smb_llist_head(&smb_node_hash_table[i]); 156 ASSERT(node == NULL); 157 } 158 #endif 159 160 for (i = 0; i <= SMBND_HASH_MASK; i++) { 161 smb_llist_destructor(&smb_node_hash_table[i]); 162 } 163 smb_node_initialized = B_FALSE; 164 } 165 166 /* 167 * smb_node_lookup() 168 * 169 * NOTE: This routine should only be called by the file system interface layer, 170 * and not by SMB. 171 * 172 * smb_node_lookup() is called upon successful lookup, mkdir, and create 173 * (for both non-streams and streams). In each of these cases, a held vnode is 174 * passed into this routine. If an smb_node already exists for this vnode, 175 * the vp is released. Otherwise, a new smb_node will be created and the 176 * reference will be held until the refcnt on the node goes to 0 (see 177 * smb_node_release()). 178 * 179 * A reference is taken on the smb_node whether found in the hash table 180 * or newly created. 181 * 182 * If an smb_node needs to be created, a reference is also taken on the 183 * dir_snode (if passed in). 184 * 185 * See smb_node_release() for details on the release of these references. 186 */ 187 188 /*ARGSUSED*/ 189 smb_node_t * 190 smb_node_lookup( 191 struct smb_request *sr, 192 struct open_param *op, 193 cred_t *cred, 194 vnode_t *vp, 195 char *od_name, 196 smb_node_t *dir_snode, 197 smb_node_t *unnamed_node, 198 smb_attr_t *attr) 199 { 200 smb_llist_t *node_hdr; 201 smb_node_t *node; 202 uint32_t hashkey = 0; 203 fs_desc_t fsd; 204 int error; 205 krw_t lock_mode; 206 vnode_t *unnamed_vp = NULL; 207 208 /* 209 * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 210 * because the node may not yet exist. We also do not want to call 211 * it with the list lock held. 212 */ 213 214 if (unnamed_node) 215 unnamed_vp = unnamed_node->vp; 216 217 /* 218 * This getattr is performed on behalf of the server 219 * that's why kcred is used not the user's cred 220 */ 221 attr->sa_mask = SMB_AT_ALL; 222 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 223 if (error) 224 return (NULL); 225 226 if (sr) { 227 if (sr->tid_tree) { 228 /* 229 * The fsd for a file is that of the tree, even 230 * if the file resides in a different mountpoint 231 * under the share. 232 */ 233 fsd = sr->tid_tree->t_fsd; 234 } else { 235 /* 236 * This should be getting executed only for the 237 * tree's root smb_node. 238 */ 239 fsd = vp->v_vfsp->vfs_fsid; 240 } 241 } else { 242 fsd = vp->v_vfsp->vfs_fsid; 243 } 244 245 hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid; 246 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 247 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 248 lock_mode = RW_READER; 249 250 smb_llist_enter(node_hdr, lock_mode); 251 for (;;) { 252 node = list_head(&node_hdr->ll_list); 253 while (node) { 254 ASSERT(node->n_magic == SMB_NODE_MAGIC); 255 ASSERT(node->n_hash_bucket == node_hdr); 256 if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 257 smb_rwx_xenter(&node->n_lock); 258 DTRACE_PROBE1(smb_node_lookup_hit, 259 smb_node_t *, node); 260 switch (node->n_state) { 261 case SMB_NODE_STATE_AVAILABLE: 262 /* The node was found. */ 263 node->n_refcnt++; 264 if ((node->dir_snode == NULL) && 265 (dir_snode != NULL) && 266 (strcmp(od_name, "..") != 0) && 267 (strcmp(od_name, ".") != 0)) { 268 VALIDATE_DIR_NODE(dir_snode, 269 node); 270 node->dir_snode = dir_snode; 271 smb_node_ref(dir_snode); 272 } 273 node->attr = *attr; 274 node->n_size = attr->sa_vattr.va_size; 275 276 smb_audit_node(node); 277 smb_rwx_xexit(&node->n_lock); 278 smb_llist_exit(node_hdr); 279 VN_RELE(vp); 280 return (node); 281 282 case SMB_NODE_STATE_DESTROYING: 283 /* 284 * Although the node exists it is about 285 * to be destroyed. We act as it hasn't 286 * been found. 287 */ 288 smb_rwx_xexit(&node->n_lock); 289 break; 290 default: 291 /* 292 * Although the node exists it is in an 293 * unknown state. We act as it hasn't 294 * been found. 295 */ 296 ASSERT(0); 297 smb_rwx_xexit(&node->n_lock); 298 break; 299 } 300 } 301 node = smb_llist_next(node_hdr, node); 302 } 303 if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 304 lock_mode = RW_WRITER; 305 continue; 306 } 307 break; 308 } 309 node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP); 310 bzero(node, sizeof (smb_node_t)); 311 312 node->n_state = SMB_NODE_STATE_AVAILABLE; 313 node->n_hash_bucket = node_hdr; 314 node->n_sr = sr; 315 node->vp = vp; 316 node->n_hashkey = hashkey; 317 node->n_refcnt = 1; 318 node->tree_fsd = vp->v_vfsp->vfs_fsid; 319 node->attr = *attr; 320 node->flags |= NODE_FLAGS_ATTR_VALID; 321 node->n_size = node->attr.sa_vattr.va_size; 322 node->n_orig_session_id = sr->session->s_kid; 323 node->n_orig_uid = crgetuid(sr->user_cr); 324 node->n_cache = sr->sr_server->si_cache_node; 325 326 ASSERT(od_name); 327 (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 328 329 if (fsd_chkcap(&vp->v_vfsp->vfs_fsid, FSOLF_READONLY) > 0) 330 node->flags |= NODE_READ_ONLY; 331 332 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 333 offsetof(smb_ofile_t, f_nnd)); 334 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 335 offsetof(smb_lock_t, l_lnd)); 336 337 338 if (strcmp(od_name, XATTR_DIR) == 0) 339 node->flags |= NODE_XATTR_DIR; 340 if (op) 341 node->flags |= smb_is_executable(op->fqi.last_comp); 342 343 if (dir_snode) { 344 smb_node_ref(dir_snode); 345 node->dir_snode = dir_snode; 346 ASSERT(dir_snode->dir_snode != node); 347 ASSERT((dir_snode->vp->v_xattrdir) || 348 (dir_snode->vp->v_type == VDIR)); 349 } 350 351 if (unnamed_node) { 352 smb_node_ref(unnamed_node); 353 node->unnamed_stream_node = unnamed_node; 354 } 355 356 smb_rwx_init(&node->n_lock); 357 node->n_magic = SMB_NODE_MAGIC; 358 smb_audit_buf_node_create(node); 359 DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 360 smb_audit_node(node); 361 smb_llist_insert_head(node_hdr, node); 362 363 smb_llist_exit(node_hdr); 364 return (node); 365 } 366 367 /* 368 * smb_stream_node_lookup() 369 * 370 * Note: stream_name (the name that will be stored in the "od_name" field 371 * of a stream's smb_node) is the same as the on-disk name for the stream 372 * except that it does not have SMB_STREAM_PREFIX prepended. 373 */ 374 375 smb_node_t * 376 smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, 377 vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 378 { 379 smb_node_t *xattrdir_node; 380 smb_node_t *snode; 381 smb_attr_t tmp_attr; 382 383 xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 384 fnode, NULL, &tmp_attr); 385 386 if (xattrdir_node == NULL) 387 return (NULL); 388 389 snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 390 fnode, ret_attr); 391 392 /* 393 * The following VN_HOLD is necessary because the caller will VN_RELE 394 * xattrdirvp in the case of an error. (xattrdir_node has the original 395 * hold on the vnode, which the smb_node_release() call below will 396 * release.) 397 */ 398 if (snode == NULL) { 399 VN_HOLD(xattrdirvp); 400 } 401 (void) smb_node_release(xattrdir_node); 402 return (snode); 403 } 404 405 406 /* 407 * This function should be called whenever a reference is needed on an 408 * smb_node pointer. The copy of an smb_node pointer from one non-local 409 * data structure to another requires a reference to be taken on the smb_node 410 * (unless the usage is localized). Each data structure deallocation routine 411 * will call smb_node_release() on its smb_node pointers. 412 * 413 * In general, an smb_node pointer residing in a structure should never be 414 * stale. A node pointer may be NULL, however, and care should be taken 415 * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 416 * Care also needs to be taken with respect to racing deallocations of a 417 * structure. 418 */ 419 420 void 421 smb_node_ref(smb_node_t *node) 422 { 423 ASSERT(node); 424 ASSERT(node->n_magic == SMB_NODE_MAGIC); 425 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 426 427 smb_rwx_xenter(&node->n_lock); 428 node->n_refcnt++; 429 ASSERT(node->n_refcnt); 430 DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 431 smb_audit_node(node); 432 smb_rwx_xexit(&node->n_lock); 433 } 434 435 /* 436 * smb_node_lookup() takes a hold on an smb_node, whether found in the 437 * hash table or newly created. This hold is expected to be released 438 * in the following manner. 439 * 440 * smb_node_lookup() takes an address of an smb_node pointer. This should 441 * be getting passed down via a lookup (whether path name or component), mkdir, 442 * create. If the original smb_node pointer resides in a data structure, then 443 * the deallocation routine for the data structure is responsible for calling 444 * smb_node_release() on the smb_node pointer. Alternatively, 445 * smb_node_release() can be called as soon as the smb_node pointer is no longer 446 * needed. In this case, callers are responsible for setting an embedded 447 * pointer to NULL if it is known that the last reference is being released. 448 * 449 * If the passed-in address of the smb_node pointer belongs to a local variable, 450 * then the caller with the local variable should call smb_node_release() 451 * directly. 452 * 453 * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 454 * as smb_node_lookup() takes a hold on dir_snode. 455 */ 456 void 457 smb_node_release(smb_node_t *node) 458 { 459 ASSERT(node); 460 ASSERT(node->n_magic == SMB_NODE_MAGIC); 461 462 smb_rwx_xenter(&node->n_lock); 463 ASSERT(node->n_refcnt); 464 DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 465 if (--node->n_refcnt == 0) { 466 switch (node->n_state) { 467 468 case SMB_NODE_STATE_AVAILABLE: 469 node->n_state = SMB_NODE_STATE_DESTROYING; 470 smb_rwx_xexit(&node->n_lock); 471 472 smb_llist_enter(node->n_hash_bucket, RW_WRITER); 473 smb_llist_remove(node->n_hash_bucket, node); 474 smb_llist_exit(node->n_hash_bucket); 475 476 /* 477 * Check if the file was deleted 478 */ 479 smb_node_delete_on_close(node); 480 node->n_magic = (uint32_t)~SMB_NODE_MAGIC; 481 482 /* These lists should be empty. */ 483 smb_llist_destructor(&node->n_ofile_list); 484 smb_llist_destructor(&node->n_lock_list); 485 486 if (node->dir_snode) { 487 ASSERT(node->dir_snode->n_magic == 488 SMB_NODE_MAGIC); 489 smb_node_release(node->dir_snode); 490 } 491 492 if (node->unnamed_stream_node) { 493 ASSERT(node->unnamed_stream_node->n_magic == 494 SMB_NODE_MAGIC); 495 smb_node_release(node->unnamed_stream_node); 496 } 497 498 ASSERT(node->vp); 499 VN_RELE(node->vp); 500 501 smb_audit_buf_node_destroy(node); 502 smb_rwx_destroy(&node->n_lock); 503 kmem_cache_free(node->n_cache, node); 504 return; 505 506 default: 507 ASSERT(0); 508 break; 509 } 510 } 511 smb_audit_node(node); 512 smb_rwx_xexit(&node->n_lock); 513 } 514 515 static void 516 smb_node_delete_on_close(smb_node_t *node) 517 { 518 smb_node_t *d_snode; 519 int rc = 0; 520 521 d_snode = node->dir_snode; 522 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 523 524 node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 525 ASSERT(node->od_name != NULL); 526 if (node->attr.sa_vattr.va_type == VDIR) 527 rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 528 d_snode, node->od_name, 1); 529 else 530 rc = smb_fsop_remove(0, node->delete_on_close_cred, 531 d_snode, node->od_name, 1); 532 smb_cred_rele(node->delete_on_close_cred); 533 } 534 if (rc != 0) 535 cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 536 node->od_name, rc); 537 DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 538 } 539 540 /* 541 * smb_node_rename() 542 * 543 */ 544 int 545 smb_node_rename( 546 smb_node_t *from_dir_snode, 547 smb_node_t *ret_snode, 548 smb_node_t *to_dir_snode, 549 char *to_name) 550 { 551 ASSERT(from_dir_snode); 552 ASSERT(to_dir_snode); 553 ASSERT(ret_snode); 554 ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 555 ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 556 ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC); 557 ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 558 ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 559 ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE); 560 561 smb_node_ref(to_dir_snode); 562 smb_rwx_xenter(&ret_snode->n_lock); 563 ret_snode->dir_snode = to_dir_snode; 564 smb_rwx_xexit(&ret_snode->n_lock); 565 ASSERT(to_dir_snode->dir_snode != ret_snode); 566 ASSERT((to_dir_snode->vp->v_xattrdir) || 567 (to_dir_snode->vp->v_type == VDIR)); 568 smb_node_release(from_dir_snode); 569 570 (void) strcpy(ret_snode->od_name, to_name); 571 572 /* 573 * XXX Need to update attributes? 574 */ 575 576 return (0); 577 } 578 579 int 580 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 581 { 582 smb_attr_t va; 583 int error; 584 uint32_t hashkey; 585 smb_llist_t *node_hdr; 586 smb_node_t *node; 587 588 /* 589 * Take an explicit hold on rootdir. This goes with the 590 * corresponding release in smb_node_root_fini()/smb_node_release(). 591 */ 592 VN_HOLD(vp); 593 594 va.sa_mask = SMB_AT_ALL; 595 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 596 if (error) { 597 VN_RELE(vp); 598 return (error); 599 } 600 601 hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid; 602 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 603 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 604 605 node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP); 606 bzero(node, sizeof (smb_node_t)); 607 608 node->n_state = SMB_NODE_STATE_AVAILABLE; 609 node->n_hash_bucket = node_hdr; 610 node->vp = vp; 611 node->n_hashkey = hashkey; 612 node->n_refcnt = 1; 613 node->tree_fsd = vp->v_vfsp->vfs_fsid; 614 node->attr = va; 615 node->flags |= NODE_FLAGS_ATTR_VALID; 616 node->n_size = node->attr.sa_vattr.va_size; 617 node->n_cache = sv->si_cache_node; 618 (void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name)); 619 620 if (fsd_chkcap(&vp->v_vfsp->vfs_fsid, FSOLF_READONLY) > 0) 621 node->flags |= NODE_READ_ONLY; 622 623 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 624 offsetof(smb_ofile_t, f_nnd)); 625 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 626 offsetof(smb_lock_t, l_lnd)); 627 628 smb_rwx_init(&node->n_lock); 629 node->n_magic = SMB_NODE_MAGIC; 630 smb_audit_buf_node_create(node); 631 632 sv->si_root_smb_node = node; 633 634 smb_audit_node(node); 635 smb_llist_enter(node_hdr, RW_WRITER); 636 smb_llist_insert_head(node_hdr, node); 637 smb_llist_exit(node_hdr); 638 639 *root = node; 640 641 return (0); 642 } 643 644 /* 645 * smb_node_get_size 646 */ 647 uint64_t 648 smb_node_get_size( 649 smb_node_t *node, 650 smb_attr_t *attr) 651 { 652 uint64_t size; 653 654 if (attr->sa_vattr.va_type == VDIR) 655 return (0); 656 657 smb_rwx_xenter(&node->n_lock); 658 if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 659 size = node->n_size; 660 else 661 size = attr->sa_vattr.va_size; 662 smb_rwx_xexit(&node->n_lock); 663 return (size); 664 } 665 666 static int 667 timeval_cmp(timestruc_t *a, timestruc_t *b) 668 { 669 if (a->tv_sec < b->tv_sec) 670 return (-1); 671 if (a->tv_sec > b->tv_sec) 672 return (1); 673 /* Seconds are equal compare tv_nsec */ 674 if (a->tv_nsec < b->tv_nsec) 675 return (-1); 676 return (a->tv_nsec > b->tv_nsec); 677 } 678 679 /* 680 * smb_node_set_time 681 * 682 * This function will update the time stored in the node and 683 * set the appropriate flags. If there is nothing to update 684 * or the node is readonly, the function would return without 685 * any updates. The update is only in the node level and the 686 * attribute in the file system will be updated when client 687 * close the file. 688 */ 689 void 690 smb_node_set_time(struct smb_node *node, struct timestruc *crtime, 691 struct timestruc *mtime, struct timestruc *atime, 692 struct timestruc *ctime, unsigned int what) 693 { 694 smb_rwx_xenter(&node->n_lock); 695 if (node->flags & NODE_READ_ONLY || what == 0) { 696 smb_rwx_xexit(&node->n_lock); 697 return; 698 } 699 700 if ((what & SMB_AT_CRTIME && crtime == 0) || 701 (what & SMB_AT_MTIME && mtime == 0) || 702 (what & SMB_AT_ATIME && atime == 0) || 703 (what & SMB_AT_CTIME && ctime == 0)) { 704 smb_rwx_xexit(&node->n_lock); 705 return; 706 } 707 708 if ((what & SMB_AT_CRTIME) && 709 timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 710 crtime) != 0) { 711 node->what |= SMB_AT_CRTIME; 712 node->attr.sa_crtime = *((timestruc_t *)crtime); 713 } 714 715 if ((what & SMB_AT_MTIME) && 716 timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 717 mtime) != 0) { 718 node->what |= SMB_AT_MTIME; 719 node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 720 } 721 722 if ((what & SMB_AT_ATIME) && 723 timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 724 atime) != 0) { 725 node->what |= SMB_AT_ATIME; 726 node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 727 } 728 729 /* 730 * The ctime handling is trickier. It has three scenarios. 731 * 1. Only ctime need to be set and it is the same as the ctime 732 * stored in the node. (update not necessary) 733 * 2. The ctime is the same as the ctime stored in the node but 734 * is not the only time need to be set. (update required) 735 * 3. The ctime need to be set and is not the same as the ctime 736 * stored in the node. (update required) 737 * Unlike other time setting, the ctime needs to be set even when 738 * it is the same as the ctime in the node if there are other time 739 * needs to be set (#2). This will ensure the ctime not being 740 * updated when other times are being updated in the file system. 741 * 742 * Retained file rules: 743 * 744 * 1. Don't add SMB_AT_CTIME to node->what by default because the 745 * request will be rejected by filesystem 746 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 747 * any request for changing ctime on these files should have 748 * been already rejected 749 */ 750 node->what |= SMB_AT_CTIME; 751 if (what & SMB_AT_CTIME) { 752 if ((what == SMB_AT_CTIME) && 753 timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 754 ctime) == 0) { 755 node->what &= ~SMB_AT_CTIME; 756 } else { 757 gethrestime(&node->attr.sa_vattr.va_ctime); 758 } 759 } else { 760 gethrestime(&node->attr.sa_vattr.va_ctime); 761 } 762 smb_rwx_xexit(&node->n_lock); 763 } 764 765 766 timestruc_t * 767 smb_node_get_crtime(smb_node_t *node) 768 { 769 return ((timestruc_t *)&node->attr.sa_crtime); 770 } 771 772 timestruc_t * 773 smb_node_get_atime(smb_node_t *node) 774 { 775 return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 776 } 777 778 timestruc_t * 779 smb_node_get_ctime(smb_node_t *node) 780 { 781 return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 782 } 783 784 timestruc_t * 785 smb_node_get_mtime(smb_node_t *node) 786 { 787 return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 788 } 789 790 /* 791 * smb_node_set_dosattr 792 * 793 * Parse the specified DOS attributes and, if they have been modified, 794 * update the node cache. This call should be followed by a 795 * smb_sync_fsattr() call to write the attribute changes to filesystem. 796 */ 797 void 798 smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr) 799 { 800 unsigned int mode; /* New mode */ 801 802 mode = 0; 803 804 /* Handle the archive bit */ 805 if (dos_attr & SMB_FA_ARCHIVE) 806 mode |= FILE_ATTRIBUTE_ARCHIVE; 807 808 /* Handle the readonly bit */ 809 if (dos_attr & SMB_FA_READONLY) 810 mode |= FILE_ATTRIBUTE_READONLY; 811 812 /* Handle the hidden bit */ 813 if (dos_attr & SMB_FA_HIDDEN) 814 mode |= FILE_ATTRIBUTE_HIDDEN; 815 816 /* Handle the system bit */ 817 if (dos_attr & SMB_FA_SYSTEM) 818 mode |= FILE_ATTRIBUTE_SYSTEM; 819 820 smb_rwx_xenter(&node->n_lock); 821 if (node->attr.sa_dosattr != mode) { 822 node->attr.sa_dosattr = mode; 823 node->what |= SMB_AT_DOSATTR; 824 } 825 smb_rwx_xexit(&node->n_lock); 826 } 827 828 /* 829 * smb_node_get_dosattr 830 * 831 * This function will get dos attribute using the node. 832 */ 833 uint32_t 834 smb_node_get_dosattr(smb_node_t *node) 835 { 836 return (smb_mode_to_dos_attributes(&node->attr)); 837 } 838 839 int 840 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) 841 { 842 int rc = -1; 843 844 smb_rwx_xenter(&node->n_lock); 845 if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 846 !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 847 crhold(cr); 848 node->delete_on_close_cred = cr; 849 node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 850 rc = 0; 851 } 852 smb_rwx_xexit(&node->n_lock); 853 return (rc); 854 } 855 856 void 857 smb_node_reset_delete_on_close(smb_node_t *node) 858 { 859 smb_rwx_xenter(&node->n_lock); 860 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 861 node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 862 crfree(node->delete_on_close_cred); 863 node->delete_on_close_cred = NULL; 864 } 865 smb_rwx_xexit(&node->n_lock); 866 } 867 868 /* 869 * smb_node_share_check 870 * 871 * check file sharing rules for current open request 872 * against all existing opens for a file. 873 * 874 * Returns NT_STATUS_SHARING_VIOLATION if there is any 875 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 876 */ 877 uint32_t 878 smb_node_open_check(struct smb_node *node, cred_t *cr, 879 uint32_t desired_access, uint32_t share_access) 880 { 881 smb_ofile_t *of; 882 uint32_t status; 883 884 ASSERT(node); 885 ASSERT(node->n_magic == SMB_NODE_MAGIC); 886 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 887 888 smb_llist_enter(&node->n_ofile_list, RW_READER); 889 of = smb_llist_head(&node->n_ofile_list); 890 while (of) { 891 status = smb_node_share_check(node, cr, desired_access, 892 share_access, of); 893 if (status == NT_STATUS_SHARING_VIOLATION) { 894 smb_llist_exit(&node->n_ofile_list); 895 return (status); 896 } 897 of = smb_llist_next(&node->n_ofile_list, of); 898 } 899 smb_llist_exit(&node->n_ofile_list); 900 901 return (NT_STATUS_SUCCESS); 902 } 903 904 /* 905 * smb_open_share_check 906 * 907 * check file sharing rules for current open request 908 * against the given existing open. 909 * 910 * Returns NT_STATUS_SHARING_VIOLATION if there is any 911 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 912 */ 913 uint32_t 914 smb_node_share_check( 915 struct smb_node *node, 916 cred_t *cr, 917 uint32_t desired_access, 918 uint32_t share_access, 919 smb_ofile_t *of) 920 { 921 /* 922 * It appears that share modes are not relevant to 923 * directories, but this check will remain as it is not 924 * clear whether it was originally put here for a reason. 925 */ 926 if (node->attr.sa_vattr.va_type == VDIR) { 927 if (SMB_DENY_RW(of->f_share_access) && 928 (node->n_orig_uid != crgetuid(cr))) { 929 return (NT_STATUS_SHARING_VIOLATION); 930 } 931 932 return (NT_STATUS_SUCCESS); 933 } 934 935 /* if it's just meta data */ 936 if ((of->f_granted_access & FILE_DATA_ALL) == 0) 937 return (NT_STATUS_SUCCESS); 938 939 /* 940 * Check requested share access against the 941 * open granted (desired) access 942 */ 943 if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) 944 return (NT_STATUS_SHARING_VIOLATION); 945 946 if (SMB_DENY_READ(share_access) && 947 (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) 948 return (NT_STATUS_SHARING_VIOLATION); 949 950 if (SMB_DENY_WRITE(share_access) && 951 (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 952 return (NT_STATUS_SHARING_VIOLATION); 953 954 /* check requested desired access against the open share access */ 955 if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) 956 return (NT_STATUS_SHARING_VIOLATION); 957 958 if (SMB_DENY_READ(of->f_share_access) && 959 (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) 960 return (NT_STATUS_SHARING_VIOLATION); 961 962 if (SMB_DENY_WRITE(of->f_share_access) && 963 (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 964 return (NT_STATUS_SHARING_VIOLATION); 965 966 return (NT_STATUS_SUCCESS); 967 } 968 969 /* 970 * smb_rename_share_check 971 * 972 * An open file can be renamed if 973 * 974 * 1. isn't opened for data writing or deleting 975 * 976 * 2. Opened with "Deny Delete" share mode 977 * But not opened for data reading or executing 978 * (opened for accessing meta data) 979 */ 980 981 DWORD 982 smb_node_rename_check(struct smb_node *node) 983 { 984 struct smb_ofile *open; 985 986 ASSERT(node); 987 ASSERT(node->n_magic == SMB_NODE_MAGIC); 988 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 989 990 /* 991 * Intra-CIFS check 992 */ 993 994 smb_llist_enter(&node->n_ofile_list, RW_READER); 995 open = smb_llist_head(&node->n_ofile_list); 996 while (open) { 997 if (open->f_granted_access & 998 (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) { 999 smb_llist_exit(&node->n_ofile_list); 1000 return (NT_STATUS_SHARING_VIOLATION); 1001 } 1002 1003 if ((open->f_share_access & FILE_SHARE_DELETE) == 0) { 1004 if (open->f_granted_access & 1005 (FILE_READ_DATA | FILE_EXECUTE)) { 1006 smb_llist_exit(&node->n_ofile_list); 1007 return (NT_STATUS_SHARING_VIOLATION); 1008 } 1009 } 1010 open = smb_llist_next(&node->n_ofile_list, open); 1011 } 1012 smb_llist_exit(&node->n_ofile_list); 1013 1014 /* 1015 * system-wide share check 1016 */ 1017 1018 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 1019 return (NT_STATUS_SHARING_VIOLATION); 1020 else 1021 return (NT_STATUS_SUCCESS); 1022 } 1023 1024 /* 1025 * smb_node_delete_check 1026 * 1027 * An open file can be deleted only if opened for 1028 * accessing meta data. Share modes aren't important 1029 * in this case. 1030 * 1031 * NOTE: there is another mechanism for deleting an 1032 * open file that NT clients usually use. 1033 * That's setting "Delete on close" flag for an open 1034 * file. In this way the file will be deleted after 1035 * last close. This flag can be set by SmbTrans2SetFileInfo 1036 * with FILE_DISPOSITION_INFO information level. 1037 * For setting this flag, the file should be opened by 1038 * DELETE access in the FID that is passed in the Trans2 1039 * request. 1040 */ 1041 DWORD 1042 smb_node_delete_check(smb_node_t *node) 1043 { 1044 smb_ofile_t *file; 1045 1046 ASSERT(node); 1047 ASSERT(node->n_magic == SMB_NODE_MAGIC); 1048 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 1049 1050 if (node->attr.sa_vattr.va_type == VDIR) 1051 return (NT_STATUS_SUCCESS); 1052 1053 /* 1054 * intra-CIFS check 1055 */ 1056 1057 smb_llist_enter(&node->n_ofile_list, RW_READER); 1058 file = smb_llist_head(&node->n_ofile_list); 1059 while (file) { 1060 ASSERT(file->f_magic == SMB_OFILE_MAGIC); 1061 if (file->f_granted_access & 1062 (FILE_READ_DATA | 1063 FILE_WRITE_DATA | 1064 FILE_APPEND_DATA | 1065 FILE_EXECUTE | 1066 DELETE)) { 1067 smb_llist_exit(&node->n_ofile_list); 1068 return (NT_STATUS_SHARING_VIOLATION); 1069 } 1070 file = smb_llist_next(&node->n_ofile_list, file); 1071 } 1072 smb_llist_exit(&node->n_ofile_list); 1073 1074 /* 1075 * system-wide share check 1076 */ 1077 1078 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 1079 return (NT_STATUS_SHARING_VIOLATION); 1080 else 1081 return (NT_STATUS_SUCCESS); 1082 } 1083 1084 /* 1085 * smb_node_start_crit() 1086 * 1087 * Enter critical region for share reservations. 1088 * See comments above smb_fsop_shrlock(). 1089 */ 1090 1091 void 1092 smb_node_start_crit(smb_node_t *node, krw_t mode) 1093 { 1094 rw_enter(&node->n_share_lock, mode); 1095 nbl_start_crit(node->vp, mode); 1096 } 1097 1098 /* 1099 * smb_node_end_crit() 1100 * 1101 * Exit critical region for share reservations. 1102 */ 1103 1104 void 1105 smb_node_end_crit(smb_node_t *node) 1106 { 1107 nbl_end_crit(node->vp); 1108 rw_exit(&node->n_share_lock); 1109 } 1110 1111 int 1112 smb_node_in_crit(smb_node_t *node) 1113 { 1114 return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock)); 1115 } 1116