1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  */
  38 
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/vnode.h>
  42 #include <sys/vfs.h>
  43 #include <sys/filio.h>
  44 #include <sys/uio.h>
  45 #include <sys/dirent.h>
  46 #include <sys/errno.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/kmem.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/vfs_opreg.h>
  52 #include <sys/policy.h>
  53 
  54 #include <netsmb/smb_osdep.h>
  55 #include <netsmb/smb.h>
  56 #include <netsmb/smb_conn.h>
  57 #include <netsmb/smb_subr.h>
  58 
  59 #include <smbfs/smbfs.h>
  60 #include <smbfs/smbfs_node.h>
  61 #include <smbfs/smbfs_subr.h>
  62 
  63 #include <sys/fs/smbfs_ioctl.h>
  64 #include <fs/fs_subr.h>
  65 
  66 /*
  67  * We assign directory offsets like the NFS client, where the
  68  * offset increments by _one_ after each directory entry.
  69  * Further, the entries "." and ".." are always at offsets
  70  * zero and one (respectively) and the "real" entries from
  71  * the server appear at offsets starting with two.  This
  72  * macro is used to initialize the n_dirofs field after
  73  * setting n_dirseq with a _findopen call.
  74  */
  75 #define FIRST_DIROFS    2
  76 
  77 /*
  78  * These characters are illegal in NTFS file names.
  79  * ref: http://support.microsoft.com/kb/147438
  80  *
  81  * Careful!  The check in the XATTR case skips the
  82  * first character to allow colon in XATTR names.
  83  */
  84 static const char illegal_chars[] = {
  85         ':',    /* colon - keep this first! */
  86         '\\',   /* back slash */
  87         '/',    /* slash */
  88         '*',    /* asterisk */
  89         '?',    /* question mark */
  90         '"',    /* double quote */
  91         '<', /* less than sign */
  92         '>', /* greater than sign */
  93         '|',    /* vertical bar */
  94         0
  95 };
  96 
  97 /*
  98  * Turning this on causes nodes to be created in the cache
  99  * during directory listings, normally avoiding a second
 100  * OtW attribute fetch just after a readdir.
 101  */
 102 int smbfs_fastlookup = 1;
 103 
 104 /* local static function defines */
 105 
 106 static int      smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
 107                         cred_t *);
 108 static int      smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
 109                         int cache_ok, caller_context_t *);
 110 static int      smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
 111                         cred_t *cr, caller_context_t *);
 112 static int      smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
 113 static int      smbfs_accessx(void *, int, cred_t *);
 114 static int      smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
 115                         caller_context_t *);
 116 static void     smbfs_rele_fid(smbnode_t *, struct smb_cred *);
 117 static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
 118 
 119 /*
 120  * These are the vnode ops routines which implement the vnode interface to
 121  * the networked file system.  These routines just take their parameters,
 122  * make them look networkish by putting the right info into interface structs,
 123  * and then calling the appropriate remote routine(s) to do the work.
 124  *
 125  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
 126  * we purge the directory cache relative to that vnode.  This way, the
 127  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
 128  * more details on smbnode locking.
 129  */
 130 
 131 static int      smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
 132 static int      smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
 133                         caller_context_t *);
 134 static int      smbfs_read(vnode_t *, struct uio *, int, cred_t *,
 135                         caller_context_t *);
 136 static int      smbfs_write(vnode_t *, struct uio *, int, cred_t *,
 137                         caller_context_t *);
 138 static int      smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
 139                         caller_context_t *);
 140 static int      smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
 141                         caller_context_t *);
 142 static int      smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
 143                         caller_context_t *);
 144 static int      smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
 145 static int      smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
 146 static void     smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
 147 static int      smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
 148                         int, vnode_t *, cred_t *, caller_context_t *,
 149                         int *, pathname_t *);
 150 static int      smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
 151                         int, vnode_t **, cred_t *, int, caller_context_t *,
 152                         vsecattr_t *);
 153 static int      smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
 154                         int);
 155 static int      smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
 156                         caller_context_t *, int);
 157 static int      smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
 158                         cred_t *, caller_context_t *, int, vsecattr_t *);
 159 static int      smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 160                         caller_context_t *, int);
 161 static int      smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
 162                         caller_context_t *, int);
 163 static int      smbfs_rwlock(vnode_t *, int, caller_context_t *);
 164 static void     smbfs_rwunlock(vnode_t *, int, caller_context_t *);
 165 static int      smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 166 static int      smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 167                         struct flk_callback *, cred_t *, caller_context_t *);
 168 static int      smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
 169                         cred_t *, caller_context_t *);
 170 static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 171                         caller_context_t *);
 172 static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 173                         caller_context_t *);
 174 static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 175                         caller_context_t *);
 176 static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 177                         caller_context_t *);
 178 
 179 /* Dummy function to use until correct function is ported in */
 180 int noop_vnodeop() {
 181         return (0);
 182 }
 183 
 184 struct vnodeops *smbfs_vnodeops = NULL;
 185 
 186 /*
 187  * Most unimplemented ops will return ENOSYS because of fs_nosys().
 188  * The only ops where that won't work are ACCESS (due to open(2)
 189  * failures) and ... (anything else left?)
 190  */
 191 const fs_operation_def_t smbfs_vnodeops_template[] = {
 192         { VOPNAME_OPEN,         { .vop_open = smbfs_open } },
 193         { VOPNAME_CLOSE,        { .vop_close = smbfs_close } },
 194         { VOPNAME_READ,         { .vop_read = smbfs_read } },
 195         { VOPNAME_WRITE,        { .vop_write = smbfs_write } },
 196         { VOPNAME_IOCTL,        { .vop_ioctl = smbfs_ioctl } },
 197         { VOPNAME_GETATTR,      { .vop_getattr = smbfs_getattr } },
 198         { VOPNAME_SETATTR,      { .vop_setattr = smbfs_setattr } },
 199         { VOPNAME_ACCESS,       { .vop_access = smbfs_access } },
 200         { VOPNAME_LOOKUP,       { .vop_lookup = smbfs_lookup } },
 201         { VOPNAME_CREATE,       { .vop_create = smbfs_create } },
 202         { VOPNAME_REMOVE,       { .vop_remove = smbfs_remove } },
 203         { VOPNAME_LINK,         { .error = fs_nosys } }, /* smbfs_link, */
 204         { VOPNAME_RENAME,       { .vop_rename = smbfs_rename } },
 205         { VOPNAME_MKDIR,        { .vop_mkdir = smbfs_mkdir } },
 206         { VOPNAME_RMDIR,        { .vop_rmdir = smbfs_rmdir } },
 207         { VOPNAME_READDIR,      { .vop_readdir = smbfs_readdir } },
 208         { VOPNAME_SYMLINK,      { .error = fs_nosys } }, /* smbfs_symlink, */
 209         { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 210         { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 211         { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 212         { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 213         { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 214         { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 215         { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 216         { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 217         { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 218         { VOPNAME_REALVP,       { .error = fs_nosys } }, /* smbfs_realvp, */
 219         { VOPNAME_GETPAGE,      { .error = fs_nosys } }, /* smbfs_getpage, */
 220         { VOPNAME_PUTPAGE,      { .error = fs_nosys } }, /* smbfs_putpage, */
 221         { VOPNAME_MAP,          { .error = fs_nosys } }, /* smbfs_map, */
 222         { VOPNAME_ADDMAP,       { .error = fs_nosys } }, /* smbfs_addmap, */
 223         { VOPNAME_DELMAP,       { .error = fs_nosys } }, /* smbfs_delmap, */
 224         { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 225         { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 226         { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 227         { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 228         { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 229         { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 230         { NULL, NULL }
 231 };
 232 
 233 /*
 234  * XXX
 235  * When new and relevant functionality is enabled, we should be
 236  * calling vfs_set_feature() to inform callers that pieces of
 237  * functionality are available, per PSARC 2007/227.
 238  */
 239 /* ARGSUSED */
 240 static int
 241 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 242 {
 243         smbnode_t       *np;
 244         vnode_t         *vp;
 245         smbfattr_t      fa;
 246         u_int32_t       rights, rightsrcvd;
 247         u_int16_t       fid, oldfid;
 248         int             oldgenid;
 249         struct smb_cred scred;
 250         smbmntinfo_t    *smi;
 251         smb_share_t     *ssp;
 252         cred_t          *oldcr;
 253         int             tmperror;
 254         int             error = 0;
 255 
 256         vp = *vpp;
 257         np = VTOSMB(vp);
 258         smi = VTOSMI(vp);
 259         ssp = smi->smi_share;
 260 
 261         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 262                 return (EIO);
 263 
 264         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 265                 return (EIO);
 266 
 267         if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
 268                 SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
 269                 return (EACCES);
 270         }
 271 
 272         /*
 273          * Get exclusive access to n_fid and related stuff.
 274          * No returns after this until out.
 275          */
 276         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
 277                 return (EINTR);
 278         smb_credinit(&scred, cr);
 279 
 280         /*
 281          * Keep track of the vnode type at first open.
 282          * It may change later, and we need close to do
 283          * cleanup for the type we opened.  Also deny
 284          * open of new types until old type is closed.
 285          * XXX: Per-open instance nodes whould help.
 286          */
 287         if (np->n_ovtype == VNON) {
 288                 ASSERT(np->n_dirrefs == 0);
 289                 ASSERT(np->n_fidrefs == 0);
 290         } else if (np->n_ovtype != vp->v_type) {
 291                 SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
 292                     np->n_ovtype, vp->v_type);
 293                 error = EACCES;
 294                 goto out;
 295         }
 296 
 297         /*
 298          * Directory open.  See smbfs_readvdir()
 299          */
 300         if (vp->v_type == VDIR) {
 301                 if (np->n_dirseq == NULL) {
 302                         /* first open */
 303                         error = smbfs_smb_findopen(np, "*", 1,
 304                             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
 305                             &scred, &np->n_dirseq);
 306                         if (error != 0)
 307                                 goto out;
 308                 }
 309                 np->n_dirofs = FIRST_DIROFS;
 310                 np->n_dirrefs++;
 311                 goto have_fid;
 312         }
 313 
 314         /*
 315          * If caller specified O_TRUNC/FTRUNC, then be sure to set
 316          * FWRITE (to drive successful setattr(size=0) after open)
 317          */
 318         if (flag & FTRUNC)
 319                 flag |= FWRITE;
 320 
 321         /*
 322          * If we already have it open, and the FID is still valid,
 323          * check whether the rights are sufficient for FID reuse.
 324          */
 325         if (np->n_fidrefs > 0 &&
 326             np->n_vcgenid == ssp->ss_vcgenid) {
 327                 int upgrade = 0;
 328 
 329                 if ((flag & FWRITE) &&
 330                     !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
 331                         upgrade = 1;
 332                 if ((flag & FREAD) &&
 333                     !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
 334                         upgrade = 1;
 335                 if (!upgrade) {
 336                         /*
 337                          *  the existing open is good enough
 338                          */
 339                         np->n_fidrefs++;
 340                         goto have_fid;
 341                 }
 342         }
 343         rights = np->n_fidrefs ? np->n_rights : 0;
 344 
 345         /*
 346          * we always ask for READ_CONTROL so we can always get the
 347          * owner/group IDs to satisfy a stat.  Ditto attributes.
 348          */
 349         rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
 350             SA_RIGHT_FILE_READ_ATTRIBUTES);
 351         if ((flag & FREAD))
 352                 rights |= SA_RIGHT_FILE_READ_DATA;
 353         if ((flag & FWRITE))
 354                 rights |= SA_RIGHT_FILE_WRITE_DATA |
 355                     SA_RIGHT_FILE_APPEND_DATA |
 356                     SA_RIGHT_FILE_WRITE_ATTRIBUTES;
 357 
 358         bzero(&fa, sizeof (fa));
 359         error = smbfs_smb_open(np,
 360             NULL, 0, 0, /* name nmlen xattr */
 361             rights, &scred,
 362             &fid, &rightsrcvd, &fa);
 363         if (error)
 364                 goto out;
 365         smbfs_attrcache_fa(vp, &fa);
 366 
 367         /*
 368          * We have a new FID and access rights.
 369          */
 370         oldfid = np->n_fid;
 371         oldgenid = np->n_vcgenid;
 372         np->n_fid = fid;
 373         np->n_vcgenid = ssp->ss_vcgenid;
 374         np->n_rights = rightsrcvd;
 375         np->n_fidrefs++;
 376         if (np->n_fidrefs > 1 &&
 377             oldgenid == ssp->ss_vcgenid) {
 378                 /*
 379                  * We already had it open (presumably because
 380                  * it was open with insufficient rights.)
 381                  * Close old wire-open.
 382                  */
 383                 tmperror = smbfs_smb_close(ssp,
 384                     oldfid, NULL, &scred);
 385                 if (tmperror)
 386                         SMBVDEBUG("error %d closing %s\n",
 387                             tmperror, np->n_rpath);
 388         }
 389 
 390         /*
 391          * This thread did the open.
 392          * Save our credentials too.
 393          */
 394         mutex_enter(&np->r_statelock);
 395         oldcr = np->r_cred;
 396         np->r_cred = cr;
 397         crhold(cr);
 398         if (oldcr)
 399                 crfree(oldcr);
 400         mutex_exit(&np->r_statelock);
 401 
 402 have_fid:
 403         /*
 404          * Keep track of the vnode type at first open.
 405          * (see comments above)
 406          */
 407         if (np->n_ovtype == VNON)
 408                 np->n_ovtype = vp->v_type;
 409 
 410 out:
 411         smb_credrele(&scred);
 412         smbfs_rw_exit(&np->r_lkserlock);
 413         return (error);
 414 }
 415 
 416 /*ARGSUSED*/
 417 static int
 418 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
 419         caller_context_t *ct)
 420 {
 421         smbnode_t       *np;
 422         smbmntinfo_t    *smi;
 423         struct smb_cred scred;
 424 
 425         np = VTOSMB(vp);
 426         smi = VTOSMI(vp);
 427 
 428         /*
 429          * Don't "bail out" for VFS_UNMOUNTED here,
 430          * as we want to do cleanup, etc.
 431          */
 432 
 433         /*
 434          * zone_enter(2) prevents processes from changing zones with SMBFS files
 435          * open; if we happen to get here from the wrong zone we can't do
 436          * anything over the wire.
 437          */
 438         if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
 439                 /*
 440                  * We could attempt to clean up locks, except we're sure
 441                  * that the current process didn't acquire any locks on
 442                  * the file: any attempt to lock a file belong to another zone
 443                  * will fail, and one can't lock an SMBFS file and then change
 444                  * zones, as that fails too.
 445                  *
 446                  * Returning an error here is the sane thing to do.  A
 447                  * subsequent call to VN_RELE() which translates to a
 448                  * smbfs_inactive() will clean up state: if the zone of the
 449                  * vnode's origin is still alive and kicking, an async worker
 450                  * thread will handle the request (from the correct zone), and
 451                  * everything (minus the final smbfs_getattr_otw() call) should
 452                  * be OK. If the zone is going away smbfs_async_inactive() will
 453                  * throw away cached pages inline.
 454                  */
 455                 return (EIO);
 456         }
 457 
 458         /*
 459          * If we are using local locking for this filesystem, then
 460          * release all of the SYSV style record locks.  Otherwise,
 461          * we are doing network locking and we need to release all
 462          * of the network locks.  All of the locks held by this
 463          * process on this file are released no matter what the
 464          * incoming reference count is.
 465          */
 466         if (smi->smi_flags & SMI_LLOCK) {
 467                 pid_t pid = ddi_get_pid();
 468                 cleanlocks(vp, pid, 0);
 469                 cleanshares(vp, pid);
 470         }
 471 
 472         /*
 473          * This (passed in) count is the ref. count from the
 474          * user's file_t before the closef call (fio.c).
 475          * We only care when the reference goes away.
 476          */
 477         if (count > 1)
 478                 return (0);
 479 
 480         /*
 481          * Decrement the reference count for the FID
 482          * and possibly do the OtW close.
 483          *
 484          * Exclusive lock for modifying n_fid stuff.
 485          * Don't want this one ever interruptible.
 486          */
 487         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 488         smb_credinit(&scred, cr);
 489 
 490         smbfs_rele_fid(np, &scred);
 491 
 492         smb_credrele(&scred);
 493         smbfs_rw_exit(&np->r_lkserlock);
 494 
 495         return (0);
 496 }
 497 
 498 /*
 499  * Helper for smbfs_close.  Decrement the reference count
 500  * for an SMB-level file or directory ID, and when the last
 501  * reference for the fid goes away, do the OtW close.
 502  * Also called in smbfs_inactive (defensive cleanup).
 503  */
 504 static void
 505 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
 506 {
 507         smb_share_t     *ssp;
 508         cred_t          *oldcr;
 509         struct smbfs_fctx *fctx;
 510         int             error;
 511         uint16_t ofid;
 512 
 513         ssp = np->n_mount->smi_share;
 514         error = 0;
 515 
 516         /* Make sure we serialize for n_dirseq use. */
 517         ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
 518 
 519         /*
 520          * Note that vp->v_type may change if a remote node
 521          * is deleted and recreated as a different type, and
 522          * our getattr may change v_type accordingly.
 523          * Now use n_ovtype to keep track of the v_type
 524          * we had during open (see comments above).
 525          */
 526         switch (np->n_ovtype) {
 527         case VDIR:
 528                 ASSERT(np->n_dirrefs > 0);
 529                 if (--np->n_dirrefs)
 530                         return;
 531                 if ((fctx = np->n_dirseq) != NULL) {
 532                         np->n_dirseq = NULL;
 533                         np->n_dirofs = 0;
 534                         error = smbfs_smb_findclose(fctx, scred);
 535                 }
 536                 break;
 537 
 538         case VREG:
 539                 ASSERT(np->n_fidrefs > 0);
 540                 if (--np->n_fidrefs)
 541                         return;
 542                 if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
 543                         np->n_fid = SMB_FID_UNUSED;
 544                         /* After reconnect, n_fid is invalid */
 545                         if (np->n_vcgenid == ssp->ss_vcgenid) {
 546                                 error = smbfs_smb_close(
 547                                     ssp, ofid, NULL, scred);
 548                         }
 549                 }
 550                 break;
 551 
 552         default:
 553                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
 554                 break;
 555         }
 556         if (error) {
 557                 SMBVDEBUG("error %d closing %s\n",
 558                     error, np->n_rpath);
 559         }
 560 
 561         /* Allow next open to use any v_type. */
 562         np->n_ovtype = VNON;
 563 
 564         /*
 565          * Other "last close" stuff.
 566          */
 567         mutex_enter(&np->r_statelock);
 568         if (np->n_flag & NATTRCHANGED)
 569                 smbfs_attrcache_rm_locked(np);
 570         oldcr = np->r_cred;
 571         np->r_cred = NULL;
 572         mutex_exit(&np->r_statelock);
 573         if (oldcr != NULL)
 574                 crfree(oldcr);
 575 }
 576 
 577 /* ARGSUSED */
 578 static int
 579 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 580         caller_context_t *ct)
 581 {
 582         struct smb_cred scred;
 583         struct vattr    va;
 584         smbnode_t       *np;
 585         smbmntinfo_t    *smi;
 586         smb_share_t     *ssp;
 587         offset_t        endoff;
 588         ssize_t         past_eof;
 589         int             error;
 590 
 591         np = VTOSMB(vp);
 592         smi = VTOSMI(vp);
 593         ssp = smi->smi_share;
 594 
 595         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 596                 return (EIO);
 597 
 598         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 599                 return (EIO);
 600 
 601         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 602 
 603         if (vp->v_type != VREG)
 604                 return (EISDIR);
 605 
 606         if (uiop->uio_resid == 0)
 607                 return (0);
 608 
 609         /*
 610          * Like NFS3, just check for 63-bit overflow.
 611          * Our SMB layer takes care to return EFBIG
 612          * when it has to fallback to a 32-bit call.
 613          */
 614         endoff = uiop->uio_loffset + uiop->uio_resid;
 615         if (uiop->uio_loffset < 0 || endoff < 0)
 616                 return (EINVAL);
 617 
 618         /* get vnode attributes from server */
 619         va.va_mask = AT_SIZE | AT_MTIME;
 620         if (error = smbfsgetattr(vp, &va, cr))
 621                 return (error);
 622 
 623         /* Update mtime with mtime from server here? */
 624 
 625         /* if offset is beyond EOF, read nothing */
 626         if (uiop->uio_loffset >= va.va_size)
 627                 return (0);
 628 
 629         /*
 630          * Limit the read to the remaining file size.
 631          * Do this by temporarily reducing uio_resid
 632          * by the amount the lies beyoned the EOF.
 633          */
 634         if (endoff > va.va_size) {
 635                 past_eof = (ssize_t)(endoff - va.va_size);
 636                 uiop->uio_resid -= past_eof;
 637         } else
 638                 past_eof = 0;
 639 
 640         /* Shared lock for n_fid use in smb_rwuio */
 641         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 642                 return (EINTR);
 643         smb_credinit(&scred, cr);
 644 
 645         /* After reconnect, n_fid is invalid */
 646         if (np->n_vcgenid != ssp->ss_vcgenid)
 647                 error = ESTALE;
 648         else
 649                 error = smb_rwuio(ssp, np->n_fid, UIO_READ,
 650                     uiop, &scred, smb_timo_read);
 651 
 652         smb_credrele(&scred);
 653         smbfs_rw_exit(&np->r_lkserlock);
 654 
 655         /* undo adjustment of resid */
 656         uiop->uio_resid += past_eof;
 657 
 658         return (error);
 659 }
 660 
 661 
 662 /* ARGSUSED */
 663 static int
 664 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 665         caller_context_t *ct)
 666 {
 667         struct smb_cred scred;
 668         struct vattr    va;
 669         smbnode_t       *np;
 670         smbmntinfo_t    *smi;
 671         smb_share_t     *ssp;
 672         offset_t        endoff, limit;
 673         ssize_t         past_limit;
 674         int             error, timo;
 675 
 676         np = VTOSMB(vp);
 677         smi = VTOSMI(vp);
 678         ssp = smi->smi_share;
 679 
 680         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 681                 return (EIO);
 682 
 683         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 684                 return (EIO);
 685 
 686         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
 687 
 688         if (vp->v_type != VREG)
 689                 return (EISDIR);
 690 
 691         if (uiop->uio_resid == 0)
 692                 return (0);
 693 
 694         /*
 695          * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
 696          */
 697         if (ioflag & (FAPPEND | FSYNC)) {
 698                 if (np->n_flag & NMODIFIED) {
 699                         smbfs_attrcache_remove(np);
 700                         /* XXX: smbfs_vinvalbuf? */
 701                 }
 702         }
 703         if (ioflag & FAPPEND) {
 704                 /*
 705                  * File size can be changed by another client
 706                  */
 707                 va.va_mask = AT_SIZE;
 708                 if (error = smbfsgetattr(vp, &va, cr))
 709                         return (error);
 710                 uiop->uio_loffset = va.va_size;
 711         }
 712 
 713         /*
 714          * Like NFS3, just check for 63-bit overflow.
 715          */
 716         endoff = uiop->uio_loffset + uiop->uio_resid;
 717         if (uiop->uio_loffset < 0 || endoff < 0)
 718                 return (EINVAL);
 719 
 720         /*
 721          * Check to make sure that the process will not exceed
 722          * its limit on file size.  It is okay to write up to
 723          * the limit, but not beyond.  Thus, the write which
 724          * reaches the limit will be short and the next write
 725          * will return an error.
 726          *
 727          * So if we're starting at or beyond the limit, EFBIG.
 728          * Otherwise, temporarily reduce resid to the amount
 729          * the falls after the limit.
 730          */
 731         limit = uiop->uio_llimit;
 732         if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 733                 limit = MAXOFFSET_T;
 734         if (uiop->uio_loffset >= limit)
 735                 return (EFBIG);
 736         if (endoff > limit) {
 737                 past_limit = (ssize_t)(endoff - limit);
 738                 uiop->uio_resid -= past_limit;
 739         } else
 740                 past_limit = 0;
 741 
 742         /* Timeout: longer for append. */
 743         timo = smb_timo_write;
 744         if (endoff > np->r_size)
 745                 timo = smb_timo_append;
 746 
 747         /* Shared lock for n_fid use in smb_rwuio */
 748         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 749                 return (EINTR);
 750         smb_credinit(&scred, cr);
 751 
 752         /* After reconnect, n_fid is invalid */
 753         if (np->n_vcgenid != ssp->ss_vcgenid)
 754                 error = ESTALE;
 755         else
 756                 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
 757                     uiop, &scred, timo);
 758 
 759         if (error == 0) {
 760                 mutex_enter(&np->r_statelock);
 761                 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 762                 if (uiop->uio_loffset > (offset_t)np->r_size)
 763                         np->r_size = (len_t)uiop->uio_loffset;
 764                 mutex_exit(&np->r_statelock);
 765                 if (ioflag & (FSYNC|FDSYNC)) {
 766                         /* Don't error the I/O if this fails. */
 767                         (void) smbfs_smb_flush(np, &scred);
 768                 }
 769         }
 770 
 771         smb_credrele(&scred);
 772         smbfs_rw_exit(&np->r_lkserlock);
 773 
 774         /* undo adjustment of resid */
 775         uiop->uio_resid += past_limit;
 776 
 777         return (error);
 778 }
 779 
 780 
 781 /* ARGSUSED */
 782 static int
 783 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
 784         cred_t *cr, int *rvalp, caller_context_t *ct)
 785 {
 786         int             error;
 787         smbmntinfo_t    *smi;
 788 
 789         smi = VTOSMI(vp);
 790 
 791         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 792                 return (EIO);
 793 
 794         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 795                 return (EIO);
 796 
 797         switch (cmd) {
 798                 /* First three from ZFS. XXX - need these? */
 799 
 800         case _FIOFFS:
 801                 error = smbfs_fsync(vp, 0, cr, ct);
 802                 break;
 803 
 804                 /*
 805                  * The following two ioctls are used by bfu.
 806                  * Silently ignore to avoid bfu errors.
 807                  */
 808         case _FIOGDIO:
 809         case _FIOSDIO:
 810                 error = 0;
 811                 break;
 812 
 813 #ifdef NOT_YET  /* XXX - from the NFS code. */
 814         case _FIODIRECTIO:
 815                 error = smbfs_directio(vp, (int)arg, cr);
 816 #endif
 817 
 818                 /*
 819                  * Allow get/set with "raw" security descriptor (SD) data.
 820                  * Useful for testing, diagnosing idmap problems, etc.
 821                  */
 822         case SMBFSIO_GETSD:
 823                 error = smbfs_acl_iocget(vp, arg, flag, cr);
 824                 break;
 825 
 826         case SMBFSIO_SETSD:
 827                 error = smbfs_acl_iocset(vp, arg, flag, cr);
 828                 break;
 829 
 830         default:
 831                 error = ENOTTY;
 832                 break;
 833         }
 834 
 835         return (error);
 836 }
 837 
 838 
 839 /*
 840  * Return either cached or remote attributes. If get remote attr
 841  * use them to check and invalidate caches, then cache the new attributes.
 842  */
 843 /* ARGSUSED */
 844 static int
 845 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 846         caller_context_t *ct)
 847 {
 848         smbnode_t *np;
 849         smbmntinfo_t *smi;
 850 
 851         smi = VTOSMI(vp);
 852 
 853         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 854                 return (EIO);
 855 
 856         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 857                 return (EIO);
 858 
 859         /*
 860          * If it has been specified that the return value will
 861          * just be used as a hint, and we are only being asked
 862          * for size, fsid or rdevid, then return the client's
 863          * notion of these values without checking to make sure
 864          * that the attribute cache is up to date.
 865          * The whole point is to avoid an over the wire GETATTR
 866          * call.
 867          */
 868         np = VTOSMB(vp);
 869         if (flags & ATTR_HINT) {
 870                 if (vap->va_mask ==
 871                     (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
 872                         mutex_enter(&np->r_statelock);
 873                         if (vap->va_mask | AT_SIZE)
 874                                 vap->va_size = np->r_size;
 875                         if (vap->va_mask | AT_FSID)
 876                                 vap->va_fsid = vp->v_vfsp->vfs_dev;
 877                         if (vap->va_mask | AT_RDEV)
 878                                 vap->va_rdev = vp->v_rdev;
 879                         mutex_exit(&np->r_statelock);
 880                         return (0);
 881                 }
 882         }
 883 
 884         return (smbfsgetattr(vp, vap, cr));
 885 }
 886 
 887 /* smbfsgetattr() in smbfs_client.c */
 888 
 889 /*ARGSUSED4*/
 890 static int
 891 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 892                 caller_context_t *ct)
 893 {
 894         vfs_t           *vfsp;
 895         smbmntinfo_t    *smi;
 896         int             error;
 897         uint_t          mask;
 898         struct vattr    oldva;
 899 
 900         vfsp = vp->v_vfsp;
 901         smi = VFTOSMI(vfsp);
 902 
 903         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 904                 return (EIO);
 905 
 906         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
 907                 return (EIO);
 908 
 909         mask = vap->va_mask;
 910         if (mask & AT_NOSET)
 911                 return (EINVAL);
 912 
 913         if (vfsp->vfs_flag & VFS_RDONLY)
 914                 return (EROFS);
 915 
 916         /*
 917          * This is a _local_ access check so that only the owner of
 918          * this mount can set attributes.  With ACLs enabled, the
 919          * file owner can be different from the mount owner, and we
 920          * need to check the _mount_ owner here.  See _access_rwx
 921          */
 922         bzero(&oldva, sizeof (oldva));
 923         oldva.va_mask = AT_TYPE | AT_MODE;
 924         error = smbfsgetattr(vp, &oldva, cr);
 925         if (error)
 926                 return (error);
 927         oldva.va_mask |= AT_UID | AT_GID;
 928         oldva.va_uid = smi->smi_uid;
 929         oldva.va_gid = smi->smi_gid;
 930 
 931         error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
 932             smbfs_accessx, vp);
 933         if (error)
 934                 return (error);
 935 
 936         if (mask & (AT_UID | AT_GID)) {
 937                 if (smi->smi_flags & SMI_ACL)
 938                         error = smbfs_acl_setids(vp, vap, cr);
 939                 else
 940                         error = ENOSYS;
 941                 if (error != 0) {
 942                         SMBVDEBUG("error %d seting UID/GID on %s",
 943                             error, VTOSMB(vp)->n_rpath);
 944                         /*
 945                          * It might be more correct to return the
 946                          * error here, but that causes complaints
 947                          * when root extracts a cpio archive, etc.
 948                          * So ignore this error, and go ahead with
 949                          * the rest of the setattr work.
 950                          */
 951                 }
 952         }
 953 
 954         return (smbfssetattr(vp, vap, flags, cr));
 955 }
 956 
 957 /*
 958  * Mostly from Darwin smbfs_setattr()
 959  * but then modified a lot.
 960  */
 961 /* ARGSUSED */
 962 static int
 963 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
 964 {
 965         int             error = 0;
 966         smbnode_t       *np = VTOSMB(vp);
 967         uint_t          mask = vap->va_mask;
 968         struct timespec *mtime, *atime;
 969         struct smb_cred scred;
 970         int             cerror, modified = 0;
 971         unsigned short  fid;
 972         int have_fid = 0;
 973         uint32_t rights = 0;
 974         uint32_t dosattr = 0;
 975 
 976         ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
 977 
 978         /*
 979          * There are no settable attributes on the XATTR dir,
 980          * so just silently ignore these.  On XATTR files,
 981          * you can set the size but nothing else.
 982          */
 983         if (vp->v_flag & V_XATTRDIR)
 984                 return (0);
 985         if (np->n_flag & N_XATTR) {
 986                 if (mask & AT_TIMES)
 987                         SMBVDEBUG("ignore set time on xattr\n");
 988                 mask &= AT_SIZE;
 989         }
 990 
 991         /*
 992          * If our caller is trying to set multiple attributes, they
 993          * can make no assumption about what order they are done in.
 994          * Here we try to do them in order of decreasing likelihood
 995          * of failure, just to minimize the chance we'll wind up
 996          * with a partially complete request.
 997          */
 998 
 999         /* Shared lock for (possible) n_fid use. */
1000         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1001                 return (EINTR);
1002         smb_credinit(&scred, cr);
1003 
1004         /*
1005          * If the caller has provided extensible attributes,
1006          * map those into DOS attributes supported by SMB.
1007          * Note: zero means "no change".
1008          */
1009         if (mask & AT_XVATTR)
1010                 dosattr = xvattr_to_dosattr(np, vap);
1011 
1012         /*
1013          * Will we need an open handle for this setattr?
1014          * If so, what rights will we need?
1015          */
1016         if (dosattr || (mask & (AT_ATIME | AT_MTIME))) {
1017                 rights |=
1018                     SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1019         }
1020         if (mask & AT_SIZE) {
1021                 rights |=
1022                     SA_RIGHT_FILE_WRITE_DATA |
1023                     SA_RIGHT_FILE_APPEND_DATA;
1024         }
1025 
1026         /*
1027          * Only SIZE really requires a handle, but it's
1028          * simpler and more reliable to set via a handle.
1029          * Some servers like NT4 won't set times by path.
1030          * Also, we're usually setting everything anyway.
1031          */
1032         if (rights != 0) {
1033                 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1034                 if (error) {
1035                         SMBVDEBUG("error %d opening %s\n",
1036                             error, np->n_rpath);
1037                         goto out;
1038                 }
1039                 have_fid = 1;
1040         }
1041 
1042         /*
1043          * If the server supports the UNIX extensions, right here is where
1044          * we'd support changes to uid, gid, mode, and possibly va_flags.
1045          * For now we claim to have made any such changes.
1046          */
1047 
1048         if (mask & AT_SIZE) {
1049                 /*
1050                  * If the new file size is less than what the client sees as
1051                  * the file size, then just change the size and invalidate
1052                  * the pages.
1053                  * I am commenting this code at present because the function
1054                  * smbfs_putapage() is not yet implemented.
1055                  */
1056 
1057                 /*
1058                  * Set the file size to vap->va_size.
1059                  */
1060                 ASSERT(have_fid);
1061                 error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1062                 if (error) {
1063                         SMBVDEBUG("setsize error %d file %s\n",
1064                             error, np->n_rpath);
1065                 } else {
1066                         /*
1067                          * Darwin had code here to zero-extend.
1068                          * Tests indicate the server will zero-fill,
1069                          * so looks like we don't need to do this.
1070                          * Good thing, as this could take forever.
1071                          *
1072                          * XXX: Reportedly, writing one byte of zero
1073                          * at the end offset avoids problems here.
1074                          */
1075                         mutex_enter(&np->r_statelock);
1076                         np->r_size = vap->va_size;
1077                         mutex_exit(&np->r_statelock);
1078                         modified = 1;
1079                 }
1080         }
1081 
1082         /*
1083          * XXX: When Solaris has create_time, set that too.
1084          * Note: create_time is different from ctime.
1085          */
1086         mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1087         atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1088 
1089         if (dosattr || mtime || atime) {
1090                 /*
1091                  * Always use the handle-based set attr call now.
1092                  * Not trying to set DOS attributes here so pass zero.
1093                  */
1094                 ASSERT(have_fid);
1095                 error = smbfs_smb_setfattr(np, fid,
1096                     dosattr, mtime, atime, &scred);
1097                 if (error) {
1098                         SMBVDEBUG("set times error %d file %s\n",
1099                             error, np->n_rpath);
1100                 } else {
1101                         modified = 1;
1102                 }
1103         }
1104 
1105 out:
1106         if (modified) {
1107                 /*
1108                  * Invalidate attribute cache in case the server
1109                  * doesn't set exactly the attributes we asked.
1110                  */
1111                 smbfs_attrcache_remove(np);
1112         }
1113 
1114         if (have_fid) {
1115                 cerror = smbfs_smb_tmpclose(np, fid, &scred);
1116                 if (cerror)
1117                         SMBVDEBUG("error %d closing %s\n",
1118                             cerror, np->n_rpath);
1119         }
1120 
1121         smb_credrele(&scred);
1122         smbfs_rw_exit(&np->r_lkserlock);
1123 
1124         return (error);
1125 }
1126 
1127 /*
1128  * Helper function for extensible system attributes (PSARC 2007/315)
1129  * Compute the DOS attribute word to pass to _setfattr (see above).
1130  * This returns zero IFF no change is being made to attributes.
1131  * Otherwise return the new attributes or SMB_EFA_NORMAL.
1132  */
1133 static uint32_t
1134 xvattr_to_dosattr(smbnode_t *np, struct vattr *vap)
1135 {
1136         xvattr_t *xvap = (xvattr_t *)vap;
1137         xoptattr_t *xoap = NULL;
1138         uint32_t attr = np->r_attr.fa_attr;
1139         boolean_t anyset = B_FALSE;
1140 
1141         if ((xoap = xva_getxoptattr(xvap)) == NULL)
1142                 return (0);
1143 
1144         if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
1145                 if (xoap->xoa_archive)
1146                         attr |= SMB_FA_ARCHIVE;
1147                 else
1148                         attr &= ~SMB_FA_ARCHIVE;
1149                 XVA_SET_RTN(xvap, XAT_ARCHIVE);
1150                 anyset = B_TRUE;
1151         }
1152         if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
1153                 if (xoap->xoa_system)
1154                         attr |= SMB_FA_SYSTEM;
1155                 else
1156                         attr &= ~SMB_FA_SYSTEM;
1157                 XVA_SET_RTN(xvap, XAT_SYSTEM);
1158                 anyset = B_TRUE;
1159         }
1160         if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
1161                 if (xoap->xoa_readonly)
1162                         attr |= SMB_FA_RDONLY;
1163                 else
1164                         attr &= ~SMB_FA_RDONLY;
1165                 XVA_SET_RTN(xvap, XAT_READONLY);
1166                 anyset = B_TRUE;
1167         }
1168         if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
1169                 if (xoap->xoa_hidden)
1170                         attr |= SMB_FA_HIDDEN;
1171                 else
1172                         attr &= ~SMB_FA_HIDDEN;
1173                 XVA_SET_RTN(xvap, XAT_HIDDEN);
1174                 anyset = B_TRUE;
1175         }
1176 
1177         if (anyset == B_FALSE)
1178                 return (0);     /* no change */
1179         if (attr == 0)
1180                 attr = SMB_EFA_NORMAL;
1181 
1182         return (attr);
1183 }
1184 
1185 /*
1186  * smbfs_access_rwx()
1187  * Common function for smbfs_access, etc.
1188  *
1189  * The security model implemented by the FS is unusual
1190  * due to the current "single user mounts" restriction:
1191  * All access under a given mount point uses the CIFS
1192  * credentials established by the owner of the mount.
1193  *
1194  * Most access checking is handled by the CIFS server,
1195  * but we need sufficient Unix access checks here to
1196  * prevent other local Unix users from having access
1197  * to objects under this mount that the uid/gid/mode
1198  * settings in the mount would not allow.
1199  *
1200  * With this model, there is a case where we need the
1201  * ability to do an access check before we have the
1202  * vnode for an object.  This function takes advantage
1203  * of the fact that the uid/gid/mode is per mount, and
1204  * avoids the need for a vnode.
1205  *
1206  * We still (sort of) need a vnode when we call
1207  * secpolicy_vnode_access, but that only uses
1208  * the vtype field, so we can use a pair of fake
1209  * vnodes that have only v_type filled in.
1210  *
1211  * XXX: Later, add a new secpolicy_vtype_access()
1212  * that takes the vtype instead of a vnode, and
1213  * get rid of the tmpl_vxxx fake vnodes below.
1214  */
1215 static int
1216 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1217 {
1218         /* See the secpolicy call below. */
1219         static const vnode_t tmpl_vdir = { .v_type = VDIR };
1220         static const vnode_t tmpl_vreg = { .v_type = VREG };
1221         vattr_t         va;
1222         vnode_t         *tvp;
1223         struct smbmntinfo *smi = VFTOSMI(vfsp);
1224         int shift = 0;
1225 
1226         /*
1227          * Build our (fabricated) vnode attributes.
1228          * XXX: Could make these templates in the
1229          * per-mount struct and use them here.
1230          */
1231         bzero(&va, sizeof (va));
1232         va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1233         va.va_type = vtype;
1234         va.va_mode = (vtype == VDIR) ?
1235             smi->smi_dmode : smi->smi_fmode;
1236         va.va_uid = smi->smi_uid;
1237         va.va_gid = smi->smi_gid;
1238 
1239         /*
1240          * Disallow write attempts on read-only file systems,
1241          * unless the file is a device or fifo node.  Note:
1242          * Inline vn_is_readonly and IS_DEVVP here because
1243          * we may not have a vnode ptr.  Original expr. was:
1244          * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1245          */
1246         if ((mode & VWRITE) &&
1247             (vfsp->vfs_flag & VFS_RDONLY) &&
1248             !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1249                 return (EROFS);
1250 
1251         /*
1252          * Disallow attempts to access mandatory lock files.
1253          * Similarly, expand MANDLOCK here.
1254          * XXX: not sure we need this.
1255          */
1256         if ((mode & (VWRITE | VREAD | VEXEC)) &&
1257             va.va_type == VREG && MANDMODE(va.va_mode))
1258                 return (EACCES);
1259 
1260         /*
1261          * Access check is based on only
1262          * one of owner, group, public.
1263          * If not owner, then check group.
1264          * If not a member of the group,
1265          * then check public access.
1266          */
1267         if (crgetuid(cr) != va.va_uid) {
1268                 shift += 3;
1269                 if (!groupmember(va.va_gid, cr))
1270                         shift += 3;
1271         }
1272 
1273         /*
1274          * We need a vnode for secpolicy_vnode_access,
1275          * but the only thing it looks at is v_type,
1276          * so pass one of the templates above.
1277          */
1278         tvp = (va.va_type == VDIR) ?
1279             (vnode_t *)&tmpl_vdir :
1280             (vnode_t *)&tmpl_vreg;
1281 
1282         return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1283             va.va_mode << shift, mode));
1284 }
1285 
1286 /*
1287  * See smbfs_setattr
1288  */
1289 static int
1290 smbfs_accessx(void *arg, int mode, cred_t *cr)
1291 {
1292         vnode_t *vp = arg;
1293         /*
1294          * Note: The caller has checked the current zone,
1295          * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1296          */
1297         return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1298 }
1299 
1300 /*
1301  * XXX
1302  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1303  */
1304 /* ARGSUSED */
1305 static int
1306 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1307 {
1308         vfs_t           *vfsp;
1309         smbmntinfo_t    *smi;
1310 
1311         vfsp = vp->v_vfsp;
1312         smi = VFTOSMI(vfsp);
1313 
1314         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1315                 return (EIO);
1316 
1317         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1318                 return (EIO);
1319 
1320         return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1321 }
1322 
1323 
1324 /*
1325  * Flush local dirty pages to stable storage on the server.
1326  *
1327  * If FNODSYNC is specified, then there is nothing to do because
1328  * metadata changes are not cached on the client before being
1329  * sent to the server.
1330  */
1331 /* ARGSUSED */
1332 static int
1333 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1334 {
1335         int             error = 0;
1336         smbmntinfo_t    *smi;
1337         smbnode_t       *np;
1338         struct smb_cred scred;
1339 
1340         np = VTOSMB(vp);
1341         smi = VTOSMI(vp);
1342 
1343         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1344                 return (EIO);
1345 
1346         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1347                 return (EIO);
1348 
1349         if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1350                 return (0);
1351 
1352         if ((syncflag & (FSYNC|FDSYNC)) == 0)
1353                 return (0);
1354 
1355         /* Shared lock for n_fid use in _flush */
1356         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1357                 return (EINTR);
1358         smb_credinit(&scred, cr);
1359 
1360         error = smbfs_smb_flush(np, &scred);
1361 
1362         smb_credrele(&scred);
1363         smbfs_rw_exit(&np->r_lkserlock);
1364 
1365         return (error);
1366 }
1367 
1368 /*
1369  * Last reference to vnode went away.
1370  */
1371 /* ARGSUSED */
1372 static void
1373 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1374 {
1375         smbnode_t       *np;
1376         struct smb_cred scred;
1377 
1378         /*
1379          * Don't "bail out" for VFS_UNMOUNTED here,
1380          * as we want to do cleanup, etc.
1381          * See also pcfs_inactive
1382          */
1383 
1384         np = VTOSMB(vp);
1385 
1386         /*
1387          * If this is coming from the wrong zone, we let someone in the right
1388          * zone take care of it asynchronously.  We can get here due to
1389          * VN_RELE() being called from pageout() or fsflush().  This call may
1390          * potentially turn into an expensive no-op if, for instance, v_count
1391          * gets incremented in the meantime, but it's still correct.
1392          */
1393 
1394         /*
1395          * Defend against the possibility that higher-level callers
1396          * might not correctly balance open and close calls.  If we
1397          * get here with open references remaining, it means there
1398          * was a missing VOP_CLOSE somewhere.  If that happens, do
1399          * the close here so we don't "leak" FIDs on the server.
1400          *
1401          * Exclusive lock for modifying n_fid stuff.
1402          * Don't want this one ever interruptible.
1403          */
1404         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1405         smb_credinit(&scred, cr);
1406 
1407         switch (np->n_ovtype) {
1408         case VNON:
1409                 /* not open (OK) */
1410                 break;
1411 
1412         case VDIR:
1413                 if (np->n_dirrefs == 0)
1414                         break;
1415                 SMBVDEBUG("open dir: refs %d path %s\n",
1416                     np->n_dirrefs, np->n_rpath);
1417                 /* Force last close. */
1418                 np->n_dirrefs = 1;
1419                 smbfs_rele_fid(np, &scred);
1420                 break;
1421 
1422         case VREG:
1423                 if (np->n_fidrefs == 0)
1424                         break;
1425                 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1426                     np->n_fidrefs, np->n_fid, np->n_rpath);
1427                 /* Force last close. */
1428                 np->n_fidrefs = 1;
1429                 smbfs_rele_fid(np, &scred);
1430                 break;
1431 
1432         default:
1433                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1434                 np->n_ovtype = VNON;
1435                 break;
1436         }
1437 
1438         smb_credrele(&scred);
1439         smbfs_rw_exit(&np->r_lkserlock);
1440 
1441         smbfs_addfree(np);
1442 }
1443 
1444 /*
1445  * Remote file system operations having to do with directory manipulation.
1446  */
1447 /* ARGSUSED */
1448 static int
1449 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1450         int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1451         int *direntflags, pathname_t *realpnp)
1452 {
1453         vfs_t           *vfs;
1454         smbmntinfo_t    *smi;
1455         smbnode_t       *dnp;
1456         int             error;
1457 
1458         vfs = dvp->v_vfsp;
1459         smi = VFTOSMI(vfs);
1460 
1461         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1462                 return (EPERM);
1463 
1464         if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1465                 return (EIO);
1466 
1467         dnp = VTOSMB(dvp);
1468 
1469         /*
1470          * Are we looking up extended attributes?  If so, "dvp" is
1471          * the file or directory for which we want attributes, and
1472          * we need a lookup of the (faked up) attribute directory
1473          * before we lookup the rest of the path.
1474          */
1475         if (flags & LOOKUP_XATTR) {
1476                 /*
1477                  * Require the xattr mount option.
1478                  */
1479                 if ((vfs->vfs_flag & VFS_XATTR) == 0)
1480                         return (EINVAL);
1481 
1482                 error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1483                 return (error);
1484         }
1485 
1486         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1487                 return (EINTR);
1488 
1489         error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1490 
1491         smbfs_rw_exit(&dnp->r_rwlock);
1492 
1493         return (error);
1494 }
1495 
1496 /* ARGSUSED */
1497 static int
1498 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1499         int cache_ok, caller_context_t *ct)
1500 {
1501         int             error;
1502         int             supplen; /* supported length */
1503         vnode_t         *vp;
1504         smbnode_t       *np;
1505         smbnode_t       *dnp;
1506         smbmntinfo_t    *smi;
1507         /* struct smb_vc        *vcp; */
1508         const char      *ill;
1509         const char      *name = (const char *)nm;
1510         int             nmlen = strlen(nm);
1511         int             rplen;
1512         struct smb_cred scred;
1513         struct smbfattr fa;
1514 
1515         smi = VTOSMI(dvp);
1516         dnp = VTOSMB(dvp);
1517 
1518         ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1519 
1520 #ifdef NOT_YET
1521         vcp = SSTOVC(smi->smi_share);
1522 
1523         /* XXX: Should compute this once and store it in smbmntinfo_t */
1524         supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1525 #else
1526         supplen = 255;
1527 #endif
1528 
1529         /*
1530          * RWlock must be held, either reader or writer.
1531          * XXX: Can we check without looking directly
1532          * inside the struct smbfs_rwlock_t?
1533          */
1534         ASSERT(dnp->r_rwlock.count != 0);
1535 
1536         /*
1537          * If lookup is for "", just return dvp.
1538          * No need to perform any access checks.
1539          */
1540         if (nmlen == 0) {
1541                 VN_HOLD(dvp);
1542                 *vpp = dvp;
1543                 return (0);
1544         }
1545 
1546         /*
1547          * Can't do lookups in non-directories.
1548          */
1549         if (dvp->v_type != VDIR)
1550                 return (ENOTDIR);
1551 
1552         /*
1553          * Need search permission in the directory.
1554          */
1555         error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1556         if (error)
1557                 return (error);
1558 
1559         /*
1560          * If lookup is for ".", just return dvp.
1561          * Access check was done above.
1562          */
1563         if (nmlen == 1 && name[0] == '.') {
1564                 VN_HOLD(dvp);
1565                 *vpp = dvp;
1566                 return (0);
1567         }
1568 
1569         /*
1570          * Now some sanity checks on the name.
1571          * First check the length.
1572          */
1573         if (nmlen > supplen)
1574                 return (ENAMETOOLONG);
1575 
1576         /*
1577          * Avoid surprises with characters that are
1578          * illegal in Windows file names.
1579          * Todo: CATIA mappings  XXX
1580          */
1581         ill = illegal_chars;
1582         if (dnp->n_flag & N_XATTR)
1583                 ill++; /* allow colon */
1584         if (strpbrk(nm, ill))
1585                 return (EINVAL);
1586 
1587         /*
1588          * Special handling for lookup of ".."
1589          *
1590          * We keep full pathnames (as seen on the server)
1591          * so we can just trim off the last component to
1592          * get the full pathname of the parent.  Note:
1593          * We don't actually copy and modify, but just
1594          * compute the trimmed length and pass that with
1595          * the current dir path (not null terminated).
1596          *
1597          * We don't go over-the-wire to get attributes
1598          * for ".." because we know it's a directory,
1599          * and we can just leave the rest "stale"
1600          * until someone does a getattr.
1601          */
1602         if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1603                 if (dvp->v_flag & VROOT) {
1604                         /*
1605                          * Already at the root.  This can happen
1606                          * with directory listings at the root,
1607                          * which lookup "." and ".." to get the
1608                          * inode numbers.  Let ".." be the same
1609                          * as "." in the FS root.
1610                          */
1611                         VN_HOLD(dvp);
1612                         *vpp = dvp;
1613                         return (0);
1614                 }
1615 
1616                 /*
1617                  * Special case for XATTR directory
1618                  */
1619                 if (dvp->v_flag & V_XATTRDIR) {
1620                         error = smbfs_xa_parent(dvp, vpp);
1621                         return (error);
1622                 }
1623 
1624                 /*
1625                  * Find the parent path length.
1626                  */
1627                 rplen = dnp->n_rplen;
1628                 ASSERT(rplen > 0);
1629                 while (--rplen >= 0) {
1630                         if (dnp->n_rpath[rplen] == '\\')
1631                                 break;
1632                 }
1633                 if (rplen <= 0) {
1634                         /* Found our way to the root. */
1635                         vp = SMBTOV(smi->smi_root);
1636                         VN_HOLD(vp);
1637                         *vpp = vp;
1638                         return (0);
1639                 }
1640                 np = smbfs_node_findcreate(smi,
1641                     dnp->n_rpath, rplen, NULL, 0, 0,
1642                     &smbfs_fattr0); /* force create */
1643                 ASSERT(np != NULL);
1644                 vp = SMBTOV(np);
1645                 vp->v_type = VDIR;
1646 
1647                 /* Success! */
1648                 *vpp = vp;
1649                 return (0);
1650         }
1651 
1652         /*
1653          * Normal lookup of a name under this directory.
1654          * Note we handled "", ".", ".." above.
1655          */
1656         if (cache_ok) {
1657                 /*
1658                  * The caller indicated that it's OK to use a
1659                  * cached result for this lookup, so try to
1660                  * reclaim a node from the smbfs node cache.
1661                  */
1662                 error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1663                 if (error)
1664                         return (error);
1665                 if (vp != NULL) {
1666                         /* hold taken in lookup_cache */
1667                         *vpp = vp;
1668                         return (0);
1669                 }
1670         }
1671 
1672         /*
1673          * OK, go over-the-wire to get the attributes,
1674          * then create the node.
1675          */
1676         smb_credinit(&scred, cr);
1677         /* Note: this can allocate a new "name" */
1678         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1679         smb_credrele(&scred);
1680         if (error == ENOTDIR) {
1681                 /*
1682                  * Lookup failed because this directory was
1683                  * removed or renamed by another client.
1684                  * Remove any cached attributes under it.
1685                  */
1686                 smbfs_attrcache_remove(dnp);
1687                 smbfs_attrcache_prune(dnp);
1688         }
1689         if (error)
1690                 goto out;
1691 
1692         error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1693         if (error)
1694                 goto out;
1695 
1696         /* Success! */
1697         *vpp = vp;
1698 
1699 out:
1700         /* smbfs_smb_lookup may have allocated name. */
1701         if (name != nm)
1702                 smbfs_name_free(name, nmlen);
1703 
1704         return (error);
1705 }
1706 
1707 /*
1708  * smbfslookup_cache
1709  *
1710  * Try to reclaim a node from the smbfs node cache.
1711  * Some statistics for DEBUG.
1712  *
1713  * This mechanism lets us avoid many of the five (or more)
1714  * OtW lookup calls per file seen with "ls -l" if we search
1715  * the smbfs node cache for recently inactive(ated) nodes.
1716  */
1717 #ifdef DEBUG
1718 int smbfs_lookup_cache_calls = 0;
1719 int smbfs_lookup_cache_error = 0;
1720 int smbfs_lookup_cache_miss = 0;
1721 int smbfs_lookup_cache_stale = 0;
1722 int smbfs_lookup_cache_hits = 0;
1723 #endif /* DEBUG */
1724 
1725 /* ARGSUSED */
1726 static int
1727 smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1728         vnode_t **vpp, cred_t *cr)
1729 {
1730         struct vattr va;
1731         smbnode_t *dnp;
1732         smbnode_t *np;
1733         vnode_t *vp;
1734         int error;
1735         char sep;
1736 
1737         dnp = VTOSMB(dvp);
1738         *vpp = NULL;
1739 
1740 #ifdef DEBUG
1741         smbfs_lookup_cache_calls++;
1742 #endif
1743 
1744         /*
1745          * First make sure we can get attributes for the
1746          * directory.  Cached attributes are OK here.
1747          * If we removed or renamed the directory, this
1748          * will return ENOENT.  If someone else removed
1749          * this directory or file, we'll find out when we
1750          * try to open or get attributes.
1751          */
1752         va.va_mask = AT_TYPE | AT_MODE;
1753         error = smbfsgetattr(dvp, &va, cr);
1754         if (error) {
1755 #ifdef DEBUG
1756                 smbfs_lookup_cache_error++;
1757 #endif
1758                 return (error);
1759         }
1760 
1761         /*
1762          * Passing NULL smbfattr here so we will
1763          * just look, not create.
1764          */
1765         sep = SMBFS_DNP_SEP(dnp);
1766         np = smbfs_node_findcreate(dnp->n_mount,
1767             dnp->n_rpath, dnp->n_rplen,
1768             nm, nmlen, sep, NULL);
1769         if (np == NULL) {
1770 #ifdef DEBUG
1771                 smbfs_lookup_cache_miss++;
1772 #endif
1773                 return (0);
1774         }
1775 
1776         /*
1777          * Found it.  Attributes still valid?
1778          */
1779         vp = SMBTOV(np);
1780         if (np->r_attrtime <= gethrtime()) {
1781                 /* stale */
1782 #ifdef DEBUG
1783                 smbfs_lookup_cache_stale++;
1784 #endif
1785                 VN_RELE(vp);
1786                 return (0);
1787         }
1788 
1789         /*
1790          * Success!
1791          * Caller gets hold from smbfs_node_findcreate
1792          */
1793 #ifdef DEBUG
1794         smbfs_lookup_cache_hits++;
1795 #endif
1796         *vpp = vp;
1797         return (0);
1798 }
1799 
1800 /*
1801  * XXX
1802  * vsecattr_t is new to build 77, and we need to eventually support
1803  * it in order to create an ACL when an object is created.
1804  *
1805  * This op should support the new FIGNORECASE flag for case-insensitive
1806  * lookups, per PSARC 2007/244.
1807  */
1808 /* ARGSUSED */
1809 static int
1810 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1811         int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1812         vsecattr_t *vsecp)
1813 {
1814         int             error;
1815         int             cerror;
1816         vfs_t           *vfsp;
1817         vnode_t         *vp;
1818 #ifdef NOT_YET
1819         smbnode_t       *np;
1820 #endif
1821         smbnode_t       *dnp;
1822         smbmntinfo_t    *smi;
1823         struct vattr    vattr;
1824         struct smbfattr fattr;
1825         struct smb_cred scred;
1826         const char *name = (const char *)nm;
1827         int             nmlen = strlen(nm);
1828         uint32_t        disp;
1829         uint16_t        fid;
1830         int             xattr;
1831 
1832         vfsp = dvp->v_vfsp;
1833         smi = VFTOSMI(vfsp);
1834         dnp = VTOSMB(dvp);
1835         vp = NULL;
1836 
1837         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1838                 return (EPERM);
1839 
1840         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1841                 return (EIO);
1842 
1843         /*
1844          * Note: this may break mknod(2) calls to create a directory,
1845          * but that's obscure use.  Some other filesystems do this.
1846          * XXX: Later, redirect VDIR type here to _mkdir.
1847          */
1848         if (va->va_type != VREG)
1849                 return (EINVAL);
1850 
1851         /*
1852          * If the pathname is "", just use dvp, no checks.
1853          * Do this outside of the rwlock (like zfs).
1854          */
1855         if (nmlen == 0) {
1856                 VN_HOLD(dvp);
1857                 *vpp = dvp;
1858                 return (0);
1859         }
1860 
1861         /* Don't allow "." or ".." through here. */
1862         if ((nmlen == 1 && name[0] == '.') ||
1863             (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1864                 return (EISDIR);
1865 
1866         /*
1867          * We make a copy of the attributes because the caller does not
1868          * expect us to change what va points to.
1869          */
1870         vattr = *va;
1871 
1872         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1873                 return (EINTR);
1874         smb_credinit(&scred, cr);
1875 
1876         /*
1877          * XXX: Do we need r_lkserlock too?
1878          * No use of any shared fid or fctx...
1879          */
1880 
1881         /*
1882          * NFS needs to go over the wire, just to be sure whether the
1883          * file exists or not.  Using a cached result is dangerous in
1884          * this case when making a decision regarding existence.
1885          *
1886          * The SMB protocol does NOT really need to go OTW here
1887          * thanks to the expressive NTCREATE disposition values.
1888          * Unfortunately, to do Unix access checks correctly,
1889          * we need to know if the object already exists.
1890          * When the object does not exist, we need VWRITE on
1891          * the directory.  Note: smbfslookup() checks VEXEC.
1892          */
1893         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1894         if (error == 0) {
1895                 /*
1896                  * The file already exists.  Error?
1897                  * NB: have a hold from smbfslookup
1898                  */
1899                 if (exclusive == EXCL) {
1900                         error = EEXIST;
1901                         VN_RELE(vp);
1902                         goto out;
1903                 }
1904                 /*
1905                  * Verify requested access.
1906                  */
1907                 error = smbfs_access(vp, mode, 0, cr, ct);
1908                 if (error) {
1909                         VN_RELE(vp);
1910                         goto out;
1911                 }
1912 
1913                 /*
1914                  * Truncate (if requested).
1915                  */
1916                 if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1917                         vattr.va_mask = AT_SIZE;
1918                         error = smbfssetattr(vp, &vattr, 0, cr);
1919                         if (error) {
1920                                 VN_RELE(vp);
1921                                 goto out;
1922                         }
1923                 }
1924                 /* Success! */
1925 #ifdef NOT_YET
1926                 vnevent_create(vp, ct);
1927 #endif
1928                 *vpp = vp;
1929                 goto out;
1930         }
1931 
1932         /*
1933          * The file did not exist.  Need VWRITE in the directory.
1934          */
1935         error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1936         if (error)
1937                 goto out;
1938 
1939         /*
1940          * Now things get tricky.  We also need to check the
1941          * requested open mode against the file we may create.
1942          * See comments at smbfs_access_rwx
1943          */
1944         error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1945         if (error)
1946                 goto out;
1947 
1948         /*
1949          * Now the code derived from Darwin,
1950          * but with greater use of NT_CREATE
1951          * disposition options.  Much changed.
1952          *
1953          * Create (or open) a new child node.
1954          * Note we handled "." and ".." above.
1955          */
1956 
1957         if (exclusive == EXCL)
1958                 disp = NTCREATEX_DISP_CREATE;
1959         else {
1960                 /* Truncate regular files if requested. */
1961                 if ((va->va_type == VREG) &&
1962                     (va->va_mask & AT_SIZE) &&
1963                     (va->va_size == 0))
1964                         disp = NTCREATEX_DISP_OVERWRITE_IF;
1965                 else
1966                         disp = NTCREATEX_DISP_OPEN_IF;
1967         }
1968         xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1969         error = smbfs_smb_create(dnp,
1970             name, nmlen, xattr,
1971             disp, &scred, &fid);
1972         if (error)
1973                 goto out;
1974 
1975         /*
1976          * XXX: Missing some code here to deal with
1977          * the case where we opened an existing file,
1978          * it's size is larger than 32-bits, and we're
1979          * setting the size from a process that's not
1980          * aware of large file offsets.  i.e.
1981          * from the NFS3 code:
1982          */
1983 #if NOT_YET /* XXX */
1984         if ((vattr.va_mask & AT_SIZE) &&
1985             vp->v_type == VREG) {
1986                 np = VTOSMB(vp);
1987                 /*
1988                  * Check here for large file handled
1989                  * by LF-unaware process (as
1990                  * ufs_create() does)
1991                  */
1992                 if (!(lfaware & FOFFMAX)) {
1993                         mutex_enter(&np->r_statelock);
1994                         if (np->r_size > MAXOFF32_T)
1995                                 error = EOVERFLOW;
1996                         mutex_exit(&np->r_statelock);
1997                 }
1998                 if (!error) {
1999                         vattr.va_mask = AT_SIZE;
2000                         error = smbfssetattr(vp,
2001                             &vattr, 0, cr);
2002                 }
2003         }
2004 #endif /* XXX */
2005         /*
2006          * Should use the fid to get/set the size
2007          * while we have it opened here.  See above.
2008          */
2009 
2010         cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
2011         if (cerror)
2012                 SMBVDEBUG("error %d closing %s\\%s\n",
2013                     cerror, dnp->n_rpath, name);
2014 
2015         /*
2016          * In the open case, the name may differ a little
2017          * from what we passed to create (case, etc.)
2018          * so call lookup to get the (opened) name.
2019          *
2020          * XXX: Could avoid this extra lookup if the
2021          * "createact" result from NT_CREATE says we
2022          * created the object.
2023          */
2024         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2025         if (error)
2026                 goto out;
2027 
2028         /* update attr and directory cache */
2029         smbfs_attr_touchdir(dnp);
2030 
2031         error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2032         if (error)
2033                 goto out;
2034 
2035         /* XXX invalidate pages if we truncated? */
2036 
2037         /* Success! */
2038         *vpp = vp;
2039         error = 0;
2040 
2041 out:
2042         smb_credrele(&scred);
2043         smbfs_rw_exit(&dnp->r_rwlock);
2044         if (name != nm)
2045                 smbfs_name_free(name, nmlen);
2046         return (error);
2047 }
2048 
2049 /*
2050  * XXX
2051  * This op should support the new FIGNORECASE flag for case-insensitive
2052  * lookups, per PSARC 2007/244.
2053  */
2054 /* ARGSUSED */
2055 static int
2056 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
2057         int flags)
2058 {
2059         int             error;
2060         vnode_t         *vp;
2061         smbnode_t       *np;
2062         smbnode_t       *dnp;
2063         struct smb_cred scred;
2064         /* enum smbfsstat status; */
2065         smbmntinfo_t    *smi;
2066 
2067         smi = VTOSMI(dvp);
2068 
2069         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2070                 return (EPERM);
2071 
2072         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2073                 return (EIO);
2074 
2075         dnp = VTOSMB(dvp);
2076         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2077                 return (EINTR);
2078         smb_credinit(&scred, cr);
2079 
2080         /*
2081          * Verify access to the dirctory.
2082          */
2083         error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2084         if (error)
2085                 goto out;
2086 
2087         /*
2088          * NOTE:  the darwin code gets the "vp" passed in so it looks
2089          * like the "vp" has probably been "lookup"ed by the VFS layer.
2090          * It looks like we will need to lookup the vp to check the
2091          * caches and check if the object being deleted is a directory.
2092          */
2093         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2094         if (error)
2095                 goto out;
2096 
2097         /* Never allow link/unlink directories on CIFS. */
2098         if (vp->v_type == VDIR) {
2099                 VN_RELE(vp);
2100                 error = EPERM;
2101                 goto out;
2102         }
2103 
2104         /*
2105          * Now we have the real reference count on the vnode
2106          * Do we have the file open?
2107          */
2108         np = VTOSMB(vp);
2109         mutex_enter(&np->r_statelock);
2110         if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2111                 /*
2112                  * NFS does a rename on remove here.
2113                  * Probably not applicable for SMB.
2114                  * Like Darwin, just return EBUSY.
2115                  *
2116                  * XXX: Todo - Use Trans2rename, and
2117                  * if that fails, ask the server to
2118                  * set the delete-on-close flag.
2119                  */
2120                 mutex_exit(&np->r_statelock);
2121                 error = EBUSY;
2122         } else {
2123                 smbfs_attrcache_rm_locked(np);
2124                 mutex_exit(&np->r_statelock);
2125 
2126                 error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
2127 
2128                 /*
2129                  * If the file should no longer exist, discard
2130                  * any cached attributes under this node.
2131                  */
2132                 switch (error) {
2133                 case 0:
2134                 case ENOENT:
2135                 case ENOTDIR:
2136                         smbfs_attrcache_prune(np);
2137                         break;
2138                 }
2139         }
2140 
2141         VN_RELE(vp);
2142 
2143 out:
2144         smb_credrele(&scred);
2145         smbfs_rw_exit(&dnp->r_rwlock);
2146 
2147         return (error);
2148 }
2149 
2150 
2151 /*
2152  * XXX
2153  * This op should support the new FIGNORECASE flag for case-insensitive
2154  * lookups, per PSARC 2007/244.
2155  */
2156 /* ARGSUSED */
2157 static int
2158 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2159         caller_context_t *ct, int flags)
2160 {
2161         /* vnode_t              *realvp; */
2162 
2163         if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2164             curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2165                 return (EPERM);
2166 
2167         if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2168             VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2169             odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2170             ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2171                 return (EIO);
2172 
2173         return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
2174 }
2175 
2176 /*
2177  * smbfsrename does the real work of renaming in SMBFS
2178  */
2179 /* ARGSUSED */
2180 static int
2181 smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2182         caller_context_t *ct)
2183 {
2184         int             error;
2185         int             nvp_locked = 0;
2186         vnode_t         *nvp = NULL;
2187         vnode_t         *ovp = NULL;
2188         smbnode_t       *onp;
2189         smbnode_t       *nnp;
2190         smbnode_t       *odnp;
2191         smbnode_t       *ndnp;
2192         struct smb_cred scred;
2193         /* enum smbfsstat       status; */
2194 
2195         ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2196 
2197         if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2198             strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2199                 return (EINVAL);
2200 
2201         /*
2202          * Check that everything is on the same filesystem.
2203          * vn_rename checks the fsid's, but in case we don't
2204          * fill those in correctly, check here too.
2205          */
2206         if (odvp->v_vfsp != ndvp->v_vfsp)
2207                 return (EXDEV);
2208 
2209         odnp = VTOSMB(odvp);
2210         ndnp = VTOSMB(ndvp);
2211 
2212         /*
2213          * Avoid deadlock here on old vs new directory nodes
2214          * by always taking the locks in order of address.
2215          * The order is arbitrary, but must be consistent.
2216          */
2217         if (odnp < ndnp) {
2218                 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2219                     SMBINTR(odvp)))
2220                         return (EINTR);
2221                 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2222                     SMBINTR(ndvp))) {
2223                         smbfs_rw_exit(&odnp->r_rwlock);
2224                         return (EINTR);
2225                 }
2226         } else {
2227                 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2228                     SMBINTR(ndvp)))
2229                         return (EINTR);
2230                 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2231                     SMBINTR(odvp))) {
2232                         smbfs_rw_exit(&ndnp->r_rwlock);
2233                         return (EINTR);
2234                 }
2235         }
2236         smb_credinit(&scred, cr);
2237         /*
2238          * No returns after this point (goto out)
2239          */
2240 
2241         /*
2242          * Need write access on source and target.
2243          * Server takes care of most checks.
2244          */
2245         error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2246         if (error)
2247                 goto out;
2248         if (odvp != ndvp) {
2249                 error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2250                 if (error)
2251                         goto out;
2252         }
2253 
2254         /*
2255          * Lookup the source name.  Must already exist.
2256          */
2257         error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2258         if (error)
2259                 goto out;
2260 
2261         /*
2262          * Lookup the target file.  If it exists, it needs to be
2263          * checked to see whether it is a mount point and whether
2264          * it is active (open).
2265          */
2266         error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
2267         if (!error) {
2268                 /*
2269                  * Target (nvp) already exists.  Check that it
2270                  * has the same type as the source.  The server
2271                  * will check this also, (and more reliably) but
2272                  * this lets us return the correct error codes.
2273                  */
2274                 if (ovp->v_type == VDIR) {
2275                         if (nvp->v_type != VDIR) {
2276                                 error = ENOTDIR;
2277                                 goto out;
2278                         }
2279                 } else {
2280                         if (nvp->v_type == VDIR) {
2281                                 error = EISDIR;
2282                                 goto out;
2283                         }
2284                 }
2285 
2286                 /*
2287                  * POSIX dictates that when the source and target
2288                  * entries refer to the same file object, rename
2289                  * must do nothing and exit without error.
2290                  */
2291                 if (ovp == nvp) {
2292                         error = 0;
2293                         goto out;
2294                 }
2295 
2296                 /*
2297                  * Also must ensure the target is not a mount point,
2298                  * and keep mount/umount away until we're done.
2299                  */
2300                 if (vn_vfsrlock(nvp)) {
2301                         error = EBUSY;
2302                         goto out;
2303                 }
2304                 nvp_locked = 1;
2305                 if (vn_mountedvfs(nvp) != NULL) {
2306                         error = EBUSY;
2307                         goto out;
2308                 }
2309 
2310                 /*
2311                  * CIFS gives a SHARING_VIOLATION error when
2312                  * trying to rename onto an exising object,
2313                  * so try to remove the target first.
2314                  * (Only for files, not directories.)
2315                  */
2316                 if (nvp->v_type == VDIR) {
2317                         error = EEXIST;
2318                         goto out;
2319                 }
2320 
2321                 /*
2322                  * Nodes that are "not active" here have v_count=2
2323                  * because vn_renameat (our caller) did a lookup on
2324                  * both the source and target before this call.
2325                  * Otherwise this similar to smbfs_remove.
2326                  */
2327                 nnp = VTOSMB(nvp);
2328                 mutex_enter(&nnp->r_statelock);
2329                 if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) {
2330                         /*
2331                          * The target file exists, is not the same as
2332                          * the source file, and is active.  Other FS
2333                          * implementations unlink the target here.
2334                          * For SMB, we don't assume we can remove an
2335                          * open file.  Return an error instead.
2336                          */
2337                         mutex_exit(&nnp->r_statelock);
2338                         error = EBUSY;
2339                         goto out;
2340                 }
2341 
2342                 /*
2343                  * Target file is not active. Try to remove it.
2344                  */
2345                 smbfs_attrcache_rm_locked(nnp);
2346                 mutex_exit(&nnp->r_statelock);
2347 
2348                 error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
2349 
2350                 /*
2351                  * Similar to smbfs_remove
2352                  */
2353                 switch (error) {
2354                 case 0:
2355                 case ENOENT:
2356                 case ENOTDIR:
2357                         smbfs_attrcache_prune(nnp);
2358                         break;
2359                 }
2360 
2361                 if (error)
2362                         goto out;
2363                 /*
2364                  * OK, removed the target file.  Continue as if
2365                  * lookup target had failed (nvp == NULL).
2366                  */
2367                 vn_vfsunlock(nvp);
2368                 nvp_locked = 0;
2369                 VN_RELE(nvp);
2370                 nvp = NULL;
2371         } /* nvp */
2372 
2373         onp = VTOSMB(ovp);
2374         smbfs_attrcache_remove(onp);
2375 
2376         error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
2377 
2378         /*
2379          * If the old name should no longer exist,
2380          * discard any cached attributes under it.
2381          */
2382         if (error == 0)
2383                 smbfs_attrcache_prune(onp);
2384 
2385 out:
2386         if (nvp) {
2387                 if (nvp_locked)
2388                         vn_vfsunlock(nvp);
2389                 VN_RELE(nvp);
2390         }
2391         if (ovp)
2392                 VN_RELE(ovp);
2393 
2394         smb_credrele(&scred);
2395         smbfs_rw_exit(&odnp->r_rwlock);
2396         smbfs_rw_exit(&ndnp->r_rwlock);
2397 
2398         return (error);
2399 }
2400 
2401 /*
2402  * XXX
2403  * vsecattr_t is new to build 77, and we need to eventually support
2404  * it in order to create an ACL when an object is created.
2405  *
2406  * This op should support the new FIGNORECASE flag for case-insensitive
2407  * lookups, per PSARC 2007/244.
2408  */
2409 /* ARGSUSED */
2410 static int
2411 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2412         cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2413 {
2414         vnode_t         *vp;
2415         struct smbnode  *dnp = VTOSMB(dvp);
2416         struct smbmntinfo *smi = VTOSMI(dvp);
2417         struct smb_cred scred;
2418         struct smbfattr fattr;
2419         const char              *name = (const char *) nm;
2420         int             nmlen = strlen(name);
2421         int             error, hiderr;
2422 
2423         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2424                 return (EPERM);
2425 
2426         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2427                 return (EIO);
2428 
2429         if ((nmlen == 1 && name[0] == '.') ||
2430             (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2431                 return (EEXIST);
2432 
2433         /* Only plain files are allowed in V_XATTRDIR. */
2434         if (dvp->v_flag & V_XATTRDIR)
2435                 return (EINVAL);
2436 
2437         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2438                 return (EINTR);
2439         smb_credinit(&scred, cr);
2440 
2441         /*
2442          * XXX: Do we need r_lkserlock too?
2443          * No use of any shared fid or fctx...
2444          */
2445 
2446         /*
2447          * Require write access in the containing directory.
2448          */
2449         error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2450         if (error)
2451                 goto out;
2452 
2453         error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2454         if (error)
2455                 goto out;
2456 
2457         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2458         if (error)
2459                 goto out;
2460 
2461         smbfs_attr_touchdir(dnp);
2462 
2463         error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2464         if (error)
2465                 goto out;
2466 
2467         if (name[0] == '.')
2468                 if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2469                         SMBVDEBUG("hide failure %d\n", hiderr);
2470 
2471         /* Success! */
2472         *vpp = vp;
2473         error = 0;
2474 out:
2475         smb_credrele(&scred);
2476         smbfs_rw_exit(&dnp->r_rwlock);
2477 
2478         if (name != nm)
2479                 smbfs_name_free(name, nmlen);
2480 
2481         return (error);
2482 }
2483 
2484 /*
2485  * XXX
2486  * This op should support the new FIGNORECASE flag for case-insensitive
2487  * lookups, per PSARC 2007/244.
2488  */
2489 /* ARGSUSED */
2490 static int
2491 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2492         caller_context_t *ct, int flags)
2493 {
2494         vnode_t         *vp = NULL;
2495         int             vp_locked = 0;
2496         struct smbmntinfo *smi = VTOSMI(dvp);
2497         struct smbnode  *dnp = VTOSMB(dvp);
2498         struct smbnode  *np;
2499         struct smb_cred scred;
2500         int             error;
2501 
2502         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2503                 return (EPERM);
2504 
2505         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2506                 return (EIO);
2507 
2508         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2509                 return (EINTR);
2510         smb_credinit(&scred, cr);
2511 
2512         /*
2513          * Require w/x access in the containing directory.
2514          * Server handles all other access checks.
2515          */
2516         error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2517         if (error)
2518                 goto out;
2519 
2520         /*
2521          * First lookup the entry to be removed.
2522          */
2523         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2524         if (error)
2525                 goto out;
2526         np = VTOSMB(vp);
2527 
2528         /*
2529          * Disallow rmdir of "." or current dir, or the FS root.
2530          * Also make sure it's a directory, not a mount point,
2531          * and lock to keep mount/umount away until we're done.
2532          */
2533         if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2534                 error = EINVAL;
2535                 goto out;
2536         }
2537         if (vp->v_type != VDIR) {
2538                 error = ENOTDIR;
2539                 goto out;
2540         }
2541         if (vn_vfsrlock(vp)) {
2542                 error = EBUSY;
2543                 goto out;
2544         }
2545         vp_locked = 1;
2546         if (vn_mountedvfs(vp) != NULL) {
2547                 error = EBUSY;
2548                 goto out;
2549         }
2550 
2551         smbfs_attrcache_remove(np);
2552         error = smbfs_smb_rmdir(np, &scred);
2553 
2554         /*
2555          * Similar to smbfs_remove
2556          */
2557         switch (error) {
2558         case 0:
2559         case ENOENT:
2560         case ENOTDIR:
2561                 smbfs_attrcache_prune(np);
2562                 break;
2563         }
2564 
2565         if (error)
2566                 goto out;
2567 
2568         mutex_enter(&np->r_statelock);
2569         dnp->n_flag |= NMODIFIED;
2570         mutex_exit(&np->r_statelock);
2571         smbfs_attr_touchdir(dnp);
2572         smbfs_rmhash(np);
2573 
2574 out:
2575         if (vp) {
2576                 if (vp_locked)
2577                         vn_vfsunlock(vp);
2578                 VN_RELE(vp);
2579         }
2580         smb_credrele(&scred);
2581         smbfs_rw_exit(&dnp->r_rwlock);
2582 
2583         return (error);
2584 }
2585 
2586 
2587 /* ARGSUSED */
2588 static int
2589 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2590         caller_context_t *ct, int flags)
2591 {
2592         struct smbnode  *np = VTOSMB(vp);
2593         int             error = 0;
2594         smbmntinfo_t    *smi;
2595 
2596         smi = VTOSMI(vp);
2597 
2598         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2599                 return (EIO);
2600 
2601         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2602                 return (EIO);
2603 
2604         /*
2605          * Require read access in the directory.
2606          */
2607         error = smbfs_access(vp, VREAD, 0, cr, ct);
2608         if (error)
2609                 return (error);
2610 
2611         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2612 
2613         /*
2614          * XXX: Todo readdir cache here
2615          * Note: NFS code is just below this.
2616          *
2617          * I am serializing the entire readdir opreation
2618          * now since we have not yet implemented readdir
2619          * cache. This fix needs to be revisited once
2620          * we implement readdir cache.
2621          */
2622         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2623                 return (EINTR);
2624 
2625         error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2626 
2627         smbfs_rw_exit(&np->r_lkserlock);
2628 
2629         return (error);
2630 }
2631 
2632 /* ARGSUSED */
2633 static int
2634 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2635         caller_context_t *ct)
2636 {
2637         /*
2638          * Note: "limit" tells the SMB-level FindFirst/FindNext
2639          * functions how many directory entries to request in
2640          * each OtW call.  It needs to be large enough so that
2641          * we don't make lots of tiny OtW requests, but there's
2642          * no point making it larger than the maximum number of
2643          * OtW entries that would fit in a maximum sized trans2
2644          * response (64k / 48).  Beyond that, it's just tuning.
2645          * WinNT used 512, Win2k used 1366.  We use 1000.
2646          */
2647         static const int limit = 1000;
2648         /* Largest possible dirent size. */
2649         static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2650         struct smb_cred scred;
2651         vnode_t         *newvp;
2652         struct smbnode  *np = VTOSMB(vp);
2653         struct smbfs_fctx *ctx;
2654         struct dirent64 *dp;
2655         ssize_t         save_resid;
2656         offset_t        save_offset; /* 64 bits */
2657         int             offset; /* yes, 32 bits */
2658         int             nmlen, error;
2659         ushort_t        reclen;
2660 
2661         ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2662 
2663         /* Make sure we serialize for n_dirseq use. */
2664         ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2665 
2666         /*
2667          * Make sure smbfs_open filled in n_dirseq
2668          */
2669         if (np->n_dirseq == NULL)
2670                 return (EBADF);
2671 
2672         /* Check for overflow of (32-bit) directory offset. */
2673         if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2674             (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2675                 return (EINVAL);
2676 
2677         /* Require space for at least one dirent. */
2678         if (uio->uio_resid < dbufsiz)
2679                 return (EINVAL);
2680 
2681         SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2682         smb_credinit(&scred, cr);
2683         dp = kmem_alloc(dbufsiz, KM_SLEEP);
2684 
2685         save_resid = uio->uio_resid;
2686         save_offset = uio->uio_loffset;
2687         offset = uio->uio_offset;
2688         SMBVDEBUG("in: offset=%d, resid=%d\n",
2689             (int)uio->uio_offset, (int)uio->uio_resid);
2690         error = 0;
2691 
2692         /*
2693          * Generate the "." and ".." entries here so we can
2694          * (1) make sure they appear (but only once), and
2695          * (2) deal with getting their I numbers which the
2696          * findnext below does only for normal names.
2697          */
2698         while (offset < FIRST_DIROFS) {
2699                 /*
2700                  * Tricky bit filling in the first two:
2701                  * offset 0 is ".", offset 1 is ".."
2702                  * so strlen of these is offset+1.
2703                  */
2704                 reclen = DIRENT64_RECLEN(offset + 1);
2705                 if (uio->uio_resid < reclen)
2706                         goto out;
2707                 bzero(dp, reclen);
2708                 dp->d_reclen = reclen;
2709                 dp->d_name[0] = '.';
2710                 dp->d_name[1] = '.';
2711                 dp->d_name[offset + 1] = '\0';
2712                 /*
2713                  * Want the real I-numbers for the "." and ".."
2714                  * entries.  For these two names, we know that
2715                  * smbfslookup can get the nodes efficiently.
2716                  */
2717                 error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2718                 if (error) {
2719                         dp->d_ino = np->n_ino + offset; /* fiction */
2720                 } else {
2721                         dp->d_ino = VTOSMB(newvp)->n_ino;
2722                         VN_RELE(newvp);
2723                 }
2724                 /*
2725                  * Note: d_off is the offset that a user-level program
2726                  * should seek to for reading the NEXT directory entry.
2727                  * See libc: readdir, telldir, seekdir
2728                  */
2729                 dp->d_off = offset + 1;
2730                 error = uiomove(dp, reclen, UIO_READ, uio);
2731                 if (error)
2732                         goto out;
2733                 /*
2734                  * Note: uiomove updates uio->uio_offset,
2735                  * but we want it to be our "cookie" value,
2736                  * which just counts dirents ignoring size.
2737                  */
2738                 uio->uio_offset = ++offset;
2739         }
2740 
2741         /*
2742          * If there was a backward seek, we have to reopen.
2743          */
2744         if (offset < np->n_dirofs) {
2745                 SMBVDEBUG("Reopening search %d:%d\n",
2746                     offset, np->n_dirofs);
2747                 error = smbfs_smb_findopen(np, "*", 1,
2748                     SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2749                     &scred, &ctx);
2750                 if (error) {
2751                         SMBVDEBUG("can not open search, error = %d", error);
2752                         goto out;
2753                 }
2754                 /* free the old one */
2755                 (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2756                 /* save the new one */
2757                 np->n_dirseq = ctx;
2758                 np->n_dirofs = FIRST_DIROFS;
2759         } else {
2760                 ctx = np->n_dirseq;
2761         }
2762 
2763         /*
2764          * Skip entries before the requested offset.
2765          */
2766         while (np->n_dirofs < offset) {
2767                 error = smbfs_smb_findnext(ctx, limit, &scred);
2768                 if (error != 0)
2769                         goto out;
2770                 np->n_dirofs++;
2771         }
2772 
2773         /*
2774          * While there's room in the caller's buffer:
2775          *      get a directory entry from SMB,
2776          *      convert to a dirent, copyout.
2777          * We stop when there is no longer room for a
2778          * maximum sized dirent because we must decide
2779          * before we know anything about the next entry.
2780          */
2781         while (uio->uio_resid >= dbufsiz) {
2782                 error = smbfs_smb_findnext(ctx, limit, &scred);
2783                 if (error != 0)
2784                         goto out;
2785                 np->n_dirofs++;
2786 
2787                 /* Sanity check the name length. */
2788                 nmlen = ctx->f_nmlen;
2789                 if (nmlen > SMB_MAXFNAMELEN) {
2790                         nmlen = SMB_MAXFNAMELEN;
2791                         SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2792                 }
2793                 if (smbfs_fastlookup) {
2794                         /* See comment at smbfs_fastlookup above. */
2795                         if (smbfs_nget(vp, ctx->f_name, nmlen,
2796                             &ctx->f_attr, &newvp) == 0)
2797                                 VN_RELE(newvp);
2798                 }
2799 
2800                 reclen = DIRENT64_RECLEN(nmlen);
2801                 bzero(dp, reclen);
2802                 dp->d_reclen = reclen;
2803                 bcopy(ctx->f_name, dp->d_name, nmlen);
2804                 dp->d_name[nmlen] = '\0';
2805                 dp->d_ino = ctx->f_inum;
2806                 dp->d_off = offset + 1;      /* See d_off comment above */
2807                 error = uiomove(dp, reclen, UIO_READ, uio);
2808                 if (error)
2809                         goto out;
2810                 /* See comment re. uio_offset above. */
2811                 uio->uio_offset = ++offset;
2812         }
2813 
2814 out:
2815         /*
2816          * When we come to the end of a directory, the
2817          * SMB-level functions return ENOENT, but the
2818          * caller is not expecting an error return.
2819          *
2820          * Also note that we must delay the call to
2821          * smbfs_smb_findclose(np->n_dirseq, ...)
2822          * until smbfs_close so that all reads at the
2823          * end of the directory will return no data.
2824          */
2825         if (error == ENOENT) {
2826                 error = 0;
2827                 if (eofp)
2828                         *eofp = 1;
2829         }
2830         /*
2831          * If we encountered an error (i.e. "access denied")
2832          * from the FindFirst call, we will have copied out
2833          * the "." and ".." entries leaving offset == 2.
2834          * In that case, restore the original offset/resid
2835          * so the caller gets no data with the error.
2836          */
2837         if (error != 0 && offset == FIRST_DIROFS) {
2838                 uio->uio_loffset = save_offset;
2839                 uio->uio_resid = save_resid;
2840         }
2841         SMBVDEBUG("out: offset=%d, resid=%d\n",
2842             (int)uio->uio_offset, (int)uio->uio_resid);
2843 
2844         kmem_free(dp, dbufsiz);
2845         smb_credrele(&scred);
2846         return (error);
2847 }
2848 
2849 
2850 /*
2851  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2852  * are optional functions that are called by:
2853  *    getdents, before/after VOP_READDIR
2854  *    pread, before/after ... VOP_READ
2855  *    pwrite, before/after ... VOP_WRITE
2856  *    (other places)
2857  *
2858  * Careful here: None of the above check for any
2859  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2860  * In fact, the return value from _rwlock is NOT
2861  * an error code, but V_WRITELOCK_TRUE / _FALSE.
2862  *
2863  * Therefore, it's up to _this_ code to make sure
2864  * the lock state remains balanced, which means
2865  * we can't "bail out" on interrupts, etc.
2866  */
2867 
2868 /* ARGSUSED2 */
2869 static int
2870 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2871 {
2872         smbnode_t       *np = VTOSMB(vp);
2873 
2874         if (!write_lock) {
2875                 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2876                 return (V_WRITELOCK_FALSE);
2877         }
2878 
2879 
2880         (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2881         return (V_WRITELOCK_TRUE);
2882 }
2883 
2884 /* ARGSUSED */
2885 static void
2886 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2887 {
2888         smbnode_t       *np = VTOSMB(vp);
2889 
2890         smbfs_rw_exit(&np->r_rwlock);
2891 }
2892 
2893 
2894 /* ARGSUSED */
2895 static int
2896 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2897 {
2898         smbmntinfo_t    *smi;
2899 
2900         smi = VTOSMI(vp);
2901 
2902         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2903                 return (EPERM);
2904 
2905         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2906                 return (EIO);
2907 
2908         /*
2909          * Because we stuff the readdir cookie into the offset field
2910          * someone may attempt to do an lseek with the cookie which
2911          * we want to succeed.
2912          */
2913         if (vp->v_type == VDIR)
2914                 return (0);
2915 
2916         /* Like NFS3, just check for 63-bit overflow. */
2917         if (*noffp < 0)
2918                 return (EINVAL);
2919 
2920         return (0);
2921 }
2922 
2923 
2924 /*
2925  * XXX
2926  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2927  */
2928 static int
2929 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2930         offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2931         caller_context_t *ct)
2932 {
2933         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2934                 return (EIO);
2935 
2936         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2937                 return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2938         else
2939                 return (ENOSYS);
2940 }
2941 
2942 /*
2943  * Free storage space associated with the specified vnode.  The portion
2944  * to be freed is specified by bfp->l_start and bfp->l_len (already
2945  * normalized to a "whence" of 0).
2946  *
2947  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2948  */
2949 /* ARGSUSED */
2950 static int
2951 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2952         offset_t offset, cred_t *cr, caller_context_t *ct)
2953 {
2954         int             error;
2955         smbmntinfo_t    *smi;
2956 
2957         smi = VTOSMI(vp);
2958 
2959         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2960                 return (EIO);
2961 
2962         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2963                 return (EIO);
2964 
2965         /* Caller (fcntl) has checked v_type */
2966         ASSERT(vp->v_type == VREG);
2967         if (cmd != F_FREESP)
2968                 return (EINVAL);
2969 
2970         /*
2971          * Like NFS3, no 32-bit offset checks here.
2972          * Our SMB layer takes care to return EFBIG
2973          * when it has to fallback to a 32-bit call.
2974          */
2975 
2976         error = convoff(vp, bfp, 0, offset);
2977         if (!error) {
2978                 ASSERT(bfp->l_start >= 0);
2979                 if (bfp->l_len == 0) {
2980                         struct vattr va;
2981 
2982                         /*
2983                          * ftruncate should not change the ctime and
2984                          * mtime if we truncate the file to its
2985                          * previous size.
2986                          */
2987                         va.va_mask = AT_SIZE;
2988                         error = smbfsgetattr(vp, &va, cr);
2989                         if (error || va.va_size == bfp->l_start)
2990                                 return (error);
2991                         va.va_mask = AT_SIZE;
2992                         va.va_size = bfp->l_start;
2993                         error = smbfssetattr(vp, &va, 0, cr);
2994                 } else
2995                         error = EINVAL;
2996         }
2997 
2998         return (error);
2999 }
3000 
3001 /* ARGSUSED */
3002 static int
3003 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
3004         caller_context_t *ct)
3005 {
3006         vfs_t *vfs;
3007         smbmntinfo_t *smi;
3008         struct smb_share *ssp;
3009 
3010         vfs = vp->v_vfsp;
3011         smi = VFTOSMI(vfs);
3012 
3013         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3014                 return (EIO);
3015 
3016         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3017                 return (EIO);
3018 
3019         switch (cmd) {
3020         case _PC_FILESIZEBITS:
3021                 ssp = smi->smi_share;
3022                 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
3023                         *valp = 64;
3024                 else
3025                         *valp = 32;
3026                 break;
3027 
3028         case _PC_LINK_MAX:
3029                 /* We only ever report one link to an object */
3030                 *valp = 1;
3031                 break;
3032 
3033         case _PC_ACL_ENABLED:
3034                 /*
3035                  * Always indicate that ACLs are enabled and
3036                  * that we support ACE_T format, otherwise
3037                  * libsec will ask for ACLENT_T format data
3038                  * which we don't support.
3039                  */
3040                 *valp = _ACL_ACE_ENABLED;
3041                 break;
3042 
3043         case _PC_SYMLINK_MAX:   /* No symlinks until we do Unix extensions */
3044                 *valp = 0;
3045                 break;
3046 
3047         case _PC_XATTR_EXISTS:
3048                 if (vfs->vfs_flag & VFS_XATTR) {
3049                         *valp = smbfs_xa_exists(vp, cr);
3050                         break;
3051                 }
3052                 return (EINVAL);
3053 
3054         case _PC_SATTR_ENABLED:
3055         case _PC_SATTR_EXISTS:
3056                 *valp = 1;
3057                 break;
3058 
3059         case _PC_TIMESTAMP_RESOLUTION:
3060                 /*
3061                  * Windows times are tenths of microseconds
3062                  * (multiples of 100 nanoseconds).
3063                  */
3064                 *valp = 100L;
3065                 break;
3066 
3067         default:
3068                 return (fs_pathconf(vp, cmd, valp, cr, ct));
3069         }
3070         return (0);
3071 }
3072 
3073 /* ARGSUSED */
3074 static int
3075 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3076         caller_context_t *ct)
3077 {
3078         vfs_t *vfsp;
3079         smbmntinfo_t *smi;
3080         int     error;
3081         uint_t  mask;
3082 
3083         vfsp = vp->v_vfsp;
3084         smi = VFTOSMI(vfsp);
3085 
3086         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3087                 return (EIO);
3088 
3089         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3090                 return (EIO);
3091 
3092         /*
3093          * Our _pathconf indicates _ACL_ACE_ENABLED,
3094          * so we should only see VSA_ACE, etc here.
3095          * Note: vn_create asks for VSA_DFACLCNT,
3096          * and it expects ENOSYS and empty data.
3097          */
3098         mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3099             VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3100         if (mask == 0)
3101                 return (ENOSYS);
3102 
3103         if (smi->smi_flags & SMI_ACL)
3104                 error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3105         else
3106                 error = ENOSYS;
3107 
3108         if (error == ENOSYS)
3109                 error = fs_fab_acl(vp, vsa, flag, cr, ct);
3110 
3111         return (error);
3112 }
3113 
3114 /* ARGSUSED */
3115 static int
3116 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3117         caller_context_t *ct)
3118 {
3119         vfs_t *vfsp;
3120         smbmntinfo_t *smi;
3121         int     error;
3122         uint_t  mask;
3123 
3124         vfsp = vp->v_vfsp;
3125         smi = VFTOSMI(vfsp);
3126 
3127         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3128                 return (EIO);
3129 
3130         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3131                 return (EIO);
3132 
3133         /*
3134          * Our _pathconf indicates _ACL_ACE_ENABLED,
3135          * so we should only see VSA_ACE, etc here.
3136          */
3137         mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3138         if (mask == 0)
3139                 return (ENOSYS);
3140 
3141         if (vfsp->vfs_flag & VFS_RDONLY)
3142                 return (EROFS);
3143 
3144         /*
3145          * Allow only the mount owner to do this.
3146          * See comments at smbfs_access_rwx.
3147          */
3148         error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3149         if (error != 0)
3150                 return (error);
3151 
3152         if (smi->smi_flags & SMI_ACL)
3153                 error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3154         else
3155                 error = ENOSYS;
3156 
3157         return (error);
3158 }
3159 
3160 
3161 /*
3162  * XXX
3163  * This op should eventually support PSARC 2007/268.
3164  */
3165 static int
3166 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3167         caller_context_t *ct)
3168 {
3169         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3170                 return (EIO);
3171 
3172         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3173                 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3174         else
3175                 return (ENOSYS);
3176 }