xref: /titanic_52/usr/src/uts/common/syscall/open.c (revision 06e46062ef4f5f4b687cbafb4518fb123fe23920)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include <sys/param.h>
38 #include <sys/isa_defs.h>
39 #include <sys/types.h>
40 #include <sys/sysmacros.h>
41 #include <sys/user.h>
42 #include <sys/systm.h>
43 #include <sys/errno.h>
44 #include <sys/fcntl.h>
45 #include <sys/stat.h>
46 #include <sys/vnode.h>
47 #include <sys/vfs.h>
48 #include <sys/file.h>
49 #include <sys/mode.h>
50 #include <sys/uio.h>
51 #include <sys/debug.h>
52 #include <c2/audit.h>
53 
54 /*
55  * Common code for open()/openat() and creat().  Check permissions, allocate
56  * an open file structure, and call the device open routine (if any).
57  */
58 
59 static int
60 copen(int startfd, char *fname, int filemode, int createmode)
61 {
62 	struct pathname pn;
63 	vnode_t *vp, *sdvp;
64 	file_t *fp, *startfp;
65 	enum vtype type;
66 	int error;
67 	int fd, dupfd;
68 	vnode_t *startvp;
69 	proc_t *p = curproc;
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 	if (filemode & FXATTR) {
100 
101 		/*
102 		 * Make sure we have a valid request.
103 		 * We must either have a real fd or AT_FDCWD
104 		 */
105 
106 		if (startfd != AT_FDCWD && startvp == NULL) {
107 			error = EINVAL;
108 			goto out;
109 		}
110 
111 		if (error = pn_get(fname, UIO_USERSPACE, &pn)) {
112 			goto out;
113 		}
114 
115 		if (startfd == AT_FDCWD) {
116 			mutex_enter(&p->p_lock);
117 			startvp = PTOU(p)->u_cdir;
118 			VN_HOLD(startvp);
119 			mutex_exit(&p->p_lock);
120 		}
121 
122 		/*
123 		 * Verify permission to put attributes on file
124 		 */
125 
126 		if ((VOP_ACCESS(startvp, VREAD, 0, CRED()) != 0) &&
127 		    (VOP_ACCESS(startvp, VWRITE, 0, CRED()) != 0) &&
128 		    (VOP_ACCESS(startvp, VEXEC, 0, CRED()) != 0)) {
129 			error = EACCES;
130 			pn_free(&pn);
131 			goto out;
132 		}
133 
134 		if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0) {
135 			error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
136 			    LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED());
137 		} else {
138 			error = EINVAL;
139 		}
140 		pn_free(&pn);
141 		if (error != 0)
142 			goto out;
143 
144 		VN_RELE(startvp);
145 		startvp = sdvp;
146 	}
147 
148 	if ((filemode & (FREAD|FWRITE)) != 0) {
149 		if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
150 			filemode &= ~FNDELAY;
151 		error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
152 		if (error == 0) {
153 #ifdef C2_AUDIT
154 			if (audit_active)
155 				audit_setfsat_path(1);
156 #endif /* C2_AUDIT */
157 			/*
158 			 * Last arg is a don't-care term if
159 			 * !(filemode & FCREAT).
160 			 */
161 			error = vn_openat(fname, UIO_USERSPACE, filemode,
162 			    (int)(createmode & MODEMASK), &vp, CRCREAT,
163 			    u.u_cmask, startvp);
164 
165 			if (startvp != NULL)
166 				VN_RELE(startvp);
167 			if (error == 0) {
168 #ifdef C2_AUDIT
169 				if (audit_active)
170 					audit_copen(fd, fp, vp);
171 #endif /* C2_AUDIT */
172 				if ((vp->v_flag & VDUP) == 0) {
173 					fp->f_vnode = vp;
174 					mutex_exit(&fp->f_tlock);
175 					/*
176 					 * We must now fill in the slot
177 					 * falloc reserved.
178 					 */
179 					setf(fd, fp);
180 					return (fd);
181 				} else {
182 					/*
183 					 * Special handling for /dev/fd.
184 					 * Give up the file pointer
185 					 * and dup the indicated file descriptor
186 					 * (in v_rdev). This is ugly, but I've
187 					 * seen worse.
188 					 */
189 					unfalloc(fp);
190 					dupfd = getminor(vp->v_rdev);
191 					type = vp->v_type;
192 					mutex_enter(&vp->v_lock);
193 					vp->v_flag &= ~VDUP;
194 					mutex_exit(&vp->v_lock);
195 					VN_RELE(vp);
196 					if (type != VCHR)
197 						return (set_errno(EINVAL));
198 					if ((fp = getf(dupfd)) == NULL) {
199 						setf(fd, NULL);
200 						return (set_errno(EBADF));
201 					}
202 					mutex_enter(&fp->f_tlock);
203 					fp->f_count++;
204 					mutex_exit(&fp->f_tlock);
205 					setf(fd, fp);
206 					releasef(dupfd);
207 				}
208 				return (fd);
209 			} else {
210 				setf(fd, NULL);
211 				unfalloc(fp);
212 				return (set_errno(error));
213 			}
214 		}
215 	} else {
216 		error = EINVAL;
217 	}
218 out:
219 	if (startvp != NULL)
220 		VN_RELE(startvp);
221 	return (set_errno(error));
222 }
223 
224 #define	OPENMODE32(fmode)	((int)((fmode)-FOPEN))
225 #define	CREATMODE32		(FWRITE|FCREAT|FTRUNC)
226 #define	OPENMODE64(fmode)	(OPENMODE32(fmode) | FOFFMAX)
227 #define	CREATMODE64		(CREATMODE32 | FOFFMAX)
228 #ifdef _LP64
229 #define	OPENMODE(fmode)		OPENMODE64(fmode)
230 #define	CREATMODE		CREATMODE64
231 #else
232 #define	OPENMODE		OPENMODE32
233 #define	CREATMODE		CREATMODE32
234 #endif
235 
236 /*
237  * Open a file.
238  */
239 int
240 open(char *fname, int fmode, int cmode)
241 {
242 	return (copen(AT_FDCWD, fname, OPENMODE(fmode), cmode));
243 }
244 
245 /*
246  * Create a file.
247  */
248 int
249 creat(char *fname, int cmode)
250 {
251 	return (copen(AT_FDCWD, fname, CREATMODE, cmode));
252 }
253 
254 int
255 openat(int fd, char *path, int fmode, int cmode)
256 {
257 	return (copen(fd, path, OPENMODE(fmode), cmode));
258 }
259 
260 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
261 /*
262  * Open and Creat for large files in 32-bit environment. Sets the FOFFMAX flag.
263  */
264 int
265 open64(char *fname, int fmode, int cmode)
266 {
267 	return (copen(AT_FDCWD, fname, OPENMODE64(fmode), cmode));
268 }
269 
270 int
271 creat64(char *fname, int cmode)
272 {
273 	return (copen(AT_FDCWD, fname, CREATMODE64, cmode));
274 }
275 
276 int
277 openat64(int fd, char *path, int fmode, int cmode)
278 {
279 	return (copen(fd, path, OPENMODE64(fmode), cmode));
280 }
281 
282 #endif	/* _ILP32 || _SYSCALL32_IMPL */
283 
284 #ifdef _SYSCALL32_IMPL
285 /*
286  * Open and Creat for 32-bit compatibility on 64-bit kernel
287  */
288 int
289 open32(char *fname, int fmode, int cmode)
290 {
291 	return (copen(AT_FDCWD, fname, OPENMODE32(fmode), cmode));
292 }
293 
294 int
295 creat32(char *fname, int cmode)
296 {
297 	return (copen(AT_FDCWD, fname, CREATMODE32, cmode));
298 }
299 
300 int
301 openat32(int fd, char *path, int fmode, int cmode)
302 {
303 	return (copen(fd, path, OPENMODE32(fmode), cmode));
304 }
305 #endif	/* _SYSCALL32_IMPL */
306