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