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