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