/* ARGSUSED */ static int zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp) { zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; char name[MAXNAMELEN]; int err; static enum symfollow follow = NO_FOLLOW; static enum uio_seg seg = UIO_SYSSPACE; if (snapshot_namecheck(dirname, NULL, NULL) != 0) return (EILSEQ); dmu_objset_name(zfsvfs->z_os, name); *vpp = NULL; err = zfs_secpolicy_snapshot_perms(name, cr); if (err) return (err); if (err == 0) { err = dmu_objset_snapshot(name, dirname, NULL, B_FALSE); if (err) return (err); err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp); } return (err); }
int lookupname(char *dirname, enum uio_seg seg, enum symfollow follow, vnode_t **dirvpp, vnode_t **compvpp) { return (lookupnameat(dirname, seg, follow, dirvpp, compvpp, NULL)); }
static int cfutimesat(int fd, char *fname, int nmflag, vattr_t *vap, int flags, int follow) { file_t *fp; vnode_t *startvp, *vp; int error; char startchar; if (fd == AT_FDCWD && fname == NULL) return (set_errno(EFAULT)); if (nmflag == 1 || (nmflag == 2 && fname != NULL)) { if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); } else { startchar = '\0'; } if (fd == AT_FDCWD) { startvp = NULL; } else { /* * is this absolute path? */ if (startchar != '/') { if ((fp = getf(fd)) == NULL) return (set_errno(EBADF)); startvp = fp->f_vnode; VN_HOLD(startvp); releasef(fd); } else { startvp = NULL; } } if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) { if (AU_AUDITING() && startvp != NULL) audit_setfsat_path(1); if ((error = lookupnameat(fname, UIO_USERSPACE, follow, NULLVPP, &vp, startvp)) != 0) { if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); } } else { vp = startvp; VN_HOLD(vp); } if (startvp != NULL) { VN_RELE(startvp); } if (vn_is_readonly(vp)) { error = EROFS; } else { error = VOP_SETATTR(vp, vap, flags, CRED(), NULL); } VN_RELE(vp); if (error != 0) return (set_errno(error)); return (0); }
/* * nmflag has the following values * * 1 - Always do lookup. i.e. chown, lchown. * 2 - Name is optional i.e. fchownat * 0 - Don't lookup name, vp is in file_p. i.e. fchown * */ int cfchownat(int fd, char *name, int nmflag, uid_t uid, gid_t gid, int flags) { vnode_t *startvp, *vp; file_t *filefp; struct vattr vattr; int error = 0; char startchar; if (uid < -1 || uid > MAXUID || gid < -1 || gid > MAXUID) return (set_errno(EINVAL)); vattr.va_uid = uid; vattr.va_gid = gid; vattr.va_mask = 0; if (vattr.va_uid != -1) vattr.va_mask |= AT_UID; if (vattr.va_gid != -1) vattr.va_mask |= AT_GID; if (fd == AT_FDCWD && name == NULL) return (set_errno(EFAULT)); if (nmflag == 1 || (nmflag == 2 && name != NULL)) { if (copyin(name, &startchar, sizeof (char))) return (set_errno(EFAULT)); } else startchar = '\0'; if (fd == AT_FDCWD) startvp = NULL; else { /* * only get fd if not doing absolute lookup */ if (startchar != '/' || nmflag == 0) { if ((filefp = getf(fd)) == NULL) { return (set_errno(EBADF)); } startvp = filefp->f_vnode; VN_HOLD(startvp); releasef(fd); } else { startvp = NULL; } } #if C2_AUDIT if ((nmflag == 2) && audit_active) audit_setfsat_path(1); #endif /* C2_AUDIT */ /* * Do lookups for chown, lchown and fchownat when name not NULL */ if ((nmflag == 2 && name != NULL) || nmflag == 1) { if (error = lookupnameat(name, UIO_USERSPACE, (flags == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW, NULLVPP, &vp, startvp)) { if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); } } else { vp = startvp; ASSERT(vp); VN_HOLD(vp); } if (vn_is_readonly(vp)) { error = EROFS; } else { error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL); } if (startvp != NULL) VN_RELE(startvp); if (vp != NULL) VN_RELE(vp); if (error != 0) return (set_errno(error)); else return (error); }
static int copen(int startfd, char *fname, int filemode, int createmode) { struct pathname pn; vnode_t *vp, *sdvp; file_t *fp, *startfp; enum vtype type; int error; int fd, dupfd; vnode_t *startvp; proc_t *p = curproc; uio_seg_t seg = UIO_USERSPACE; char *open_filename = fname; uint32_t auditing = AU_AUDITING(); char startchar; if (filemode & (FSEARCH|FEXEC)) { /* * Must be one or the other and neither FREAD nor FWRITE * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN * XXX: Should these just be silently ignored? */ if ((filemode & (FREAD|FWRITE)) || (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) || (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN))) return (set_errno(EINVAL)); } if (startfd == AT_FDCWD) { /* * Regular open() */ startvp = NULL; } else { /* * We're here via openat() */ if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); /* * if startchar is / then startfd is ignored */ if (startchar == '/') startvp = NULL; else { if ((startfp = getf(startfd)) == NULL) return (set_errno(EBADF)); startvp = startfp->f_vnode; VN_HOLD(startvp); releasef(startfd); } } /* * Handle __openattrdirat() requests */ if (filemode & FXATTRDIROPEN) { if (auditing && startvp != NULL) audit_setfsat_path(1); if (error = lookupnameat(fname, seg, FOLLOW, NULLVPP, &vp, startvp)) return (set_errno(error)); if (startvp != NULL) VN_RELE(startvp); startvp = vp; } /* * Do we need to go into extended attribute space? */ if (filemode & FXATTR) { if (startfd == AT_FDCWD) { if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); /* * If startchar == '/' then no extended attributes * are looked up. */ if (startchar == '/') { startvp = NULL; } else { mutex_enter(&p->p_lock); startvp = PTOU(p)->u_cdir; VN_HOLD(startvp); mutex_exit(&p->p_lock); } } /* * Make sure we have a valid extended attribute request. * We must either have a real fd or AT_FDCWD and a relative * pathname. */ if (startvp == NULL) { goto noxattr; } } if (filemode & (FXATTR|FXATTRDIROPEN)) { vattr_t vattr; if (error = pn_get(fname, UIO_USERSPACE, &pn)) { goto out; } /* * In order to access hidden attribute directory the * user must be able to stat() the file */ vattr.va_mask = AT_ALL; if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) { pn_free(&pn); goto out; } if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 || vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { error = VOP_LOOKUP(startvp, "", &sdvp, &pn, (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR : LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(), NULL, NULL, NULL); } else { error = EINVAL; } /* * For __openattrdirat() use "." as filename to open * as part of vn_openat() */ if (error == 0 && (filemode & FXATTRDIROPEN)) { open_filename = "."; seg = UIO_SYSSPACE; } pn_free(&pn); if (error != 0) goto out; VN_RELE(startvp); startvp = sdvp; } noxattr: if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) { if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) filemode &= ~FNDELAY; error = falloc((vnode_t *)NULL, filemode, &fp, &fd); if (error == 0) { if (auditing && startvp != NULL) audit_setfsat_path(1); /* * Last arg is a don't-care term if * !(filemode & FCREAT). */ error = vn_openat(open_filename, seg, filemode, (int)(createmode & MODEMASK), &vp, CRCREAT, PTOU(curproc)->u_cmask, startvp, fd); if (startvp != NULL) VN_RELE(startvp); if (error == 0) { if ((vp->v_flag & VDUP) == 0) { fp->f_vnode = vp; mutex_exit(&fp->f_tlock); /* * We must now fill in the slot * falloc reserved. */ setf(fd, fp); return (fd); } else { /* * Special handling for /dev/fd. * Give up the file pointer * and dup the indicated file descriptor * (in v_rdev). This is ugly, but I've * seen worse. */ unfalloc(fp); dupfd = getminor(vp->v_rdev); type = vp->v_type; mutex_enter(&vp->v_lock); vp->v_flag &= ~VDUP; mutex_exit(&vp->v_lock); VN_RELE(vp); if (type != VCHR) return (set_errno(EINVAL)); if ((fp = getf(dupfd)) == NULL) { setf(fd, NULL); return (set_errno(EBADF)); } mutex_enter(&fp->f_tlock); fp->f_count++; mutex_exit(&fp->f_tlock); setf(fd, fp); releasef(dupfd); } return (fd); } else { setf(fd, NULL); unfalloc(fp); return (set_errno(error)); } } } else { error = EINVAL; } out: if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); }