1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017, Joyent, Inc.
  25  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
  26  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  30 /*        All Rights Reserved   */
  31 
  32 /*
  33  * University Copyright- Copyright (c) 1982, 1986, 1988
  34  * The Regents of the University of California
  35  * All Rights Reserved
  36  *
  37  * University Acknowledgment- Portions of this document are derived from
  38  * software developed by the University of California, Berkeley, and its
  39  * contributors.
  40  */
  41 
  42 /*
  43  * Portions of code from both of:
  44  *      syscall/open.c
  45  *      fs/vnode.c
  46  * heavily modified for this use.
  47  */
  48 
  49 #include <sys/types.h>
  50 #include <sys/param.h>
  51 #include <sys/t_lock.h>
  52 #include <sys/errno.h>
  53 #include <sys/cred.h>
  54 #include <sys/user.h>
  55 #include <sys/uio.h>
  56 #include <sys/file.h>
  57 #include <sys/pathname.h>
  58 #include <sys/vfs.h>
  59 #include <sys/vfs_opreg.h>
  60 #include <sys/vnode.h>
  61 #include <sys/rwstlock.h>
  62 #include <sys/fem.h>
  63 #include <sys/stat.h>
  64 #include <sys/mode.h>
  65 #include <sys/conf.h>
  66 #include <sys/sysmacros.h>
  67 #include <sys/cmn_err.h>
  68 #include <sys/systm.h>
  69 #include <sys/kmem.h>
  70 #include <sys/debug.h>
  71 #include <sys/acl.h>
  72 #include <sys/nbmlock.h>
  73 #include <sys/fcntl.h>
  74 #include <fs/fs_subr.h>
  75 #include <sys/taskq.h>
  76 #include <fs/fs_reparse.h>
  77 #include <sys/time.h>
  78 
  79 #include <libfksmbfs.h>
  80 
  81 /* close and release */
  82 int
  83 vn_close_rele(vnode_t *vp, int flag)
  84 {
  85         int error;
  86 
  87         error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
  88         vn_rele(vp);
  89 
  90         return (error);
  91 }
  92 
  93 /*
  94  * Open/create a vnode.
  95  * This may be callable by the kernel, the only known use
  96  * of user context being that the current user credentials
  97  * are used for permissions.  crwhy is defined iff filemode & FCREAT.
  98  */
  99 int
 100 vn_open(
 101         char *pnamep,
 102         enum uio_seg seg,
 103         int filemode,
 104         int createmode,
 105         struct vnode **vpp,
 106         enum create crwhy,
 107         mode_t umask)
 108 {
 109         struct vnode *vp;
 110         int mode;
 111         int accessflags;
 112         int error;
 113         int open_done = 0;
 114         struct vattr vattr;
 115         int estale_retry = 0;
 116 
 117         mode = 0;
 118         accessflags = 0;
 119         if (filemode & FREAD)
 120                 mode |= VREAD;
 121         if (filemode & (FWRITE|FTRUNC))
 122                 mode |= VWRITE;
 123         if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
 124                 mode |= VEXEC;
 125 
 126         if (filemode & FAPPEND)
 127                 accessflags |= V_APPEND;
 128 
 129 top:
 130         if (filemode & FCREAT) {
 131                 enum vcexcl excl;
 132 
 133                 /*
 134                  * Wish to create a file.
 135                  */
 136                 vattr.va_type = VREG;
 137                 vattr.va_mode = createmode;
 138                 vattr.va_mask = AT_TYPE|AT_MODE;
 139                 if (filemode & FTRUNC) {
 140                         vattr.va_size = 0;
 141                         vattr.va_mask |= AT_SIZE;
 142                 }
 143                 if (filemode & FEXCL)
 144                         excl = EXCL;
 145                 else
 146                         excl = NONEXCL;
 147 
 148                 if ((error =
 149                     vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
 150                     (filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
 151                         return (error);
 152         } else {
 153                 /*
 154                  * Wish to open a file.  Just look it up.
 155                  * Was lookupnameat()
 156                  */
 157                 if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
 158                         if ((error == ESTALE) &&
 159                             fs_need_estale_retry(estale_retry++))
 160                                 goto top;
 161                         return (error);
 162                 }
 163 
 164                 /*
 165                  * Want the XATTRDIR under it?
 166                  */
 167                 if (filemode & FXATTRDIROPEN) {
 168                         vnode_t *xvp = NULL;
 169                         error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
 170                             LOOKUP_XATTR, rootdir, CRED(), NULL,
 171                             NULL, NULL);
 172                         VN_RELE(vp);
 173                         vp = xvp;
 174                         /* continue with vp */
 175                 }
 176 
 177                 /*
 178                  * Can't write directories, active texts, or
 179                  * read-only filesystems.  Can't truncate files
 180                  * on which mandatory locking is in effect.
 181                  */
 182                 if (filemode & (FWRITE|FTRUNC)) {
 183                         if (vp->v_type == VDIR) {
 184                                 error = EISDIR;
 185                                 goto out;
 186                         }
 187                 }
 188                 /*
 189                  * Check permissions.
 190                  */
 191                 if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
 192                         goto out;
 193                 /*
 194                  * Require FSEARCH to return a directory.
 195                  * Require FEXEC to return a regular file.
 196                  */
 197                 if ((filemode & FSEARCH) && vp->v_type != VDIR) {
 198                         error = ENOTDIR;
 199                         goto out;
 200                 }
 201                 if ((filemode & FEXEC) && vp->v_type != VREG) {
 202                         error = ENOEXEC;
 203                         goto out;
 204                 }
 205         }
 206 
 207         /*
 208          * Do remaining checks for FNOFOLLOW and FNOLINKS.
 209          */
 210         if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
 211                 error = ELOOP;
 212                 goto out;
 213         }
 214         if (filemode & FNOLINKS) {
 215                 vattr.va_mask = AT_NLINK;
 216                 if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
 217                         goto out;
 218                 }
 219                 if (vattr.va_nlink != 1) {
 220                         error = EMLINK;
 221                         goto out;
 222                 }
 223         }
 224 
 225         /*
 226          * Opening a socket corresponding to the AF_UNIX pathname
 227          * in the filesystem name space is not supported...
 228          */
 229         if (vp->v_type == VSOCK) {
 230                 error = EOPNOTSUPP;
 231                 goto out;
 232         }
 233 
 234         /*
 235          * Do opening protocol.
 236          */
 237         error = VOP_OPEN(&vp, filemode, CRED(), NULL);
 238         if (error)
 239                 goto out;
 240         open_done = 1;
 241 
 242         /*
 243          * Truncate if required.
 244          */
 245         if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
 246                 vattr.va_size = 0;
 247                 vattr.va_mask = AT_SIZE;
 248                 if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
 249                         goto out;
 250         }
 251 out:
 252         ASSERT(vp->v_count > 0);
 253 
 254         if (error) {
 255                 if (open_done) {
 256                         (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
 257                             NULL);
 258                         open_done = 0;
 259                 }
 260                 VN_RELE(vp);
 261         } else
 262                 *vpp = vp;
 263         return (error);
 264 }
 265 
 266 
 267 /*
 268  * Create a vnode (makenode).
 269  */
 270 int
 271 vn_create(
 272         char *pnamep,
 273         enum uio_seg seg,
 274         struct vattr *vap,
 275         enum vcexcl excl,
 276         int mode,
 277         struct vnode **vpp,
 278         enum create why,
 279         int flag,
 280         mode_t umask)
 281 {
 282         struct vnode *dvp = NULL;       /* ptr to parent dir vnode */
 283         char *lastcomp = NULL;
 284         int error;
 285 
 286         ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
 287 
 288         flag &= ~(FNOFOLLOW|FNOLINKS);
 289 
 290         *vpp = NULL;
 291 
 292         /*
 293          * Lookup directory and last component
 294          */
 295         error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
 296         if (error != 0) {
 297                 /* dir not found */
 298                 return (error);
 299         }
 300 
 301         /*
 302          * If default ACLs are defined for the directory don't apply the
 303          * umask if umask is passed.
 304          */
 305 
 306         if (umask) {
 307                 /*
 308                  * Apply the umask if no default ACLs...
 309                  */
 310                 vap->va_mode &= ~umask;
 311         }
 312 
 313         if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
 314                 error = EROFS;
 315                 goto out;
 316         }
 317 
 318         /*
 319          * Call mkdir() if specified, otherwise create().
 320          */
 321         if (why == CRMKDIR) {
 322                 /*
 323                  * N.B., if vn_createat() ever requests
 324                  * case-insensitive behavior then it will need
 325                  * to be passed to VOP_MKDIR().  VOP_CREATE()
 326                  * will already get it via "flag"
 327                  */
 328                 error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
 329                     NULL, 0, NULL);
 330         } else {
 331                 error = VOP_CREATE(dvp, lastcomp, vap,
 332                     excl, mode, vpp, CRED(), flag, NULL, NULL);
 333         }
 334 
 335 out:
 336         if (dvp != NULL)
 337                 VN_RELE(dvp);
 338 
 339         return (error);
 340 }