Home | History | Annotate | Download | only in syscall
      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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
     27 /*	  All Rights Reserved  	*/
     28 
     29 /*
     30  * Portions of this source code were derived from Berkeley 4.3 BSD
     31  * under license from the Regents of the University of California.
     32  */
     33 
     34 #include <sys/param.h>
     35 #include <sys/isa_defs.h>
     36 #include <sys/types.h>
     37 #include <sys/sysmacros.h>
     38 #include <sys/user.h>
     39 #include <sys/systm.h>
     40 #include <sys/errno.h>
     41 #include <sys/fcntl.h>
     42 #include <sys/stat.h>
     43 #include <sys/vnode.h>
     44 #include <sys/vfs.h>
     45 #include <sys/file.h>
     46 #include <sys/mode.h>
     47 #include <sys/uio.h>
     48 #include <sys/debug.h>
     49 #include <c2/audit.h>
     50 #include <sys/cmn_err.h>
     51 
     52 /*
     53  * Common code for open()/openat() and creat().  Check permissions, allocate
     54  * an open file structure, and call the device open routine (if any).
     55  */
     56 
     57 static int
     58 copen(int startfd, char *fname, int filemode, int createmode)
     59 {
     60 	struct pathname pn;
     61 	vnode_t *vp, *sdvp;
     62 	file_t *fp, *startfp;
     63 	enum vtype type;
     64 	int error;
     65 	int fd, dupfd;
     66 	vnode_t *startvp;
     67 	proc_t *p = curproc;
     68 	uio_seg_t seg = UIO_USERSPACE;
     69 	char *open_filename = fname;
     70 
     71 	if (startfd == AT_FDCWD) {
     72 		/*
     73 		 * Regular open()
     74 		 */
     75 		startvp = NULL;
     76 	} else {
     77 		/*
     78 		 * We're here via openat()
     79 		 */
     80 		char startchar;
     81 
     82 		if (copyin(fname, &startchar, sizeof (char)))
     83 			return (set_errno(EFAULT));
     84 
     85 		/*
     86 		 * if startchar is / then startfd is ignored
     87 		 */
     88 		if (startchar == '/')
     89 			startvp = NULL;
     90 		else {
     91 			if ((startfp = getf(startfd)) == NULL)
     92 				return (set_errno(EBADF));
     93 			startvp = startfp->f_vnode;
     94 			VN_HOLD(startvp);
     95 			releasef(startfd);
     96 		}
     97 	}
     98 
     99 	/*
    100 	 * Handle openattrdirat request
    101 	 */
    102 	if (filemode & FXATTRDIROPEN) {
    103 			if (audit_active)
    104 				audit_setfsat_path(1);
    105 
    106 		if (error = lookupnameat(fname, seg, FOLLOW,
    107 		    NULLVPP, &vp, startvp))
    108 			return (set_errno(error));
    109 		if (startvp) {
    110 			VN_RELE(startvp);
    111 			startvp = NULL;
    112 		}
    113 
    114 		startvp = vp;
    115 	}
    116 
    117 	/*
    118 	 * Do we need to go into extended attribute space?
    119 	 */
    120 	if (filemode & (FXATTR|FXATTRDIROPEN)) {
    121 		vattr_t vattr;
    122 
    123 		/*
    124 		 * Make sure we have a valid request.
    125 		 * We must either have a real fd or AT_FDCWD
    126 		 */
    127 
    128 		if (startfd != AT_FDCWD && startvp == NULL) {
    129 			error = EINVAL;
    130 			goto out;
    131 		}
    132 
    133 		if (error = pn_get(fname, UIO_USERSPACE, &pn)) {
    134 			goto out;
    135 		}
    136 
    137 		if (startfd == AT_FDCWD && !(filemode & FXATTRDIROPEN)) {
    138 			mutex_enter(&p->p_lock);
    139 			startvp = PTOU(p)->u_cdir;
    140 			VN_HOLD(startvp);
    141 			mutex_exit(&p->p_lock);
    142 		}
    143 
    144 		/*
    145 		 * In order to access hidden attribute directory the
    146 		 * user must be able to stat() the file
    147 		 */
    148 
    149 		vattr.va_mask = AT_ALL;
    150 		if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) {
    151 			pn_free(&pn);
    152 			goto out;
    153 		}
    154 
    155 		if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 ||
    156 		    vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
    157 			error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
    158 			    (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR :
    159 			    LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(),
    160 			    NULL, NULL, NULL);
    161 		} else {
    162 			error = EINVAL;
    163 		}
    164 
    165 		/*
    166 		 * For openattrdirat use "." as filename to open
    167 		 * as part of vn_openat()
    168 		 */
    169 		if (error == 0 && (filemode & FXATTRDIROPEN)) {
    170 			open_filename = ".";
    171 			seg = UIO_SYSSPACE;
    172 		}
    173 
    174 		pn_free(&pn);
    175 		if (error != 0)
    176 			goto out;
    177 
    178 		VN_RELE(startvp);
    179 		startvp = sdvp;
    180 	}
    181 
    182 	if ((filemode & (FREAD|FWRITE|FXATTRDIROPEN)) != 0) {
    183 		if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
    184 			filemode &= ~FNDELAY;
    185 		error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
    186 		if (error == 0) {
    187 			if (audit_active)
    188 				audit_setfsat_path(1);
    189 			/*
    190 			 * Last arg is a don't-care term if
    191 			 * !(filemode & FCREAT).
    192 			 */
    193 
    194 			error = vn_openat(open_filename, seg, filemode,
    195 			    (int)(createmode & MODEMASK),
    196 			    &vp, CRCREAT, PTOU(curproc)->u_cmask,
    197 			    startvp, fd);
    198 
    199 			if (startvp != NULL)
    200 				VN_RELE(startvp);
    201 			if (error == 0) {
    202 				if (audit_active)
    203 					audit_copen(fd, fp, vp);
    204 				if ((vp->v_flag & VDUP) == 0) {
    205 					fp->f_vnode = vp;
    206 					mutex_exit(&fp->f_tlock);
    207 					/*
    208 					 * We must now fill in the slot
    209 					 * falloc reserved.
    210 					 */
    211 					setf(fd, fp);
    212 					return (fd);
    213 				} else {
    214 					/*
    215 					 * Special handling for /dev/fd.
    216 					 * Give up the file pointer
    217 					 * and dup the indicated file descriptor
    218 					 * (in v_rdev). This is ugly, but I've
    219 					 * seen worse.
    220 					 */
    221 					unfalloc(fp);
    222 					dupfd = getminor(vp->v_rdev);
    223 					type = vp->v_type;
    224 					mutex_enter(&vp->v_lock);
    225 					vp->v_flag &= ~VDUP;
    226 					mutex_exit(&vp->v_lock);
    227 					VN_RELE(vp);
    228 					if (type != VCHR)
    229 						return (set_errno(EINVAL));
    230 					if ((fp = getf(dupfd)) == NULL) {
    231 						setf(fd, NULL);
    232 						return (set_errno(EBADF));
    233 					}
    234 					mutex_enter(&fp->f_tlock);
    235 					fp->f_count++;
    236 					mutex_exit(&fp->f_tlock);
    237 					setf(fd, fp);
    238 					releasef(dupfd);
    239 				}
    240 				return (fd);
    241 			} else {
    242 				setf(fd, NULL);
    243 				unfalloc(fp);
    244 				return (set_errno(error));
    245 			}
    246 		}
    247 	} else {
    248 		error = EINVAL;
    249 	}
    250 out:
    251 	if (startvp != NULL)
    252 		VN_RELE(startvp);
    253 	return (set_errno(error));
    254 }
    255 
    256 #define	OPENMODE32(fmode)	((int)((fmode)-FOPEN))
    257 #define	CREATMODE32		(FWRITE|FCREAT|FTRUNC)
    258 #define	OPENMODE64(fmode)	(OPENMODE32(fmode) | FOFFMAX)
    259 #define	OPENMODEATTRDIR		FXATTRDIROPEN
    260 #define	CREATMODE64		(CREATMODE32 | FOFFMAX)
    261 #ifdef _LP64
    262 #define	OPENMODE(fmode)		OPENMODE64(fmode)
    263 #define	CREATMODE		CREATMODE64
    264 #else
    265 #define	OPENMODE		OPENMODE32
    266 #define	CREATMODE		CREATMODE32
    267 #endif
    268 
    269 /*
    270  * Open a file.
    271  */
    272 int
    273 open(char *fname, int fmode, int cmode)
    274 {
    275 	return (copen(AT_FDCWD, fname, OPENMODE(fmode), cmode));
    276 }
    277 
    278 /*
    279  * Create a file.
    280  */
    281 int
    282 creat(char *fname, int cmode)
    283 {
    284 	return (copen(AT_FDCWD, fname, CREATMODE, cmode));
    285 }
    286 
    287 int
    288 openat(int fd, char *path, int fmode, int cmode)
    289 {
    290 	return (copen(fd, path, OPENMODE(fmode), cmode));
    291 }
    292 
    293 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
    294 /*
    295  * Open and Creat for large files in 32-bit environment. Sets the FOFFMAX flag.
    296  */
    297 int
    298 open64(char *fname, int fmode, int cmode)
    299 {
    300 	return (copen(AT_FDCWD, fname, OPENMODE64(fmode), cmode));
    301 }
    302 
    303 int
    304 creat64(char *fname, int cmode)
    305 {
    306 	return (copen(AT_FDCWD, fname, CREATMODE64, cmode));
    307 }
    308 
    309 int
    310 openat64(int fd, char *path, int fmode, int cmode)
    311 {
    312 	return (copen(fd, path, OPENMODE64(fmode), cmode));
    313 }
    314 
    315 #endif	/* _ILP32 || _SYSCALL32_IMPL */
    316 
    317 #ifdef _SYSCALL32_IMPL
    318 /*
    319  * Open and Creat for 32-bit compatibility on 64-bit kernel
    320  */
    321 int
    322 open32(char *fname, int fmode, int cmode)
    323 {
    324 	return (copen(AT_FDCWD, fname, OPENMODE32(fmode), cmode));
    325 }
    326 
    327 int
    328 creat32(char *fname, int cmode)
    329 {
    330 	return (copen(AT_FDCWD, fname, CREATMODE32, cmode));
    331 }
    332 
    333 int
    334 openat32(int fd, char *path, int fmode, int cmode)
    335 {
    336 	return (copen(fd, path, OPENMODE32(fmode), cmode));
    337 }
    338 
    339 #endif	/* _SYSCALL32_IMPL */
    340 
    341 /*
    342  * Special interface to open hidden attribute directory.
    343  */
    344 int
    345 openattrdirat(int fd, char *fname)
    346 {
    347 	return (copen(fd, fname, OPENMODEATTRDIR, 0));
    348 }
    349