14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001 Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow /* 36134a1f4eSCasper H.S. Dik * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 374bff34e3Sthurlow */ 384bff34e3Sthurlow 394bff34e3Sthurlow #include <sys/systm.h> 404bff34e3Sthurlow #include <sys/cred.h> 414bff34e3Sthurlow #include <sys/vnode.h> 424bff34e3Sthurlow #include <sys/vfs.h> 437568150aSgwr #include <sys/filio.h> 444bff34e3Sthurlow #include <sys/uio.h> 454bff34e3Sthurlow #include <sys/dirent.h> 464bff34e3Sthurlow #include <sys/errno.h> 47613a2f6bSGordon Ross #include <sys/sunddi.h> 484bff34e3Sthurlow #include <sys/sysmacros.h> 494bff34e3Sthurlow #include <sys/kmem.h> 504bff34e3Sthurlow #include <sys/cmn_err.h> 514bff34e3Sthurlow #include <sys/vfs_opreg.h> 524bff34e3Sthurlow #include <sys/policy.h> 534bff34e3Sthurlow 544bff34e3Sthurlow #include <netsmb/smb_osdep.h> 554bff34e3Sthurlow #include <netsmb/smb.h> 564bff34e3Sthurlow #include <netsmb/smb_conn.h> 574bff34e3Sthurlow #include <netsmb/smb_subr.h> 584bff34e3Sthurlow 594bff34e3Sthurlow #include <smbfs/smbfs.h> 604bff34e3Sthurlow #include <smbfs/smbfs_node.h> 614bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 624bff34e3Sthurlow 637568150aSgwr #include <sys/fs/smbfs_ioctl.h> 644bff34e3Sthurlow #include <fs/fs_subr.h> 654bff34e3Sthurlow 665ecede33SGordon Ross /* 675ecede33SGordon Ross * We assign directory offsets like the NFS client, where the 685ecede33SGordon Ross * offset increments by _one_ after each directory entry. 695ecede33SGordon Ross * Further, the entries "." and ".." are always at offsets 705ecede33SGordon Ross * zero and one (respectively) and the "real" entries from 715ecede33SGordon Ross * the server appear at offsets starting with two. This 725ecede33SGordon Ross * macro is used to initialize the n_dirofs field after 735ecede33SGordon Ross * setting n_dirseq with a _findopen call. 745ecede33SGordon Ross */ 755ecede33SGordon Ross #define FIRST_DIROFS 2 765ecede33SGordon Ross 774bff34e3Sthurlow /* 784bff34e3Sthurlow * These characters are illegal in NTFS file names. 794bff34e3Sthurlow * ref: http://support.microsoft.com/kb/147438 8091d632c8Sgwr * 8191d632c8Sgwr * Careful! The check in the XATTR case skips the 8291d632c8Sgwr * first character to allow colon in XATTR names. 834bff34e3Sthurlow */ 844bff34e3Sthurlow static const char illegal_chars[] = { 8591d632c8Sgwr ':', /* colon - keep this first! */ 864bff34e3Sthurlow '\\', /* back slash */ 874bff34e3Sthurlow '/', /* slash */ 884bff34e3Sthurlow '*', /* asterisk */ 894bff34e3Sthurlow '?', /* question mark */ 904bff34e3Sthurlow '"', /* double quote */ 914bff34e3Sthurlow '<', /* less than sign */ 924bff34e3Sthurlow '>', /* greater than sign */ 934bff34e3Sthurlow '|', /* vertical bar */ 944bff34e3Sthurlow 0 954bff34e3Sthurlow }; 964bff34e3Sthurlow 974bff34e3Sthurlow /* 984bff34e3Sthurlow * Turning this on causes nodes to be created in the cache 9902d09e03SGordon Ross * during directory listings, normally avoiding a second 10002d09e03SGordon Ross * OtW attribute fetch just after a readdir. 1014bff34e3Sthurlow */ 10202d09e03SGordon Ross int smbfs_fastlookup = 1; 1034bff34e3Sthurlow 1044bff34e3Sthurlow /* local static function defines */ 1054bff34e3Sthurlow 10602d09e03SGordon Ross static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **, 10702d09e03SGordon Ross cred_t *); 1084bff34e3Sthurlow static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 10902d09e03SGordon Ross int cache_ok, caller_context_t *); 1104bff34e3Sthurlow static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, 1114bff34e3Sthurlow cred_t *cr, caller_context_t *); 1124bff34e3Sthurlow static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); 1134bff34e3Sthurlow static int smbfs_accessx(void *, int, cred_t *); 1144bff34e3Sthurlow static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 1154bff34e3Sthurlow caller_context_t *); 11642d15982SGordon Ross static void smbfs_rele_fid(smbnode_t *, struct smb_cred *); 117*28162916SGordon Ross static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *); 11842d15982SGordon Ross 1194bff34e3Sthurlow /* 1204bff34e3Sthurlow * These are the vnode ops routines which implement the vnode interface to 1214bff34e3Sthurlow * the networked file system. These routines just take their parameters, 1224bff34e3Sthurlow * make them look networkish by putting the right info into interface structs, 1234bff34e3Sthurlow * and then calling the appropriate remote routine(s) to do the work. 1244bff34e3Sthurlow * 1254bff34e3Sthurlow * Note on directory name lookup cacheing: If we detect a stale fhandle, 1264bff34e3Sthurlow * we purge the directory cache relative to that vnode. This way, the 1274bff34e3Sthurlow * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for 1284bff34e3Sthurlow * more details on smbnode locking. 1294bff34e3Sthurlow */ 1304bff34e3Sthurlow 1314bff34e3Sthurlow static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *); 1324bff34e3Sthurlow static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *, 1334bff34e3Sthurlow caller_context_t *); 1344bff34e3Sthurlow static int smbfs_read(vnode_t *, struct uio *, int, cred_t *, 1354bff34e3Sthurlow caller_context_t *); 1364bff34e3Sthurlow static int smbfs_write(vnode_t *, struct uio *, int, cred_t *, 1374bff34e3Sthurlow caller_context_t *); 1387568150aSgwr static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *, 1397568150aSgwr caller_context_t *); 1404bff34e3Sthurlow static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *, 1414bff34e3Sthurlow caller_context_t *); 1424bff34e3Sthurlow static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *, 1434bff34e3Sthurlow caller_context_t *); 1444bff34e3Sthurlow static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *); 1454bff34e3Sthurlow static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *); 1464bff34e3Sthurlow static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *); 1474bff34e3Sthurlow static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *, 1484bff34e3Sthurlow int, vnode_t *, cred_t *, caller_context_t *, 1494bff34e3Sthurlow int *, pathname_t *); 1504bff34e3Sthurlow static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl, 1514bff34e3Sthurlow int, vnode_t **, cred_t *, int, caller_context_t *, 1524bff34e3Sthurlow vsecattr_t *); 1534bff34e3Sthurlow static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *, 1544bff34e3Sthurlow int); 1554bff34e3Sthurlow static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *, 1564bff34e3Sthurlow caller_context_t *, int); 1574bff34e3Sthurlow static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **, 1584bff34e3Sthurlow cred_t *, caller_context_t *, int, vsecattr_t *); 1594bff34e3Sthurlow static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *, 1604bff34e3Sthurlow caller_context_t *, int); 1614bff34e3Sthurlow static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *, 1624bff34e3Sthurlow caller_context_t *, int); 1634bff34e3Sthurlow static int smbfs_rwlock(vnode_t *, int, caller_context_t *); 1644bff34e3Sthurlow static void smbfs_rwunlock(vnode_t *, int, caller_context_t *); 1654bff34e3Sthurlow static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *); 1664bff34e3Sthurlow static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t, 1674bff34e3Sthurlow struct flk_callback *, cred_t *, caller_context_t *); 1684bff34e3Sthurlow static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t, 1694bff34e3Sthurlow cred_t *, caller_context_t *); 1704bff34e3Sthurlow static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *, 1714bff34e3Sthurlow caller_context_t *); 1727568150aSgwr static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1737568150aSgwr caller_context_t *); 1747568150aSgwr static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1757568150aSgwr caller_context_t *); 1764bff34e3Sthurlow static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *, 1774bff34e3Sthurlow caller_context_t *); 1784bff34e3Sthurlow 1794bff34e3Sthurlow /* Dummy function to use until correct function is ported in */ 1804bff34e3Sthurlow int noop_vnodeop() { 1814bff34e3Sthurlow return (0); 1824bff34e3Sthurlow } 1834bff34e3Sthurlow 1844bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL; 1854bff34e3Sthurlow 1864bff34e3Sthurlow /* 1874bff34e3Sthurlow * Most unimplemented ops will return ENOSYS because of fs_nosys(). 1884bff34e3Sthurlow * The only ops where that won't work are ACCESS (due to open(2) 1897568150aSgwr * failures) and ... (anything else left?) 1904bff34e3Sthurlow */ 1914bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = { 1927568150aSgwr { VOPNAME_OPEN, { .vop_open = smbfs_open } }, 1937568150aSgwr { VOPNAME_CLOSE, { .vop_close = smbfs_close } }, 1947568150aSgwr { VOPNAME_READ, { .vop_read = smbfs_read } }, 1957568150aSgwr { VOPNAME_WRITE, { .vop_write = smbfs_write } }, 1967568150aSgwr { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } }, 1977568150aSgwr { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } }, 1987568150aSgwr { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } }, 1997568150aSgwr { VOPNAME_ACCESS, { .vop_access = smbfs_access } }, 2007568150aSgwr { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } }, 2017568150aSgwr { VOPNAME_CREATE, { .vop_create = smbfs_create } }, 2027568150aSgwr { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } }, 2037568150aSgwr { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */ 2047568150aSgwr { VOPNAME_RENAME, { .vop_rename = smbfs_rename } }, 2057568150aSgwr { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } }, 2067568150aSgwr { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } }, 2077568150aSgwr { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } }, 2087568150aSgwr { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */ 2097568150aSgwr { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */ 2107568150aSgwr { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } }, 2117568150aSgwr { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } }, 2127568150aSgwr { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */ 2137568150aSgwr { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } }, 2147568150aSgwr { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } }, 2157568150aSgwr { VOPNAME_SEEK, { .vop_seek = smbfs_seek } }, 2167568150aSgwr { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } }, 2177568150aSgwr { VOPNAME_SPACE, { .vop_space = smbfs_space } }, 2187568150aSgwr { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */ 2197568150aSgwr { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */ 2207568150aSgwr { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */ 2217568150aSgwr { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */ 2227568150aSgwr { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */ 2237568150aSgwr { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */ 2247568150aSgwr { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */ 2257568150aSgwr { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } }, 2267568150aSgwr { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */ 2277568150aSgwr { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } }, 2287568150aSgwr { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } }, 2297568150aSgwr { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } }, 2304bff34e3Sthurlow { NULL, NULL } 2314bff34e3Sthurlow }; 2324bff34e3Sthurlow 2334bff34e3Sthurlow /* 2344bff34e3Sthurlow * XXX 2354bff34e3Sthurlow * When new and relevant functionality is enabled, we should be 2364bff34e3Sthurlow * calling vfs_set_feature() to inform callers that pieces of 2379660e5cbSJanice Chang * functionality are available, per PSARC 2007/227. 2384bff34e3Sthurlow */ 2394bff34e3Sthurlow /* ARGSUSED */ 2404bff34e3Sthurlow static int 2414bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 2424bff34e3Sthurlow { 2434bff34e3Sthurlow smbnode_t *np; 2444bff34e3Sthurlow vnode_t *vp; 24502d09e03SGordon Ross smbfattr_t fa; 2464bff34e3Sthurlow u_int32_t rights, rightsrcvd; 2474bff34e3Sthurlow u_int16_t fid, oldfid; 248613a2f6bSGordon Ross int oldgenid; 2494bff34e3Sthurlow struct smb_cred scred; 2504bff34e3Sthurlow smbmntinfo_t *smi; 251613a2f6bSGordon Ross smb_share_t *ssp; 2524bff34e3Sthurlow cred_t *oldcr; 2534bff34e3Sthurlow int tmperror; 2544bff34e3Sthurlow int error = 0; 2554bff34e3Sthurlow 2564bff34e3Sthurlow vp = *vpp; 2574bff34e3Sthurlow np = VTOSMB(vp); 2584bff34e3Sthurlow smi = VTOSMI(vp); 259613a2f6bSGordon Ross ssp = smi->smi_share; 2604bff34e3Sthurlow 261a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 2624bff34e3Sthurlow return (EIO); 2634bff34e3Sthurlow 2644bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 2654bff34e3Sthurlow return (EIO); 2664bff34e3Sthurlow 2674bff34e3Sthurlow if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */ 2684bff34e3Sthurlow SMBVDEBUG("open eacces vtype=%d\n", vp->v_type); 2694bff34e3Sthurlow return (EACCES); 2704bff34e3Sthurlow } 2714bff34e3Sthurlow 2724bff34e3Sthurlow /* 2734bff34e3Sthurlow * Get exclusive access to n_fid and related stuff. 2744bff34e3Sthurlow * No returns after this until out. 2754bff34e3Sthurlow */ 2764bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 2774bff34e3Sthurlow return (EINTR); 278613a2f6bSGordon Ross smb_credinit(&scred, cr); 2794bff34e3Sthurlow 28091d632c8Sgwr /* 28191d632c8Sgwr * Keep track of the vnode type at first open. 28291d632c8Sgwr * It may change later, and we need close to do 28391d632c8Sgwr * cleanup for the type we opened. Also deny 28491d632c8Sgwr * open of new types until old type is closed. 28591d632c8Sgwr * XXX: Per-open instance nodes whould help. 28691d632c8Sgwr */ 28791d632c8Sgwr if (np->n_ovtype == VNON) { 28891d632c8Sgwr ASSERT(np->n_dirrefs == 0); 28991d632c8Sgwr ASSERT(np->n_fidrefs == 0); 29091d632c8Sgwr } else if (np->n_ovtype != vp->v_type) { 29191d632c8Sgwr SMBVDEBUG("open n_ovtype=%d v_type=%d\n", 29291d632c8Sgwr np->n_ovtype, vp->v_type); 29391d632c8Sgwr error = EACCES; 29491d632c8Sgwr goto out; 29591d632c8Sgwr } 29691d632c8Sgwr 2974bff34e3Sthurlow /* 2985ecede33SGordon Ross * Directory open. See smbfs_readvdir() 2994bff34e3Sthurlow */ 3004bff34e3Sthurlow if (vp->v_type == VDIR) { 3015ecede33SGordon Ross if (np->n_dirseq == NULL) { 3025ecede33SGordon Ross /* first open */ 3035ecede33SGordon Ross error = smbfs_smb_findopen(np, "*", 1, 3045ecede33SGordon Ross SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 3055ecede33SGordon Ross &scred, &np->n_dirseq); 3065ecede33SGordon Ross if (error != 0) 3075ecede33SGordon Ross goto out; 3085ecede33SGordon Ross } 3095ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 3104bff34e3Sthurlow np->n_dirrefs++; 3114bff34e3Sthurlow goto have_fid; 3124bff34e3Sthurlow } 3134bff34e3Sthurlow 3144bff34e3Sthurlow /* 3154bff34e3Sthurlow * If caller specified O_TRUNC/FTRUNC, then be sure to set 3164bff34e3Sthurlow * FWRITE (to drive successful setattr(size=0) after open) 3174bff34e3Sthurlow */ 3184bff34e3Sthurlow if (flag & FTRUNC) 3194bff34e3Sthurlow flag |= FWRITE; 3204bff34e3Sthurlow 3214bff34e3Sthurlow /* 322613a2f6bSGordon Ross * If we already have it open, and the FID is still valid, 323613a2f6bSGordon Ross * check whether the rights are sufficient for FID reuse. 3244bff34e3Sthurlow */ 325613a2f6bSGordon Ross if (np->n_fidrefs > 0 && 326613a2f6bSGordon Ross np->n_vcgenid == ssp->ss_vcgenid) { 3274bff34e3Sthurlow int upgrade = 0; 3284bff34e3Sthurlow 3294bff34e3Sthurlow if ((flag & FWRITE) && 33002d09e03SGordon Ross !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA)) 3314bff34e3Sthurlow upgrade = 1; 3324bff34e3Sthurlow if ((flag & FREAD) && 33302d09e03SGordon Ross !(np->n_rights & SA_RIGHT_FILE_READ_DATA)) 3344bff34e3Sthurlow upgrade = 1; 3354bff34e3Sthurlow if (!upgrade) { 3364bff34e3Sthurlow /* 3374bff34e3Sthurlow * the existing open is good enough 3384bff34e3Sthurlow */ 3394bff34e3Sthurlow np->n_fidrefs++; 3404bff34e3Sthurlow goto have_fid; 3414bff34e3Sthurlow } 3424bff34e3Sthurlow } 3434bff34e3Sthurlow rights = np->n_fidrefs ? np->n_rights : 0; 3444bff34e3Sthurlow 3454bff34e3Sthurlow /* 3464bff34e3Sthurlow * we always ask for READ_CONTROL so we can always get the 34791d632c8Sgwr * owner/group IDs to satisfy a stat. Ditto attributes. 3484bff34e3Sthurlow */ 34991d632c8Sgwr rights |= (STD_RIGHT_READ_CONTROL_ACCESS | 35091d632c8Sgwr SA_RIGHT_FILE_READ_ATTRIBUTES); 3514bff34e3Sthurlow if ((flag & FREAD)) 3524bff34e3Sthurlow rights |= SA_RIGHT_FILE_READ_DATA; 3534bff34e3Sthurlow if ((flag & FWRITE)) 35402d09e03SGordon Ross rights |= SA_RIGHT_FILE_WRITE_DATA | 35502d09e03SGordon Ross SA_RIGHT_FILE_APPEND_DATA | 35602d09e03SGordon Ross SA_RIGHT_FILE_WRITE_ATTRIBUTES; 35702d09e03SGordon Ross 35802d09e03SGordon Ross bzero(&fa, sizeof (fa)); 35902d09e03SGordon Ross error = smbfs_smb_open(np, 36002d09e03SGordon Ross NULL, 0, 0, /* name nmlen xattr */ 36102d09e03SGordon Ross rights, &scred, 36202d09e03SGordon Ross &fid, &rightsrcvd, &fa); 3634bff34e3Sthurlow if (error) 3644bff34e3Sthurlow goto out; 36502d09e03SGordon Ross smbfs_attrcache_fa(vp, &fa); 3664bff34e3Sthurlow 3674bff34e3Sthurlow /* 3684bff34e3Sthurlow * We have a new FID and access rights. 3694bff34e3Sthurlow */ 3704bff34e3Sthurlow oldfid = np->n_fid; 371613a2f6bSGordon Ross oldgenid = np->n_vcgenid; 3724bff34e3Sthurlow np->n_fid = fid; 373613a2f6bSGordon Ross np->n_vcgenid = ssp->ss_vcgenid; 3744bff34e3Sthurlow np->n_rights = rightsrcvd; 3754bff34e3Sthurlow np->n_fidrefs++; 376613a2f6bSGordon Ross if (np->n_fidrefs > 1 && 377613a2f6bSGordon Ross oldgenid == ssp->ss_vcgenid) { 3784bff34e3Sthurlow /* 3794bff34e3Sthurlow * We already had it open (presumably because 3804bff34e3Sthurlow * it was open with insufficient rights.) 3814bff34e3Sthurlow * Close old wire-open. 3824bff34e3Sthurlow */ 383613a2f6bSGordon Ross tmperror = smbfs_smb_close(ssp, 38402d09e03SGordon Ross oldfid, NULL, &scred); 3854bff34e3Sthurlow if (tmperror) 3864bff34e3Sthurlow SMBVDEBUG("error %d closing %s\n", 3874bff34e3Sthurlow tmperror, np->n_rpath); 3884bff34e3Sthurlow } 3894bff34e3Sthurlow 3904bff34e3Sthurlow /* 3914bff34e3Sthurlow * This thread did the open. 3924bff34e3Sthurlow * Save our credentials too. 3934bff34e3Sthurlow */ 3944bff34e3Sthurlow mutex_enter(&np->r_statelock); 3954bff34e3Sthurlow oldcr = np->r_cred; 3964bff34e3Sthurlow np->r_cred = cr; 3974bff34e3Sthurlow crhold(cr); 3984bff34e3Sthurlow if (oldcr) 3994bff34e3Sthurlow crfree(oldcr); 4004bff34e3Sthurlow mutex_exit(&np->r_statelock); 4014bff34e3Sthurlow 4024bff34e3Sthurlow have_fid: 40391d632c8Sgwr /* 40491d632c8Sgwr * Keep track of the vnode type at first open. 40591d632c8Sgwr * (see comments above) 40691d632c8Sgwr */ 40791d632c8Sgwr if (np->n_ovtype == VNON) 40891d632c8Sgwr np->n_ovtype = vp->v_type; 4094bff34e3Sthurlow 4104bff34e3Sthurlow out: 4114bff34e3Sthurlow smb_credrele(&scred); 4124bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 4134bff34e3Sthurlow return (error); 4144bff34e3Sthurlow } 4154bff34e3Sthurlow 4164bff34e3Sthurlow /*ARGSUSED*/ 4174bff34e3Sthurlow static int 4184bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 4194bff34e3Sthurlow caller_context_t *ct) 4204bff34e3Sthurlow { 4214bff34e3Sthurlow smbnode_t *np; 422613a2f6bSGordon Ross smbmntinfo_t *smi; 4234bff34e3Sthurlow struct smb_cred scred; 4244bff34e3Sthurlow 4254bff34e3Sthurlow np = VTOSMB(vp); 426613a2f6bSGordon Ross smi = VTOSMI(vp); 4274bff34e3Sthurlow 4284bff34e3Sthurlow /* 4294bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 4304bff34e3Sthurlow * as we want to do cleanup, etc. 4314bff34e3Sthurlow */ 4324bff34e3Sthurlow 4334bff34e3Sthurlow /* 4344bff34e3Sthurlow * zone_enter(2) prevents processes from changing zones with SMBFS files 4354bff34e3Sthurlow * open; if we happen to get here from the wrong zone we can't do 4364bff34e3Sthurlow * anything over the wire. 4374bff34e3Sthurlow */ 438a19609f8Sjv if (smi->smi_zone_ref.zref_zone != curproc->p_zone) { 4394bff34e3Sthurlow /* 4404bff34e3Sthurlow * We could attempt to clean up locks, except we're sure 4414bff34e3Sthurlow * that the current process didn't acquire any locks on 4424bff34e3Sthurlow * the file: any attempt to lock a file belong to another zone 4434bff34e3Sthurlow * will fail, and one can't lock an SMBFS file and then change 4444bff34e3Sthurlow * zones, as that fails too. 4454bff34e3Sthurlow * 4464bff34e3Sthurlow * Returning an error here is the sane thing to do. A 4474bff34e3Sthurlow * subsequent call to VN_RELE() which translates to a 4484bff34e3Sthurlow * smbfs_inactive() will clean up state: if the zone of the 4494bff34e3Sthurlow * vnode's origin is still alive and kicking, an async worker 4504bff34e3Sthurlow * thread will handle the request (from the correct zone), and 4514bff34e3Sthurlow * everything (minus the final smbfs_getattr_otw() call) should 4524bff34e3Sthurlow * be OK. If the zone is going away smbfs_async_inactive() will 4534bff34e3Sthurlow * throw away cached pages inline. 4544bff34e3Sthurlow */ 4554bff34e3Sthurlow return (EIO); 4564bff34e3Sthurlow } 4574bff34e3Sthurlow 4584bff34e3Sthurlow /* 4594bff34e3Sthurlow * If we are using local locking for this filesystem, then 4604bff34e3Sthurlow * release all of the SYSV style record locks. Otherwise, 4614bff34e3Sthurlow * we are doing network locking and we need to release all 4624bff34e3Sthurlow * of the network locks. All of the locks held by this 4634bff34e3Sthurlow * process on this file are released no matter what the 4644bff34e3Sthurlow * incoming reference count is. 4654bff34e3Sthurlow */ 46642d15982SGordon Ross if (smi->smi_flags & SMI_LLOCK) { 467613a2f6bSGordon Ross pid_t pid = ddi_get_pid(); 468613a2f6bSGordon Ross cleanlocks(vp, pid, 0); 469613a2f6bSGordon Ross cleanshares(vp, pid); 4704bff34e3Sthurlow } 4714bff34e3Sthurlow 4724bff34e3Sthurlow /* 47302d09e03SGordon Ross * This (passed in) count is the ref. count from the 47402d09e03SGordon Ross * user's file_t before the closef call (fio.c). 47502d09e03SGordon Ross * We only care when the reference goes away. 4764bff34e3Sthurlow */ 47702d09e03SGordon Ross if (count > 1) 47802d09e03SGordon Ross return (0); 4794bff34e3Sthurlow 4804bff34e3Sthurlow /* 48142d15982SGordon Ross * Decrement the reference count for the FID 48242d15982SGordon Ross * and possibly do the OtW close. 48342d15982SGordon Ross * 4844bff34e3Sthurlow * Exclusive lock for modifying n_fid stuff. 4854bff34e3Sthurlow * Don't want this one ever interruptible. 4864bff34e3Sthurlow */ 4874bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 488613a2f6bSGordon Ross smb_credinit(&scred, cr); 4894bff34e3Sthurlow 49042d15982SGordon Ross smbfs_rele_fid(np, &scred); 49142d15982SGordon Ross 49242d15982SGordon Ross smb_credrele(&scred); 49342d15982SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 49442d15982SGordon Ross 49542d15982SGordon Ross return (0); 49642d15982SGordon Ross } 49742d15982SGordon Ross 49842d15982SGordon Ross /* 49942d15982SGordon Ross * Helper for smbfs_close. Decrement the reference count 50042d15982SGordon Ross * for an SMB-level file or directory ID, and when the last 50142d15982SGordon Ross * reference for the fid goes away, do the OtW close. 50242d15982SGordon Ross * Also called in smbfs_inactive (defensive cleanup). 50342d15982SGordon Ross */ 50442d15982SGordon Ross static void 50542d15982SGordon Ross smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred) 50642d15982SGordon Ross { 50742d15982SGordon Ross smb_share_t *ssp; 50842d15982SGordon Ross cred_t *oldcr; 50942d15982SGordon Ross struct smbfs_fctx *fctx; 51042d15982SGordon Ross int error; 51142d15982SGordon Ross uint16_t ofid; 51242d15982SGordon Ross 51342d15982SGordon Ross ssp = np->n_mount->smi_share; 5144bff34e3Sthurlow error = 0; 51591d632c8Sgwr 51642d15982SGordon Ross /* Make sure we serialize for n_dirseq use. */ 51742d15982SGordon Ross ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 51842d15982SGordon Ross 51991d632c8Sgwr /* 52091d632c8Sgwr * Note that vp->v_type may change if a remote node 52191d632c8Sgwr * is deleted and recreated as a different type, and 52291d632c8Sgwr * our getattr may change v_type accordingly. 52391d632c8Sgwr * Now use n_ovtype to keep track of the v_type 52491d632c8Sgwr * we had during open (see comments above). 52591d632c8Sgwr */ 52642d15982SGordon Ross switch (np->n_ovtype) { 52742d15982SGordon Ross case VDIR: 5284bff34e3Sthurlow ASSERT(np->n_dirrefs > 0); 5294bff34e3Sthurlow if (--np->n_dirrefs) 53042d15982SGordon Ross return; 5314bff34e3Sthurlow if ((fctx = np->n_dirseq) != NULL) { 5324bff34e3Sthurlow np->n_dirseq = NULL; 5335ecede33SGordon Ross np->n_dirofs = 0; 53442d15982SGordon Ross error = smbfs_smb_findclose(fctx, scred); 5354bff34e3Sthurlow } 53642d15982SGordon Ross break; 53742d15982SGordon Ross 53842d15982SGordon Ross case VREG: 5394bff34e3Sthurlow ASSERT(np->n_fidrefs > 0); 5404bff34e3Sthurlow if (--np->n_fidrefs) 54142d15982SGordon Ross return; 5424bff34e3Sthurlow if ((ofid = np->n_fid) != SMB_FID_UNUSED) { 5434bff34e3Sthurlow np->n_fid = SMB_FID_UNUSED; 544613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 545613a2f6bSGordon Ross if (np->n_vcgenid == ssp->ss_vcgenid) { 546613a2f6bSGordon Ross error = smbfs_smb_close( 54742d15982SGordon Ross ssp, ofid, NULL, scred); 548613a2f6bSGordon Ross } 5494bff34e3Sthurlow } 55042d15982SGordon Ross break; 55142d15982SGordon Ross 55242d15982SGordon Ross default: 55342d15982SGordon Ross SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype); 55442d15982SGordon Ross break; 5554bff34e3Sthurlow } 5564bff34e3Sthurlow if (error) { 55702d09e03SGordon Ross SMBVDEBUG("error %d closing %s\n", 5584bff34e3Sthurlow error, np->n_rpath); 5594bff34e3Sthurlow } 5604bff34e3Sthurlow 56191d632c8Sgwr /* Allow next open to use any v_type. */ 56291d632c8Sgwr np->n_ovtype = VNON; 56391d632c8Sgwr 56402d09e03SGordon Ross /* 56502d09e03SGordon Ross * Other "last close" stuff. 56602d09e03SGordon Ross */ 56702d09e03SGordon Ross mutex_enter(&np->r_statelock); 5684bff34e3Sthurlow if (np->n_flag & NATTRCHANGED) 56902d09e03SGordon Ross smbfs_attrcache_rm_locked(np); 57002d09e03SGordon Ross oldcr = np->r_cred; 57102d09e03SGordon Ross np->r_cred = NULL; 57202d09e03SGordon Ross mutex_exit(&np->r_statelock); 57302d09e03SGordon Ross if (oldcr != NULL) 57402d09e03SGordon Ross crfree(oldcr); 5754bff34e3Sthurlow } 5764bff34e3Sthurlow 5774bff34e3Sthurlow /* ARGSUSED */ 5784bff34e3Sthurlow static int 5794bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 5804bff34e3Sthurlow caller_context_t *ct) 5814bff34e3Sthurlow { 5829c9af259SGordon Ross struct smb_cred scred; 5839c9af259SGordon Ross struct vattr va; 584613a2f6bSGordon Ross smbnode_t *np; 585613a2f6bSGordon Ross smbmntinfo_t *smi; 586613a2f6bSGordon Ross smb_share_t *ssp; 5879c9af259SGordon Ross offset_t endoff; 5889c9af259SGordon Ross ssize_t past_eof; 5899c9af259SGordon Ross int error; 5904bff34e3Sthurlow 5914bff34e3Sthurlow np = VTOSMB(vp); 5924bff34e3Sthurlow smi = VTOSMI(vp); 593613a2f6bSGordon Ross ssp = smi->smi_share; 5944bff34e3Sthurlow 595a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 5964bff34e3Sthurlow return (EIO); 5974bff34e3Sthurlow 5984bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 5994bff34e3Sthurlow return (EIO); 6004bff34e3Sthurlow 6014bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 6024bff34e3Sthurlow 6034bff34e3Sthurlow if (vp->v_type != VREG) 6044bff34e3Sthurlow return (EISDIR); 6054bff34e3Sthurlow 6064bff34e3Sthurlow if (uiop->uio_resid == 0) 6074bff34e3Sthurlow return (0); 6084bff34e3Sthurlow 6094bff34e3Sthurlow /* 6104bff34e3Sthurlow * Like NFS3, just check for 63-bit overflow. 6114bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 6124bff34e3Sthurlow * when it has to fallback to a 32-bit call. 6134bff34e3Sthurlow */ 614613a2f6bSGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 615613a2f6bSGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 6164bff34e3Sthurlow return (EINVAL); 6174bff34e3Sthurlow 6184bff34e3Sthurlow /* get vnode attributes from server */ 6194bff34e3Sthurlow va.va_mask = AT_SIZE | AT_MTIME; 6204bff34e3Sthurlow if (error = smbfsgetattr(vp, &va, cr)) 6219c9af259SGordon Ross return (error); 6224bff34e3Sthurlow 6239c9af259SGordon Ross /* Update mtime with mtime from server here? */ 6249c9af259SGordon Ross 6259c9af259SGordon Ross /* if offset is beyond EOF, read nothing */ 6269c9af259SGordon Ross if (uiop->uio_loffset >= va.va_size) 6279c9af259SGordon Ross return (0); 6284bff34e3Sthurlow 6294bff34e3Sthurlow /* 6309c9af259SGordon Ross * Limit the read to the remaining file size. 6319c9af259SGordon Ross * Do this by temporarily reducing uio_resid 6329c9af259SGordon Ross * by the amount the lies beyoned the EOF. 6334bff34e3Sthurlow */ 6349c9af259SGordon Ross if (endoff > va.va_size) { 6359c9af259SGordon Ross past_eof = (ssize_t)(endoff - va.va_size); 6369c9af259SGordon Ross uiop->uio_resid -= past_eof; 6379c9af259SGordon Ross } else 6389c9af259SGordon Ross past_eof = 0; 6399c9af259SGordon Ross 6409c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 6419c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 6429c9af259SGordon Ross return (EINTR); 643613a2f6bSGordon Ross smb_credinit(&scred, cr); 6444bff34e3Sthurlow 645613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 646613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 647613a2f6bSGordon Ross error = ESTALE; 648613a2f6bSGordon Ross else 649613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_READ, 650613a2f6bSGordon Ross uiop, &scred, smb_timo_read); 6519c9af259SGordon Ross 6529c9af259SGordon Ross smb_credrele(&scred); 6534bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 6544bff34e3Sthurlow 6559c9af259SGordon Ross /* undo adjustment of resid */ 6569c9af259SGordon Ross uiop->uio_resid += past_eof; 6579c9af259SGordon Ross 6589c9af259SGordon Ross return (error); 6594bff34e3Sthurlow } 6604bff34e3Sthurlow 6614bff34e3Sthurlow 6624bff34e3Sthurlow /* ARGSUSED */ 6634bff34e3Sthurlow static int 6644bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 6654bff34e3Sthurlow caller_context_t *ct) 6664bff34e3Sthurlow { 6679c9af259SGordon Ross struct smb_cred scred; 6689c9af259SGordon Ross struct vattr va; 669613a2f6bSGordon Ross smbnode_t *np; 670613a2f6bSGordon Ross smbmntinfo_t *smi; 671613a2f6bSGordon Ross smb_share_t *ssp; 6729c9af259SGordon Ross offset_t endoff, limit; 6739c9af259SGordon Ross ssize_t past_limit; 6749c9af259SGordon Ross int error, timo; 6754bff34e3Sthurlow 6764bff34e3Sthurlow np = VTOSMB(vp); 6774bff34e3Sthurlow smi = VTOSMI(vp); 678613a2f6bSGordon Ross ssp = smi->smi_share; 6794bff34e3Sthurlow 680a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 6814bff34e3Sthurlow return (EIO); 6824bff34e3Sthurlow 6834bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 6844bff34e3Sthurlow return (EIO); 6854bff34e3Sthurlow 6864bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER)); 6874bff34e3Sthurlow 6884bff34e3Sthurlow if (vp->v_type != VREG) 6894bff34e3Sthurlow return (EISDIR); 6904bff34e3Sthurlow 6914bff34e3Sthurlow if (uiop->uio_resid == 0) 6924bff34e3Sthurlow return (0); 6934bff34e3Sthurlow 6949c9af259SGordon Ross /* 6959c9af259SGordon Ross * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC) 6969c9af259SGordon Ross */ 6979c9af259SGordon Ross if (ioflag & (FAPPEND | FSYNC)) { 6989c9af259SGordon Ross if (np->n_flag & NMODIFIED) { 69902d09e03SGordon Ross smbfs_attrcache_remove(np); 7009c9af259SGordon Ross /* XXX: smbfs_vinvalbuf? */ 7019c9af259SGordon Ross } 7029c9af259SGordon Ross } 7039c9af259SGordon Ross if (ioflag & FAPPEND) { 7049c9af259SGordon Ross /* 7059c9af259SGordon Ross * File size can be changed by another client 7069c9af259SGordon Ross */ 7079c9af259SGordon Ross va.va_mask = AT_SIZE; 7089c9af259SGordon Ross if (error = smbfsgetattr(vp, &va, cr)) 7099c9af259SGordon Ross return (error); 7109c9af259SGordon Ross uiop->uio_loffset = va.va_size; 7119c9af259SGordon Ross } 7124bff34e3Sthurlow 7139c9af259SGordon Ross /* 7149c9af259SGordon Ross * Like NFS3, just check for 63-bit overflow. 7159c9af259SGordon Ross */ 7169c9af259SGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 7179c9af259SGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 7189c9af259SGordon Ross return (EINVAL); 7194bff34e3Sthurlow 7204bff34e3Sthurlow /* 7219c9af259SGordon Ross * Check to make sure that the process will not exceed 7229c9af259SGordon Ross * its limit on file size. It is okay to write up to 7239c9af259SGordon Ross * the limit, but not beyond. Thus, the write which 7249c9af259SGordon Ross * reaches the limit will be short and the next write 7259c9af259SGordon Ross * will return an error. 7269c9af259SGordon Ross * 7279c9af259SGordon Ross * So if we're starting at or beyond the limit, EFBIG. 7289c9af259SGordon Ross * Otherwise, temporarily reduce resid to the amount 7299c9af259SGordon Ross * the falls after the limit. 7304bff34e3Sthurlow */ 7319c9af259SGordon Ross limit = uiop->uio_llimit; 7329c9af259SGordon Ross if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 7339c9af259SGordon Ross limit = MAXOFFSET_T; 7349c9af259SGordon Ross if (uiop->uio_loffset >= limit) 7359c9af259SGordon Ross return (EFBIG); 7369c9af259SGordon Ross if (endoff > limit) { 7379c9af259SGordon Ross past_limit = (ssize_t)(endoff - limit); 7389c9af259SGordon Ross uiop->uio_resid -= past_limit; 7399c9af259SGordon Ross } else 7409c9af259SGordon Ross past_limit = 0; 7419c9af259SGordon Ross 7429c9af259SGordon Ross /* Timeout: longer for append. */ 7439c9af259SGordon Ross timo = smb_timo_write; 74402d09e03SGordon Ross if (endoff > np->r_size) 7459c9af259SGordon Ross timo = smb_timo_append; 7469c9af259SGordon Ross 7479c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 7489c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 7499c9af259SGordon Ross return (EINTR); 750613a2f6bSGordon Ross smb_credinit(&scred, cr); 7514bff34e3Sthurlow 752613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 753613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 754613a2f6bSGordon Ross error = ESTALE; 755613a2f6bSGordon Ross else 756613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, 757613a2f6bSGordon Ross uiop, &scred, timo); 7589c9af259SGordon Ross 7599c9af259SGordon Ross if (error == 0) { 7609c9af259SGordon Ross mutex_enter(&np->r_statelock); 7619c9af259SGordon Ross np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 76202d09e03SGordon Ross if (uiop->uio_loffset > (offset_t)np->r_size) 76302d09e03SGordon Ross np->r_size = (len_t)uiop->uio_loffset; 7649c9af259SGordon Ross mutex_exit(&np->r_statelock); 7659c9af259SGordon Ross if (ioflag & (FSYNC|FDSYNC)) { 7669c9af259SGordon Ross /* Don't error the I/O if this fails. */ 7679c9af259SGordon Ross (void) smbfs_smb_flush(np, &scred); 7689c9af259SGordon Ross } 7699c9af259SGordon Ross } 7709c9af259SGordon Ross 7719c9af259SGordon Ross smb_credrele(&scred); 7724bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 7734bff34e3Sthurlow 7749c9af259SGordon Ross /* undo adjustment of resid */ 7759c9af259SGordon Ross uiop->uio_resid += past_limit; 7769c9af259SGordon Ross 7779c9af259SGordon Ross return (error); 7784bff34e3Sthurlow } 7794bff34e3Sthurlow 7804bff34e3Sthurlow 7817568150aSgwr /* ARGSUSED */ 7827568150aSgwr static int 7837568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, 7847568150aSgwr cred_t *cr, int *rvalp, caller_context_t *ct) 7857568150aSgwr { 7867568150aSgwr int error; 7877568150aSgwr smbmntinfo_t *smi; 7887568150aSgwr 7897568150aSgwr smi = VTOSMI(vp); 7907568150aSgwr 791a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 7927568150aSgwr return (EIO); 7937568150aSgwr 7947568150aSgwr if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 7957568150aSgwr return (EIO); 7967568150aSgwr 7977568150aSgwr switch (cmd) { 7987568150aSgwr /* First three from ZFS. XXX - need these? */ 7997568150aSgwr 8007568150aSgwr case _FIOFFS: 8017568150aSgwr error = smbfs_fsync(vp, 0, cr, ct); 8027568150aSgwr break; 8037568150aSgwr 8047568150aSgwr /* 8057568150aSgwr * The following two ioctls are used by bfu. 8067568150aSgwr * Silently ignore to avoid bfu errors. 8077568150aSgwr */ 8087568150aSgwr case _FIOGDIO: 8097568150aSgwr case _FIOSDIO: 8107568150aSgwr error = 0; 8117568150aSgwr break; 8127568150aSgwr 8137568150aSgwr #ifdef NOT_YET /* XXX - from the NFS code. */ 8147568150aSgwr case _FIODIRECTIO: 8157568150aSgwr error = smbfs_directio(vp, (int)arg, cr); 8167568150aSgwr #endif 8177568150aSgwr 8187568150aSgwr /* 8197568150aSgwr * Allow get/set with "raw" security descriptor (SD) data. 8207568150aSgwr * Useful for testing, diagnosing idmap problems, etc. 8217568150aSgwr */ 8227568150aSgwr case SMBFSIO_GETSD: 823bd7c6f51SGordon Ross error = smbfs_acl_iocget(vp, arg, flag, cr); 8247568150aSgwr break; 8257568150aSgwr 8267568150aSgwr case SMBFSIO_SETSD: 827bd7c6f51SGordon Ross error = smbfs_acl_iocset(vp, arg, flag, cr); 8287568150aSgwr break; 8297568150aSgwr 8307568150aSgwr default: 8317568150aSgwr error = ENOTTY; 8327568150aSgwr break; 8337568150aSgwr } 8347568150aSgwr 8357568150aSgwr return (error); 8367568150aSgwr } 8377568150aSgwr 8387568150aSgwr 8394bff34e3Sthurlow /* 8404bff34e3Sthurlow * Return either cached or remote attributes. If get remote attr 8414bff34e3Sthurlow * use them to check and invalidate caches, then cache the new attributes. 8424bff34e3Sthurlow */ 8434bff34e3Sthurlow /* ARGSUSED */ 8444bff34e3Sthurlow static int 8454bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 8464bff34e3Sthurlow caller_context_t *ct) 8474bff34e3Sthurlow { 8484bff34e3Sthurlow smbnode_t *np; 8494bff34e3Sthurlow smbmntinfo_t *smi; 8504bff34e3Sthurlow 8514bff34e3Sthurlow smi = VTOSMI(vp); 8524bff34e3Sthurlow 853a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 8544bff34e3Sthurlow return (EIO); 8554bff34e3Sthurlow 8564bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 8574bff34e3Sthurlow return (EIO); 8584bff34e3Sthurlow 8594bff34e3Sthurlow /* 8604bff34e3Sthurlow * If it has been specified that the return value will 8614bff34e3Sthurlow * just be used as a hint, and we are only being asked 8624bff34e3Sthurlow * for size, fsid or rdevid, then return the client's 8634bff34e3Sthurlow * notion of these values without checking to make sure 8644bff34e3Sthurlow * that the attribute cache is up to date. 8654bff34e3Sthurlow * The whole point is to avoid an over the wire GETATTR 8664bff34e3Sthurlow * call. 8674bff34e3Sthurlow */ 8684bff34e3Sthurlow np = VTOSMB(vp); 8694bff34e3Sthurlow if (flags & ATTR_HINT) { 8704bff34e3Sthurlow if (vap->va_mask == 8714bff34e3Sthurlow (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) { 8724bff34e3Sthurlow mutex_enter(&np->r_statelock); 8734bff34e3Sthurlow if (vap->va_mask | AT_SIZE) 8744bff34e3Sthurlow vap->va_size = np->r_size; 8754bff34e3Sthurlow if (vap->va_mask | AT_FSID) 87602d09e03SGordon Ross vap->va_fsid = vp->v_vfsp->vfs_dev; 8774bff34e3Sthurlow if (vap->va_mask | AT_RDEV) 87802d09e03SGordon Ross vap->va_rdev = vp->v_rdev; 8794bff34e3Sthurlow mutex_exit(&np->r_statelock); 8804bff34e3Sthurlow return (0); 8814bff34e3Sthurlow } 8824bff34e3Sthurlow } 8834bff34e3Sthurlow 8844bff34e3Sthurlow return (smbfsgetattr(vp, vap, cr)); 8854bff34e3Sthurlow } 8864bff34e3Sthurlow 88702d09e03SGordon Ross /* smbfsgetattr() in smbfs_client.c */ 8884bff34e3Sthurlow 8894bff34e3Sthurlow /*ARGSUSED4*/ 8904bff34e3Sthurlow static int 8914bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 8924bff34e3Sthurlow caller_context_t *ct) 8934bff34e3Sthurlow { 89402d09e03SGordon Ross vfs_t *vfsp; 89502d09e03SGordon Ross smbmntinfo_t *smi; 8964bff34e3Sthurlow int error; 8974bff34e3Sthurlow uint_t mask; 8984bff34e3Sthurlow struct vattr oldva; 8994bff34e3Sthurlow 90002d09e03SGordon Ross vfsp = vp->v_vfsp; 90102d09e03SGordon Ross smi = VFTOSMI(vfsp); 9024bff34e3Sthurlow 903a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 9044bff34e3Sthurlow return (EIO); 9054bff34e3Sthurlow 90602d09e03SGordon Ross if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 9074bff34e3Sthurlow return (EIO); 9084bff34e3Sthurlow 9094bff34e3Sthurlow mask = vap->va_mask; 9104bff34e3Sthurlow if (mask & AT_NOSET) 9114bff34e3Sthurlow return (EINVAL); 9124bff34e3Sthurlow 91302d09e03SGordon Ross if (vfsp->vfs_flag & VFS_RDONLY) 91402d09e03SGordon Ross return (EROFS); 91502d09e03SGordon Ross 916bd7c6f51SGordon Ross /* 917bd7c6f51SGordon Ross * This is a _local_ access check so that only the owner of 918bd7c6f51SGordon Ross * this mount can set attributes. With ACLs enabled, the 919bd7c6f51SGordon Ross * file owner can be different from the mount owner, and we 920bd7c6f51SGordon Ross * need to check the _mount_ owner here. See _access_rwx 921bd7c6f51SGordon Ross */ 92202d09e03SGordon Ross bzero(&oldva, sizeof (oldva)); 923bd7c6f51SGordon Ross oldva.va_mask = AT_TYPE | AT_MODE; 9244bff34e3Sthurlow error = smbfsgetattr(vp, &oldva, cr); 9254bff34e3Sthurlow if (error) 9264bff34e3Sthurlow return (error); 927bd7c6f51SGordon Ross oldva.va_mask |= AT_UID | AT_GID; 928bd7c6f51SGordon Ross oldva.va_uid = smi->smi_uid; 929bd7c6f51SGordon Ross oldva.va_gid = smi->smi_gid; 9304bff34e3Sthurlow 9314bff34e3Sthurlow error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, 9324bff34e3Sthurlow smbfs_accessx, vp); 9334bff34e3Sthurlow if (error) 9344bff34e3Sthurlow return (error); 9354bff34e3Sthurlow 936bd7c6f51SGordon Ross if (mask & (AT_UID | AT_GID)) { 937bd7c6f51SGordon Ross if (smi->smi_flags & SMI_ACL) 938bd7c6f51SGordon Ross error = smbfs_acl_setids(vp, vap, cr); 939bd7c6f51SGordon Ross else 940bd7c6f51SGordon Ross error = ENOSYS; 941bd7c6f51SGordon Ross if (error != 0) { 942bd7c6f51SGordon Ross SMBVDEBUG("error %d seting UID/GID on %s", 943bd7c6f51SGordon Ross error, VTOSMB(vp)->n_rpath); 944bd7c6f51SGordon Ross /* 945bd7c6f51SGordon Ross * It might be more correct to return the 946bd7c6f51SGordon Ross * error here, but that causes complaints 947bd7c6f51SGordon Ross * when root extracts a cpio archive, etc. 948bd7c6f51SGordon Ross * So ignore this error, and go ahead with 949bd7c6f51SGordon Ross * the rest of the setattr work. 950bd7c6f51SGordon Ross */ 951bd7c6f51SGordon Ross } 952bd7c6f51SGordon Ross } 953bd7c6f51SGordon Ross 9544bff34e3Sthurlow return (smbfssetattr(vp, vap, flags, cr)); 9554bff34e3Sthurlow } 9564bff34e3Sthurlow 9574bff34e3Sthurlow /* 9584bff34e3Sthurlow * Mostly from Darwin smbfs_setattr() 9594bff34e3Sthurlow * but then modified a lot. 9604bff34e3Sthurlow */ 9614bff34e3Sthurlow /* ARGSUSED */ 9624bff34e3Sthurlow static int 9634bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) 9644bff34e3Sthurlow { 9654bff34e3Sthurlow int error = 0; 9664bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 9674bff34e3Sthurlow uint_t mask = vap->va_mask; 9684bff34e3Sthurlow struct timespec *mtime, *atime; 9694bff34e3Sthurlow struct smb_cred scred; 9704bff34e3Sthurlow int cerror, modified = 0; 9714bff34e3Sthurlow unsigned short fid; 9724bff34e3Sthurlow int have_fid = 0; 9734bff34e3Sthurlow uint32_t rights = 0; 974*28162916SGordon Ross uint32_t dosattr = 0; 9754bff34e3Sthurlow 976a19609f8Sjv ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone); 9774bff34e3Sthurlow 97891d632c8Sgwr /* 97991d632c8Sgwr * There are no settable attributes on the XATTR dir, 98091d632c8Sgwr * so just silently ignore these. On XATTR files, 98191d632c8Sgwr * you can set the size but nothing else. 98291d632c8Sgwr */ 98391d632c8Sgwr if (vp->v_flag & V_XATTRDIR) 98491d632c8Sgwr return (0); 98591d632c8Sgwr if (np->n_flag & N_XATTR) { 98691d632c8Sgwr if (mask & AT_TIMES) 98791d632c8Sgwr SMBVDEBUG("ignore set time on xattr\n"); 98891d632c8Sgwr mask &= AT_SIZE; 98991d632c8Sgwr } 99091d632c8Sgwr 9914bff34e3Sthurlow /* 9924bff34e3Sthurlow * If our caller is trying to set multiple attributes, they 9934bff34e3Sthurlow * can make no assumption about what order they are done in. 9944bff34e3Sthurlow * Here we try to do them in order of decreasing likelihood 9954bff34e3Sthurlow * of failure, just to minimize the chance we'll wind up 9964bff34e3Sthurlow * with a partially complete request. 9974bff34e3Sthurlow */ 9984bff34e3Sthurlow 9994bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 10004bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 10014bff34e3Sthurlow return (EINTR); 1002613a2f6bSGordon Ross smb_credinit(&scred, cr); 10034bff34e3Sthurlow 1004*28162916SGordon Ross /* 1005*28162916SGordon Ross * If the caller has provided extensible attributes, 1006*28162916SGordon Ross * map those into DOS attributes supported by SMB. 1007*28162916SGordon Ross * Note: zero means "no change". 1008*28162916SGordon Ross */ 1009*28162916SGordon Ross if (mask & AT_XVATTR) 1010*28162916SGordon Ross dosattr = xvattr_to_dosattr(np, vap); 1011*28162916SGordon Ross 10124bff34e3Sthurlow /* 10134bff34e3Sthurlow * Will we need an open handle for this setattr? 10144bff34e3Sthurlow * If so, what rights will we need? 10154bff34e3Sthurlow */ 1016*28162916SGordon Ross if (dosattr || (mask & (AT_ATIME | AT_MTIME))) { 10174bff34e3Sthurlow rights |= 101802d09e03SGordon Ross SA_RIGHT_FILE_WRITE_ATTRIBUTES; 10194bff34e3Sthurlow } 10204bff34e3Sthurlow if (mask & AT_SIZE) { 10214bff34e3Sthurlow rights |= 10224bff34e3Sthurlow SA_RIGHT_FILE_WRITE_DATA | 10234bff34e3Sthurlow SA_RIGHT_FILE_APPEND_DATA; 102402d09e03SGordon Ross } 102502d09e03SGordon Ross 102602d09e03SGordon Ross /* 102702d09e03SGordon Ross * Only SIZE really requires a handle, but it's 102802d09e03SGordon Ross * simpler and more reliable to set via a handle. 102902d09e03SGordon Ross * Some servers like NT4 won't set times by path. 103002d09e03SGordon Ross * Also, we're usually setting everything anyway. 103102d09e03SGordon Ross */ 1032*28162916SGordon Ross if (rights != 0) { 10334bff34e3Sthurlow error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 10344bff34e3Sthurlow if (error) { 10354bff34e3Sthurlow SMBVDEBUG("error %d opening %s\n", 10364bff34e3Sthurlow error, np->n_rpath); 10374bff34e3Sthurlow goto out; 10384bff34e3Sthurlow } 10394bff34e3Sthurlow have_fid = 1; 10404bff34e3Sthurlow } 10414bff34e3Sthurlow 10424bff34e3Sthurlow /* 10434bff34e3Sthurlow * If the server supports the UNIX extensions, right here is where 10444bff34e3Sthurlow * we'd support changes to uid, gid, mode, and possibly va_flags. 10454bff34e3Sthurlow * For now we claim to have made any such changes. 10464bff34e3Sthurlow */ 10474bff34e3Sthurlow 10484bff34e3Sthurlow if (mask & AT_SIZE) { 10494bff34e3Sthurlow /* 10504bff34e3Sthurlow * If the new file size is less than what the client sees as 10514bff34e3Sthurlow * the file size, then just change the size and invalidate 10524bff34e3Sthurlow * the pages. 10534bff34e3Sthurlow * I am commenting this code at present because the function 10544bff34e3Sthurlow * smbfs_putapage() is not yet implemented. 10554bff34e3Sthurlow */ 10564bff34e3Sthurlow 10574bff34e3Sthurlow /* 10584bff34e3Sthurlow * Set the file size to vap->va_size. 10594bff34e3Sthurlow */ 10604bff34e3Sthurlow ASSERT(have_fid); 10614bff34e3Sthurlow error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); 10624bff34e3Sthurlow if (error) { 10634bff34e3Sthurlow SMBVDEBUG("setsize error %d file %s\n", 10644bff34e3Sthurlow error, np->n_rpath); 10654bff34e3Sthurlow } else { 10664bff34e3Sthurlow /* 10674bff34e3Sthurlow * Darwin had code here to zero-extend. 10684bff34e3Sthurlow * Tests indicate the server will zero-fill, 10694bff34e3Sthurlow * so looks like we don't need to do this. 10704bff34e3Sthurlow * Good thing, as this could take forever. 1071613a2f6bSGordon Ross * 1072613a2f6bSGordon Ross * XXX: Reportedly, writing one byte of zero 1073613a2f6bSGordon Ross * at the end offset avoids problems here. 10744bff34e3Sthurlow */ 10754bff34e3Sthurlow mutex_enter(&np->r_statelock); 10764bff34e3Sthurlow np->r_size = vap->va_size; 10774bff34e3Sthurlow mutex_exit(&np->r_statelock); 10784bff34e3Sthurlow modified = 1; 10794bff34e3Sthurlow } 10804bff34e3Sthurlow } 10814bff34e3Sthurlow 10824bff34e3Sthurlow /* 10834bff34e3Sthurlow * XXX: When Solaris has create_time, set that too. 10844bff34e3Sthurlow * Note: create_time is different from ctime. 10854bff34e3Sthurlow */ 10864bff34e3Sthurlow mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0); 10874bff34e3Sthurlow atime = ((mask & AT_ATIME) ? &vap->va_atime : 0); 10884bff34e3Sthurlow 1089*28162916SGordon Ross if (dosattr || mtime || atime) { 10904bff34e3Sthurlow /* 109102d09e03SGordon Ross * Always use the handle-based set attr call now. 10924bff34e3Sthurlow */ 109302d09e03SGordon Ross ASSERT(have_fid); 109402d09e03SGordon Ross error = smbfs_smb_setfattr(np, fid, 1095*28162916SGordon Ross dosattr, mtime, atime, &scred); 10964bff34e3Sthurlow if (error) { 10974bff34e3Sthurlow SMBVDEBUG("set times error %d file %s\n", 10984bff34e3Sthurlow error, np->n_rpath); 10994bff34e3Sthurlow } else { 11004bff34e3Sthurlow modified = 1; 11014bff34e3Sthurlow } 11024bff34e3Sthurlow } 11034bff34e3Sthurlow 11044bff34e3Sthurlow out: 11054bff34e3Sthurlow if (modified) { 11064bff34e3Sthurlow /* 110702d09e03SGordon Ross * Invalidate attribute cache in case the server 110802d09e03SGordon Ross * doesn't set exactly the attributes we asked. 11094bff34e3Sthurlow */ 111002d09e03SGordon Ross smbfs_attrcache_remove(np); 11114bff34e3Sthurlow } 11124bff34e3Sthurlow 11134bff34e3Sthurlow if (have_fid) { 11144bff34e3Sthurlow cerror = smbfs_smb_tmpclose(np, fid, &scred); 11154bff34e3Sthurlow if (cerror) 111602d09e03SGordon Ross SMBVDEBUG("error %d closing %s\n", 11174bff34e3Sthurlow cerror, np->n_rpath); 11184bff34e3Sthurlow } 11194bff34e3Sthurlow 11204bff34e3Sthurlow smb_credrele(&scred); 11214bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 11224bff34e3Sthurlow 11234bff34e3Sthurlow return (error); 11244bff34e3Sthurlow } 11254bff34e3Sthurlow 1126*28162916SGordon Ross /* 1127*28162916SGordon Ross * Helper function for extensible system attributes (PSARC 2007/315) 1128*28162916SGordon Ross * Compute the DOS attribute word to pass to _setfattr (see above). 1129*28162916SGordon Ross * This returns zero IFF no change is being made to attributes. 1130*28162916SGordon Ross * Otherwise return the new attributes or SMB_EFA_NORMAL. 1131*28162916SGordon Ross */ 1132*28162916SGordon Ross static uint32_t 1133*28162916SGordon Ross xvattr_to_dosattr(smbnode_t *np, struct vattr *vap) 1134*28162916SGordon Ross { 1135*28162916SGordon Ross xvattr_t *xvap = (xvattr_t *)vap; 1136*28162916SGordon Ross xoptattr_t *xoap = NULL; 1137*28162916SGordon Ross uint32_t attr = np->r_attr.fa_attr; 1138*28162916SGordon Ross boolean_t anyset = B_FALSE; 1139*28162916SGordon Ross 1140*28162916SGordon Ross if ((xoap = xva_getxoptattr(xvap)) == NULL) 1141*28162916SGordon Ross return (0); 1142*28162916SGordon Ross 1143*28162916SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) { 1144*28162916SGordon Ross if (xoap->xoa_archive) 1145*28162916SGordon Ross attr |= SMB_FA_ARCHIVE; 1146*28162916SGordon Ross else 1147*28162916SGordon Ross attr &= ~SMB_FA_ARCHIVE; 1148*28162916SGordon Ross XVA_SET_RTN(xvap, XAT_ARCHIVE); 1149*28162916SGordon Ross anyset = B_TRUE; 1150*28162916SGordon Ross } 1151*28162916SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) { 1152*28162916SGordon Ross if (xoap->xoa_system) 1153*28162916SGordon Ross attr |= SMB_FA_SYSTEM; 1154*28162916SGordon Ross else 1155*28162916SGordon Ross attr &= ~SMB_FA_SYSTEM; 1156*28162916SGordon Ross XVA_SET_RTN(xvap, XAT_SYSTEM); 1157*28162916SGordon Ross anyset = B_TRUE; 1158*28162916SGordon Ross } 1159*28162916SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_READONLY)) { 1160*28162916SGordon Ross if (xoap->xoa_readonly) 1161*28162916SGordon Ross attr |= SMB_FA_RDONLY; 1162*28162916SGordon Ross else 1163*28162916SGordon Ross attr &= ~SMB_FA_RDONLY; 1164*28162916SGordon Ross XVA_SET_RTN(xvap, XAT_READONLY); 1165*28162916SGordon Ross anyset = B_TRUE; 1166*28162916SGordon Ross } 1167*28162916SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) { 1168*28162916SGordon Ross if (xoap->xoa_hidden) 1169*28162916SGordon Ross attr |= SMB_FA_HIDDEN; 1170*28162916SGordon Ross else 1171*28162916SGordon Ross attr &= ~SMB_FA_HIDDEN; 1172*28162916SGordon Ross XVA_SET_RTN(xvap, XAT_HIDDEN); 1173*28162916SGordon Ross anyset = B_TRUE; 1174*28162916SGordon Ross } 1175*28162916SGordon Ross 1176*28162916SGordon Ross if (anyset == B_FALSE) 1177*28162916SGordon Ross return (0); /* no change */ 1178*28162916SGordon Ross if (attr == 0) 1179*28162916SGordon Ross attr = SMB_EFA_NORMAL; 1180*28162916SGordon Ross 1181*28162916SGordon Ross return (attr); 1182*28162916SGordon Ross } 1183*28162916SGordon Ross 11844bff34e3Sthurlow /* 11854bff34e3Sthurlow * smbfs_access_rwx() 11864bff34e3Sthurlow * Common function for smbfs_access, etc. 11874bff34e3Sthurlow * 11884bff34e3Sthurlow * The security model implemented by the FS is unusual 1189bd7c6f51SGordon Ross * due to the current "single user mounts" restriction: 11904bff34e3Sthurlow * All access under a given mount point uses the CIFS 11914bff34e3Sthurlow * credentials established by the owner of the mount. 11924bff34e3Sthurlow * 11934bff34e3Sthurlow * Most access checking is handled by the CIFS server, 11944bff34e3Sthurlow * but we need sufficient Unix access checks here to 11954bff34e3Sthurlow * prevent other local Unix users from having access 11964bff34e3Sthurlow * to objects under this mount that the uid/gid/mode 11974bff34e3Sthurlow * settings in the mount would not allow. 11984bff34e3Sthurlow * 11994bff34e3Sthurlow * With this model, there is a case where we need the 12004bff34e3Sthurlow * ability to do an access check before we have the 12014bff34e3Sthurlow * vnode for an object. This function takes advantage 12024bff34e3Sthurlow * of the fact that the uid/gid/mode is per mount, and 12034bff34e3Sthurlow * avoids the need for a vnode. 12044bff34e3Sthurlow * 12054bff34e3Sthurlow * We still (sort of) need a vnode when we call 12064bff34e3Sthurlow * secpolicy_vnode_access, but that only uses 12074bff34e3Sthurlow * the vtype field, so we can use a pair of fake 12084bff34e3Sthurlow * vnodes that have only v_type filled in. 12094bff34e3Sthurlow * 12104bff34e3Sthurlow * XXX: Later, add a new secpolicy_vtype_access() 12114bff34e3Sthurlow * that takes the vtype instead of a vnode, and 12124bff34e3Sthurlow * get rid of the tmpl_vxxx fake vnodes below. 12134bff34e3Sthurlow */ 12144bff34e3Sthurlow static int 12154bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) 12164bff34e3Sthurlow { 12174bff34e3Sthurlow /* See the secpolicy call below. */ 12184bff34e3Sthurlow static const vnode_t tmpl_vdir = { .v_type = VDIR }; 12194bff34e3Sthurlow static const vnode_t tmpl_vreg = { .v_type = VREG }; 12204bff34e3Sthurlow vattr_t va; 12214bff34e3Sthurlow vnode_t *tvp; 12224bff34e3Sthurlow struct smbmntinfo *smi = VFTOSMI(vfsp); 12234bff34e3Sthurlow int shift = 0; 12244bff34e3Sthurlow 12254bff34e3Sthurlow /* 12264bff34e3Sthurlow * Build our (fabricated) vnode attributes. 12274bff34e3Sthurlow * XXX: Could make these templates in the 12284bff34e3Sthurlow * per-mount struct and use them here. 12294bff34e3Sthurlow */ 12304bff34e3Sthurlow bzero(&va, sizeof (va)); 12314bff34e3Sthurlow va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 12324bff34e3Sthurlow va.va_type = vtype; 12334bff34e3Sthurlow va.va_mode = (vtype == VDIR) ? 123402d09e03SGordon Ross smi->smi_dmode : smi->smi_fmode; 123502d09e03SGordon Ross va.va_uid = smi->smi_uid; 123602d09e03SGordon Ross va.va_gid = smi->smi_gid; 12374bff34e3Sthurlow 12384bff34e3Sthurlow /* 12394bff34e3Sthurlow * Disallow write attempts on read-only file systems, 12404bff34e3Sthurlow * unless the file is a device or fifo node. Note: 12414bff34e3Sthurlow * Inline vn_is_readonly and IS_DEVVP here because 12424bff34e3Sthurlow * we may not have a vnode ptr. Original expr. was: 12434bff34e3Sthurlow * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp)) 12444bff34e3Sthurlow */ 12454bff34e3Sthurlow if ((mode & VWRITE) && 12464bff34e3Sthurlow (vfsp->vfs_flag & VFS_RDONLY) && 12474bff34e3Sthurlow !(vtype == VCHR || vtype == VBLK || vtype == VFIFO)) 12484bff34e3Sthurlow return (EROFS); 12494bff34e3Sthurlow 12504bff34e3Sthurlow /* 12514bff34e3Sthurlow * Disallow attempts to access mandatory lock files. 12524bff34e3Sthurlow * Similarly, expand MANDLOCK here. 12534bff34e3Sthurlow * XXX: not sure we need this. 12544bff34e3Sthurlow */ 12554bff34e3Sthurlow if ((mode & (VWRITE | VREAD | VEXEC)) && 12564bff34e3Sthurlow va.va_type == VREG && MANDMODE(va.va_mode)) 12574bff34e3Sthurlow return (EACCES); 12584bff34e3Sthurlow 12594bff34e3Sthurlow /* 12604bff34e3Sthurlow * Access check is based on only 12614bff34e3Sthurlow * one of owner, group, public. 12624bff34e3Sthurlow * If not owner, then check group. 12634bff34e3Sthurlow * If not a member of the group, 12644bff34e3Sthurlow * then check public access. 12654bff34e3Sthurlow */ 12664bff34e3Sthurlow if (crgetuid(cr) != va.va_uid) { 12674bff34e3Sthurlow shift += 3; 12684bff34e3Sthurlow if (!groupmember(va.va_gid, cr)) 12694bff34e3Sthurlow shift += 3; 12704bff34e3Sthurlow } 12714bff34e3Sthurlow 12724bff34e3Sthurlow /* 12734bff34e3Sthurlow * We need a vnode for secpolicy_vnode_access, 12744bff34e3Sthurlow * but the only thing it looks at is v_type, 12754bff34e3Sthurlow * so pass one of the templates above. 12764bff34e3Sthurlow */ 12774bff34e3Sthurlow tvp = (va.va_type == VDIR) ? 12784bff34e3Sthurlow (vnode_t *)&tmpl_vdir : 12794bff34e3Sthurlow (vnode_t *)&tmpl_vreg; 1280134a1f4eSCasper H.S. Dik 1281134a1f4eSCasper H.S. Dik return (secpolicy_vnode_access2(cr, tvp, va.va_uid, 1282134a1f4eSCasper H.S. Dik va.va_mode << shift, mode)); 12834bff34e3Sthurlow } 12844bff34e3Sthurlow 12854bff34e3Sthurlow /* 12864bff34e3Sthurlow * See smbfs_setattr 12874bff34e3Sthurlow */ 12884bff34e3Sthurlow static int 12894bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr) 12904bff34e3Sthurlow { 12914bff34e3Sthurlow vnode_t *vp = arg; 12924bff34e3Sthurlow /* 12934bff34e3Sthurlow * Note: The caller has checked the current zone, 12944bff34e3Sthurlow * the SMI_DEAD and VFS_UNMOUNTED flags, etc. 12954bff34e3Sthurlow */ 12964bff34e3Sthurlow return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr)); 12974bff34e3Sthurlow } 12984bff34e3Sthurlow 12994bff34e3Sthurlow /* 13004bff34e3Sthurlow * XXX 13014bff34e3Sthurlow * This op should support PSARC 2007/403, Modified Access Checks for CIFS 13024bff34e3Sthurlow */ 13034bff34e3Sthurlow /* ARGSUSED */ 13044bff34e3Sthurlow static int 13054bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) 13064bff34e3Sthurlow { 13074bff34e3Sthurlow vfs_t *vfsp; 13084bff34e3Sthurlow smbmntinfo_t *smi; 13094bff34e3Sthurlow 13104bff34e3Sthurlow vfsp = vp->v_vfsp; 13114bff34e3Sthurlow smi = VFTOSMI(vfsp); 13124bff34e3Sthurlow 1313a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 13144bff34e3Sthurlow return (EIO); 13154bff34e3Sthurlow 13164bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 13174bff34e3Sthurlow return (EIO); 13184bff34e3Sthurlow 13194bff34e3Sthurlow return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr)); 13204bff34e3Sthurlow } 13214bff34e3Sthurlow 13224bff34e3Sthurlow 13234bff34e3Sthurlow /* 13244bff34e3Sthurlow * Flush local dirty pages to stable storage on the server. 13254bff34e3Sthurlow * 13264bff34e3Sthurlow * If FNODSYNC is specified, then there is nothing to do because 13274bff34e3Sthurlow * metadata changes are not cached on the client before being 13284bff34e3Sthurlow * sent to the server. 13294bff34e3Sthurlow */ 13304bff34e3Sthurlow /* ARGSUSED */ 13314bff34e3Sthurlow static int 13324bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 13334bff34e3Sthurlow { 13344bff34e3Sthurlow int error = 0; 13354bff34e3Sthurlow smbmntinfo_t *smi; 13362f5e3e91SGordon Ross smbnode_t *np; 13372f5e3e91SGordon Ross struct smb_cred scred; 13384bff34e3Sthurlow 13392f5e3e91SGordon Ross np = VTOSMB(vp); 13404bff34e3Sthurlow smi = VTOSMI(vp); 13414bff34e3Sthurlow 1342a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 13434bff34e3Sthurlow return (EIO); 13444bff34e3Sthurlow 13454bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 13464bff34e3Sthurlow return (EIO); 13474bff34e3Sthurlow 13484bff34e3Sthurlow if ((syncflag & FNODSYNC) || IS_SWAPVP(vp)) 13494bff34e3Sthurlow return (0); 13504bff34e3Sthurlow 13512f5e3e91SGordon Ross if ((syncflag & (FSYNC|FDSYNC)) == 0) 13522f5e3e91SGordon Ross return (0); 13532f5e3e91SGordon Ross 13542f5e3e91SGordon Ross /* Shared lock for n_fid use in _flush */ 13552f5e3e91SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 13562f5e3e91SGordon Ross return (EINTR); 1357613a2f6bSGordon Ross smb_credinit(&scred, cr); 13582f5e3e91SGordon Ross 13592f5e3e91SGordon Ross error = smbfs_smb_flush(np, &scred); 13602f5e3e91SGordon Ross 13612f5e3e91SGordon Ross smb_credrele(&scred); 13622f5e3e91SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 13632f5e3e91SGordon Ross 13644bff34e3Sthurlow return (error); 13654bff34e3Sthurlow } 13664bff34e3Sthurlow 13674bff34e3Sthurlow /* 13684bff34e3Sthurlow * Last reference to vnode went away. 13694bff34e3Sthurlow */ 13704bff34e3Sthurlow /* ARGSUSED */ 13714bff34e3Sthurlow static void 13724bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 13734bff34e3Sthurlow { 13744bff34e3Sthurlow smbnode_t *np; 137542d15982SGordon Ross struct smb_cred scred; 13764bff34e3Sthurlow 13774bff34e3Sthurlow /* 13784bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 13794bff34e3Sthurlow * as we want to do cleanup, etc. 13804bff34e3Sthurlow * See also pcfs_inactive 13814bff34e3Sthurlow */ 13824bff34e3Sthurlow 13834bff34e3Sthurlow np = VTOSMB(vp); 13844bff34e3Sthurlow 13854bff34e3Sthurlow /* 13864bff34e3Sthurlow * If this is coming from the wrong zone, we let someone in the right 13874bff34e3Sthurlow * zone take care of it asynchronously. We can get here due to 13884bff34e3Sthurlow * VN_RELE() being called from pageout() or fsflush(). This call may 13894bff34e3Sthurlow * potentially turn into an expensive no-op if, for instance, v_count 13904bff34e3Sthurlow * gets incremented in the meantime, but it's still correct. 13914bff34e3Sthurlow */ 13924bff34e3Sthurlow 13934bff34e3Sthurlow /* 139442d15982SGordon Ross * Defend against the possibility that higher-level callers 139542d15982SGordon Ross * might not correctly balance open and close calls. If we 139642d15982SGordon Ross * get here with open references remaining, it means there 139742d15982SGordon Ross * was a missing VOP_CLOSE somewhere. If that happens, do 139842d15982SGordon Ross * the close here so we don't "leak" FIDs on the server. 13994bff34e3Sthurlow * 140042d15982SGordon Ross * Exclusive lock for modifying n_fid stuff. 140142d15982SGordon Ross * Don't want this one ever interruptible. 14024bff34e3Sthurlow */ 140342d15982SGordon Ross (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 140442d15982SGordon Ross smb_credinit(&scred, cr); 140542d15982SGordon Ross 140642d15982SGordon Ross switch (np->n_ovtype) { 140742d15982SGordon Ross case VNON: 140842d15982SGordon Ross /* not open (OK) */ 140942d15982SGordon Ross break; 141042d15982SGordon Ross 141142d15982SGordon Ross case VDIR: 141242d15982SGordon Ross if (np->n_dirrefs == 0) 141342d15982SGordon Ross break; 141442d15982SGordon Ross SMBVDEBUG("open dir: refs %d path %s\n", 141542d15982SGordon Ross np->n_dirrefs, np->n_rpath); 141642d15982SGordon Ross /* Force last close. */ 141742d15982SGordon Ross np->n_dirrefs = 1; 141842d15982SGordon Ross smbfs_rele_fid(np, &scred); 141942d15982SGordon Ross break; 142042d15982SGordon Ross 142142d15982SGordon Ross case VREG: 142242d15982SGordon Ross if (np->n_fidrefs == 0) 142342d15982SGordon Ross break; 142442d15982SGordon Ross SMBVDEBUG("open file: refs %d id 0x%x path %s\n", 14254bff34e3Sthurlow np->n_fidrefs, np->n_fid, np->n_rpath); 142642d15982SGordon Ross /* Force last close. */ 142742d15982SGordon Ross np->n_fidrefs = 1; 142842d15982SGordon Ross smbfs_rele_fid(np, &scred); 142942d15982SGordon Ross break; 143042d15982SGordon Ross 143142d15982SGordon Ross default: 143242d15982SGordon Ross SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype); 143342d15982SGordon Ross np->n_ovtype = VNON; 143442d15982SGordon Ross break; 14354bff34e3Sthurlow } 143642d15982SGordon Ross 143742d15982SGordon Ross smb_credrele(&scred); 143842d15982SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 14394bff34e3Sthurlow 144002d09e03SGordon Ross smbfs_addfree(np); 14414bff34e3Sthurlow } 14424bff34e3Sthurlow 14434bff34e3Sthurlow /* 14444bff34e3Sthurlow * Remote file system operations having to do with directory manipulation. 14454bff34e3Sthurlow */ 14464bff34e3Sthurlow /* ARGSUSED */ 14474bff34e3Sthurlow static int 14484bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, 14494bff34e3Sthurlow int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 14504bff34e3Sthurlow int *direntflags, pathname_t *realpnp) 14514bff34e3Sthurlow { 145291d632c8Sgwr vfs_t *vfs; 14534bff34e3Sthurlow smbmntinfo_t *smi; 145491d632c8Sgwr smbnode_t *dnp; 145591d632c8Sgwr int error; 14564bff34e3Sthurlow 145791d632c8Sgwr vfs = dvp->v_vfsp; 145891d632c8Sgwr smi = VFTOSMI(vfs); 14594bff34e3Sthurlow 1460a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 14614bff34e3Sthurlow return (EPERM); 14624bff34e3Sthurlow 146391d632c8Sgwr if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED) 14644bff34e3Sthurlow return (EIO); 14654bff34e3Sthurlow 14664bff34e3Sthurlow dnp = VTOSMB(dvp); 146791d632c8Sgwr 146891d632c8Sgwr /* 146991d632c8Sgwr * Are we looking up extended attributes? If so, "dvp" is 147091d632c8Sgwr * the file or directory for which we want attributes, and 147191d632c8Sgwr * we need a lookup of the (faked up) attribute directory 147291d632c8Sgwr * before we lookup the rest of the path. 147391d632c8Sgwr */ 147491d632c8Sgwr if (flags & LOOKUP_XATTR) { 147591d632c8Sgwr /* 147691d632c8Sgwr * Require the xattr mount option. 147791d632c8Sgwr */ 147891d632c8Sgwr if ((vfs->vfs_flag & VFS_XATTR) == 0) 147991d632c8Sgwr return (EINVAL); 148091d632c8Sgwr 148191d632c8Sgwr error = smbfs_get_xattrdir(dvp, vpp, cr, flags); 148291d632c8Sgwr return (error); 148391d632c8Sgwr } 148491d632c8Sgwr 148502d09e03SGordon Ross if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) 148602d09e03SGordon Ross return (EINTR); 14874bff34e3Sthurlow 14884bff34e3Sthurlow error = smbfslookup(dvp, nm, vpp, cr, 1, ct); 14894bff34e3Sthurlow 14904bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 14914bff34e3Sthurlow 14924bff34e3Sthurlow return (error); 14934bff34e3Sthurlow } 14944bff34e3Sthurlow 14954bff34e3Sthurlow /* ARGSUSED */ 14964bff34e3Sthurlow static int 149702d09e03SGordon Ross smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 149802d09e03SGordon Ross int cache_ok, caller_context_t *ct) 14994bff34e3Sthurlow { 15004bff34e3Sthurlow int error; 15014bff34e3Sthurlow int supplen; /* supported length */ 15024bff34e3Sthurlow vnode_t *vp; 150302d09e03SGordon Ross smbnode_t *np; 15044bff34e3Sthurlow smbnode_t *dnp; 15054bff34e3Sthurlow smbmntinfo_t *smi; 15064bff34e3Sthurlow /* struct smb_vc *vcp; */ 150791d632c8Sgwr const char *ill; 15084bff34e3Sthurlow const char *name = (const char *)nm; 15094bff34e3Sthurlow int nmlen = strlen(nm); 15104bff34e3Sthurlow int rplen; 15114bff34e3Sthurlow struct smb_cred scred; 15124bff34e3Sthurlow struct smbfattr fa; 15134bff34e3Sthurlow 15144bff34e3Sthurlow smi = VTOSMI(dvp); 15154bff34e3Sthurlow dnp = VTOSMB(dvp); 15164bff34e3Sthurlow 1517a19609f8Sjv ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone); 15184bff34e3Sthurlow 15194bff34e3Sthurlow #ifdef NOT_YET 15204bff34e3Sthurlow vcp = SSTOVC(smi->smi_share); 15214bff34e3Sthurlow 15224bff34e3Sthurlow /* XXX: Should compute this once and store it in smbmntinfo_t */ 15234bff34e3Sthurlow supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12; 15244bff34e3Sthurlow #else 15254bff34e3Sthurlow supplen = 255; 15264bff34e3Sthurlow #endif 15274bff34e3Sthurlow 15284bff34e3Sthurlow /* 15294bff34e3Sthurlow * RWlock must be held, either reader or writer. 15304bff34e3Sthurlow * XXX: Can we check without looking directly 15314bff34e3Sthurlow * inside the struct smbfs_rwlock_t? 15324bff34e3Sthurlow */ 15334bff34e3Sthurlow ASSERT(dnp->r_rwlock.count != 0); 15344bff34e3Sthurlow 15354bff34e3Sthurlow /* 153602d09e03SGordon Ross * If lookup is for "", just return dvp. 153702d09e03SGordon Ross * No need to perform any access checks. 15384bff34e3Sthurlow */ 15394bff34e3Sthurlow if (nmlen == 0) { 15404bff34e3Sthurlow VN_HOLD(dvp); 15414bff34e3Sthurlow *vpp = dvp; 15424bff34e3Sthurlow return (0); 15434bff34e3Sthurlow } 15444bff34e3Sthurlow 15454bff34e3Sthurlow /* 154691d632c8Sgwr * Can't do lookups in non-directories. 15474bff34e3Sthurlow */ 15484bff34e3Sthurlow if (dvp->v_type != VDIR) 15494bff34e3Sthurlow return (ENOTDIR); 15504bff34e3Sthurlow 155191d632c8Sgwr /* 155291d632c8Sgwr * Need search permission in the directory. 155391d632c8Sgwr */ 15544bff34e3Sthurlow error = smbfs_access(dvp, VEXEC, 0, cr, ct); 15554bff34e3Sthurlow if (error) 15564bff34e3Sthurlow return (error); 15574bff34e3Sthurlow 15584bff34e3Sthurlow /* 155902d09e03SGordon Ross * If lookup is for ".", just return dvp. 156002d09e03SGordon Ross * Access check was done above. 15614bff34e3Sthurlow */ 15624bff34e3Sthurlow if (nmlen == 1 && name[0] == '.') { 15634bff34e3Sthurlow VN_HOLD(dvp); 15644bff34e3Sthurlow *vpp = dvp; 15654bff34e3Sthurlow return (0); 15664bff34e3Sthurlow } 15674bff34e3Sthurlow 15684bff34e3Sthurlow /* 156991d632c8Sgwr * Now some sanity checks on the name. 157091d632c8Sgwr * First check the length. 15714bff34e3Sthurlow */ 157291d632c8Sgwr if (nmlen > supplen) 157391d632c8Sgwr return (ENAMETOOLONG); 157491d632c8Sgwr 157591d632c8Sgwr /* 157691d632c8Sgwr * Avoid surprises with characters that are 157791d632c8Sgwr * illegal in Windows file names. 157891d632c8Sgwr * Todo: CATIA mappings XXX 157991d632c8Sgwr */ 158091d632c8Sgwr ill = illegal_chars; 158191d632c8Sgwr if (dnp->n_flag & N_XATTR) 158291d632c8Sgwr ill++; /* allow colon */ 158391d632c8Sgwr if (strpbrk(nm, ill)) 158491d632c8Sgwr return (EINVAL); 158591d632c8Sgwr 15864bff34e3Sthurlow /* 158702d09e03SGordon Ross * Special handling for lookup of ".." 15884bff34e3Sthurlow * 15894bff34e3Sthurlow * We keep full pathnames (as seen on the server) 15904bff34e3Sthurlow * so we can just trim off the last component to 15914bff34e3Sthurlow * get the full pathname of the parent. Note: 15924bff34e3Sthurlow * We don't actually copy and modify, but just 15934bff34e3Sthurlow * compute the trimmed length and pass that with 15944bff34e3Sthurlow * the current dir path (not null terminated). 15954bff34e3Sthurlow * 15964bff34e3Sthurlow * We don't go over-the-wire to get attributes 15974bff34e3Sthurlow * for ".." because we know it's a directory, 15984bff34e3Sthurlow * and we can just leave the rest "stale" 15994bff34e3Sthurlow * until someone does a getattr. 16004bff34e3Sthurlow */ 16014bff34e3Sthurlow if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 16024bff34e3Sthurlow if (dvp->v_flag & VROOT) { 16034bff34e3Sthurlow /* 16044bff34e3Sthurlow * Already at the root. This can happen 16054bff34e3Sthurlow * with directory listings at the root, 16064bff34e3Sthurlow * which lookup "." and ".." to get the 16074bff34e3Sthurlow * inode numbers. Let ".." be the same 16084bff34e3Sthurlow * as "." in the FS root. 16094bff34e3Sthurlow */ 16104bff34e3Sthurlow VN_HOLD(dvp); 16114bff34e3Sthurlow *vpp = dvp; 16124bff34e3Sthurlow return (0); 16134bff34e3Sthurlow } 16144bff34e3Sthurlow 161591d632c8Sgwr /* 161691d632c8Sgwr * Special case for XATTR directory 161791d632c8Sgwr */ 161891d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) { 161991d632c8Sgwr error = smbfs_xa_parent(dvp, vpp); 162091d632c8Sgwr return (error); 162191d632c8Sgwr } 162291d632c8Sgwr 16234bff34e3Sthurlow /* 16244bff34e3Sthurlow * Find the parent path length. 16254bff34e3Sthurlow */ 16264bff34e3Sthurlow rplen = dnp->n_rplen; 16274bff34e3Sthurlow ASSERT(rplen > 0); 16284bff34e3Sthurlow while (--rplen >= 0) { 16294bff34e3Sthurlow if (dnp->n_rpath[rplen] == '\\') 16304bff34e3Sthurlow break; 16314bff34e3Sthurlow } 163202d09e03SGordon Ross if (rplen <= 0) { 16334bff34e3Sthurlow /* Found our way to the root. */ 16344bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 16354bff34e3Sthurlow VN_HOLD(vp); 16364bff34e3Sthurlow *vpp = vp; 16374bff34e3Sthurlow return (0); 16384bff34e3Sthurlow } 163902d09e03SGordon Ross np = smbfs_node_findcreate(smi, 164002d09e03SGordon Ross dnp->n_rpath, rplen, NULL, 0, 0, 164102d09e03SGordon Ross &smbfs_fattr0); /* force create */ 164202d09e03SGordon Ross ASSERT(np != NULL); 164302d09e03SGordon Ross vp = SMBTOV(np); 16444bff34e3Sthurlow vp->v_type = VDIR; 16454bff34e3Sthurlow 16464bff34e3Sthurlow /* Success! */ 16474bff34e3Sthurlow *vpp = vp; 16484bff34e3Sthurlow return (0); 16494bff34e3Sthurlow } 16504bff34e3Sthurlow 16514bff34e3Sthurlow /* 165202d09e03SGordon Ross * Normal lookup of a name under this directory. 165302d09e03SGordon Ross * Note we handled "", ".", ".." above. 165402d09e03SGordon Ross */ 165502d09e03SGordon Ross if (cache_ok) { 165602d09e03SGordon Ross /* 165702d09e03SGordon Ross * The caller indicated that it's OK to use a 165802d09e03SGordon Ross * cached result for this lookup, so try to 165902d09e03SGordon Ross * reclaim a node from the smbfs node cache. 166002d09e03SGordon Ross */ 166102d09e03SGordon Ross error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr); 166202d09e03SGordon Ross if (error) 166302d09e03SGordon Ross return (error); 166402d09e03SGordon Ross if (vp != NULL) { 166502d09e03SGordon Ross /* hold taken in lookup_cache */ 166602d09e03SGordon Ross *vpp = vp; 166702d09e03SGordon Ross return (0); 166802d09e03SGordon Ross } 166902d09e03SGordon Ross } 167002d09e03SGordon Ross 167102d09e03SGordon Ross /* 167202d09e03SGordon Ross * OK, go over-the-wire to get the attributes, 167302d09e03SGordon Ross * then create the node. 16744bff34e3Sthurlow */ 1675613a2f6bSGordon Ross smb_credinit(&scred, cr); 16764bff34e3Sthurlow /* Note: this can allocate a new "name" */ 16774bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); 16784bff34e3Sthurlow smb_credrele(&scred); 167902d09e03SGordon Ross if (error == ENOTDIR) { 168002d09e03SGordon Ross /* 168102d09e03SGordon Ross * Lookup failed because this directory was 168202d09e03SGordon Ross * removed or renamed by another client. 168302d09e03SGordon Ross * Remove any cached attributes under it. 168402d09e03SGordon Ross */ 168502d09e03SGordon Ross smbfs_attrcache_remove(dnp); 168602d09e03SGordon Ross smbfs_attrcache_prune(dnp); 168702d09e03SGordon Ross } 16884bff34e3Sthurlow if (error) 16894bff34e3Sthurlow goto out; 16904bff34e3Sthurlow 16914bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fa, &vp); 16924bff34e3Sthurlow if (error) 16934bff34e3Sthurlow goto out; 16944bff34e3Sthurlow 16954bff34e3Sthurlow /* Success! */ 16964bff34e3Sthurlow *vpp = vp; 16974bff34e3Sthurlow 16984bff34e3Sthurlow out: 16994bff34e3Sthurlow /* smbfs_smb_lookup may have allocated name. */ 17004bff34e3Sthurlow if (name != nm) 17014bff34e3Sthurlow smbfs_name_free(name, nmlen); 17024bff34e3Sthurlow 17034bff34e3Sthurlow return (error); 17044bff34e3Sthurlow } 17054bff34e3Sthurlow 170602d09e03SGordon Ross /* 170702d09e03SGordon Ross * smbfslookup_cache 170802d09e03SGordon Ross * 170902d09e03SGordon Ross * Try to reclaim a node from the smbfs node cache. 171002d09e03SGordon Ross * Some statistics for DEBUG. 171102d09e03SGordon Ross * 171202d09e03SGordon Ross * This mechanism lets us avoid many of the five (or more) 171302d09e03SGordon Ross * OtW lookup calls per file seen with "ls -l" if we search 171402d09e03SGordon Ross * the smbfs node cache for recently inactive(ated) nodes. 171502d09e03SGordon Ross */ 171691d632c8Sgwr #ifdef DEBUG 171702d09e03SGordon Ross int smbfs_lookup_cache_calls = 0; 171802d09e03SGordon Ross int smbfs_lookup_cache_error = 0; 171902d09e03SGordon Ross int smbfs_lookup_cache_miss = 0; 172002d09e03SGordon Ross int smbfs_lookup_cache_stale = 0; 172102d09e03SGordon Ross int smbfs_lookup_cache_hits = 0; 172202d09e03SGordon Ross #endif /* DEBUG */ 172391d632c8Sgwr 172491d632c8Sgwr /* ARGSUSED */ 172591d632c8Sgwr static int 172602d09e03SGordon Ross smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen, 172702d09e03SGordon Ross vnode_t **vpp, cred_t *cr) 172891d632c8Sgwr { 172991d632c8Sgwr struct vattr va; 173091d632c8Sgwr smbnode_t *dnp; 173102d09e03SGordon Ross smbnode_t *np; 173202d09e03SGordon Ross vnode_t *vp; 173302d09e03SGordon Ross int error; 173402d09e03SGordon Ross char sep; 173591d632c8Sgwr 173691d632c8Sgwr dnp = VTOSMB(dvp); 173702d09e03SGordon Ross *vpp = NULL; 173891d632c8Sgwr 173902d09e03SGordon Ross #ifdef DEBUG 174002d09e03SGordon Ross smbfs_lookup_cache_calls++; 174102d09e03SGordon Ross #endif 174291d632c8Sgwr 174391d632c8Sgwr /* 174402d09e03SGordon Ross * First make sure we can get attributes for the 174502d09e03SGordon Ross * directory. Cached attributes are OK here. 174602d09e03SGordon Ross * If we removed or renamed the directory, this 174702d09e03SGordon Ross * will return ENOENT. If someone else removed 174802d09e03SGordon Ross * this directory or file, we'll find out when we 174902d09e03SGordon Ross * try to open or get attributes. 175091d632c8Sgwr */ 175102d09e03SGordon Ross va.va_mask = AT_TYPE | AT_MODE; 175202d09e03SGordon Ross error = smbfsgetattr(dvp, &va, cr); 175302d09e03SGordon Ross if (error) { 175491d632c8Sgwr #ifdef DEBUG 175502d09e03SGordon Ross smbfs_lookup_cache_error++; 175691d632c8Sgwr #endif 175702d09e03SGordon Ross return (error); 175802d09e03SGordon Ross } 175902d09e03SGordon Ross 176002d09e03SGordon Ross /* 176102d09e03SGordon Ross * Passing NULL smbfattr here so we will 176202d09e03SGordon Ross * just look, not create. 176302d09e03SGordon Ross */ 176402d09e03SGordon Ross sep = SMBFS_DNP_SEP(dnp); 176502d09e03SGordon Ross np = smbfs_node_findcreate(dnp->n_mount, 176602d09e03SGordon Ross dnp->n_rpath, dnp->n_rplen, 176702d09e03SGordon Ross nm, nmlen, sep, NULL); 176802d09e03SGordon Ross if (np == NULL) { 176991d632c8Sgwr #ifdef DEBUG 177002d09e03SGordon Ross smbfs_lookup_cache_miss++; 177191d632c8Sgwr #endif 177202d09e03SGordon Ross return (0); 177302d09e03SGordon Ross } 177402d09e03SGordon Ross 177502d09e03SGordon Ross /* 177602d09e03SGordon Ross * Found it. Attributes still valid? 177702d09e03SGordon Ross */ 177802d09e03SGordon Ross vp = SMBTOV(np); 177902d09e03SGordon Ross if (np->r_attrtime <= gethrtime()) { 178002d09e03SGordon Ross /* stale */ 178191d632c8Sgwr #ifdef DEBUG 178202d09e03SGordon Ross smbfs_lookup_cache_stale++; 178391d632c8Sgwr #endif 178402d09e03SGordon Ross VN_RELE(vp); 178502d09e03SGordon Ross return (0); 178691d632c8Sgwr } 178702d09e03SGordon Ross 178802d09e03SGordon Ross /* 178902d09e03SGordon Ross * Success! 179002d09e03SGordon Ross * Caller gets hold from smbfs_node_findcreate 179102d09e03SGordon Ross */ 179291d632c8Sgwr #ifdef DEBUG 179302d09e03SGordon Ross smbfs_lookup_cache_hits++; 179491d632c8Sgwr #endif 179502d09e03SGordon Ross *vpp = vp; 179691d632c8Sgwr return (0); 179791d632c8Sgwr } 179891d632c8Sgwr 17994bff34e3Sthurlow /* 18004bff34e3Sthurlow * XXX 18014bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 18024bff34e3Sthurlow * it in order to create an ACL when an object is created. 18034bff34e3Sthurlow * 18044bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 18054bff34e3Sthurlow * lookups, per PSARC 2007/244. 18064bff34e3Sthurlow */ 18074bff34e3Sthurlow /* ARGSUSED */ 18084bff34e3Sthurlow static int 18094bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, 18104bff34e3Sthurlow int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct, 18114bff34e3Sthurlow vsecattr_t *vsecp) 18124bff34e3Sthurlow { 18134bff34e3Sthurlow int error; 18144bff34e3Sthurlow int cerror; 18154bff34e3Sthurlow vfs_t *vfsp; 18164bff34e3Sthurlow vnode_t *vp; 18174bff34e3Sthurlow #ifdef NOT_YET 18184bff34e3Sthurlow smbnode_t *np; 18194bff34e3Sthurlow #endif 18204bff34e3Sthurlow smbnode_t *dnp; 18214bff34e3Sthurlow smbmntinfo_t *smi; 18224bff34e3Sthurlow struct vattr vattr; 18234bff34e3Sthurlow struct smbfattr fattr; 18244bff34e3Sthurlow struct smb_cred scred; 18254bff34e3Sthurlow const char *name = (const char *)nm; 18264bff34e3Sthurlow int nmlen = strlen(nm); 18274bff34e3Sthurlow uint32_t disp; 18284bff34e3Sthurlow uint16_t fid; 182991d632c8Sgwr int xattr; 18304bff34e3Sthurlow 18314bff34e3Sthurlow vfsp = dvp->v_vfsp; 18324bff34e3Sthurlow smi = VFTOSMI(vfsp); 18334bff34e3Sthurlow dnp = VTOSMB(dvp); 18344bff34e3Sthurlow vp = NULL; 18354bff34e3Sthurlow 1836a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 18374bff34e3Sthurlow return (EPERM); 18384bff34e3Sthurlow 18394bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 18404bff34e3Sthurlow return (EIO); 18414bff34e3Sthurlow 18424bff34e3Sthurlow /* 18434bff34e3Sthurlow * Note: this may break mknod(2) calls to create a directory, 18444bff34e3Sthurlow * but that's obscure use. Some other filesystems do this. 18454bff34e3Sthurlow * XXX: Later, redirect VDIR type here to _mkdir. 18464bff34e3Sthurlow */ 18474bff34e3Sthurlow if (va->va_type != VREG) 18484bff34e3Sthurlow return (EINVAL); 18494bff34e3Sthurlow 18504bff34e3Sthurlow /* 18514bff34e3Sthurlow * If the pathname is "", just use dvp, no checks. 18524bff34e3Sthurlow * Do this outside of the rwlock (like zfs). 18534bff34e3Sthurlow */ 18544bff34e3Sthurlow if (nmlen == 0) { 18554bff34e3Sthurlow VN_HOLD(dvp); 18564bff34e3Sthurlow *vpp = dvp; 18574bff34e3Sthurlow return (0); 18584bff34e3Sthurlow } 18594bff34e3Sthurlow 18604bff34e3Sthurlow /* Don't allow "." or ".." through here. */ 18614bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 18624bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 18634bff34e3Sthurlow return (EISDIR); 18644bff34e3Sthurlow 18654bff34e3Sthurlow /* 18664bff34e3Sthurlow * We make a copy of the attributes because the caller does not 18674bff34e3Sthurlow * expect us to change what va points to. 18684bff34e3Sthurlow */ 18694bff34e3Sthurlow vattr = *va; 18704bff34e3Sthurlow 18714bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 18724bff34e3Sthurlow return (EINTR); 1873613a2f6bSGordon Ross smb_credinit(&scred, cr); 18744bff34e3Sthurlow 18754bff34e3Sthurlow /* 18764bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 18774bff34e3Sthurlow * No use of any shared fid or fctx... 18784bff34e3Sthurlow */ 18794bff34e3Sthurlow 18804bff34e3Sthurlow /* 18814bff34e3Sthurlow * NFS needs to go over the wire, just to be sure whether the 188202d09e03SGordon Ross * file exists or not. Using a cached result is dangerous in 18834bff34e3Sthurlow * this case when making a decision regarding existence. 18844bff34e3Sthurlow * 18854bff34e3Sthurlow * The SMB protocol does NOT really need to go OTW here 18864bff34e3Sthurlow * thanks to the expressive NTCREATE disposition values. 18874bff34e3Sthurlow * Unfortunately, to do Unix access checks correctly, 18884bff34e3Sthurlow * we need to know if the object already exists. 18894bff34e3Sthurlow * When the object does not exist, we need VWRITE on 18904bff34e3Sthurlow * the directory. Note: smbfslookup() checks VEXEC. 18914bff34e3Sthurlow */ 18924bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 18934bff34e3Sthurlow if (error == 0) { 18944bff34e3Sthurlow /* 189542645588SGordon Ross * The file already exists. Error? 189642645588SGordon Ross * NB: have a hold from smbfslookup 18974bff34e3Sthurlow */ 18984bff34e3Sthurlow if (exclusive == EXCL) { 18994bff34e3Sthurlow error = EEXIST; 190042645588SGordon Ross VN_RELE(vp); 19014bff34e3Sthurlow goto out; 19024bff34e3Sthurlow } 19034bff34e3Sthurlow /* 19044bff34e3Sthurlow * Verify requested access. 19054bff34e3Sthurlow */ 19064bff34e3Sthurlow error = smbfs_access(vp, mode, 0, cr, ct); 190742645588SGordon Ross if (error) { 190842645588SGordon Ross VN_RELE(vp); 19094bff34e3Sthurlow goto out; 191042645588SGordon Ross } 19114bff34e3Sthurlow 19124bff34e3Sthurlow /* 19134bff34e3Sthurlow * Truncate (if requested). 19144bff34e3Sthurlow */ 19154bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) { 19164bff34e3Sthurlow vattr.va_mask = AT_SIZE; 19174bff34e3Sthurlow error = smbfssetattr(vp, &vattr, 0, cr); 191842645588SGordon Ross if (error) { 191942645588SGordon Ross VN_RELE(vp); 19204bff34e3Sthurlow goto out; 192142645588SGordon Ross } 19224bff34e3Sthurlow } 19234bff34e3Sthurlow /* Success! */ 19244bff34e3Sthurlow #ifdef NOT_YET 19254bff34e3Sthurlow vnevent_create(vp, ct); 19264bff34e3Sthurlow #endif 19274bff34e3Sthurlow *vpp = vp; 19284bff34e3Sthurlow goto out; 19294bff34e3Sthurlow } 19304bff34e3Sthurlow 19314bff34e3Sthurlow /* 19324bff34e3Sthurlow * The file did not exist. Need VWRITE in the directory. 19334bff34e3Sthurlow */ 19344bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 19354bff34e3Sthurlow if (error) 19364bff34e3Sthurlow goto out; 19374bff34e3Sthurlow 19384bff34e3Sthurlow /* 19394bff34e3Sthurlow * Now things get tricky. We also need to check the 19404bff34e3Sthurlow * requested open mode against the file we may create. 19414bff34e3Sthurlow * See comments at smbfs_access_rwx 19424bff34e3Sthurlow */ 19434bff34e3Sthurlow error = smbfs_access_rwx(vfsp, VREG, mode, cr); 19444bff34e3Sthurlow if (error) 19454bff34e3Sthurlow goto out; 19464bff34e3Sthurlow 19474bff34e3Sthurlow /* 19484bff34e3Sthurlow * Now the code derived from Darwin, 19494bff34e3Sthurlow * but with greater use of NT_CREATE 19504bff34e3Sthurlow * disposition options. Much changed. 19514bff34e3Sthurlow * 19524bff34e3Sthurlow * Create (or open) a new child node. 19534bff34e3Sthurlow * Note we handled "." and ".." above. 19544bff34e3Sthurlow */ 19554bff34e3Sthurlow 19564bff34e3Sthurlow if (exclusive == EXCL) 19574bff34e3Sthurlow disp = NTCREATEX_DISP_CREATE; 19584bff34e3Sthurlow else { 19594bff34e3Sthurlow /* Truncate regular files if requested. */ 19604bff34e3Sthurlow if ((va->va_type == VREG) && 19614bff34e3Sthurlow (va->va_mask & AT_SIZE) && 19624bff34e3Sthurlow (va->va_size == 0)) 19634bff34e3Sthurlow disp = NTCREATEX_DISP_OVERWRITE_IF; 19644bff34e3Sthurlow else 19654bff34e3Sthurlow disp = NTCREATEX_DISP_OPEN_IF; 19664bff34e3Sthurlow } 196791d632c8Sgwr xattr = (dnp->n_flag & N_XATTR) ? 1 : 0; 196802d09e03SGordon Ross error = smbfs_smb_create(dnp, 196902d09e03SGordon Ross name, nmlen, xattr, 197002d09e03SGordon Ross disp, &scred, &fid); 19714bff34e3Sthurlow if (error) 19724bff34e3Sthurlow goto out; 19734bff34e3Sthurlow 19744bff34e3Sthurlow /* 19754bff34e3Sthurlow * XXX: Missing some code here to deal with 19764bff34e3Sthurlow * the case where we opened an existing file, 19774bff34e3Sthurlow * it's size is larger than 32-bits, and we're 19784bff34e3Sthurlow * setting the size from a process that's not 19794bff34e3Sthurlow * aware of large file offsets. i.e. 19804bff34e3Sthurlow * from the NFS3 code: 19814bff34e3Sthurlow */ 19824bff34e3Sthurlow #if NOT_YET /* XXX */ 19834bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && 19844bff34e3Sthurlow vp->v_type == VREG) { 19854bff34e3Sthurlow np = VTOSMB(vp); 19864bff34e3Sthurlow /* 19874bff34e3Sthurlow * Check here for large file handled 19884bff34e3Sthurlow * by LF-unaware process (as 19894bff34e3Sthurlow * ufs_create() does) 19904bff34e3Sthurlow */ 19914bff34e3Sthurlow if (!(lfaware & FOFFMAX)) { 19924bff34e3Sthurlow mutex_enter(&np->r_statelock); 19934bff34e3Sthurlow if (np->r_size > MAXOFF32_T) 19944bff34e3Sthurlow error = EOVERFLOW; 19954bff34e3Sthurlow mutex_exit(&np->r_statelock); 19964bff34e3Sthurlow } 19974bff34e3Sthurlow if (!error) { 19984bff34e3Sthurlow vattr.va_mask = AT_SIZE; 19994bff34e3Sthurlow error = smbfssetattr(vp, 20004bff34e3Sthurlow &vattr, 0, cr); 20014bff34e3Sthurlow } 20024bff34e3Sthurlow } 20034bff34e3Sthurlow #endif /* XXX */ 20044bff34e3Sthurlow /* 20054bff34e3Sthurlow * Should use the fid to get/set the size 20064bff34e3Sthurlow * while we have it opened here. See above. 20074bff34e3Sthurlow */ 20084bff34e3Sthurlow 20094bff34e3Sthurlow cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); 20104bff34e3Sthurlow if (cerror) 201102d09e03SGordon Ross SMBVDEBUG("error %d closing %s\\%s\n", 20124bff34e3Sthurlow cerror, dnp->n_rpath, name); 20134bff34e3Sthurlow 20144bff34e3Sthurlow /* 20154bff34e3Sthurlow * In the open case, the name may differ a little 20164bff34e3Sthurlow * from what we passed to create (case, etc.) 20174bff34e3Sthurlow * so call lookup to get the (opened) name. 20184bff34e3Sthurlow * 20194bff34e3Sthurlow * XXX: Could avoid this extra lookup if the 20204bff34e3Sthurlow * "createact" result from NT_CREATE says we 20214bff34e3Sthurlow * created the object. 20224bff34e3Sthurlow */ 20234bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 20244bff34e3Sthurlow if (error) 20254bff34e3Sthurlow goto out; 20264bff34e3Sthurlow 20274bff34e3Sthurlow /* update attr and directory cache */ 20284bff34e3Sthurlow smbfs_attr_touchdir(dnp); 20294bff34e3Sthurlow 20304bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 20314bff34e3Sthurlow if (error) 20324bff34e3Sthurlow goto out; 20334bff34e3Sthurlow 203491d632c8Sgwr /* XXX invalidate pages if we truncated? */ 203591d632c8Sgwr 20364bff34e3Sthurlow /* Success! */ 20374bff34e3Sthurlow *vpp = vp; 20384bff34e3Sthurlow error = 0; 20394bff34e3Sthurlow 20404bff34e3Sthurlow out: 20414bff34e3Sthurlow smb_credrele(&scred); 204202d09e03SGordon Ross smbfs_rw_exit(&dnp->r_rwlock); 20434bff34e3Sthurlow if (name != nm) 20444bff34e3Sthurlow smbfs_name_free(name, nmlen); 20454bff34e3Sthurlow return (error); 20464bff34e3Sthurlow } 20474bff34e3Sthurlow 20484bff34e3Sthurlow /* 20494bff34e3Sthurlow * XXX 20504bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 20514bff34e3Sthurlow * lookups, per PSARC 2007/244. 20524bff34e3Sthurlow */ 20534bff34e3Sthurlow /* ARGSUSED */ 20544bff34e3Sthurlow static int 20554bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 20564bff34e3Sthurlow int flags) 20574bff34e3Sthurlow { 20584bff34e3Sthurlow int error; 20594bff34e3Sthurlow vnode_t *vp; 20604bff34e3Sthurlow smbnode_t *np; 20614bff34e3Sthurlow smbnode_t *dnp; 20624bff34e3Sthurlow struct smb_cred scred; 20634bff34e3Sthurlow /* enum smbfsstat status; */ 20644bff34e3Sthurlow smbmntinfo_t *smi; 20654bff34e3Sthurlow 20664bff34e3Sthurlow smi = VTOSMI(dvp); 20674bff34e3Sthurlow 2068a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 20694bff34e3Sthurlow return (EPERM); 20704bff34e3Sthurlow 20714bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 20724bff34e3Sthurlow return (EIO); 20734bff34e3Sthurlow 20744bff34e3Sthurlow dnp = VTOSMB(dvp); 20754bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 20764bff34e3Sthurlow return (EINTR); 207702d09e03SGordon Ross smb_credinit(&scred, cr); 20784bff34e3Sthurlow 20794bff34e3Sthurlow /* 20804bff34e3Sthurlow * Verify access to the dirctory. 20814bff34e3Sthurlow */ 20824bff34e3Sthurlow error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); 20834bff34e3Sthurlow if (error) 20844bff34e3Sthurlow goto out; 20854bff34e3Sthurlow 20864bff34e3Sthurlow /* 20874bff34e3Sthurlow * NOTE: the darwin code gets the "vp" passed in so it looks 20884bff34e3Sthurlow * like the "vp" has probably been "lookup"ed by the VFS layer. 20894bff34e3Sthurlow * It looks like we will need to lookup the vp to check the 20904bff34e3Sthurlow * caches and check if the object being deleted is a directory. 20914bff34e3Sthurlow */ 20924bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 20934bff34e3Sthurlow if (error) 20944bff34e3Sthurlow goto out; 20954bff34e3Sthurlow 20964bff34e3Sthurlow /* Never allow link/unlink directories on CIFS. */ 20974bff34e3Sthurlow if (vp->v_type == VDIR) { 20984bff34e3Sthurlow VN_RELE(vp); 20994bff34e3Sthurlow error = EPERM; 21004bff34e3Sthurlow goto out; 21014bff34e3Sthurlow } 21024bff34e3Sthurlow 21034bff34e3Sthurlow /* 21044bff34e3Sthurlow * Now we have the real reference count on the vnode 210502d09e03SGordon Ross * Do we have the file open? 21064bff34e3Sthurlow */ 21074bff34e3Sthurlow np = VTOSMB(vp); 21084bff34e3Sthurlow mutex_enter(&np->r_statelock); 210902d09e03SGordon Ross if ((vp->v_count > 1) && (np->n_fidrefs > 0)) { 21104bff34e3Sthurlow /* 21114bff34e3Sthurlow * NFS does a rename on remove here. 21124bff34e3Sthurlow * Probably not applicable for SMB. 21134bff34e3Sthurlow * Like Darwin, just return EBUSY. 21144bff34e3Sthurlow * 211502d09e03SGordon Ross * XXX: Todo - Use Trans2rename, and 211602d09e03SGordon Ross * if that fails, ask the server to 21174bff34e3Sthurlow * set the delete-on-close flag. 21184bff34e3Sthurlow */ 21194bff34e3Sthurlow mutex_exit(&np->r_statelock); 21204bff34e3Sthurlow error = EBUSY; 21214bff34e3Sthurlow } else { 212202d09e03SGordon Ross smbfs_attrcache_rm_locked(np); 21234bff34e3Sthurlow mutex_exit(&np->r_statelock); 21244bff34e3Sthurlow 21254bff34e3Sthurlow error = smbfs_smb_delete(np, &scred, NULL, 0, 0); 21264bff34e3Sthurlow 212702d09e03SGordon Ross /* 212802d09e03SGordon Ross * If the file should no longer exist, discard 212902d09e03SGordon Ross * any cached attributes under this node. 213002d09e03SGordon Ross */ 213102d09e03SGordon Ross switch (error) { 213202d09e03SGordon Ross case 0: 213302d09e03SGordon Ross case ENOENT: 213402d09e03SGordon Ross case ENOTDIR: 213502d09e03SGordon Ross smbfs_attrcache_prune(np); 213602d09e03SGordon Ross break; 213702d09e03SGordon Ross } 21384bff34e3Sthurlow } 21394bff34e3Sthurlow 21404bff34e3Sthurlow VN_RELE(vp); 21414bff34e3Sthurlow 21424bff34e3Sthurlow out: 214302d09e03SGordon Ross smb_credrele(&scred); 21444bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 21454bff34e3Sthurlow 21464bff34e3Sthurlow return (error); 21474bff34e3Sthurlow } 21484bff34e3Sthurlow 21494bff34e3Sthurlow 21504bff34e3Sthurlow /* 21514bff34e3Sthurlow * XXX 21524bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 21534bff34e3Sthurlow * lookups, per PSARC 2007/244. 21544bff34e3Sthurlow */ 21554bff34e3Sthurlow /* ARGSUSED */ 21564bff34e3Sthurlow static int 21574bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 21584bff34e3Sthurlow caller_context_t *ct, int flags) 21594bff34e3Sthurlow { 21604bff34e3Sthurlow /* vnode_t *realvp; */ 21614bff34e3Sthurlow 2162a19609f8Sjv if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone || 2163a19609f8Sjv curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone) 21644bff34e3Sthurlow return (EPERM); 21654bff34e3Sthurlow 21664bff34e3Sthurlow if (VTOSMI(odvp)->smi_flags & SMI_DEAD || 21674bff34e3Sthurlow VTOSMI(ndvp)->smi_flags & SMI_DEAD || 21684bff34e3Sthurlow odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED || 21694bff34e3Sthurlow ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 21704bff34e3Sthurlow return (EIO); 21714bff34e3Sthurlow 21724bff34e3Sthurlow return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct)); 21734bff34e3Sthurlow } 21744bff34e3Sthurlow 21754bff34e3Sthurlow /* 21764bff34e3Sthurlow * smbfsrename does the real work of renaming in SMBFS 21774bff34e3Sthurlow */ 21784bff34e3Sthurlow /* ARGSUSED */ 21794bff34e3Sthurlow static int 21804bff34e3Sthurlow smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 21814bff34e3Sthurlow caller_context_t *ct) 21824bff34e3Sthurlow { 21834bff34e3Sthurlow int error; 21844bff34e3Sthurlow int nvp_locked = 0; 21854bff34e3Sthurlow vnode_t *nvp = NULL; 21864bff34e3Sthurlow vnode_t *ovp = NULL; 21874bff34e3Sthurlow smbnode_t *onp; 218891d632c8Sgwr smbnode_t *nnp; 21894bff34e3Sthurlow smbnode_t *odnp; 21904bff34e3Sthurlow smbnode_t *ndnp; 21914bff34e3Sthurlow struct smb_cred scred; 21924bff34e3Sthurlow /* enum smbfsstat status; */ 21934bff34e3Sthurlow 2194a19609f8Sjv ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone); 21954bff34e3Sthurlow 21964bff34e3Sthurlow if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 || 21974bff34e3Sthurlow strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) 21984bff34e3Sthurlow return (EINVAL); 21994bff34e3Sthurlow 22004bff34e3Sthurlow /* 22014bff34e3Sthurlow * Check that everything is on the same filesystem. 22024bff34e3Sthurlow * vn_rename checks the fsid's, but in case we don't 22034bff34e3Sthurlow * fill those in correctly, check here too. 22044bff34e3Sthurlow */ 22054bff34e3Sthurlow if (odvp->v_vfsp != ndvp->v_vfsp) 22064bff34e3Sthurlow return (EXDEV); 22074bff34e3Sthurlow 22084bff34e3Sthurlow odnp = VTOSMB(odvp); 22094bff34e3Sthurlow ndnp = VTOSMB(ndvp); 22104bff34e3Sthurlow 22114bff34e3Sthurlow /* 22124bff34e3Sthurlow * Avoid deadlock here on old vs new directory nodes 22134bff34e3Sthurlow * by always taking the locks in order of address. 22144bff34e3Sthurlow * The order is arbitrary, but must be consistent. 22154bff34e3Sthurlow */ 22164bff34e3Sthurlow if (odnp < ndnp) { 22174bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 22184bff34e3Sthurlow SMBINTR(odvp))) 22194bff34e3Sthurlow return (EINTR); 22204bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 22214bff34e3Sthurlow SMBINTR(ndvp))) { 22224bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 22234bff34e3Sthurlow return (EINTR); 22244bff34e3Sthurlow } 22254bff34e3Sthurlow } else { 22264bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 22274bff34e3Sthurlow SMBINTR(ndvp))) 22284bff34e3Sthurlow return (EINTR); 22294bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 22304bff34e3Sthurlow SMBINTR(odvp))) { 22314bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 22324bff34e3Sthurlow return (EINTR); 22334bff34e3Sthurlow } 22344bff34e3Sthurlow } 223502d09e03SGordon Ross smb_credinit(&scred, cr); 22364bff34e3Sthurlow /* 22374bff34e3Sthurlow * No returns after this point (goto out) 22384bff34e3Sthurlow */ 22394bff34e3Sthurlow 22404bff34e3Sthurlow /* 22414bff34e3Sthurlow * Need write access on source and target. 22424bff34e3Sthurlow * Server takes care of most checks. 22434bff34e3Sthurlow */ 22444bff34e3Sthurlow error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct); 22454bff34e3Sthurlow if (error) 22464bff34e3Sthurlow goto out; 22474bff34e3Sthurlow if (odvp != ndvp) { 22484bff34e3Sthurlow error = smbfs_access(ndvp, VWRITE, 0, cr, ct); 22494bff34e3Sthurlow if (error) 22504bff34e3Sthurlow goto out; 22514bff34e3Sthurlow } 22524bff34e3Sthurlow 22534bff34e3Sthurlow /* 22544bff34e3Sthurlow * Lookup the source name. Must already exist. 22554bff34e3Sthurlow */ 22564bff34e3Sthurlow error = smbfslookup(odvp, onm, &ovp, cr, 0, ct); 22574bff34e3Sthurlow if (error) 22584bff34e3Sthurlow goto out; 22594bff34e3Sthurlow 22604bff34e3Sthurlow /* 22614bff34e3Sthurlow * Lookup the target file. If it exists, it needs to be 22624bff34e3Sthurlow * checked to see whether it is a mount point and whether 22634bff34e3Sthurlow * it is active (open). 22644bff34e3Sthurlow */ 22654bff34e3Sthurlow error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct); 22664bff34e3Sthurlow if (!error) { 22674bff34e3Sthurlow /* 22684bff34e3Sthurlow * Target (nvp) already exists. Check that it 22694bff34e3Sthurlow * has the same type as the source. The server 22704bff34e3Sthurlow * will check this also, (and more reliably) but 22714bff34e3Sthurlow * this lets us return the correct error codes. 22724bff34e3Sthurlow */ 22734bff34e3Sthurlow if (ovp->v_type == VDIR) { 22744bff34e3Sthurlow if (nvp->v_type != VDIR) { 22754bff34e3Sthurlow error = ENOTDIR; 22764bff34e3Sthurlow goto out; 22774bff34e3Sthurlow } 22784bff34e3Sthurlow } else { 22794bff34e3Sthurlow if (nvp->v_type == VDIR) { 22804bff34e3Sthurlow error = EISDIR; 22814bff34e3Sthurlow goto out; 22824bff34e3Sthurlow } 22834bff34e3Sthurlow } 22844bff34e3Sthurlow 22854bff34e3Sthurlow /* 22864bff34e3Sthurlow * POSIX dictates that when the source and target 22874bff34e3Sthurlow * entries refer to the same file object, rename 22884bff34e3Sthurlow * must do nothing and exit without error. 22894bff34e3Sthurlow */ 22904bff34e3Sthurlow if (ovp == nvp) { 22914bff34e3Sthurlow error = 0; 22924bff34e3Sthurlow goto out; 22934bff34e3Sthurlow } 22944bff34e3Sthurlow 22954bff34e3Sthurlow /* 22964bff34e3Sthurlow * Also must ensure the target is not a mount point, 22974bff34e3Sthurlow * and keep mount/umount away until we're done. 22984bff34e3Sthurlow */ 22994bff34e3Sthurlow if (vn_vfsrlock(nvp)) { 23004bff34e3Sthurlow error = EBUSY; 23014bff34e3Sthurlow goto out; 23024bff34e3Sthurlow } 23034bff34e3Sthurlow nvp_locked = 1; 23044bff34e3Sthurlow if (vn_mountedvfs(nvp) != NULL) { 23054bff34e3Sthurlow error = EBUSY; 23064bff34e3Sthurlow goto out; 23074bff34e3Sthurlow } 23084bff34e3Sthurlow 230991d632c8Sgwr /* 231091d632c8Sgwr * CIFS gives a SHARING_VIOLATION error when 231191d632c8Sgwr * trying to rename onto an exising object, 231291d632c8Sgwr * so try to remove the target first. 231391d632c8Sgwr * (Only for files, not directories.) 231491d632c8Sgwr */ 231591d632c8Sgwr if (nvp->v_type == VDIR) { 231691d632c8Sgwr error = EEXIST; 231791d632c8Sgwr goto out; 231891d632c8Sgwr } 23194bff34e3Sthurlow 232091d632c8Sgwr /* 232142645588SGordon Ross * Nodes that are "not active" here have v_count=2 232242645588SGordon Ross * because vn_renameat (our caller) did a lookup on 232342645588SGordon Ross * both the source and target before this call. 232442645588SGordon Ross * Otherwise this similar to smbfs_remove. 232591d632c8Sgwr */ 232691d632c8Sgwr nnp = VTOSMB(nvp); 232791d632c8Sgwr mutex_enter(&nnp->r_statelock); 232802d09e03SGordon Ross if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) { 23294bff34e3Sthurlow /* 23304bff34e3Sthurlow * The target file exists, is not the same as 23314bff34e3Sthurlow * the source file, and is active. Other FS 23324bff34e3Sthurlow * implementations unlink the target here. 23334bff34e3Sthurlow * For SMB, we don't assume we can remove an 23344bff34e3Sthurlow * open file. Return an error instead. 23354bff34e3Sthurlow */ 233691d632c8Sgwr mutex_exit(&nnp->r_statelock); 233791d632c8Sgwr error = EBUSY; 23384bff34e3Sthurlow goto out; 23394bff34e3Sthurlow } 234091d632c8Sgwr 234191d632c8Sgwr /* 234291d632c8Sgwr * Target file is not active. Try to remove it. 234391d632c8Sgwr */ 234402d09e03SGordon Ross smbfs_attrcache_rm_locked(nnp); 234502d09e03SGordon Ross mutex_exit(&nnp->r_statelock); 234602d09e03SGordon Ross 234791d632c8Sgwr error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0); 234802d09e03SGordon Ross 234902d09e03SGordon Ross /* 235002d09e03SGordon Ross * Similar to smbfs_remove 235102d09e03SGordon Ross */ 235202d09e03SGordon Ross switch (error) { 235302d09e03SGordon Ross case 0: 235402d09e03SGordon Ross case ENOENT: 235502d09e03SGordon Ross case ENOTDIR: 235602d09e03SGordon Ross smbfs_attrcache_prune(nnp); 235702d09e03SGordon Ross break; 235802d09e03SGordon Ross } 235902d09e03SGordon Ross 236091d632c8Sgwr if (error) 236191d632c8Sgwr goto out; 236291d632c8Sgwr /* 236391d632c8Sgwr * OK, removed the target file. Continue as if 236491d632c8Sgwr * lookup target had failed (nvp == NULL). 236591d632c8Sgwr */ 236691d632c8Sgwr vn_vfsunlock(nvp); 236791d632c8Sgwr nvp_locked = 0; 236891d632c8Sgwr VN_RELE(nvp); 236991d632c8Sgwr nvp = NULL; 23704bff34e3Sthurlow } /* nvp */ 23714bff34e3Sthurlow 23724bff34e3Sthurlow onp = VTOSMB(ovp); 237302d09e03SGordon Ross smbfs_attrcache_remove(onp); 237402d09e03SGordon Ross 23754bff34e3Sthurlow error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); 23764bff34e3Sthurlow 237702d09e03SGordon Ross /* 237802d09e03SGordon Ross * If the old name should no longer exist, 237902d09e03SGordon Ross * discard any cached attributes under it. 238002d09e03SGordon Ross */ 238102d09e03SGordon Ross if (error == 0) 238202d09e03SGordon Ross smbfs_attrcache_prune(onp); 23834bff34e3Sthurlow 23844bff34e3Sthurlow out: 23854bff34e3Sthurlow if (nvp) { 23864bff34e3Sthurlow if (nvp_locked) 23874bff34e3Sthurlow vn_vfsunlock(nvp); 23884bff34e3Sthurlow VN_RELE(nvp); 23894bff34e3Sthurlow } 23904bff34e3Sthurlow if (ovp) 23914bff34e3Sthurlow VN_RELE(ovp); 23924bff34e3Sthurlow 239302d09e03SGordon Ross smb_credrele(&scred); 23944bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 23954bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 23964bff34e3Sthurlow 23974bff34e3Sthurlow return (error); 23984bff34e3Sthurlow } 23994bff34e3Sthurlow 24004bff34e3Sthurlow /* 24014bff34e3Sthurlow * XXX 24024bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 24034bff34e3Sthurlow * it in order to create an ACL when an object is created. 24044bff34e3Sthurlow * 24054bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 24064bff34e3Sthurlow * lookups, per PSARC 2007/244. 24074bff34e3Sthurlow */ 24084bff34e3Sthurlow /* ARGSUSED */ 24094bff34e3Sthurlow static int 24104bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, 24114bff34e3Sthurlow cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 24124bff34e3Sthurlow { 24134bff34e3Sthurlow vnode_t *vp; 24144bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 24154bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 24164bff34e3Sthurlow struct smb_cred scred; 24174bff34e3Sthurlow struct smbfattr fattr; 24184bff34e3Sthurlow const char *name = (const char *) nm; 24194bff34e3Sthurlow int nmlen = strlen(name); 24204bff34e3Sthurlow int error, hiderr; 24214bff34e3Sthurlow 2422a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 24234bff34e3Sthurlow return (EPERM); 24244bff34e3Sthurlow 24254bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 24264bff34e3Sthurlow return (EIO); 24274bff34e3Sthurlow 24284bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 24294bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 24304bff34e3Sthurlow return (EEXIST); 24314bff34e3Sthurlow 243291d632c8Sgwr /* Only plain files are allowed in V_XATTRDIR. */ 243391d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) 243491d632c8Sgwr return (EINVAL); 243591d632c8Sgwr 24364bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 24374bff34e3Sthurlow return (EINTR); 2438613a2f6bSGordon Ross smb_credinit(&scred, cr); 24394bff34e3Sthurlow 24404bff34e3Sthurlow /* 24414bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 24424bff34e3Sthurlow * No use of any shared fid or fctx... 24434bff34e3Sthurlow */ 24444bff34e3Sthurlow 24454bff34e3Sthurlow /* 24464bff34e3Sthurlow * Require write access in the containing directory. 24474bff34e3Sthurlow */ 24484bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 24494bff34e3Sthurlow if (error) 24504bff34e3Sthurlow goto out; 24514bff34e3Sthurlow 24524bff34e3Sthurlow error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); 24534bff34e3Sthurlow if (error) 24544bff34e3Sthurlow goto out; 24554bff34e3Sthurlow 24564bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 24574bff34e3Sthurlow if (error) 24584bff34e3Sthurlow goto out; 24594bff34e3Sthurlow 24604bff34e3Sthurlow smbfs_attr_touchdir(dnp); 24614bff34e3Sthurlow 24624bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 24634bff34e3Sthurlow if (error) 24644bff34e3Sthurlow goto out; 24654bff34e3Sthurlow 24664bff34e3Sthurlow if (name[0] == '.') 24674bff34e3Sthurlow if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) 24684bff34e3Sthurlow SMBVDEBUG("hide failure %d\n", hiderr); 24694bff34e3Sthurlow 24704bff34e3Sthurlow /* Success! */ 24714bff34e3Sthurlow *vpp = vp; 24724bff34e3Sthurlow error = 0; 24734bff34e3Sthurlow out: 24744bff34e3Sthurlow smb_credrele(&scred); 24754bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 24764bff34e3Sthurlow 24774bff34e3Sthurlow if (name != nm) 24784bff34e3Sthurlow smbfs_name_free(name, nmlen); 24794bff34e3Sthurlow 24804bff34e3Sthurlow return (error); 24814bff34e3Sthurlow } 24824bff34e3Sthurlow 24834bff34e3Sthurlow /* 24844bff34e3Sthurlow * XXX 24854bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 24864bff34e3Sthurlow * lookups, per PSARC 2007/244. 24874bff34e3Sthurlow */ 24884bff34e3Sthurlow /* ARGSUSED */ 24894bff34e3Sthurlow static int 24904bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 24914bff34e3Sthurlow caller_context_t *ct, int flags) 24924bff34e3Sthurlow { 24934bff34e3Sthurlow vnode_t *vp = NULL; 24944bff34e3Sthurlow int vp_locked = 0; 24954bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 24964bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 24974bff34e3Sthurlow struct smbnode *np; 24984bff34e3Sthurlow struct smb_cred scred; 24994bff34e3Sthurlow int error; 25004bff34e3Sthurlow 2501a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 25024bff34e3Sthurlow return (EPERM); 25034bff34e3Sthurlow 25044bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 25054bff34e3Sthurlow return (EIO); 25064bff34e3Sthurlow 25074bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 25084bff34e3Sthurlow return (EINTR); 2509613a2f6bSGordon Ross smb_credinit(&scred, cr); 25104bff34e3Sthurlow 25114bff34e3Sthurlow /* 25124bff34e3Sthurlow * Require w/x access in the containing directory. 25134bff34e3Sthurlow * Server handles all other access checks. 25144bff34e3Sthurlow */ 25154bff34e3Sthurlow error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); 25164bff34e3Sthurlow if (error) 25174bff34e3Sthurlow goto out; 25184bff34e3Sthurlow 25194bff34e3Sthurlow /* 25204bff34e3Sthurlow * First lookup the entry to be removed. 25214bff34e3Sthurlow */ 25224bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 25234bff34e3Sthurlow if (error) 25244bff34e3Sthurlow goto out; 25254bff34e3Sthurlow np = VTOSMB(vp); 25264bff34e3Sthurlow 25274bff34e3Sthurlow /* 25284bff34e3Sthurlow * Disallow rmdir of "." or current dir, or the FS root. 25294bff34e3Sthurlow * Also make sure it's a directory, not a mount point, 25304bff34e3Sthurlow * and lock to keep mount/umount away until we're done. 25314bff34e3Sthurlow */ 25324bff34e3Sthurlow if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) { 25334bff34e3Sthurlow error = EINVAL; 25344bff34e3Sthurlow goto out; 25354bff34e3Sthurlow } 25364bff34e3Sthurlow if (vp->v_type != VDIR) { 25374bff34e3Sthurlow error = ENOTDIR; 25384bff34e3Sthurlow goto out; 25394bff34e3Sthurlow } 25404bff34e3Sthurlow if (vn_vfsrlock(vp)) { 25414bff34e3Sthurlow error = EBUSY; 25424bff34e3Sthurlow goto out; 25434bff34e3Sthurlow } 25444bff34e3Sthurlow vp_locked = 1; 25454bff34e3Sthurlow if (vn_mountedvfs(vp) != NULL) { 25464bff34e3Sthurlow error = EBUSY; 25474bff34e3Sthurlow goto out; 25484bff34e3Sthurlow } 25494bff34e3Sthurlow 255002d09e03SGordon Ross smbfs_attrcache_remove(np); 255102d09e03SGordon Ross error = smbfs_smb_rmdir(np, &scred); 255291d632c8Sgwr 255391d632c8Sgwr /* 255402d09e03SGordon Ross * Similar to smbfs_remove 255591d632c8Sgwr */ 255602d09e03SGordon Ross switch (error) { 255702d09e03SGordon Ross case 0: 255802d09e03SGordon Ross case ENOENT: 255902d09e03SGordon Ross case ENOTDIR: 256002d09e03SGordon Ross smbfs_attrcache_prune(np); 256102d09e03SGordon Ross break; 256291d632c8Sgwr } 256391d632c8Sgwr 25644bff34e3Sthurlow if (error) 25654bff34e3Sthurlow goto out; 25664bff34e3Sthurlow 25674bff34e3Sthurlow mutex_enter(&np->r_statelock); 25684bff34e3Sthurlow dnp->n_flag |= NMODIFIED; 25694bff34e3Sthurlow mutex_exit(&np->r_statelock); 25704bff34e3Sthurlow smbfs_attr_touchdir(dnp); 257102d09e03SGordon Ross smbfs_rmhash(np); 25724bff34e3Sthurlow 25734bff34e3Sthurlow out: 25744bff34e3Sthurlow if (vp) { 25754bff34e3Sthurlow if (vp_locked) 25764bff34e3Sthurlow vn_vfsunlock(vp); 25774bff34e3Sthurlow VN_RELE(vp); 25784bff34e3Sthurlow } 25794bff34e3Sthurlow smb_credrele(&scred); 25804bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 25814bff34e3Sthurlow 25824bff34e3Sthurlow return (error); 25834bff34e3Sthurlow } 25844bff34e3Sthurlow 25854bff34e3Sthurlow 25864bff34e3Sthurlow /* ARGSUSED */ 25874bff34e3Sthurlow static int 25884bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp, 25894bff34e3Sthurlow caller_context_t *ct, int flags) 25904bff34e3Sthurlow { 25914bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 25924bff34e3Sthurlow int error = 0; 25934bff34e3Sthurlow smbmntinfo_t *smi; 25944bff34e3Sthurlow 25954bff34e3Sthurlow smi = VTOSMI(vp); 25964bff34e3Sthurlow 2597a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 25984bff34e3Sthurlow return (EIO); 25994bff34e3Sthurlow 26004bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 26014bff34e3Sthurlow return (EIO); 26024bff34e3Sthurlow 26034bff34e3Sthurlow /* 26044bff34e3Sthurlow * Require read access in the directory. 26054bff34e3Sthurlow */ 26064bff34e3Sthurlow error = smbfs_access(vp, VREAD, 0, cr, ct); 26074bff34e3Sthurlow if (error) 26084bff34e3Sthurlow return (error); 26094bff34e3Sthurlow 26104bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 26114bff34e3Sthurlow 26124bff34e3Sthurlow /* 26134bff34e3Sthurlow * XXX: Todo readdir cache here 26144bff34e3Sthurlow * Note: NFS code is just below this. 26154bff34e3Sthurlow * 26164bff34e3Sthurlow * I am serializing the entire readdir opreation 26174bff34e3Sthurlow * now since we have not yet implemented readdir 26184bff34e3Sthurlow * cache. This fix needs to be revisited once 26194bff34e3Sthurlow * we implement readdir cache. 26204bff34e3Sthurlow */ 26214bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 26224bff34e3Sthurlow return (EINTR); 26234bff34e3Sthurlow 26244bff34e3Sthurlow error = smbfs_readvdir(vp, uiop, cr, eofp, ct); 26254bff34e3Sthurlow 26264bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 26274bff34e3Sthurlow 26284bff34e3Sthurlow return (error); 26294bff34e3Sthurlow } 26304bff34e3Sthurlow 26314bff34e3Sthurlow /* ARGSUSED */ 26324bff34e3Sthurlow static int 26334bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 26344bff34e3Sthurlow caller_context_t *ct) 26354bff34e3Sthurlow { 26365ecede33SGordon Ross /* 26375ecede33SGordon Ross * Note: "limit" tells the SMB-level FindFirst/FindNext 26385ecede33SGordon Ross * functions how many directory entries to request in 26395ecede33SGordon Ross * each OtW call. It needs to be large enough so that 26405ecede33SGordon Ross * we don't make lots of tiny OtW requests, but there's 26415ecede33SGordon Ross * no point making it larger than the maximum number of 26425ecede33SGordon Ross * OtW entries that would fit in a maximum sized trans2 26435ecede33SGordon Ross * response (64k / 48). Beyond that, it's just tuning. 26445ecede33SGordon Ross * WinNT used 512, Win2k used 1366. We use 1000. 26455ecede33SGordon Ross */ 26465ecede33SGordon Ross static const int limit = 1000; 26475ecede33SGordon Ross /* Largest possible dirent size. */ 26485ecede33SGordon Ross static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN); 26494bff34e3Sthurlow struct smb_cred scred; 26504bff34e3Sthurlow vnode_t *newvp; 26514bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 26524bff34e3Sthurlow struct smbfs_fctx *ctx; 26535ecede33SGordon Ross struct dirent64 *dp; 26545ecede33SGordon Ross ssize_t save_resid; 26555ecede33SGordon Ross offset_t save_offset; /* 64 bits */ 26565ecede33SGordon Ross int offset; /* yes, 32 bits */ 26575ecede33SGordon Ross int nmlen, error; 26585ecede33SGordon Ross ushort_t reclen; 26594bff34e3Sthurlow 2660a19609f8Sjv ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone); 26614bff34e3Sthurlow 26624bff34e3Sthurlow /* Make sure we serialize for n_dirseq use. */ 26634bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 26644bff34e3Sthurlow 26655ecede33SGordon Ross /* 26665ecede33SGordon Ross * Make sure smbfs_open filled in n_dirseq 26675ecede33SGordon Ross */ 26685ecede33SGordon Ross if (np->n_dirseq == NULL) 26695ecede33SGordon Ross return (EBADF); 26705ecede33SGordon Ross 26715ecede33SGordon Ross /* Check for overflow of (32-bit) directory offset. */ 26725ecede33SGordon Ross if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX || 26735ecede33SGordon Ross (uio->uio_loffset + uio->uio_resid) > INT32_MAX) 26745ecede33SGordon Ross return (EINVAL); 26755ecede33SGordon Ross 26765ecede33SGordon Ross /* Require space for at least one dirent. */ 26775ecede33SGordon Ross if (uio->uio_resid < dbufsiz) 26784bff34e3Sthurlow return (EINVAL); 26794bff34e3Sthurlow 26804bff34e3Sthurlow SMBVDEBUG("dirname='%s'\n", np->n_rpath); 2681613a2f6bSGordon Ross smb_credinit(&scred, cr); 26824bff34e3Sthurlow dp = kmem_alloc(dbufsiz, KM_SLEEP); 26834bff34e3Sthurlow 26845ecede33SGordon Ross save_resid = uio->uio_resid; 26855ecede33SGordon Ross save_offset = uio->uio_loffset; 26865ecede33SGordon Ross offset = uio->uio_offset; 26875ecede33SGordon Ross SMBVDEBUG("in: offset=%d, resid=%d\n", 26885ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 26895ecede33SGordon Ross error = 0; 26904bff34e3Sthurlow 26914bff34e3Sthurlow /* 26924bff34e3Sthurlow * Generate the "." and ".." entries here so we can 26934bff34e3Sthurlow * (1) make sure they appear (but only once), and 26944bff34e3Sthurlow * (2) deal with getting their I numbers which the 26954bff34e3Sthurlow * findnext below does only for normal names. 26964bff34e3Sthurlow */ 26975ecede33SGordon Ross while (offset < FIRST_DIROFS) { 26985ecede33SGordon Ross /* 26995ecede33SGordon Ross * Tricky bit filling in the first two: 27005ecede33SGordon Ross * offset 0 is ".", offset 1 is ".." 27015ecede33SGordon Ross * so strlen of these is offset+1. 27025ecede33SGordon Ross */ 27034bff34e3Sthurlow reclen = DIRENT64_RECLEN(offset + 1); 27045ecede33SGordon Ross if (uio->uio_resid < reclen) 27055ecede33SGordon Ross goto out; 27064bff34e3Sthurlow bzero(dp, reclen); 27074bff34e3Sthurlow dp->d_reclen = reclen; 27084bff34e3Sthurlow dp->d_name[0] = '.'; 27094bff34e3Sthurlow dp->d_name[1] = '.'; 27104bff34e3Sthurlow dp->d_name[offset + 1] = '\0'; 27114bff34e3Sthurlow /* 27124bff34e3Sthurlow * Want the real I-numbers for the "." and ".." 27134bff34e3Sthurlow * entries. For these two names, we know that 27145ecede33SGordon Ross * smbfslookup can get the nodes efficiently. 27154bff34e3Sthurlow */ 27164bff34e3Sthurlow error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct); 27174bff34e3Sthurlow if (error) { 27184bff34e3Sthurlow dp->d_ino = np->n_ino + offset; /* fiction */ 27194bff34e3Sthurlow } else { 27204bff34e3Sthurlow dp->d_ino = VTOSMB(newvp)->n_ino; 27214bff34e3Sthurlow VN_RELE(newvp); 27224bff34e3Sthurlow } 27235ecede33SGordon Ross /* 27245ecede33SGordon Ross * Note: d_off is the offset that a user-level program 27255ecede33SGordon Ross * should seek to for reading the NEXT directory entry. 27265ecede33SGordon Ross * See libc: readdir, telldir, seekdir 27275ecede33SGordon Ross */ 27285ecede33SGordon Ross dp->d_off = offset + 1; 27295ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 27304bff34e3Sthurlow if (error) 27314bff34e3Sthurlow goto out; 27325ecede33SGordon Ross /* 27335ecede33SGordon Ross * Note: uiomove updates uio->uio_offset, 27345ecede33SGordon Ross * but we want it to be our "cookie" value, 27355ecede33SGordon Ross * which just counts dirents ignoring size. 27365ecede33SGordon Ross */ 27374bff34e3Sthurlow uio->uio_offset = ++offset; 27384bff34e3Sthurlow } 27395ecede33SGordon Ross 27405ecede33SGordon Ross /* 27415ecede33SGordon Ross * If there was a backward seek, we have to reopen. 27425ecede33SGordon Ross */ 27435ecede33SGordon Ross if (offset < np->n_dirofs) { 27445ecede33SGordon Ross SMBVDEBUG("Reopening search %d:%d\n", 27455ecede33SGordon Ross offset, np->n_dirofs); 27464bff34e3Sthurlow error = smbfs_smb_findopen(np, "*", 1, 27474bff34e3Sthurlow SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 27484bff34e3Sthurlow &scred, &ctx); 27494bff34e3Sthurlow if (error) { 27504bff34e3Sthurlow SMBVDEBUG("can not open search, error = %d", error); 27514bff34e3Sthurlow goto out; 27524bff34e3Sthurlow } 27535ecede33SGordon Ross /* free the old one */ 27545ecede33SGordon Ross (void) smbfs_smb_findclose(np->n_dirseq, &scred); 27555ecede33SGordon Ross /* save the new one */ 27564bff34e3Sthurlow np->n_dirseq = ctx; 27575ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 27585ecede33SGordon Ross } else { 27594bff34e3Sthurlow ctx = np->n_dirseq; 27605ecede33SGordon Ross } 27615ecede33SGordon Ross 27625ecede33SGordon Ross /* 27635ecede33SGordon Ross * Skip entries before the requested offset. 27645ecede33SGordon Ross */ 27654bff34e3Sthurlow while (np->n_dirofs < offset) { 27665ecede33SGordon Ross error = smbfs_smb_findnext(ctx, limit, &scred); 27675ecede33SGordon Ross if (error != 0) 27684bff34e3Sthurlow goto out; 27695ecede33SGordon Ross np->n_dirofs++; 27704bff34e3Sthurlow } 27715ecede33SGordon Ross 27725ecede33SGordon Ross /* 27735ecede33SGordon Ross * While there's room in the caller's buffer: 27745ecede33SGordon Ross * get a directory entry from SMB, 27755ecede33SGordon Ross * convert to a dirent, copyout. 27765ecede33SGordon Ross * We stop when there is no longer room for a 27775ecede33SGordon Ross * maximum sized dirent because we must decide 27785ecede33SGordon Ross * before we know anything about the next entry. 27795ecede33SGordon Ross */ 27805ecede33SGordon Ross while (uio->uio_resid >= dbufsiz) { 27814bff34e3Sthurlow error = smbfs_smb_findnext(ctx, limit, &scred); 27825ecede33SGordon Ross if (error != 0) 27835ecede33SGordon Ross goto out; 27844bff34e3Sthurlow np->n_dirofs++; 27855ecede33SGordon Ross 27864bff34e3Sthurlow /* Sanity check the name length. */ 27874bff34e3Sthurlow nmlen = ctx->f_nmlen; 2788613a2f6bSGordon Ross if (nmlen > SMB_MAXFNAMELEN) { 2789613a2f6bSGordon Ross nmlen = SMB_MAXFNAMELEN; 27904bff34e3Sthurlow SMBVDEBUG("Truncating name: %s\n", ctx->f_name); 27914bff34e3Sthurlow } 27924bff34e3Sthurlow if (smbfs_fastlookup) { 279302d09e03SGordon Ross /* See comment at smbfs_fastlookup above. */ 27945ecede33SGordon Ross if (smbfs_nget(vp, ctx->f_name, nmlen, 27955ecede33SGordon Ross &ctx->f_attr, &newvp) == 0) 27964bff34e3Sthurlow VN_RELE(newvp); 27974bff34e3Sthurlow } 27985ecede33SGordon Ross 27995ecede33SGordon Ross reclen = DIRENT64_RECLEN(nmlen); 28005ecede33SGordon Ross bzero(dp, reclen); 28015ecede33SGordon Ross dp->d_reclen = reclen; 28025ecede33SGordon Ross bcopy(ctx->f_name, dp->d_name, nmlen); 28035ecede33SGordon Ross dp->d_name[nmlen] = '\0'; 280402d09e03SGordon Ross dp->d_ino = ctx->f_inum; 28055ecede33SGordon Ross dp->d_off = offset + 1; /* See d_off comment above */ 28065ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 28074bff34e3Sthurlow if (error) 28085ecede33SGordon Ross goto out; 28095ecede33SGordon Ross /* See comment re. uio_offset above. */ 28104bff34e3Sthurlow uio->uio_offset = ++offset; 28114bff34e3Sthurlow } 28125ecede33SGordon Ross 28134bff34e3Sthurlow out: 28145ecede33SGordon Ross /* 28155ecede33SGordon Ross * When we come to the end of a directory, the 28165ecede33SGordon Ross * SMB-level functions return ENOENT, but the 28175ecede33SGordon Ross * caller is not expecting an error return. 28185ecede33SGordon Ross * 28195ecede33SGordon Ross * Also note that we must delay the call to 28205ecede33SGordon Ross * smbfs_smb_findclose(np->n_dirseq, ...) 28215ecede33SGordon Ross * until smbfs_close so that all reads at the 28225ecede33SGordon Ross * end of the directory will return no data. 28235ecede33SGordon Ross */ 28245ecede33SGordon Ross if (error == ENOENT) { 28255ecede33SGordon Ross error = 0; 28265ecede33SGordon Ross if (eofp) 28275ecede33SGordon Ross *eofp = 1; 28285ecede33SGordon Ross } 28295ecede33SGordon Ross /* 28305ecede33SGordon Ross * If we encountered an error (i.e. "access denied") 28315ecede33SGordon Ross * from the FindFirst call, we will have copied out 28325ecede33SGordon Ross * the "." and ".." entries leaving offset == 2. 28335ecede33SGordon Ross * In that case, restore the original offset/resid 28345ecede33SGordon Ross * so the caller gets no data with the error. 28355ecede33SGordon Ross */ 28365ecede33SGordon Ross if (error != 0 && offset == FIRST_DIROFS) { 28375ecede33SGordon Ross uio->uio_loffset = save_offset; 28385ecede33SGordon Ross uio->uio_resid = save_resid; 28395ecede33SGordon Ross } 28405ecede33SGordon Ross SMBVDEBUG("out: offset=%d, resid=%d\n", 28415ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 28425ecede33SGordon Ross 28434bff34e3Sthurlow kmem_free(dp, dbufsiz); 28444bff34e3Sthurlow smb_credrele(&scred); 28454bff34e3Sthurlow return (error); 28464bff34e3Sthurlow } 28474bff34e3Sthurlow 28484bff34e3Sthurlow 28494bff34e3Sthurlow /* 28504bff34e3Sthurlow * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK 28514bff34e3Sthurlow * are optional functions that are called by: 28524bff34e3Sthurlow * getdents, before/after VOP_READDIR 28534bff34e3Sthurlow * pread, before/after ... VOP_READ 28544bff34e3Sthurlow * pwrite, before/after ... VOP_WRITE 28554bff34e3Sthurlow * (other places) 28564bff34e3Sthurlow * 28574bff34e3Sthurlow * Careful here: None of the above check for any 28584bff34e3Sthurlow * error returns from VOP_RWLOCK / VOP_RWUNLOCK! 28594bff34e3Sthurlow * In fact, the return value from _rwlock is NOT 28604bff34e3Sthurlow * an error code, but V_WRITELOCK_TRUE / _FALSE. 28614bff34e3Sthurlow * 28624bff34e3Sthurlow * Therefore, it's up to _this_ code to make sure 28634bff34e3Sthurlow * the lock state remains balanced, which means 28644bff34e3Sthurlow * we can't "bail out" on interrupts, etc. 28654bff34e3Sthurlow */ 28664bff34e3Sthurlow 28674bff34e3Sthurlow /* ARGSUSED2 */ 28684bff34e3Sthurlow static int 28694bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 28704bff34e3Sthurlow { 28714bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 28724bff34e3Sthurlow 28734bff34e3Sthurlow if (!write_lock) { 28744bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE); 28754bff34e3Sthurlow return (V_WRITELOCK_FALSE); 28764bff34e3Sthurlow } 28774bff34e3Sthurlow 28784bff34e3Sthurlow 28794bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE); 28804bff34e3Sthurlow return (V_WRITELOCK_TRUE); 28814bff34e3Sthurlow } 28824bff34e3Sthurlow 28834bff34e3Sthurlow /* ARGSUSED */ 28844bff34e3Sthurlow static void 28854bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 28864bff34e3Sthurlow { 28874bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 28884bff34e3Sthurlow 28894bff34e3Sthurlow smbfs_rw_exit(&np->r_rwlock); 28904bff34e3Sthurlow } 28914bff34e3Sthurlow 28924bff34e3Sthurlow 28934bff34e3Sthurlow /* ARGSUSED */ 28944bff34e3Sthurlow static int 28954bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 28964bff34e3Sthurlow { 28974bff34e3Sthurlow smbmntinfo_t *smi; 28984bff34e3Sthurlow 28994bff34e3Sthurlow smi = VTOSMI(vp); 29004bff34e3Sthurlow 2901a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 29024bff34e3Sthurlow return (EPERM); 29034bff34e3Sthurlow 29044bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 29054bff34e3Sthurlow return (EIO); 29064bff34e3Sthurlow 29074bff34e3Sthurlow /* 29084bff34e3Sthurlow * Because we stuff the readdir cookie into the offset field 29094bff34e3Sthurlow * someone may attempt to do an lseek with the cookie which 29104bff34e3Sthurlow * we want to succeed. 29114bff34e3Sthurlow */ 29124bff34e3Sthurlow if (vp->v_type == VDIR) 29134bff34e3Sthurlow return (0); 29144bff34e3Sthurlow 29154bff34e3Sthurlow /* Like NFS3, just check for 63-bit overflow. */ 29164bff34e3Sthurlow if (*noffp < 0) 29174bff34e3Sthurlow return (EINVAL); 29184bff34e3Sthurlow 29194bff34e3Sthurlow return (0); 29204bff34e3Sthurlow } 29214bff34e3Sthurlow 29224bff34e3Sthurlow 29234bff34e3Sthurlow /* 29244bff34e3Sthurlow * XXX 29254bff34e3Sthurlow * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service. 29264bff34e3Sthurlow */ 29274bff34e3Sthurlow static int 29284bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 29294bff34e3Sthurlow offset_t offset, struct flk_callback *flk_cbp, cred_t *cr, 29304bff34e3Sthurlow caller_context_t *ct) 29314bff34e3Sthurlow { 2932a19609f8Sjv if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone) 29334bff34e3Sthurlow return (EIO); 29344bff34e3Sthurlow 29354bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 29364bff34e3Sthurlow return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 29374bff34e3Sthurlow else 29384bff34e3Sthurlow return (ENOSYS); 29394bff34e3Sthurlow } 29404bff34e3Sthurlow 29414bff34e3Sthurlow /* 29424bff34e3Sthurlow * Free storage space associated with the specified vnode. The portion 29434bff34e3Sthurlow * to be freed is specified by bfp->l_start and bfp->l_len (already 29444bff34e3Sthurlow * normalized to a "whence" of 0). 29454bff34e3Sthurlow * 29464bff34e3Sthurlow * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc. 29474bff34e3Sthurlow */ 29484bff34e3Sthurlow /* ARGSUSED */ 29494bff34e3Sthurlow static int 29504bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 29514bff34e3Sthurlow offset_t offset, cred_t *cr, caller_context_t *ct) 29524bff34e3Sthurlow { 29534bff34e3Sthurlow int error; 29544bff34e3Sthurlow smbmntinfo_t *smi; 29554bff34e3Sthurlow 29564bff34e3Sthurlow smi = VTOSMI(vp); 29574bff34e3Sthurlow 2958a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 29594bff34e3Sthurlow return (EIO); 29604bff34e3Sthurlow 29614bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 29624bff34e3Sthurlow return (EIO); 29634bff34e3Sthurlow 296491d632c8Sgwr /* Caller (fcntl) has checked v_type */ 29654bff34e3Sthurlow ASSERT(vp->v_type == VREG); 29664bff34e3Sthurlow if (cmd != F_FREESP) 29674bff34e3Sthurlow return (EINVAL); 29684bff34e3Sthurlow 29694bff34e3Sthurlow /* 29704bff34e3Sthurlow * Like NFS3, no 32-bit offset checks here. 29714bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 29724bff34e3Sthurlow * when it has to fallback to a 32-bit call. 29734bff34e3Sthurlow */ 29744bff34e3Sthurlow 29754bff34e3Sthurlow error = convoff(vp, bfp, 0, offset); 29764bff34e3Sthurlow if (!error) { 29774bff34e3Sthurlow ASSERT(bfp->l_start >= 0); 29784bff34e3Sthurlow if (bfp->l_len == 0) { 29794bff34e3Sthurlow struct vattr va; 29804bff34e3Sthurlow 29814bff34e3Sthurlow /* 29824bff34e3Sthurlow * ftruncate should not change the ctime and 29834bff34e3Sthurlow * mtime if we truncate the file to its 29844bff34e3Sthurlow * previous size. 29854bff34e3Sthurlow */ 29864bff34e3Sthurlow va.va_mask = AT_SIZE; 29874bff34e3Sthurlow error = smbfsgetattr(vp, &va, cr); 29884bff34e3Sthurlow if (error || va.va_size == bfp->l_start) 29894bff34e3Sthurlow return (error); 29904bff34e3Sthurlow va.va_mask = AT_SIZE; 29914bff34e3Sthurlow va.va_size = bfp->l_start; 29924bff34e3Sthurlow error = smbfssetattr(vp, &va, 0, cr); 29934bff34e3Sthurlow } else 29944bff34e3Sthurlow error = EINVAL; 29954bff34e3Sthurlow } 29964bff34e3Sthurlow 29974bff34e3Sthurlow return (error); 29984bff34e3Sthurlow } 29994bff34e3Sthurlow 30004bff34e3Sthurlow /* ARGSUSED */ 30014bff34e3Sthurlow static int 30024bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 30034bff34e3Sthurlow caller_context_t *ct) 30044bff34e3Sthurlow { 300591d632c8Sgwr vfs_t *vfs; 30064bff34e3Sthurlow smbmntinfo_t *smi; 30074bff34e3Sthurlow struct smb_share *ssp; 30084bff34e3Sthurlow 300991d632c8Sgwr vfs = vp->v_vfsp; 301091d632c8Sgwr smi = VFTOSMI(vfs); 30114bff34e3Sthurlow 3012a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 30134bff34e3Sthurlow return (EIO); 30144bff34e3Sthurlow 30154bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 30164bff34e3Sthurlow return (EIO); 30174bff34e3Sthurlow 30184bff34e3Sthurlow switch (cmd) { 30194bff34e3Sthurlow case _PC_FILESIZEBITS: 30204bff34e3Sthurlow ssp = smi->smi_share; 30214bff34e3Sthurlow if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) 30224bff34e3Sthurlow *valp = 64; 30234bff34e3Sthurlow else 30244bff34e3Sthurlow *valp = 32; 30254bff34e3Sthurlow break; 30264bff34e3Sthurlow 30274bff34e3Sthurlow case _PC_LINK_MAX: 30284bff34e3Sthurlow /* We only ever report one link to an object */ 30294bff34e3Sthurlow *valp = 1; 30304bff34e3Sthurlow break; 30314bff34e3Sthurlow 30327568150aSgwr case _PC_ACL_ENABLED: 30337568150aSgwr /* 303402d09e03SGordon Ross * Always indicate that ACLs are enabled and 303502d09e03SGordon Ross * that we support ACE_T format, otherwise 303602d09e03SGordon Ross * libsec will ask for ACLENT_T format data 303702d09e03SGordon Ross * which we don't support. 30387568150aSgwr */ 30397568150aSgwr *valp = _ACL_ACE_ENABLED; 30407568150aSgwr break; 30417568150aSgwr 30424bff34e3Sthurlow case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */ 30434bff34e3Sthurlow *valp = 0; 30444bff34e3Sthurlow break; 30454bff34e3Sthurlow 304691d632c8Sgwr case _PC_XATTR_EXISTS: 304791d632c8Sgwr if (vfs->vfs_flag & VFS_XATTR) { 304891d632c8Sgwr *valp = smbfs_xa_exists(vp, cr); 304991d632c8Sgwr break; 305091d632c8Sgwr } 305191d632c8Sgwr return (EINVAL); 305291d632c8Sgwr 3053*28162916SGordon Ross case _PC_SATTR_ENABLED: 3054*28162916SGordon Ross case _PC_SATTR_EXISTS: 3055*28162916SGordon Ross *valp = 1; 3056*28162916SGordon Ross break; 3057*28162916SGordon Ross 30583b862e9aSRoger A. Faulkner case _PC_TIMESTAMP_RESOLUTION: 305902d09e03SGordon Ross /* 306002d09e03SGordon Ross * Windows times are tenths of microseconds 306102d09e03SGordon Ross * (multiples of 100 nanoseconds). 306202d09e03SGordon Ross */ 306302d09e03SGordon Ross *valp = 100L; 30643b862e9aSRoger A. Faulkner break; 30653b862e9aSRoger A. Faulkner 30664bff34e3Sthurlow default: 30674bff34e3Sthurlow return (fs_pathconf(vp, cmd, valp, cr, ct)); 30684bff34e3Sthurlow } 30694bff34e3Sthurlow return (0); 30704bff34e3Sthurlow } 30714bff34e3Sthurlow 30727568150aSgwr /* ARGSUSED */ 30737568150aSgwr static int 30747568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 30757568150aSgwr caller_context_t *ct) 30767568150aSgwr { 30777568150aSgwr vfs_t *vfsp; 30787568150aSgwr smbmntinfo_t *smi; 307902d09e03SGordon Ross int error; 30807568150aSgwr uint_t mask; 30817568150aSgwr 30827568150aSgwr vfsp = vp->v_vfsp; 30837568150aSgwr smi = VFTOSMI(vfsp); 30847568150aSgwr 3085a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 30867568150aSgwr return (EIO); 30877568150aSgwr 30887568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 30897568150aSgwr return (EIO); 30907568150aSgwr 30917568150aSgwr /* 30927568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 30937568150aSgwr * so we should only see VSA_ACE, etc here. 30947568150aSgwr * Note: vn_create asks for VSA_DFACLCNT, 30957568150aSgwr * and it expects ENOSYS and empty data. 30967568150aSgwr */ 30977568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT | 30987568150aSgwr VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 30997568150aSgwr if (mask == 0) 31007568150aSgwr return (ENOSYS); 31017568150aSgwr 310202d09e03SGordon Ross if (smi->smi_flags & SMI_ACL) 3103bd7c6f51SGordon Ross error = smbfs_acl_getvsa(vp, vsa, flag, cr); 310402d09e03SGordon Ross else 31057568150aSgwr error = ENOSYS; 31067568150aSgwr 31077568150aSgwr if (error == ENOSYS) 31087568150aSgwr error = fs_fab_acl(vp, vsa, flag, cr, ct); 31097568150aSgwr 31107568150aSgwr return (error); 31117568150aSgwr } 31127568150aSgwr 31137568150aSgwr /* ARGSUSED */ 31147568150aSgwr static int 31157568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 31167568150aSgwr caller_context_t *ct) 31177568150aSgwr { 31187568150aSgwr vfs_t *vfsp; 31197568150aSgwr smbmntinfo_t *smi; 31207568150aSgwr int error; 31217568150aSgwr uint_t mask; 31227568150aSgwr 31237568150aSgwr vfsp = vp->v_vfsp; 31247568150aSgwr smi = VFTOSMI(vfsp); 31257568150aSgwr 3126a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 31277568150aSgwr return (EIO); 31287568150aSgwr 31297568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 31307568150aSgwr return (EIO); 31317568150aSgwr 31327568150aSgwr /* 31337568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 31347568150aSgwr * so we should only see VSA_ACE, etc here. 31357568150aSgwr */ 31367568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT); 31377568150aSgwr if (mask == 0) 31387568150aSgwr return (ENOSYS); 31397568150aSgwr 31407568150aSgwr if (vfsp->vfs_flag & VFS_RDONLY) 31417568150aSgwr return (EROFS); 31427568150aSgwr 314302d09e03SGordon Ross /* 314402d09e03SGordon Ross * Allow only the mount owner to do this. 314502d09e03SGordon Ross * See comments at smbfs_access_rwx. 314602d09e03SGordon Ross */ 314702d09e03SGordon Ross error = secpolicy_vnode_setdac(cr, smi->smi_uid); 314802d09e03SGordon Ross if (error != 0) 314902d09e03SGordon Ross return (error); 315002d09e03SGordon Ross 315102d09e03SGordon Ross if (smi->smi_flags & SMI_ACL) 3152bd7c6f51SGordon Ross error = smbfs_acl_setvsa(vp, vsa, flag, cr); 315302d09e03SGordon Ross else 31547568150aSgwr error = ENOSYS; 31557568150aSgwr 31567568150aSgwr return (error); 31577568150aSgwr } 31584bff34e3Sthurlow 31594bff34e3Sthurlow 31604bff34e3Sthurlow /* 31614bff34e3Sthurlow * XXX 31624bff34e3Sthurlow * This op should eventually support PSARC 2007/268. 31634bff34e3Sthurlow */ 31644bff34e3Sthurlow static int 31654bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, 31664bff34e3Sthurlow caller_context_t *ct) 31674bff34e3Sthurlow { 3168a19609f8Sjv if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone) 31694bff34e3Sthurlow return (EIO); 31704bff34e3Sthurlow 31714bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 31724bff34e3Sthurlow return (fs_shrlock(vp, cmd, shr, flag, cr, ct)); 31734bff34e3Sthurlow else 31744bff34e3Sthurlow return (ENOSYS); 31754bff34e3Sthurlow } 3176