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