xref: /onnv-gate/usr/src/uts/common/syscall/open.c (revision 12789:82cffaae72d5)
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