10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53446Smrj * Common Development and Distribution License (the "License").
63446Smrj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
2111798SRoger.Faulkner@Sun.COM
220Sstevel@tonic-gate /*
2312617SMarek.Pospisil@Sun.COM * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
310Sstevel@tonic-gate * under license from the Regents of the University of California.
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/isa_defs.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/user.h>
390Sstevel@tonic-gate #include <sys/systm.h>
400Sstevel@tonic-gate #include <sys/errno.h>
410Sstevel@tonic-gate #include <sys/fcntl.h>
420Sstevel@tonic-gate #include <sys/stat.h>
430Sstevel@tonic-gate #include <sys/vnode.h>
440Sstevel@tonic-gate #include <sys/vfs.h>
450Sstevel@tonic-gate #include <sys/file.h>
460Sstevel@tonic-gate #include <sys/mode.h>
470Sstevel@tonic-gate #include <sys/uio.h>
480Sstevel@tonic-gate #include <sys/debug.h>
490Sstevel@tonic-gate #include <c2/audit.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate /*
5211798SRoger.Faulkner@Sun.COM * Common code for openat(). Check permissions, allocate an open
5311798SRoger.Faulkner@Sun.COM * file structure, and call the device open routine (if any).
540Sstevel@tonic-gate */
550Sstevel@tonic-gate
560Sstevel@tonic-gate static int
copen(int startfd,char * fname,int filemode,int createmode)570Sstevel@tonic-gate copen(int startfd, char *fname, int filemode, int createmode)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate struct pathname pn;
600Sstevel@tonic-gate vnode_t *vp, *sdvp;
610Sstevel@tonic-gate file_t *fp, *startfp;
620Sstevel@tonic-gate enum vtype type;
630Sstevel@tonic-gate int error;
640Sstevel@tonic-gate int fd, dupfd;
650Sstevel@tonic-gate vnode_t *startvp;
660Sstevel@tonic-gate proc_t *p = curproc;
675331Samw uio_seg_t seg = UIO_USERSPACE;
685331Samw char *open_filename = fname;
6911861SMarek.Pospisil@Sun.COM uint32_t auditing = AU_AUDITING();
7012689SBrent.Paulson@Oracle.COM char startchar;
710Sstevel@tonic-gate
72*12789SRoger.Faulkner@Oracle.COM if (filemode & (FSEARCH|FEXEC)) {
73*12789SRoger.Faulkner@Oracle.COM /*
74*12789SRoger.Faulkner@Oracle.COM * Must be one or the other and neither FREAD nor FWRITE
75*12789SRoger.Faulkner@Oracle.COM * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN
76*12789SRoger.Faulkner@Oracle.COM * XXX: Should these just be silently ignored?
77*12789SRoger.Faulkner@Oracle.COM */
78*12789SRoger.Faulkner@Oracle.COM if ((filemode & (FREAD|FWRITE)) ||
79*12789SRoger.Faulkner@Oracle.COM (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) ||
80*12789SRoger.Faulkner@Oracle.COM (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN)))
81*12789SRoger.Faulkner@Oracle.COM return (set_errno(EINVAL));
82*12789SRoger.Faulkner@Oracle.COM }
83*12789SRoger.Faulkner@Oracle.COM
840Sstevel@tonic-gate if (startfd == AT_FDCWD) {
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * Regular open()
870Sstevel@tonic-gate */
880Sstevel@tonic-gate startvp = NULL;
890Sstevel@tonic-gate } else {
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate * We're here via openat()
920Sstevel@tonic-gate */
930Sstevel@tonic-gate if (copyin(fname, &startchar, sizeof (char)))
940Sstevel@tonic-gate return (set_errno(EFAULT));
950Sstevel@tonic-gate
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate * if startchar is / then startfd is ignored
980Sstevel@tonic-gate */
990Sstevel@tonic-gate if (startchar == '/')
1000Sstevel@tonic-gate startvp = NULL;
1010Sstevel@tonic-gate else {
1020Sstevel@tonic-gate if ((startfp = getf(startfd)) == NULL)
1030Sstevel@tonic-gate return (set_errno(EBADF));
1040Sstevel@tonic-gate startvp = startfp->f_vnode;
1050Sstevel@tonic-gate VN_HOLD(startvp);
1060Sstevel@tonic-gate releasef(startfd);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1105331Samw /*
11112689SBrent.Paulson@Oracle.COM * Handle __openattrdirat() requests
1125331Samw */
1135331Samw if (filemode & FXATTRDIROPEN) {
114*12789SRoger.Faulkner@Oracle.COM if (auditing && startvp != NULL)
11511798SRoger.Faulkner@Sun.COM audit_setfsat_path(1);
1165331Samw if (error = lookupnameat(fname, seg, FOLLOW,
1175331Samw NULLVPP, &vp, startvp))
1185331Samw return (set_errno(error));
11912689SBrent.Paulson@Oracle.COM if (startvp != NULL)
1205331Samw VN_RELE(startvp);
1215331Samw
1225331Samw startvp = vp;
1235331Samw }
1245331Samw
1255331Samw /*
1265331Samw * Do we need to go into extended attribute space?
1275331Samw */
12812689SBrent.Paulson@Oracle.COM if (filemode & FXATTR) {
12912689SBrent.Paulson@Oracle.COM if (startfd == AT_FDCWD) {
13012689SBrent.Paulson@Oracle.COM if (copyin(fname, &startchar, sizeof (char)))
13112689SBrent.Paulson@Oracle.COM return (set_errno(EFAULT));
13212689SBrent.Paulson@Oracle.COM
13312689SBrent.Paulson@Oracle.COM /*
13412689SBrent.Paulson@Oracle.COM * If startchar == '/' then no extended attributes
13512689SBrent.Paulson@Oracle.COM * are looked up.
13612689SBrent.Paulson@Oracle.COM */
13712689SBrent.Paulson@Oracle.COM if (startchar == '/') {
13812689SBrent.Paulson@Oracle.COM startvp = NULL;
13912689SBrent.Paulson@Oracle.COM } else {
14012689SBrent.Paulson@Oracle.COM mutex_enter(&p->p_lock);
14112689SBrent.Paulson@Oracle.COM startvp = PTOU(p)->u_cdir;
14212689SBrent.Paulson@Oracle.COM VN_HOLD(startvp);
14312689SBrent.Paulson@Oracle.COM mutex_exit(&p->p_lock);
14412689SBrent.Paulson@Oracle.COM }
14512689SBrent.Paulson@Oracle.COM }
14612689SBrent.Paulson@Oracle.COM
14712689SBrent.Paulson@Oracle.COM /*
14812689SBrent.Paulson@Oracle.COM * Make sure we have a valid extended attribute request.
14912689SBrent.Paulson@Oracle.COM * We must either have a real fd or AT_FDCWD and a relative
15012689SBrent.Paulson@Oracle.COM * pathname.
15112689SBrent.Paulson@Oracle.COM */
15212689SBrent.Paulson@Oracle.COM if (startvp == NULL) {
15312689SBrent.Paulson@Oracle.COM goto noxattr;
15412689SBrent.Paulson@Oracle.COM }
15512689SBrent.Paulson@Oracle.COM }
15612689SBrent.Paulson@Oracle.COM
1575331Samw if (filemode & (FXATTR|FXATTRDIROPEN)) {
1585331Samw vattr_t vattr;
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate if (error = pn_get(fname, UIO_USERSPACE, &pn)) {
1610Sstevel@tonic-gate goto out;
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /*
1655331Samw * In order to access hidden attribute directory the
1665331Samw * user must be able to stat() the file
1670Sstevel@tonic-gate */
1685331Samw vattr.va_mask = AT_ALL;
1695331Samw if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) {
1700Sstevel@tonic-gate pn_free(&pn);
1710Sstevel@tonic-gate goto out;
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1745331Samw if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 ||
1757757SJanice.Chang@Sun.COM vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
1760Sstevel@tonic-gate error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
1777067Smarks (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR :
1785331Samw LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(),
1795331Samw NULL, NULL, NULL);
1800Sstevel@tonic-gate } else {
1810Sstevel@tonic-gate error = EINVAL;
1820Sstevel@tonic-gate }
1835331Samw
1845331Samw /*
18512689SBrent.Paulson@Oracle.COM * For __openattrdirat() use "." as filename to open
1865331Samw * as part of vn_openat()
1875331Samw */
1885331Samw if (error == 0 && (filemode & FXATTRDIROPEN)) {
1895331Samw open_filename = ".";
1905331Samw seg = UIO_SYSSPACE;
1915331Samw }
1925331Samw
1930Sstevel@tonic-gate pn_free(&pn);
1940Sstevel@tonic-gate if (error != 0)
1950Sstevel@tonic-gate goto out;
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate VN_RELE(startvp);
1980Sstevel@tonic-gate startvp = sdvp;
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate
20112689SBrent.Paulson@Oracle.COM noxattr:
202*12789SRoger.Faulkner@Oracle.COM if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) {
2030Sstevel@tonic-gate if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
2040Sstevel@tonic-gate filemode &= ~FNDELAY;
2050Sstevel@tonic-gate error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
2060Sstevel@tonic-gate if (error == 0) {
207*12789SRoger.Faulkner@Oracle.COM if (auditing && startvp != NULL)
2080Sstevel@tonic-gate audit_setfsat_path(1);
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate * Last arg is a don't-care term if
2110Sstevel@tonic-gate * !(filemode & FCREAT).
2120Sstevel@tonic-gate */
2135331Samw error = vn_openat(open_filename, seg, filemode,
2145331Samw (int)(createmode & MODEMASK),
2155331Samw &vp, CRCREAT, PTOU(curproc)->u_cmask,
2165331Samw startvp, fd);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate if (startvp != NULL)
2190Sstevel@tonic-gate VN_RELE(startvp);
2200Sstevel@tonic-gate if (error == 0) {
2210Sstevel@tonic-gate if ((vp->v_flag & VDUP) == 0) {
2220Sstevel@tonic-gate fp->f_vnode = vp;
2230Sstevel@tonic-gate mutex_exit(&fp->f_tlock);
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * We must now fill in the slot
2260Sstevel@tonic-gate * falloc reserved.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate setf(fd, fp);
2290Sstevel@tonic-gate return (fd);
2300Sstevel@tonic-gate } else {
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate * Special handling for /dev/fd.
2330Sstevel@tonic-gate * Give up the file pointer
2340Sstevel@tonic-gate * and dup the indicated file descriptor
2350Sstevel@tonic-gate * (in v_rdev). This is ugly, but I've
2360Sstevel@tonic-gate * seen worse.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate unfalloc(fp);
2390Sstevel@tonic-gate dupfd = getminor(vp->v_rdev);
2400Sstevel@tonic-gate type = vp->v_type;
2410Sstevel@tonic-gate mutex_enter(&vp->v_lock);
2420Sstevel@tonic-gate vp->v_flag &= ~VDUP;
2430Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2440Sstevel@tonic-gate VN_RELE(vp);
2450Sstevel@tonic-gate if (type != VCHR)
2460Sstevel@tonic-gate return (set_errno(EINVAL));
2470Sstevel@tonic-gate if ((fp = getf(dupfd)) == NULL) {
2480Sstevel@tonic-gate setf(fd, NULL);
2490Sstevel@tonic-gate return (set_errno(EBADF));
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate mutex_enter(&fp->f_tlock);
2520Sstevel@tonic-gate fp->f_count++;
2530Sstevel@tonic-gate mutex_exit(&fp->f_tlock);
2540Sstevel@tonic-gate setf(fd, fp);
2550Sstevel@tonic-gate releasef(dupfd);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate return (fd);
2580Sstevel@tonic-gate } else {
2590Sstevel@tonic-gate setf(fd, NULL);
2600Sstevel@tonic-gate unfalloc(fp);
2610Sstevel@tonic-gate return (set_errno(error));
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate } else {
2650Sstevel@tonic-gate error = EINVAL;
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate out:
2680Sstevel@tonic-gate if (startvp != NULL)
2690Sstevel@tonic-gate VN_RELE(startvp);
2700Sstevel@tonic-gate return (set_errno(error));
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
273*12789SRoger.Faulkner@Oracle.COM #define OPENMODE32(fmode) (((fmode) & (FSEARCH | FEXEC))? \
274*12789SRoger.Faulkner@Oracle.COM (fmode) : (fmode) - FOPEN)
2750Sstevel@tonic-gate #define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX)
2760Sstevel@tonic-gate #ifdef _LP64
2770Sstevel@tonic-gate #define OPENMODE(fmode) OPENMODE64(fmode)
2780Sstevel@tonic-gate #else
279*12789SRoger.Faulkner@Oracle.COM #define OPENMODE(fmode) OPENMODE32(fmode)
2800Sstevel@tonic-gate #endif
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate * Open a file.
2840Sstevel@tonic-gate */
2850Sstevel@tonic-gate int
openat(int fd,char * path,int fmode,int cmode)2860Sstevel@tonic-gate openat(int fd, char *path, int fmode, int cmode)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate return (copen(fd, path, OPENMODE(fmode), cmode));
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate
29111798SRoger.Faulkner@Sun.COM int
open(char * path,int fmode,int cmode)29211798SRoger.Faulkner@Sun.COM open(char *path, int fmode, int cmode)
29311798SRoger.Faulkner@Sun.COM {
29411798SRoger.Faulkner@Sun.COM return (openat(AT_FDCWD, path, fmode, cmode));
29511798SRoger.Faulkner@Sun.COM }
29611798SRoger.Faulkner@Sun.COM
2970Sstevel@tonic-gate #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
2980Sstevel@tonic-gate /*
29911798SRoger.Faulkner@Sun.COM * Open for large files in 32-bit environment. Sets the FOFFMAX flag.
3000Sstevel@tonic-gate */
3010Sstevel@tonic-gate int
openat64(int fd,char * path,int fmode,int cmode)3020Sstevel@tonic-gate openat64(int fd, char *path, int fmode, int cmode)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate return (copen(fd, path, OPENMODE64(fmode), cmode));
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
30711798SRoger.Faulkner@Sun.COM int
open64(char * path,int fmode,int cmode)30811798SRoger.Faulkner@Sun.COM open64(char *path, int fmode, int cmode)
30911798SRoger.Faulkner@Sun.COM {
31011798SRoger.Faulkner@Sun.COM return (openat64(AT_FDCWD, path, fmode, cmode));
31111798SRoger.Faulkner@Sun.COM }
31211798SRoger.Faulkner@Sun.COM
3130Sstevel@tonic-gate #endif /* _ILP32 || _SYSCALL32_IMPL */
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
3160Sstevel@tonic-gate /*
31711798SRoger.Faulkner@Sun.COM * Open for 32-bit compatibility on 64-bit kernel
3180Sstevel@tonic-gate */
3190Sstevel@tonic-gate int
openat32(int fd,char * path,int fmode,int cmode)3200Sstevel@tonic-gate openat32(int fd, char *path, int fmode, int cmode)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate return (copen(fd, path, OPENMODE32(fmode), cmode));
3230Sstevel@tonic-gate }
3245331Samw
32511798SRoger.Faulkner@Sun.COM int
open32(char * path,int fmode,int cmode)32611798SRoger.Faulkner@Sun.COM open32(char *path, int fmode, int cmode)
32711798SRoger.Faulkner@Sun.COM {
32811798SRoger.Faulkner@Sun.COM return (openat32(AT_FDCWD, path, fmode, cmode));
32911798SRoger.Faulkner@Sun.COM }
3305331Samw
33111798SRoger.Faulkner@Sun.COM #endif /* _SYSCALL32_IMPL */
332