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 2007 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 #include <sys/sid.h> 29 #include <smbsrv/smb_incl.h> 30 #include <smbsrv/smb_fsops.h> 31 #include <acl/acl_common.h> 32 33 u_longlong_t smb_caller_id; 34 35 static int smb_fsop_amask_to_omode(uint32_t granted_access); 36 37 extern uint32_t smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd); 38 39 extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd, 40 uint32_t secinfo); 41 42 extern int smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, 43 int *aclbsize); 44 45 static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, 46 smb_fssd_t *fs_sd); 47 48 static void smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, 49 int which_acl); 50 static acl_t *smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl); 51 52 /* 53 * The smb_fsop_* functions have knowledge of CIFS semantics. 54 * 55 * The smb_vop_* functions have minimal knowledge of CIFS semantics and 56 * serve as an interface to the VFS layer. 57 * 58 * Hence, smb_request_t and smb_node_t structures should not be passed 59 * from the smb_fsop_* layer to the smb_vop_* layer. 60 * 61 * In general, CIFS service code should only ever call smb_fsop_* 62 * functions directly, and never smb_vop_* functions directly. 63 * 64 * smb_fsop_* functions should call smb_vop_* functions where possible, instead 65 * of their smb_fsop_* counterparts. However, there are times when 66 * this cannot be avoided. 67 */ 68 69 /* 70 * Note: Stream names cannot be mangled. 71 */ 72 73 int 74 smb_fsop_start() 75 { 76 int error; 77 78 smb_caller_id = fs_new_caller_id(); 79 error = smb_node_root_init(); 80 81 if (error == 0) 82 error = smb_fem_init(); 83 84 return (error); 85 } 86 87 void 88 smb_fsop_stop() 89 { 90 smb_fem_shutdown(); 91 smb_vfs_rele_all(); 92 smb_node_root_fini(); 93 } 94 95 int 96 smb_fsop_open(smb_ofile_t *of) 97 { 98 caller_context_t ct; 99 int mode; 100 101 mode = smb_fsop_amask_to_omode(of->f_granted_access); 102 103 smb_get_caller_context(NULL, &ct); 104 105 /* 106 * Assuming that same vnode is returned as we had before 107 * (i.e. no special vnodes) 108 */ 109 110 return (smb_vop_open(&of->f_node->vp, mode, of->f_cr, &ct)); 111 } 112 113 int 114 smb_fsop_close(smb_ofile_t *of) 115 { 116 caller_context_t ct; 117 int mode; 118 119 mode = smb_fsop_amask_to_omode(of->f_granted_access); 120 121 smb_get_caller_context(NULL, &ct); 122 123 return (smb_vop_close(of->f_node->vp, mode, of->f_cr, &ct)); 124 } 125 126 static int 127 smb_fsop_amask_to_omode(uint32_t granted_access) 128 { 129 int mode = 0; 130 131 if (granted_access & (ACE_READ_DATA | ACE_EXECUTE)) 132 mode |= FREAD; 133 134 if (granted_access & (ACE_WRITE_DATA | ACE_APPEND_DATA)) 135 mode |= FWRITE; 136 137 if (granted_access & ACE_APPEND_DATA) 138 mode |= FAPPEND; 139 140 return (mode); 141 } 142 143 static int 144 smb_fsop_create_with_sd( 145 struct smb_request *sr, 146 cred_t *cr, 147 smb_node_t *snode, 148 char *name, 149 smb_attr_t *attr, 150 smb_node_t **ret_snode, 151 smb_attr_t *ret_attr, 152 smb_fssd_t *fs_sd) 153 { 154 caller_context_t ct; 155 vsecattr_t *vsap; 156 vsecattr_t vsecattr; 157 acl_t *acl, *dacl, *sacl; 158 smb_attr_t set_attr; 159 vnode_t *vp; 160 int aclbsize = 0; /* size of acl list in bytes */ 161 int flags = 0; 162 int is_dir; 163 int rc; 164 165 ASSERT(fs_sd); 166 167 if (SMB_TREE_CASE_INSENSITIVE(sr)) 168 flags = SMB_IGNORE_CASE; 169 170 ASSERT(cr); 171 smb_get_caller_context(sr, &ct); 172 173 is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 174 175 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACLONCREATE) { 176 if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 177 dacl = fs_sd->sd_zdacl; 178 sacl = fs_sd->sd_zsacl; 179 ASSERT(dacl || sacl); 180 if (dacl && sacl) { 181 acl = smb_fsop_aclmerge(dacl, sacl); 182 } else if (dacl) { 183 acl = dacl; 184 } else { 185 acl = sacl; 186 } 187 188 rc = smb_vop_acl_to_vsa(acl, &vsecattr, &aclbsize); 189 190 if (dacl && sacl) 191 acl_free(acl); 192 193 if (rc) 194 return (rc); 195 196 vsap = &vsecattr; 197 } 198 else 199 vsap = NULL; 200 201 if (is_dir) { 202 rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags, 203 cr, &ct, vsap); 204 } else { 205 rc = smb_vop_create(snode->vp, name, attr, &vp, flags, 206 cr, &ct, vsap); 207 } 208 209 if (vsap != NULL) 210 kmem_free(vsap->vsa_aclentp, aclbsize); 211 212 if (rc != 0) 213 return (rc); 214 215 set_attr.sa_mask = 0; 216 217 /* 218 * Ideally we should be able to specify the owner and owning 219 * group at create time along with the ACL. Since we cannot 220 * do that right now, kcred is passed to smb_vop_setattr so it 221 * doesn't fail due to lack of permission. 222 */ 223 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 224 set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 225 set_attr.sa_mask |= SMB_AT_UID; 226 } 227 228 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 229 set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 230 set_attr.sa_mask |= SMB_AT_GID; 231 } 232 233 if (set_attr.sa_mask) { 234 rc = smb_vop_setattr(snode->vp, NULL, &set_attr, 235 0, kcred, &ct); 236 } 237 238 } else { 239 /* 240 * For filesystems that don't support ACL-on-create, try 241 * to set the specified SD after create, which could actually 242 * fail because of conflicts between inherited security 243 * attributes upon creation and the specified SD. 244 * 245 * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 246 */ 247 248 if (is_dir) { 249 rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags, 250 cr, &ct, NULL); 251 } else { 252 rc = smb_vop_create(snode->vp, name, attr, &vp, flags, 253 cr, &ct, NULL); 254 } 255 256 if (rc == 0) 257 rc = smb_fsop_sdwrite(sr, kcred, snode, fs_sd, 1); 258 } 259 260 if (rc == 0) { 261 *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name, 262 snode, NULL, ret_attr); 263 264 if (*ret_snode == NULL) { 265 VN_RELE(vp); 266 rc = ENOMEM; 267 } 268 } 269 270 return (rc); 271 } 272 273 274 /* 275 * smb_fsop_create 276 * 277 * All SMB functions should use this wrapper to ensure that 278 * all the smb_vop_creates are performed with the appropriate credentials. 279 * Please document any direct calls to explain the reason 280 * for avoiding this wrapper. 281 * 282 * It is assumed that a reference exists on snode coming into this routine. 283 * 284 * *ret_snode is returned with a reference upon success. No reference is 285 * taken if an error is returned. 286 */ 287 288 int 289 smb_fsop_create( 290 struct smb_request *sr, 291 cred_t *cr, 292 smb_node_t *dir_snode, 293 char *name, 294 smb_attr_t *attr, 295 smb_node_t **ret_snode, 296 smb_attr_t *ret_attr) 297 { 298 struct open_param *op = &sr->arg.open; 299 smb_node_t *fnode; 300 smb_attr_t file_attr; 301 caller_context_t ct; 302 vnode_t *xattrdirvp; 303 vnode_t *vp; 304 char *longname = NULL; 305 char *namep; 306 char *fname; 307 char *sname; 308 int is_stream; 309 int flags = 0; 310 int rc = 0; 311 smb_fssd_t fs_sd; 312 uint32_t secinfo; 313 uint32_t status; 314 315 ASSERT(cr); 316 ASSERT(dir_snode); 317 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 318 ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 319 320 ASSERT(ret_snode); 321 *ret_snode = 0; 322 323 ASSERT(name); 324 if (*name == 0) 325 return (EINVAL); 326 327 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 328 return (EACCES); 329 330 ASSERT(sr); 331 ASSERT(sr->tid_tree); 332 if (SMB_TREE_IS_READ_ONLY(sr)) 333 return (EROFS); 334 335 if (SMB_TREE_CASE_INSENSITIVE(sr)) 336 flags = SMB_IGNORE_CASE; 337 338 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 339 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 340 341 is_stream = smb_stream_parse_name(name, fname, sname); 342 343 if (is_stream) 344 namep = fname; 345 else 346 namep = name; 347 348 if (smb_maybe_mangled_name(namep)) { 349 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 350 351 rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 352 MAXNAMELEN, NULL, NULL, 1); 353 354 if ((is_stream == 0) && (rc == 0)) 355 rc = EEXIST; 356 357 if ((is_stream && rc) || 358 ((is_stream == 0) && (rc != ENOENT))) { 359 kmem_free(longname, MAXNAMELEN); 360 kmem_free(fname, MAXNAMELEN); 361 kmem_free(sname, MAXNAMELEN); 362 return (rc); 363 } 364 365 if (is_stream) 366 namep = longname; 367 else 368 kmem_free(longname, MAXNAMELEN); 369 } 370 371 if (is_stream) { 372 /* 373 * Look up the unnamed stream. 374 * 375 * Mangle processing in smb_fsop_lookup() for the unnamed 376 * stream won't be needed (as it was done above), but 377 * it may be needed on any link target (which 378 * smb_fsop_lookup() will provide). 379 */ 380 rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 381 sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 382 0, 0); 383 384 if (longname) { 385 kmem_free(longname, MAXNAMELEN); 386 namep = NULL; 387 } 388 389 if (rc != 0) { 390 kmem_free(fname, MAXNAMELEN); 391 kmem_free(sname, MAXNAMELEN); 392 return (rc); 393 } 394 395 smb_get_caller_context(sr, &ct); 396 397 rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 398 &xattrdirvp, flags, cr, &ct); 399 400 if (rc != 0) { 401 smb_node_release(fnode); 402 kmem_free(fname, MAXNAMELEN); 403 kmem_free(sname, MAXNAMELEN); 404 return (rc); 405 } 406 407 *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 408 vp, sname, ret_attr); 409 410 smb_node_release(fnode); 411 412 if (*ret_snode == NULL) { 413 VN_RELE(xattrdirvp); 414 VN_RELE(vp); 415 kmem_free(fname, MAXNAMELEN); 416 kmem_free(sname, MAXNAMELEN); 417 return (ENOMEM); 418 } 419 } else { 420 if (op->sd_buf) { 421 /* 422 * SD sent by client in Windows format. Needs to be 423 * converted to FS format. No inheritance. 424 */ 425 secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf); 426 smb_fsop_sdinit(&fs_sd, secinfo, 0); 427 428 status = smb_sd_tofs(op->sd_buf, &fs_sd); 429 if (status == NT_STATUS_SUCCESS) { 430 rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 431 name, attr, ret_snode, ret_attr, &fs_sd); 432 } 433 else 434 rc = EINVAL; 435 smb_fsop_sdterm(&fs_sd); 436 } else if (sr->tid_tree->t_acltype == ACE_T) { 437 /* 438 * No incoming SD and filesystem is ZFS 439 * Server applies Windows inheritance rules, 440 * see smb_fsop_sdinherit() comments as to why. 441 */ 442 smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, 0); 443 rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 444 if (rc == 0) { 445 rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 446 name, attr, ret_snode, ret_attr, &fs_sd); 447 } 448 449 smb_fsop_sdterm(&fs_sd); 450 } else { 451 /* 452 * No incoming SD and filesystem is not ZFS 453 * let the filesystem handles the inheritance. 454 */ 455 smb_get_caller_context(sr, &ct); 456 rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 457 flags, cr, &ct, NULL); 458 459 if (rc == 0) { 460 *ret_snode = smb_node_lookup(sr, op, cr, vp, 461 name, dir_snode, NULL, ret_attr); 462 463 if (*ret_snode == NULL) { 464 VN_RELE(vp); 465 rc = ENOMEM; 466 } 467 } 468 469 } 470 } 471 472 kmem_free(fname, MAXNAMELEN); 473 kmem_free(sname, MAXNAMELEN); 474 return (rc); 475 } 476 477 /* 478 * smb_fsop_mkdir 479 * 480 * All SMB functions should use this wrapper to ensure that 481 * the the calls are performed with the appropriate credentials. 482 * Please document any direct call to explain the reason 483 * for avoiding this wrapper. 484 * 485 * It is assumed that a reference exists on snode coming into this routine. 486 * 487 * *ret_snode is returned with a reference upon success. No reference is 488 * taken if an error is returned. 489 */ 490 int 491 smb_fsop_mkdir( 492 struct smb_request *sr, 493 cred_t *cr, 494 smb_node_t *dir_snode, 495 char *name, 496 smb_attr_t *attr, 497 smb_node_t **ret_snode, 498 smb_attr_t *ret_attr) 499 { 500 struct open_param *op = &sr->arg.open; 501 caller_context_t ct; 502 char *longname; 503 vnode_t *vp; 504 int flags = 0; 505 smb_fssd_t fs_sd; 506 uint32_t secinfo; 507 uint32_t status; 508 int rc; 509 510 ASSERT(cr); 511 ASSERT(dir_snode); 512 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 513 ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 514 515 ASSERT(ret_snode); 516 *ret_snode = 0; 517 518 ASSERT(name); 519 if (*name == 0) 520 return (EINVAL); 521 522 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 523 return (EACCES); 524 525 ASSERT(sr); 526 ASSERT(sr->tid_tree); 527 if (SMB_TREE_IS_READ_ONLY(sr)) 528 return (EROFS); 529 530 if (smb_maybe_mangled_name(name)) { 531 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 532 rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 533 MAXNAMELEN, NULL, NULL, 1); 534 535 kmem_free(longname, MAXNAMELEN); 536 537 /* 538 * If the name passed in by the client has an unmangled 539 * equivalent that is found in the specified directory, 540 * then the mkdir cannot succeed. Return EEXIST. 541 * 542 * Only if ENOENT is returned will a mkdir be attempted. 543 */ 544 545 if (rc == 0) 546 rc = EEXIST; 547 548 if (rc != ENOENT) 549 return (rc); 550 } 551 552 if (SMB_TREE_CASE_INSENSITIVE(sr)) 553 flags = SMB_IGNORE_CASE; 554 555 smb_get_caller_context(sr, &ct); 556 557 if (op->sd_buf) { 558 /* 559 * SD sent by client in Windows format. Needs to be 560 * converted to FS format. No inheritance. 561 */ 562 secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf); 563 smb_fsop_sdinit(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 564 565 status = smb_sd_tofs(op->sd_buf, &fs_sd); 566 if (status == NT_STATUS_SUCCESS) { 567 rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 568 name, attr, ret_snode, ret_attr, &fs_sd); 569 } 570 else 571 rc = EINVAL; 572 smb_fsop_sdterm(&fs_sd); 573 } else if (sr->tid_tree->t_acltype == ACE_T) { 574 /* 575 * No incoming SD and filesystem is ZFS 576 * Server applies Windows inheritance rules, 577 * see smb_fsop_sdinherit() comments as to why. 578 */ 579 smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 580 rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 581 if (rc == 0) { 582 rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 583 name, attr, ret_snode, ret_attr, &fs_sd); 584 } 585 586 smb_fsop_sdterm(&fs_sd); 587 588 } else { 589 rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 590 &ct, NULL); 591 592 if (rc == 0) { 593 *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 594 dir_snode, NULL, ret_attr); 595 596 if (*ret_snode == NULL) { 597 VN_RELE(vp); 598 rc = ENOMEM; 599 } 600 } 601 } 602 603 return (rc); 604 } 605 606 /* 607 * smb_fsop_remove 608 * 609 * All SMB functions should use this wrapper to ensure that 610 * the the calls are performed with the appropriate credentials. 611 * Please document any direct call to explain the reason 612 * for avoiding this wrapper. 613 * 614 * It is assumed that a reference exists on snode coming into this routine. 615 * 616 * od: This means that the name passed in is an on-disk name. 617 * A null smb_request might be passed to this function. 618 */ 619 620 int 621 smb_fsop_remove( 622 struct smb_request *sr, 623 cred_t *cr, 624 smb_node_t *dir_snode, 625 char *name, 626 int od) 627 { 628 smb_node_t *fnode; 629 smb_attr_t file_attr; 630 caller_context_t ct; 631 char *longname; 632 char *fname; 633 char *sname; 634 int flags = 0; 635 int rc; 636 637 ASSERT(cr); 638 /* 639 * The state of the node could be SMB_NODE_STATE_DESTROYING if this 640 * function is called during the deletion of the node (because of 641 * DELETE_ON_CLOSE). 642 */ 643 ASSERT(dir_snode); 644 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 645 646 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 647 return (EACCES); 648 649 if (SMB_TREE_IS_READ_ONLY(sr)) 650 return (EROFS); 651 652 smb_get_caller_context(sr, &ct); 653 654 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 655 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 656 657 if (smb_stream_parse_name(name, fname, sname)) { 658 659 ASSERT(od == 0); 660 661 if (SMB_TREE_CASE_INSENSITIVE(sr)) 662 flags = SMB_IGNORE_CASE; 663 664 /* 665 * Look up the unnamed stream (i.e. fname). 666 * Unmangle processing will be done on fname 667 * as well as any link target. 668 */ 669 670 rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 671 sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 672 0, 0); 673 674 if (rc != 0) { 675 kmem_free(fname, MAXNAMELEN); 676 kmem_free(sname, MAXNAMELEN); 677 return (rc); 678 } 679 680 /* 681 * XXX 682 * Need to find out what permission is required by NTFS 683 * to remove a stream. 684 */ 685 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr, &ct); 686 687 smb_node_release(fnode); 688 } else { 689 /* 690 * If the passed-in name is an on-disk name, 691 * then we need to do a case-sensitive remove. 692 * This is important if the on-disk name 693 * corresponds to a mangled name passed in by 694 * the client. We want to make sure to remove 695 * the exact file specified by the client, 696 * instead of letting the underlying file system 697 * do a remove on the "first match." 698 */ 699 700 if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr)) 701 flags = SMB_IGNORE_CASE; 702 703 rc = smb_vop_remove(dir_snode->vp, name, flags, cr, &ct); 704 705 if (rc == ENOENT) { 706 if (smb_maybe_mangled_name(name) == 0) { 707 kmem_free(fname, MAXNAMELEN); 708 kmem_free(sname, MAXNAMELEN); 709 return (rc); 710 } 711 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 712 713 rc = smb_unmangle_name(sr, cr, dir_snode, name, 714 longname, MAXNAMELEN, NULL, NULL, 1); 715 716 if (rc == 0) { 717 /* 718 * We passed "1" as the "od" parameter 719 * to smb_unmangle_name(), such that longname 720 * is the real (case-sensitive) on-disk name. 721 * We make sure we do a remove on this exact 722 * name, as the name was mangled and denotes 723 * a unique file. 724 */ 725 flags &= ~SMB_IGNORE_CASE; 726 rc = smb_vop_remove(dir_snode->vp, longname, 727 flags, cr, &ct); 728 } 729 730 kmem_free(longname, MAXNAMELEN); 731 } 732 } 733 734 kmem_free(fname, MAXNAMELEN); 735 kmem_free(sname, MAXNAMELEN); 736 return (rc); 737 } 738 739 /* 740 * smb_fsop_remove_streams 741 * 742 * This function removes a file's streams without removing the 743 * file itself. 744 * 745 * It is assumed that snode is not a link. 746 */ 747 int 748 smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr, 749 smb_node_t *fnode) 750 { 751 struct fs_stream_info stream_info; 752 caller_context_t ct; 753 uint32_t cookie = 0; 754 int flags = 0; 755 int rc; 756 757 ASSERT(cr); 758 ASSERT(fnode); 759 ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 760 ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 761 762 if (SMB_TREE_ROOT_FS(sr, fnode) == 0) 763 return (EACCES); 764 765 if (SMB_TREE_IS_READ_ONLY(sr)) 766 return (EROFS); 767 768 if (SMB_TREE_CASE_INSENSITIVE(sr)) 769 flags = SMB_IGNORE_CASE; 770 771 smb_get_caller_context(sr, &ct); 772 773 for (;;) { 774 rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info, 775 NULL, NULL, flags, cr, &ct); 776 777 if ((rc != 0) || (cookie == SMB_EOF)) 778 break; 779 780 (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags, 781 cr, &ct); 782 } 783 return (rc); 784 } 785 786 /* 787 * smb_fsop_rmdir 788 * 789 * All SMB functions should use this wrapper to ensure that 790 * the the calls are performed with the appropriate credentials. 791 * Please document any direct call to explain the reason 792 * for avoiding this wrapper. 793 * 794 * It is assumed that a reference exists on snode coming into this routine. 795 * 796 * od: This means that the name passed in is an on-disk name. 797 */ 798 799 int 800 smb_fsop_rmdir( 801 struct smb_request *sr, 802 cred_t *cr, 803 smb_node_t *dir_snode, 804 char *name, 805 int od) 806 { 807 caller_context_t ct; 808 int rc; 809 int flags = 0; 810 char *longname; 811 812 ASSERT(cr); 813 /* 814 * The state of the node could be SMB_NODE_STATE_DESTROYING if this 815 * function is called during the deletion of the node (because of 816 * DELETE_ON_CLOSE). 817 */ 818 ASSERT(dir_snode); 819 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 820 821 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 822 return (EACCES); 823 824 if (SMB_TREE_IS_READ_ONLY(sr)) 825 return (EROFS); 826 827 /* 828 * If the passed-in name is an on-disk name, 829 * then we need to do a case-sensitive rmdir. 830 * This is important if the on-disk name 831 * corresponds to a mangled name passed in by 832 * the client. We want to make sure to remove 833 * the exact directory specified by the client, 834 * instead of letting the underlying file system 835 * do a rmdir on the "first match." 836 */ 837 838 if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr)) 839 flags = SMB_IGNORE_CASE; 840 841 smb_get_caller_context(sr, &ct); 842 843 rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr, &ct); 844 845 if (rc == ENOENT) { 846 if (smb_maybe_mangled_name(name) == 0) 847 return (rc); 848 849 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 850 851 rc = smb_unmangle_name(sr, cr, dir_snode, 852 name, longname, MAXNAMELEN, NULL, 853 NULL, 1); 854 855 if (rc == 0) { 856 /* 857 * We passed "1" as the "od" parameter 858 * to smb_unmangle_name(), such that longname 859 * is the real (case-sensitive) on-disk name. 860 * We make sure we do a rmdir on this exact 861 * name, as the name was mangled and denotes 862 * a unique directory. 863 */ 864 flags &= ~SMB_IGNORE_CASE; 865 rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr, 866 &ct); 867 } 868 869 kmem_free(longname, MAXNAMELEN); 870 } 871 872 return (rc); 873 } 874 875 /* 876 * smb_fsop_getattr 877 * 878 * All SMB functions should use this wrapper to ensure that 879 * the the calls are performed with the appropriate credentials. 880 * Please document any direct call to explain the reason 881 * for avoiding this wrapper. 882 * 883 * It is assumed that a reference exists on snode coming into this routine. 884 */ 885 int 886 smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode, 887 smb_attr_t *attr) 888 { 889 smb_node_t *unnamed_node; 890 vnode_t *unnamed_vp = NULL; 891 caller_context_t ct; 892 uint32_t status; 893 uint32_t access = 0; 894 int flags = 0; 895 896 ASSERT(cr); 897 ASSERT(snode); 898 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 899 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 900 901 if (SMB_TREE_ROOT_FS(sr, snode) == 0) 902 return (EACCES); 903 904 if (sr->fid_ofile) { 905 /* if uid and/or gid is requested */ 906 if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 907 access |= READ_CONTROL; 908 909 /* if anything else is also requested */ 910 if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 911 access |= FILE_READ_ATTRIBUTES; 912 913 status = smb_ofile_access(sr->fid_ofile, cr, access); 914 if (status != NT_STATUS_SUCCESS) 915 return (EACCES); 916 917 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 918 flags = ATTR_NOACLCHECK; 919 } 920 921 smb_get_caller_context(sr, &ct); 922 923 unnamed_node = SMB_IS_STREAM(snode); 924 925 if (unnamed_node) { 926 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 927 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 928 unnamed_vp = unnamed_node->vp; 929 } 930 931 return (smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr, &ct)); 932 } 933 934 /* 935 * smb_fsop_readdir 936 * 937 * All SMB functions should use this smb_fsop_readdir wrapper to ensure that 938 * the smb_vop_readdir is performed with the appropriate credentials. 939 * Please document any direct call to smb_vop_readdir to explain the reason 940 * for avoiding this wrapper. 941 * 942 * It is assumed that a reference exists on snode coming into this routine. 943 */ 944 int 945 smb_fsop_readdir( 946 struct smb_request *sr, 947 cred_t *cr, 948 smb_node_t *dir_snode, 949 uint32_t *cookie, 950 char *name, 951 int *namelen, 952 ino64_t *fileid, 953 struct fs_stream_info *stream_info, 954 smb_node_t **ret_snode, 955 smb_attr_t *ret_attr) 956 { 957 caller_context_t ct; 958 smb_node_t *ret_snodep; 959 smb_node_t *fnode; 960 smb_attr_t tmp_attr; 961 vnode_t *xattrdirvp; 962 vnode_t *fvp; 963 vnode_t *vp = NULL; 964 char *od_name; 965 int rc; 966 int flags = 0; 967 968 ASSERT(cr); 969 ASSERT(dir_snode); 970 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 971 ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 972 973 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 974 return (EACCES); 975 976 if (*cookie == SMB_EOF) { 977 *namelen = 0; 978 return (0); 979 } 980 981 if (SMB_TREE_CASE_INSENSITIVE(sr)) 982 flags = SMB_IGNORE_CASE; 983 984 smb_get_caller_context(sr, &ct); 985 986 od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 987 988 if (stream_info) { 989 rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name, 990 SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr, &ct); 991 992 if (rc != 0) { 993 kmem_free(od_name, MAXNAMELEN); 994 return (rc); 995 } 996 997 fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode, 998 NULL, ret_attr); 999 1000 kmem_free(od_name, MAXNAMELEN); 1001 1002 if (fnode == NULL) { 1003 VN_RELE(fvp); 1004 return (ENOMEM); 1005 } 1006 1007 /* 1008 * XXX 1009 * Need to find out what permission(s) NTFS requires for getting 1010 * a file's streams list. 1011 * 1012 * Might have to use kcred. 1013 */ 1014 rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp, 1015 &xattrdirvp, flags, cr, &ct); 1016 1017 if ((rc != 0) || (*cookie == SMB_EOF)) { 1018 smb_node_release(fnode); 1019 return (rc); 1020 } 1021 1022 ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1023 vp, stream_info->name, &tmp_attr); 1024 1025 smb_node_release(fnode); 1026 1027 if (ret_snodep == NULL) { 1028 VN_RELE(xattrdirvp); 1029 VN_RELE(vp); 1030 return (ENOMEM); 1031 } 1032 1033 stream_info->size = tmp_attr.sa_vattr.va_size; 1034 1035 if (ret_attr) 1036 *ret_attr = tmp_attr; 1037 1038 if (ret_snode) 1039 *ret_snode = ret_snodep; 1040 else 1041 smb_node_release(ret_snodep); 1042 1043 } else { 1044 rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen, 1045 fileid, &vp, od_name, flags, cr, &ct); 1046 1047 if (rc != 0) { 1048 kmem_free(od_name, MAXNAMELEN); 1049 return (rc); 1050 } 1051 1052 if (*namelen) { 1053 ASSERT(vp); 1054 if (ret_attr || ret_snode) { 1055 ret_snodep = smb_node_lookup(sr, NULL, cr, vp, 1056 od_name, dir_snode, NULL, &tmp_attr); 1057 1058 if (ret_snodep == NULL) { 1059 kmem_free(od_name, MAXNAMELEN); 1060 VN_RELE(vp); 1061 return (ENOMEM); 1062 } 1063 1064 if (ret_attr) 1065 *ret_attr = tmp_attr; 1066 1067 if (ret_snode) 1068 *ret_snode = ret_snodep; 1069 else 1070 smb_node_release(ret_snodep); 1071 } 1072 } 1073 1074 kmem_free(od_name, MAXNAMELEN); 1075 } 1076 1077 return (rc); 1078 } 1079 1080 /* 1081 * smb_fsop_getdents 1082 * 1083 * All SMB functions should use this smb_vop_getdents wrapper to ensure that 1084 * the smb_vop_getdents is performed with the appropriate credentials. 1085 * Please document any direct call to smb_vop_getdents to explain the reason 1086 * for avoiding this wrapper. 1087 * 1088 * It is assumed that a reference exists on snode coming into this routine. 1089 */ 1090 /*ARGSUSED*/ 1091 int 1092 smb_fsop_getdents( 1093 struct smb_request *sr, 1094 cred_t *cr, 1095 smb_node_t *dir_snode, 1096 uint32_t *cookie, 1097 uint64_t *verifierp, 1098 int32_t *maxcnt, 1099 char *args, 1100 char *pattern) 1101 { 1102 caller_context_t ct; 1103 int flags = 0; 1104 1105 ASSERT(cr); 1106 ASSERT(dir_snode); 1107 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1108 ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1109 1110 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 1111 return (EACCES); 1112 1113 if (SMB_TREE_CASE_INSENSITIVE(sr)) 1114 flags = SMB_IGNORE_CASE; 1115 1116 smb_get_caller_context(sr, &ct); 1117 1118 return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern, 1119 flags, sr, cr, &ct)); 1120 } 1121 1122 /* 1123 * smb_fsop_rename 1124 * 1125 * All SMB functions should use this smb_vop_rename wrapper to ensure that 1126 * the smb_vop_rename is performed with the appropriate credentials. 1127 * Please document any direct call to smb_vop_rename to explain the reason 1128 * for avoiding this wrapper. 1129 * 1130 * It is assumed that references exist on from_dir_snode and to_dir_snode coming 1131 * into this routine. 1132 */ 1133 int 1134 smb_fsop_rename( 1135 struct smb_request *sr, 1136 cred_t *cr, 1137 smb_node_t *from_dir_snode, 1138 char *from_name, 1139 smb_node_t *to_dir_snode, 1140 char *to_name) 1141 { 1142 smb_node_t *from_snode; 1143 caller_context_t ct; 1144 smb_attr_t tmp_attr; 1145 vnode_t *from_vp; 1146 int flags = 0; 1147 int rc; 1148 1149 ASSERT(cr); 1150 ASSERT(from_dir_snode); 1151 ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 1152 ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1153 1154 ASSERT(to_dir_snode); 1155 ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 1156 ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1157 1158 if (SMB_TREE_ROOT_FS(sr, from_dir_snode) == 0) 1159 return (EACCES); 1160 1161 if (SMB_TREE_ROOT_FS(sr, to_dir_snode) == 0) 1162 return (EACCES); 1163 1164 ASSERT(sr); 1165 ASSERT(sr->tid_tree); 1166 if (SMB_TREE_IS_READ_ONLY(sr)) 1167 return (EROFS); 1168 1169 /* 1170 * Note: There is no need to check SMB_TREE_CASE_INSENSITIVE(sr) 1171 * here. 1172 * 1173 * A case-sensitive rename is always done in this routine 1174 * because we are using the on-disk name from an earlier lookup. 1175 * If a mangled name was passed in by the caller (denoting a 1176 * deterministic lookup), then the exact file must be renamed 1177 * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 1178 * else the underlying file system might return a "first-match" 1179 * on this on-disk name, possibly resulting in the wrong file). 1180 */ 1181 1182 /* 1183 * XXX: Lock required through smb_node_release() below? 1184 */ 1185 1186 smb_get_caller_context(sr, &ct); 1187 1188 rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 1189 NULL, cr, &ct); 1190 1191 if (rc != 0) 1192 return (rc); 1193 1194 rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 1195 to_name, flags, cr, &ct); 1196 1197 if (rc == 0) { 1198 from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 1199 from_dir_snode, NULL, &tmp_attr); 1200 1201 if (from_snode == NULL) { 1202 VN_RELE(from_vp); 1203 return (ENOMEM); 1204 } 1205 1206 (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode, 1207 to_name); 1208 1209 smb_node_release(from_snode); 1210 } else { 1211 VN_RELE(from_vp); 1212 } 1213 1214 /* XXX: unlock */ 1215 1216 return (rc); 1217 } 1218 1219 /* 1220 * smb_fsop_setattr 1221 * 1222 * All SMB functions should use this wrapper to ensure that 1223 * the the calls are performed with the appropriate credentials. 1224 * Please document any direct call to explain the reason 1225 * for avoiding this wrapper. 1226 * 1227 * It is assumed that a reference exists on snode coming into this routine. 1228 * A null smb_request might be passed to this function. 1229 */ 1230 int 1231 smb_fsop_setattr( 1232 smb_request_t *sr, 1233 cred_t *cr, 1234 smb_node_t *snode, 1235 smb_attr_t *set_attr, 1236 smb_attr_t *ret_attr) 1237 { 1238 smb_node_t *unnamed_node; 1239 vnode_t *unnamed_vp = NULL; 1240 caller_context_t ct; 1241 uint32_t status; 1242 uint32_t access = 0; 1243 int rc = 0; 1244 int flags = 0; 1245 1246 ASSERT(cr); 1247 ASSERT(snode); 1248 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1249 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1250 1251 if (SMB_TREE_ROOT_FS(sr, snode) == 0) 1252 return (EACCES); 1253 1254 if (SMB_TREE_IS_READ_ONLY(sr)) 1255 return (EROFS); 1256 1257 /* sr could be NULL in some cases */ 1258 if (sr && sr->fid_ofile) { 1259 /* if uid and/or gid is requested */ 1260 if (set_attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 1261 access |= WRITE_OWNER; 1262 1263 /* if anything else is also requested */ 1264 if (set_attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 1265 access |= FILE_WRITE_ATTRIBUTES; 1266 1267 status = smb_ofile_access(sr->fid_ofile, cr, access); 1268 if (status != NT_STATUS_SUCCESS) 1269 return (EACCES); 1270 1271 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 1272 flags = ATTR_NOACLCHECK; 1273 } 1274 1275 smb_get_caller_context(sr, &ct); 1276 1277 unnamed_node = SMB_IS_STREAM(snode); 1278 1279 if (unnamed_node) { 1280 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1281 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1282 unnamed_vp = unnamed_node->vp; 1283 } 1284 1285 rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, &ct); 1286 1287 if ((rc == 0) && ret_attr) { 1288 /* 1289 * This is an operation on behalf of CIFS service (to update 1290 * smb node's attr) not on behalf of the user so it's done 1291 * using kcred and the return value is intentionally ignored. 1292 */ 1293 ret_attr->sa_mask = SMB_AT_ALL; 1294 (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1295 kcred, &ct); 1296 } 1297 1298 return (rc); 1299 } 1300 1301 /* 1302 * smb_fsop_read 1303 * 1304 * All SMB functions should use this wrapper to ensure that 1305 * the the calls are performed with the appropriate credentials. 1306 * Please document any direct call to explain the reason 1307 * for avoiding this wrapper. 1308 * 1309 * It is assumed that a reference exists on snode coming into this routine. 1310 */ 1311 int 1312 smb_fsop_read( 1313 struct smb_request *sr, 1314 cred_t *cr, 1315 smb_node_t *snode, 1316 uio_t *uio, 1317 smb_attr_t *ret_attr) 1318 { 1319 smb_node_t *unnamed_node; 1320 vnode_t *unnamed_vp = NULL; 1321 caller_context_t ct; 1322 int rc; 1323 1324 ASSERT(cr); 1325 ASSERT(snode); 1326 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1327 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1328 1329 ASSERT(sr); 1330 ASSERT(sr->fid_ofile); 1331 1332 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 1333 if (rc != NT_STATUS_SUCCESS) { 1334 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 1335 if (rc != NT_STATUS_SUCCESS) 1336 return (EACCES); 1337 } 1338 1339 unnamed_node = SMB_IS_STREAM(snode); 1340 if (unnamed_node) { 1341 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1342 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1343 unnamed_vp = unnamed_node->vp; 1344 /* 1345 * Streams permission are checked against the unnamed stream, 1346 * but in FS level they have their own permissions. To avoid 1347 * rejection by FS due to lack of permission on the actual 1348 * extended attr kcred is passed for streams. 1349 */ 1350 cr = kcred; 1351 } 1352 1353 smb_get_caller_context(sr, &ct); 1354 rc = smb_vop_read(snode->vp, uio, cr, &ct); 1355 1356 if (rc == 0) { 1357 /* 1358 * This is an operation on behalf of CIFS service (to update 1359 * smb node's attr) not on behalf of the user so it's done 1360 * using kcred and the return value is intentionally ignored. 1361 */ 1362 ret_attr->sa_mask = SMB_AT_ALL; 1363 (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1364 kcred, &ct); 1365 } 1366 1367 return (rc); 1368 } 1369 1370 /* 1371 * smb_fsop_write 1372 * 1373 * This is a wrapper function used for smb_write and smb_write_raw operations. 1374 * 1375 * It is assumed that a reference exists on snode coming into this routine. 1376 */ 1377 int 1378 smb_fsop_write( 1379 struct smb_request *sr, 1380 cred_t *cr, 1381 smb_node_t *snode, 1382 uio_t *uio, 1383 uint32_t *lcount, 1384 smb_attr_t *ret_attr, 1385 uint32_t *flag) 1386 { 1387 smb_node_t *unnamed_node; 1388 vnode_t *unnamed_vp = NULL; 1389 caller_context_t ct; 1390 int rc; 1391 1392 ASSERT(cr); 1393 ASSERT(snode); 1394 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1395 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1396 1397 ASSERT(sr); 1398 ASSERT(sr->tid_tree); 1399 ASSERT(sr->fid_ofile); 1400 1401 if (SMB_TREE_IS_READ_ONLY(sr)) 1402 return (EROFS); 1403 /* 1404 * XXX what if the file has been opened only with 1405 * FILE_APPEND_DATA? 1406 */ 1407 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 1408 if (rc != NT_STATUS_SUCCESS) 1409 return (EACCES); 1410 1411 smb_get_caller_context(sr, &ct); 1412 1413 unnamed_node = SMB_IS_STREAM(snode); 1414 1415 if (unnamed_node) { 1416 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1417 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1418 unnamed_vp = unnamed_node->vp; 1419 /* 1420 * Streams permission are checked against the unnamed stream, 1421 * but in FS level they have their own permissions. To avoid 1422 * rejection by FS due to lack of permission on the actual 1423 * extended attr kcred is passed for streams. 1424 */ 1425 cr = kcred; 1426 } 1427 1428 rc = smb_vop_write(snode->vp, uio, flag, lcount, cr, &ct); 1429 1430 if (rc == 0) { 1431 /* 1432 * This is an operation on behalf of CIFS service (to update 1433 * smb node's attr) not on behalf of the user so it's done 1434 * using kcred and the return value is intentionally ignored. 1435 */ 1436 ret_attr->sa_mask = SMB_AT_ALL; 1437 (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1438 kcred, &ct); 1439 } 1440 1441 return (rc); 1442 } 1443 1444 /* 1445 * smb_fsop_statfs 1446 * 1447 * This is a wrapper function used for stat operations. 1448 */ 1449 int 1450 smb_fsop_statfs( 1451 cred_t *cr, 1452 smb_node_t *snode, 1453 struct statvfs64 *statp) 1454 { 1455 ASSERT(cr); 1456 ASSERT(snode); 1457 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1458 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1459 1460 return (smb_vop_statfs(snode->vp, statp, cr)); 1461 } 1462 1463 /* 1464 * smb_fsop_access 1465 */ 1466 int 1467 smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1468 uint32_t faccess) 1469 { 1470 int access = 0; 1471 int error; 1472 vnode_t *dir_vp; 1473 boolean_t acl_check = B_TRUE; 1474 smb_node_t *unnamed_node; 1475 1476 ASSERT(cr); 1477 ASSERT(snode); 1478 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1479 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1480 1481 if (faccess == 0) 1482 return (NT_STATUS_SUCCESS); 1483 1484 if (SMB_TREE_IS_READ_ONLY(sr)) { 1485 if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 1486 FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 1487 DELETE|WRITE_DAC|WRITE_OWNER)) { 1488 return (NT_STATUS_ACCESS_DENIED); 1489 } 1490 } 1491 1492 unnamed_node = SMB_IS_STREAM(snode); 1493 if (unnamed_node) { 1494 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1495 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1496 /* 1497 * Streams authorization should be performed against the 1498 * unnamed stream. 1499 */ 1500 snode = unnamed_node; 1501 } 1502 1503 if (faccess & ACCESS_SYSTEM_SECURITY) { 1504 /* 1505 * This permission is required for reading/writing SACL and 1506 * it's not part of DACL. It's only granted via proper 1507 * privileges. 1508 */ 1509 if ((sr->uid_user->u_privileges & 1510 (SMB_USER_PRIV_BACKUP | 1511 SMB_USER_PRIV_RESTORE | 1512 SMB_USER_PRIV_SECURITY)) == 0) 1513 return (NT_STATUS_PRIVILEGE_NOT_HELD); 1514 1515 faccess &= ~ACCESS_SYSTEM_SECURITY; 1516 } 1517 1518 /* Links don't have ACL */ 1519 if (((sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) == 0) || 1520 (snode->attr.sa_vattr.va_type == VLNK)) 1521 acl_check = B_FALSE; 1522 1523 if (acl_check) { 1524 dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 1525 error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 1526 cr); 1527 } else { 1528 /* 1529 * FS doesn't understand 32-bit mask, need to map 1530 */ 1531 if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 1532 access |= VWRITE; 1533 1534 if (faccess & FILE_READ_DATA) 1535 access |= VREAD; 1536 1537 if (faccess & FILE_EXECUTE) 1538 access |= VEXEC; 1539 1540 error = smb_vop_access(snode->vp, access, 0, NULL, cr); 1541 } 1542 1543 return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 1544 } 1545 1546 /* 1547 * smb_fsop_lookup_name() 1548 * 1549 * Sanity checks on dir_snode done in smb_fsop_lookup(). 1550 * 1551 * Note: This function is called only from the open path. 1552 * It will check if the file is a stream. 1553 * It will also return an error if the looked-up file is in 1554 * a child mount. 1555 */ 1556 1557 int 1558 smb_fsop_lookup_name( 1559 struct smb_request *sr, 1560 cred_t *cr, 1561 int flags, 1562 smb_node_t *root_node, 1563 smb_node_t *dir_snode, 1564 char *name, 1565 smb_node_t **ret_snode, 1566 smb_attr_t *ret_attr) 1567 { 1568 smb_node_t *fnode; 1569 smb_attr_t file_attr; 1570 caller_context_t ct; 1571 vnode_t *xattrdirvp; 1572 vnode_t *vp; 1573 char *od_name; 1574 char *fname; 1575 char *sname; 1576 int rc; 1577 1578 ASSERT(cr); 1579 ASSERT(dir_snode); 1580 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1581 ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1582 1583 /* 1584 * The following check is required for streams processing, below 1585 */ 1586 1587 if (SMB_TREE_CASE_INSENSITIVE(sr)) 1588 flags |= SMB_IGNORE_CASE; 1589 1590 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1591 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1592 1593 if (smb_stream_parse_name(name, fname, sname)) { 1594 /* 1595 * Look up the unnamed stream (i.e. fname). 1596 * Unmangle processing will be done on fname 1597 * as well as any link target. 1598 */ 1599 rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 1600 &fnode, &file_attr, NULL, NULL); 1601 1602 if (rc != 0) { 1603 kmem_free(fname, MAXNAMELEN); 1604 kmem_free(sname, MAXNAMELEN); 1605 return (rc); 1606 } 1607 1608 od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1609 1610 /* 1611 * od_name is the on-disk name of the stream, except 1612 * without the prepended stream prefix (SMB_STREAM_PREFIX) 1613 */ 1614 1615 /* 1616 * XXX 1617 * What permissions NTFS requires for stream lookup if any? 1618 */ 1619 rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 1620 &xattrdirvp, flags, root_node->vp, cr, &ct); 1621 1622 if (rc != 0) { 1623 smb_node_release(fnode); 1624 kmem_free(fname, MAXNAMELEN); 1625 kmem_free(sname, MAXNAMELEN); 1626 kmem_free(od_name, MAXNAMELEN); 1627 return (rc); 1628 } 1629 1630 *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1631 vp, od_name, ret_attr); 1632 1633 kmem_free(od_name, MAXNAMELEN); 1634 smb_node_release(fnode); 1635 1636 if (*ret_snode == NULL) { 1637 VN_RELE(xattrdirvp); 1638 VN_RELE(vp); 1639 kmem_free(fname, MAXNAMELEN); 1640 kmem_free(sname, MAXNAMELEN); 1641 return (ENOMEM); 1642 } 1643 } else { 1644 rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 1645 ret_snode, ret_attr, NULL, NULL); 1646 } 1647 1648 if (rc == 0) { 1649 ASSERT(ret_snode); 1650 if (SMB_TREE_ROOT_FS(sr, *ret_snode) == 0) { 1651 smb_node_release(*ret_snode); 1652 *ret_snode = NULL; 1653 rc = EACCES; 1654 } 1655 } 1656 1657 kmem_free(fname, MAXNAMELEN); 1658 kmem_free(sname, MAXNAMELEN); 1659 1660 return (rc); 1661 } 1662 1663 /* 1664 * smb_fsop_lookup 1665 * 1666 * All SMB functions should use this smb_vop_lookup wrapper to ensure that 1667 * the smb_vop_lookup is performed with the appropriate credentials and using 1668 * case insensitive compares. Please document any direct call to smb_vop_lookup 1669 * to explain the reason for avoiding this wrapper. 1670 * 1671 * It is assumed that a reference exists on dir_snode coming into this routine 1672 * (and that it is safe from deallocation). 1673 * 1674 * Same with the root_node. 1675 * 1676 * *ret_snode is returned with a reference upon success. No reference is 1677 * taken if an error is returned. 1678 * 1679 * Note: The returned ret_snode may be in a child mount. This is ok for 1680 * readdir and getdents. 1681 * 1682 * Other smb_fsop_* routines will call SMB_TREE_ROOT_FS() to prevent 1683 * operations on files not in the parent mount. 1684 */ 1685 int 1686 smb_fsop_lookup( 1687 struct smb_request *sr, 1688 cred_t *cr, 1689 int flags, 1690 smb_node_t *root_node, 1691 smb_node_t *dir_snode, 1692 char *name, 1693 smb_node_t **ret_snode, 1694 smb_attr_t *ret_attr, 1695 char *ret_shortname, /* Must be at least MANGLE_NAMELEN chars */ 1696 char *ret_name83) /* Must be at least MANGLE_NAMELEN chars */ 1697 { 1698 smb_node_t *lnk_target_node; 1699 smb_node_t *lnk_dnode; 1700 caller_context_t ct; 1701 char *longname; 1702 char *od_name; 1703 vnode_t *vp; 1704 int rc; 1705 1706 ASSERT(cr); 1707 ASSERT(dir_snode); 1708 ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1709 ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1710 1711 if (name == NULL) 1712 return (EINVAL); 1713 1714 if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 1715 return (EACCES); 1716 1717 if (SMB_TREE_CASE_INSENSITIVE(sr)) 1718 flags |= SMB_IGNORE_CASE; 1719 1720 smb_get_caller_context(sr, &ct); 1721 1722 od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1723 1724 rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 1725 root_node ? root_node->vp : NULL, cr, &ct); 1726 1727 if (rc != 0) { 1728 if (smb_maybe_mangled_name(name) == 0) { 1729 kmem_free(od_name, MAXNAMELEN); 1730 return (rc); 1731 } 1732 1733 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1734 1735 rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 1736 MAXNAMELEN, ret_shortname, ret_name83, 1); 1737 1738 if (rc != 0) { 1739 kmem_free(od_name, MAXNAMELEN); 1740 kmem_free(longname, MAXNAMELEN); 1741 return (rc); 1742 } 1743 1744 /* 1745 * We passed "1" as the "od" parameter 1746 * to smb_unmangle_name(), such that longname 1747 * is the real (case-sensitive) on-disk name. 1748 * We make sure we do a lookup on this exact 1749 * name, as the name was mangled and denotes 1750 * a unique file. 1751 */ 1752 1753 if (flags & SMB_IGNORE_CASE) 1754 flags &= ~SMB_IGNORE_CASE; 1755 1756 rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 1757 flags, root_node ? root_node->vp : NULL, cr, &ct); 1758 1759 kmem_free(longname, MAXNAMELEN); 1760 1761 if (rc != 0) { 1762 kmem_free(od_name, MAXNAMELEN); 1763 return (rc); 1764 } 1765 } 1766 1767 if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 1768 1769 rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 1770 &lnk_dnode, &lnk_target_node, cr); 1771 1772 if (rc != 0) { 1773 /* 1774 * The link is assumed to be for the last component 1775 * of a path. Hence any ENOTDIR error will be returned 1776 * as ENOENT. 1777 */ 1778 if (rc == ENOTDIR) 1779 rc = ENOENT; 1780 1781 VN_RELE(vp); 1782 kmem_free(od_name, MAXNAMELEN); 1783 return (rc); 1784 } 1785 1786 /* 1787 * Release the original VLNK vnode 1788 */ 1789 1790 VN_RELE(vp); 1791 vp = lnk_target_node->vp; 1792 1793 rc = smb_vop_traverse_check(&vp); 1794 1795 if (rc != 0) { 1796 smb_node_release(lnk_dnode); 1797 smb_node_release(lnk_target_node); 1798 kmem_free(od_name, MAXNAMELEN); 1799 return (rc); 1800 } 1801 1802 /* 1803 * smb_vop_traverse_check() may have returned a different vnode 1804 */ 1805 1806 if (lnk_target_node->vp == vp) { 1807 *ret_snode = lnk_target_node; 1808 *ret_attr = (*ret_snode)->attr; 1809 } else { 1810 *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 1811 lnk_target_node->od_name, lnk_dnode, NULL, 1812 ret_attr); 1813 1814 if (*ret_snode == NULL) { 1815 VN_RELE(vp); 1816 rc = ENOMEM; 1817 } 1818 smb_node_release(lnk_target_node); 1819 } 1820 1821 smb_node_release(lnk_dnode); 1822 1823 } else { 1824 1825 rc = smb_vop_traverse_check(&vp); 1826 if (rc) { 1827 VN_RELE(vp); 1828 kmem_free(od_name, MAXNAMELEN); 1829 return (rc); 1830 } 1831 1832 *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 1833 dir_snode, NULL, ret_attr); 1834 1835 if (*ret_snode == NULL) { 1836 VN_RELE(vp); 1837 rc = ENOMEM; 1838 } 1839 } 1840 1841 kmem_free(od_name, MAXNAMELEN); 1842 return (rc); 1843 } 1844 1845 /* 1846 * smb_fsop_stream_readdir() 1847 * 1848 * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in) 1849 * 1850 * This routine will return only NTFS streams. If an NTFS stream is not 1851 * found at the offset specified, the directory will be read until an NTFS 1852 * stream is found or until EOF. 1853 * 1854 * Note: Sanity checks done in caller 1855 * (smb_fsop_readdir(), smb_fsop_remove_streams()) 1856 */ 1857 1858 int 1859 smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, 1860 uint32_t *cookiep, struct fs_stream_info *stream_info, 1861 smb_node_t **ret_snode, smb_attr_t *ret_attr) 1862 { 1863 smb_node_t *ret_snodep = NULL; 1864 caller_context_t ct; 1865 smb_attr_t tmp_attr; 1866 vnode_t *xattrdirvp; 1867 vnode_t *vp; 1868 int rc = 0; 1869 int flags = 0; 1870 1871 /* 1872 * XXX NTFS permission requirements if any? 1873 */ 1874 ASSERT(cr); 1875 ASSERT(fnode); 1876 ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 1877 ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 1878 1879 if (SMB_TREE_CASE_INSENSITIVE(sr)) 1880 flags = SMB_IGNORE_CASE; 1881 1882 smb_get_caller_context(sr, &ct); 1883 1884 rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp, 1885 &xattrdirvp, flags, cr, &ct); 1886 1887 if ((rc != 0) || *cookiep == SMB_EOF) 1888 return (rc); 1889 1890 ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, 1891 stream_info->name, &tmp_attr); 1892 1893 if (ret_snodep == NULL) { 1894 VN_RELE(xattrdirvp); 1895 VN_RELE(vp); 1896 return (ENOMEM); 1897 } 1898 1899 stream_info->size = tmp_attr.sa_vattr.va_size; 1900 1901 if (ret_attr) 1902 *ret_attr = tmp_attr; 1903 1904 if (ret_snode) 1905 *ret_snode = ret_snodep; 1906 else 1907 smb_node_release(ret_snodep); 1908 1909 return (rc); 1910 } 1911 1912 int /*ARGSUSED*/ 1913 smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 1914 { 1915 caller_context_t ct; 1916 1917 ASSERT(cr); 1918 ASSERT(snode); 1919 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1920 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1921 1922 ASSERT(sr); 1923 ASSERT(sr->tid_tree); 1924 if (SMB_TREE_IS_READ_ONLY(sr)) 1925 return (EROFS); 1926 1927 smb_get_caller_context(sr, &ct); 1928 1929 return (smb_vop_commit(snode->vp, cr, &ct)); 1930 } 1931 1932 /* 1933 * smb_fsop_sdinit 1934 * 1935 * Initializes the given FS SD structure. 1936 */ 1937 void 1938 smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags) 1939 { 1940 bzero(fs_sd, sizeof (smb_fssd_t)); 1941 fs_sd->sd_secinfo = secinfo; 1942 fs_sd->sd_flags = flags; 1943 } 1944 1945 /* 1946 * smb_fsop_sdterm 1947 * 1948 * Frees allocated memory for acl fields. 1949 */ 1950 void 1951 smb_fsop_sdterm(smb_fssd_t *fs_sd) 1952 { 1953 ASSERT(fs_sd); 1954 1955 smb_fsop_aclfree(fs_sd->sd_zdacl); 1956 smb_fsop_aclfree(fs_sd->sd_zsacl); 1957 bzero(fs_sd, sizeof (smb_fssd_t)); 1958 } 1959 1960 /* 1961 * smb_fsop_aclread 1962 * 1963 * Retrieve filesystem ACL. Depends on requested ACLs in 1964 * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 1965 * fs_sd. Note that requesting a DACL/SACL doesn't mean that 1966 * the corresponding field in fs_sd should be non-NULL upon 1967 * return, since the target ACL might not contain that type of 1968 * entries. 1969 * 1970 * Returned ACL is always in ACE_T (aka ZFS) format. 1971 * If successful the allocated memory for the ACL should be freed 1972 * using smb_fsop_aclfree() or smb_fsop_sdterm() 1973 */ 1974 int 1975 smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1976 smb_fssd_t *fs_sd) 1977 { 1978 int error = 0; 1979 int flags = 0; 1980 int access = 0; 1981 acl_t *acl; 1982 caller_context_t ct; 1983 smb_node_t *unnamed_node; 1984 1985 ASSERT(cr); 1986 1987 if (sr->fid_ofile) { 1988 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 1989 access = READ_CONTROL; 1990 1991 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 1992 access |= ACCESS_SYSTEM_SECURITY; 1993 1994 error = smb_ofile_access(sr->fid_ofile, cr, access); 1995 if (error != NT_STATUS_SUCCESS) { 1996 return (EACCES); 1997 } 1998 } 1999 2000 unnamed_node = SMB_IS_STREAM(snode); 2001 if (unnamed_node) { 2002 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2003 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2004 /* 2005 * Streams don't have ACL, any read ACL attempt on a stream 2006 * should be performed on the unnamed stream. 2007 */ 2008 snode = unnamed_node; 2009 } 2010 2011 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 2012 flags = ATTR_NOACLCHECK; 2013 2014 smb_get_caller_context(sr, &ct); 2015 error = smb_vop_acl_read(snode->vp, &acl, flags, 2016 sr->tid_tree->t_acltype, cr, &ct); 2017 if (error != 0) { 2018 return (error); 2019 } 2020 2021 error = acl_translate(acl, _ACL_ACE_ENABLED, 2022 (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 2023 2024 if (error == 0) { 2025 smb_fsop_aclsplit(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 2026 fs_sd->sd_secinfo); 2027 } 2028 2029 acl_free(acl); 2030 return (error); 2031 } 2032 2033 /* 2034 * smb_fsop_aclwrite 2035 * 2036 * Stores the filesystem ACL provided in fs_sd->sd_acl. 2037 */ 2038 int 2039 smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2040 smb_fssd_t *fs_sd) 2041 { 2042 int target_flavor; 2043 int error = 0; 2044 int flags = 0; 2045 int access = 0; 2046 caller_context_t ct; 2047 acl_t *acl, *dacl, *sacl; 2048 smb_node_t *unnamed_node; 2049 2050 ASSERT(cr); 2051 2052 ASSERT(sr); 2053 ASSERT(sr->tid_tree); 2054 if (SMB_TREE_IS_READ_ONLY(sr)) 2055 return (EROFS); 2056 2057 if (sr->fid_ofile) { 2058 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2059 access = WRITE_DAC; 2060 2061 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2062 access |= ACCESS_SYSTEM_SECURITY; 2063 2064 error = smb_ofile_access(sr->fid_ofile, cr, access); 2065 if (error != NT_STATUS_SUCCESS) 2066 return (EACCES); 2067 } 2068 2069 switch (sr->tid_tree->t_acltype) { 2070 case ACLENT_T: 2071 target_flavor = _ACL_ACLENT_ENABLED; 2072 break; 2073 2074 case ACE_T: 2075 target_flavor = _ACL_ACE_ENABLED; 2076 break; 2077 default: 2078 return (EINVAL); 2079 } 2080 2081 unnamed_node = SMB_IS_STREAM(snode); 2082 if (unnamed_node) { 2083 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2084 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2085 /* 2086 * Streams don't have ACL, any write ACL attempt on a stream 2087 * should be performed on the unnamed stream. 2088 */ 2089 snode = unnamed_node; 2090 } 2091 2092 dacl = fs_sd->sd_zdacl; 2093 sacl = fs_sd->sd_zsacl; 2094 2095 ASSERT(dacl || sacl); 2096 if ((dacl == NULL) && (sacl == NULL)) 2097 return (EINVAL); 2098 2099 if (dacl && sacl) 2100 acl = smb_fsop_aclmerge(dacl, sacl); 2101 else if (dacl) 2102 acl = dacl; 2103 else 2104 acl = sacl; 2105 2106 error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 2107 fs_sd->sd_uid, fs_sd->sd_gid); 2108 if (error == 0) { 2109 smb_get_caller_context(sr, &ct); 2110 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 2111 flags = ATTR_NOACLCHECK; 2112 2113 error = smb_vop_acl_write(snode->vp, acl, flags, cr, &ct); 2114 } 2115 2116 if (dacl && sacl) 2117 acl_free(acl); 2118 2119 return (error); 2120 } 2121 2122 acl_t * 2123 smb_fsop_aclalloc(int acenum, int flags) 2124 { 2125 acl_t *acl; 2126 2127 acl = acl_alloc(ACE_T); 2128 acl->acl_cnt = acenum; 2129 acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP); 2130 acl->acl_flags = flags; 2131 return (acl); 2132 } 2133 2134 void 2135 smb_fsop_aclfree(acl_t *acl) 2136 { 2137 if (acl) 2138 acl_free(acl); 2139 } 2140 2141 /* 2142 * smb_fsop_aclmerge 2143 * 2144 * smb_fsop_aclread/write routines which interact with filesystem 2145 * work with single ACL. This routine merges given DACL and SACL 2146 * which might have been created during CIFS to FS conversion into 2147 * one single ACL. 2148 */ 2149 static acl_t * 2150 smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl) 2151 { 2152 acl_t *acl; 2153 int dacl_size; 2154 2155 ASSERT(dacl); 2156 ASSERT(sacl); 2157 2158 acl = smb_fsop_aclalloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags); 2159 dacl_size = dacl->acl_cnt * dacl->acl_entry_size; 2160 bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size); 2161 bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size, 2162 sacl->acl_cnt * sacl->acl_entry_size); 2163 2164 return (acl); 2165 } 2166 2167 /* 2168 * smb_fsop_aclsplit 2169 * 2170 * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on 2171 * the 'which_acl' parameter. Note that output dacl/sacl parameters could be 2172 * NULL even if they're specified in 'which_acl', which means the target 2173 * doesn't have any access and/or audit ACEs. 2174 */ 2175 static void 2176 smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl) 2177 { 2178 ace_t *zace; 2179 ace_t *access_ace; 2180 ace_t *audit_ace; 2181 int naccess, naudit; 2182 int get_dacl, get_sacl; 2183 int i; 2184 2185 *dacl = *sacl = NULL; 2186 naccess = naudit = 0; 2187 get_dacl = (which_acl & SMB_DACL_SECINFO); 2188 get_sacl = (which_acl & SMB_SACL_SECINFO); 2189 2190 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 2191 if (get_dacl && smb_ace_is_access(zace->a_type)) 2192 naccess++; 2193 else if (get_sacl && smb_ace_is_audit(zace->a_type)) 2194 naudit++; 2195 } 2196 2197 if (naccess) { 2198 *dacl = smb_fsop_aclalloc(naccess, zacl->acl_flags); 2199 access_ace = (*dacl)->acl_aclp; 2200 } 2201 2202 if (naudit) { 2203 *sacl = smb_fsop_aclalloc(naudit, zacl->acl_flags); 2204 audit_ace = (*sacl)->acl_aclp; 2205 } 2206 2207 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 2208 if (get_dacl && smb_ace_is_access(zace->a_type)) { 2209 *access_ace = *zace; 2210 access_ace++; 2211 } else if (get_sacl && smb_ace_is_audit(zace->a_type)) { 2212 *audit_ace = *zace; 2213 audit_ace++; 2214 } 2215 } 2216 } 2217 2218 acl_type_t 2219 smb_fsop_acltype(smb_node_t *snode) 2220 { 2221 return (smb_vop_acl_type(snode->vp)); 2222 } 2223 2224 /* 2225 * smb_fsop_sdread 2226 * 2227 * Read the requested security descriptor items from filesystem. 2228 * The items are specified in fs_sd->sd_secinfo. 2229 */ 2230 int 2231 smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2232 smb_fssd_t *fs_sd) 2233 { 2234 int error = 0; 2235 int getowner = 0; 2236 cred_t *ga_cred; 2237 smb_attr_t attr; 2238 2239 ASSERT(cr); 2240 ASSERT(fs_sd); 2241 2242 /* 2243 * File's uid/gid is fetched in two cases: 2244 * 2245 * 1. it's explicitly requested 2246 * 2247 * 2. target ACL is ACE_T (ZFS ACL). They're needed for 2248 * owner@/group@ entries. In this case kcred should be used 2249 * because uid/gid are fetched on behalf of smb server. 2250 */ 2251 if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 2252 getowner = 1; 2253 ga_cred = cr; 2254 } else if (sr->tid_tree->t_acltype == ACE_T) { 2255 getowner = 1; 2256 ga_cred = kcred; 2257 } 2258 2259 if (getowner) { 2260 /* 2261 * Windows require READ_CONTROL to read owner/group SID since 2262 * they're part of Security Descriptor. 2263 * ZFS only requires read_attribute. Need to have a explicit 2264 * access check here. 2265 */ 2266 if (sr->fid_ofile == NULL) { 2267 error = smb_fsop_access(sr, ga_cred, snode, 2268 READ_CONTROL); 2269 if (error) 2270 return (error); 2271 } 2272 2273 attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2274 error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 2275 if (error == 0) { 2276 fs_sd->sd_uid = attr.sa_vattr.va_uid; 2277 fs_sd->sd_gid = attr.sa_vattr.va_gid; 2278 } else { 2279 return (error); 2280 } 2281 } 2282 2283 if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2284 error = smb_fsop_aclread(sr, cr, snode, fs_sd); 2285 } 2286 2287 return (error); 2288 } 2289 2290 /* 2291 * smb_fsop_sdmerge 2292 * 2293 * From SMB point of view DACL and SACL are two separate list 2294 * which can be manipulated independently without one affecting 2295 * the other, but entries for both DACL and SACL will end up 2296 * in the same ACL if target filesystem supports ACE_T ACLs. 2297 * 2298 * So, if either DACL or SACL is present in the client set request 2299 * the entries corresponding to the non-present ACL shouldn't 2300 * be touched in the FS ACL. 2301 * 2302 * fs_sd parameter contains DACL and SACL specified by SMB 2303 * client to be set on a file/directory. The client could 2304 * specify both or one of these ACLs (if none is specified 2305 * we don't get this far). When both DACL and SACL are given 2306 * by client the existing ACL should be overwritten. If only 2307 * one of them is specified the entries corresponding to the other 2308 * ACL should not be touched. For example, if only DACL 2309 * is specified in input fs_sd, the function reads audit entries 2310 * of the existing ACL of the file and point fs_sd->sd_zsdacl 2311 * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 2312 * function is called the passed fs_sd would point to the specified 2313 * DACL by client and fetched SACL from filesystem, so the file 2314 * will end up with correct ACL. 2315 */ 2316 static int 2317 smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 2318 { 2319 smb_fssd_t cur_sd; 2320 int error = 0; 2321 2322 if (sr->tid_tree->t_acltype != ACE_T) 2323 /* Don't bother if target FS doesn't support ACE_T */ 2324 return (0); 2325 2326 if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 2327 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 2328 /* 2329 * Don't overwrite existing audit entries 2330 */ 2331 smb_fsop_sdinit(&cur_sd, SMB_SACL_SECINFO, 2332 fs_sd->sd_flags); 2333 2334 error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2335 if (error == 0) { 2336 ASSERT(fs_sd->sd_zsacl == NULL); 2337 fs_sd->sd_zsacl = cur_sd.sd_zsacl; 2338 if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 2339 fs_sd->sd_zsacl->acl_flags = 2340 fs_sd->sd_zdacl->acl_flags; 2341 } 2342 } else { 2343 /* 2344 * Don't overwrite existing access entries 2345 */ 2346 smb_fsop_sdinit(&cur_sd, SMB_DACL_SECINFO, 2347 fs_sd->sd_flags); 2348 2349 error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2350 if (error == 0) { 2351 ASSERT(fs_sd->sd_zdacl == NULL); 2352 fs_sd->sd_zdacl = cur_sd.sd_zdacl; 2353 if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 2354 fs_sd->sd_zdacl->acl_flags = 2355 fs_sd->sd_zsacl->acl_flags; 2356 } 2357 } 2358 2359 if (error) 2360 smb_fsop_sdterm(&cur_sd); 2361 } 2362 2363 return (error); 2364 } 2365 2366 /* 2367 * smb_fsop_sdwrite 2368 * 2369 * Stores the given uid, gid and acl in filesystem. 2370 * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 2371 * 2372 * A SMB security descriptor could contain owner, primary group, 2373 * DACL and SACL. Setting an SD should be atomic but here it has to 2374 * be done via two separate FS operations: VOP_SETATTR and 2375 * VOP_SETSECATTR. Therefore, this function has to simulate the 2376 * atomicity as well as it can. 2377 */ 2378 int 2379 smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2380 smb_fssd_t *fs_sd, int overwrite) 2381 { 2382 int error = 0; 2383 int access = 0; 2384 smb_attr_t set_attr; 2385 smb_attr_t orig_attr; 2386 2387 ASSERT(cr); 2388 ASSERT(fs_sd); 2389 2390 ASSERT(sr); 2391 ASSERT(sr->tid_tree); 2392 if (SMB_TREE_IS_READ_ONLY(sr)) 2393 return (EROFS); 2394 2395 bzero(&set_attr, sizeof (smb_attr_t)); 2396 2397 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2398 set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2399 set_attr.sa_mask |= SMB_AT_UID; 2400 } 2401 2402 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2403 set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2404 set_attr.sa_mask |= SMB_AT_GID; 2405 } 2406 2407 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2408 access |= WRITE_DAC; 2409 2410 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2411 access |= ACCESS_SYSTEM_SECURITY; 2412 2413 if (sr->fid_ofile) 2414 error = smb_ofile_access(sr->fid_ofile, cr, access); 2415 else 2416 error = smb_fsop_access(sr, cr, snode, access); 2417 2418 if (error) 2419 return (EACCES); 2420 2421 if (set_attr.sa_mask) { 2422 /* 2423 * Get the current uid, gid so if smb_fsop_aclwrite fails 2424 * we can revert uid, gid changes. 2425 * 2426 * We use root cred here so the operation doesn't fail 2427 * due to lack of permission for the user to read the attrs 2428 */ 2429 2430 orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2431 error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 2432 if (error == 0) 2433 error = smb_fsop_setattr(sr, cr, snode, &set_attr, 2434 NULL); 2435 2436 if (error) 2437 return (error); 2438 } 2439 2440 if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2441 if (overwrite == 0) { 2442 error = smb_fsop_sdmerge(sr, snode, fs_sd); 2443 if (error) 2444 return (error); 2445 } 2446 2447 error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 2448 if (error) { 2449 /* 2450 * Revert uid/gid changes if required. 2451 */ 2452 if (set_attr.sa_mask) { 2453 orig_attr.sa_mask = set_attr.sa_mask; 2454 (void) smb_fsop_setattr(sr, kcred, snode, 2455 &orig_attr, NULL); 2456 } 2457 } 2458 } 2459 2460 return (error); 2461 } 2462 2463 /*ARGSUSED*/ 2464 void 2465 smb_get_caller_context(smb_request_t *sr, caller_context_t *ct) 2466 { 2467 ct->cc_caller_id = smb_caller_id; 2468 ct->cc_pid = 0; /* TBD */ 2469 ct->cc_sysid = 0; /* TBD */ 2470 } 2471 2472 /* 2473 * smb_fsop_sdinherit 2474 * 2475 * Inherit the security descriptor from the parent container. 2476 * This function is called after FS has created the file/folder 2477 * so if this doesn't do anything it means FS inheritance is 2478 * in place. 2479 * 2480 * Do inheritance for ZFS internally. 2481 * 2482 * If we want to let ZFS does the inheritance the 2483 * following setting should be true: 2484 * 2485 * - aclinherit = passthrough 2486 * - aclmode = passthrough 2487 * - smbd umask = 0777 2488 * 2489 * This will result in right effective permissions but 2490 * ZFS will always add 6 ACEs for owner, owning group 2491 * and others to be POSIX compliant. This is not what 2492 * Windows clients/users expect, so we decided that CIFS 2493 * implements Windows rules and overwrite whatever ZFS 2494 * comes up with. This way we also don't have to care 2495 * about ZFS aclinherit and aclmode settings. 2496 */ 2497 static int 2498 smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 2499 { 2500 int is_dir; 2501 acl_t *dacl; 2502 acl_t *sacl; 2503 ksid_t *owner_sid; 2504 int error; 2505 2506 ASSERT(fs_sd); 2507 2508 if (sr->tid_tree->t_acltype != ACE_T) { 2509 /* 2510 * No forced inheritance for non-ZFS filesystems. 2511 */ 2512 fs_sd->sd_secinfo = 0; 2513 return (0); 2514 } 2515 2516 2517 /* Fetch parent directory's ACL */ 2518 error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 2519 if (error) { 2520 return (error); 2521 } 2522 2523 is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 2524 owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 2525 ASSERT(owner_sid); 2526 dacl = smb_acl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 2527 owner_sid->ks_id); 2528 sacl = smb_acl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 2529 (uid_t)-1); 2530 2531 smb_fsop_aclfree(fs_sd->sd_zdacl); 2532 smb_fsop_aclfree(fs_sd->sd_zsacl); 2533 2534 fs_sd->sd_zdacl = dacl; 2535 fs_sd->sd_zsacl = sacl; 2536 2537 return (0); 2538 } 2539 2540 /* 2541 * smb_fsop_eaccess 2542 * 2543 * Returns the effective permission of the given credential for the 2544 * specified object. 2545 * 2546 * This is just a workaround. We need VFS/FS support for this. 2547 */ 2548 void 2549 smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2550 uint32_t *eaccess) 2551 { 2552 int access = 0; 2553 vnode_t *dir_vp; 2554 smb_node_t *unnamed_node; 2555 2556 ASSERT(cr); 2557 ASSERT(snode); 2558 ASSERT(snode->n_magic == SMB_NODE_MAGIC); 2559 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 2560 2561 unnamed_node = SMB_IS_STREAM(snode); 2562 if (unnamed_node) { 2563 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2564 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2565 /* 2566 * Streams authorization should be performed against the 2567 * unnamed stream. 2568 */ 2569 snode = unnamed_node; 2570 } 2571 2572 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) { 2573 dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 2574 smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 2575 cr); 2576 return; 2577 } 2578 2579 /* 2580 * FS doesn't understand 32-bit mask 2581 */ 2582 smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 2583 2584 *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 2585 2586 if (access & VREAD) 2587 *eaccess |= FILE_READ_DATA; 2588 2589 if (access & VEXEC) 2590 *eaccess |= FILE_EXECUTE; 2591 2592 if (access & VWRITE) 2593 *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 2594 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 2595 } 2596