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