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