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