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 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 #include <sys/param.h> 37 #include <sys/isa_defs.h> 38 #include <sys/types.h> 39 #include <sys/sysmacros.h> 40 #include <sys/user.h> 41 #include <sys/systm.h> 42 #include <sys/errno.h> 43 #include <sys/fcntl.h> 44 #include <sys/stat.h> 45 #include <sys/vnode.h> 46 #include <sys/vfs.h> 47 #include <sys/file.h> 48 #include <sys/mode.h> 49 #include <sys/uio.h> 50 #include <sys/debug.h> 51 #include <c2/audit.h> 52 53 /* 54 * Common code for open()/openat() and creat(). Check permissions, allocate 55 * an open file structure, and call the device open routine (if any). 56 */ 57 58 static int 59 copen(int startfd, char *fname, int filemode, int createmode) 60 { 61 struct pathname pn; 62 vnode_t *vp, *sdvp; 63 file_t *fp, *startfp; 64 enum vtype type; 65 int error; 66 int fd, dupfd; 67 vnode_t *startvp; 68 proc_t *p = curproc; 69 70 if (startfd == AT_FDCWD) { 71 /* 72 * Regular open() 73 */ 74 startvp = NULL; 75 } else { 76 /* 77 * We're here via openat() 78 */ 79 char startchar; 80 81 if (copyin(fname, &startchar, sizeof (char))) 82 return (set_errno(EFAULT)); 83 84 /* 85 * if startchar is / then startfd is ignored 86 */ 87 if (startchar == '/') 88 startvp = NULL; 89 else { 90 if ((startfp = getf(startfd)) == NULL) 91 return (set_errno(EBADF)); 92 startvp = startfp->f_vnode; 93 VN_HOLD(startvp); 94 releasef(startfd); 95 } 96 } 97 98 if (filemode & FXATTR) { 99 100 /* 101 * Make sure we have a valid request. 102 * We must either have a real fd or AT_FDCWD 103 */ 104 105 if (startfd != AT_FDCWD && startvp == NULL) { 106 error = EINVAL; 107 goto out; 108 } 109 110 if (error = pn_get(fname, UIO_USERSPACE, &pn)) { 111 goto out; 112 } 113 114 if (startfd == AT_FDCWD) { 115 mutex_enter(&p->p_lock); 116 startvp = PTOU(p)->u_cdir; 117 VN_HOLD(startvp); 118 mutex_exit(&p->p_lock); 119 } 120 121 /* 122 * Verify permission to put attributes on file 123 */ 124 125 if ((VOP_ACCESS(startvp, VREAD, 0, CRED()) != 0) && 126 (VOP_ACCESS(startvp, VWRITE, 0, CRED()) != 0) && 127 (VOP_ACCESS(startvp, VEXEC, 0, CRED()) != 0)) { 128 error = EACCES; 129 pn_free(&pn); 130 goto out; 131 } 132 133 if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0) { 134 error = VOP_LOOKUP(startvp, "", &sdvp, &pn, 135 LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED()); 136 } else { 137 error = EINVAL; 138 } 139 pn_free(&pn); 140 if (error != 0) 141 goto out; 142 143 VN_RELE(startvp); 144 startvp = sdvp; 145 } 146 147 if ((filemode & (FREAD|FWRITE)) != 0) { 148 if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 149 filemode &= ~FNDELAY; 150 error = falloc((vnode_t *)NULL, filemode, &fp, &fd); 151 if (error == 0) { 152 #ifdef C2_AUDIT 153 if (audit_active) 154 audit_setfsat_path(1); 155 #endif /* C2_AUDIT */ 156 /* 157 * Last arg is a don't-care term if 158 * !(filemode & FCREAT). 159 */ 160 error = vn_openat(fname, UIO_USERSPACE, filemode, 161 (int)(createmode & MODEMASK), &vp, CRCREAT, 162 PTOU(curproc)->u_cmask, startvp); 163 164 if (startvp != NULL) 165 VN_RELE(startvp); 166 if (error == 0) { 167 #ifdef C2_AUDIT 168 if (audit_active) 169 audit_copen(fd, fp, vp); 170 #endif /* C2_AUDIT */ 171 if ((vp->v_flag & VDUP) == 0) { 172 fp->f_vnode = vp; 173 mutex_exit(&fp->f_tlock); 174 /* 175 * We must now fill in the slot 176 * falloc reserved. 177 */ 178 setf(fd, fp); 179 return (fd); 180 } else { 181 /* 182 * Special handling for /dev/fd. 183 * Give up the file pointer 184 * and dup the indicated file descriptor 185 * (in v_rdev). This is ugly, but I've 186 * seen worse. 187 */ 188 unfalloc(fp); 189 dupfd = getminor(vp->v_rdev); 190 type = vp->v_type; 191 mutex_enter(&vp->v_lock); 192 vp->v_flag &= ~VDUP; 193 mutex_exit(&vp->v_lock); 194 VN_RELE(vp); 195 if (type != VCHR) 196 return (set_errno(EINVAL)); 197 if ((fp = getf(dupfd)) == NULL) { 198 setf(fd, NULL); 199 return (set_errno(EBADF)); 200 } 201 mutex_enter(&fp->f_tlock); 202 fp->f_count++; 203 mutex_exit(&fp->f_tlock); 204 setf(fd, fp); 205 releasef(dupfd); 206 } 207 return (fd); 208 } else { 209 setf(fd, NULL); 210 unfalloc(fp); 211 return (set_errno(error)); 212 } 213 } 214 } else { 215 error = EINVAL; 216 } 217 out: 218 if (startvp != NULL) 219 VN_RELE(startvp); 220 return (set_errno(error)); 221 } 222 223 #define OPENMODE32(fmode) ((int)((fmode)-FOPEN)) 224 #define CREATMODE32 (FWRITE|FCREAT|FTRUNC) 225 #define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX) 226 #define CREATMODE64 (CREATMODE32 | FOFFMAX) 227 #ifdef _LP64 228 #define OPENMODE(fmode) OPENMODE64(fmode) 229 #define CREATMODE CREATMODE64 230 #else 231 #define OPENMODE OPENMODE32 232 #define CREATMODE CREATMODE32 233 #endif 234 235 /* 236 * Open a file. 237 */ 238 int 239 open(char *fname, int fmode, int cmode) 240 { 241 return (copen(AT_FDCWD, fname, OPENMODE(fmode), cmode)); 242 } 243 244 /* 245 * Create a file. 246 */ 247 int 248 creat(char *fname, int cmode) 249 { 250 return (copen(AT_FDCWD, fname, CREATMODE, cmode)); 251 } 252 253 int 254 openat(int fd, char *path, int fmode, int cmode) 255 { 256 return (copen(fd, path, OPENMODE(fmode), cmode)); 257 } 258 259 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 260 /* 261 * Open and Creat for large files in 32-bit environment. Sets the FOFFMAX flag. 262 */ 263 int 264 open64(char *fname, int fmode, int cmode) 265 { 266 return (copen(AT_FDCWD, fname, OPENMODE64(fmode), cmode)); 267 } 268 269 int 270 creat64(char *fname, int cmode) 271 { 272 return (copen(AT_FDCWD, fname, CREATMODE64, cmode)); 273 } 274 275 int 276 openat64(int fd, char *path, int fmode, int cmode) 277 { 278 return (copen(fd, path, OPENMODE64(fmode), cmode)); 279 } 280 281 #endif /* _ILP32 || _SYSCALL32_IMPL */ 282 283 #ifdef _SYSCALL32_IMPL 284 /* 285 * Open and Creat for 32-bit compatibility on 64-bit kernel 286 */ 287 int 288 open32(char *fname, int fmode, int cmode) 289 { 290 return (copen(AT_FDCWD, fname, OPENMODE32(fmode), cmode)); 291 } 292 293 int 294 creat32(char *fname, int cmode) 295 { 296 return (copen(AT_FDCWD, fname, CREATMODE32, cmode)); 297 } 298 299 int 300 openat32(int fd, char *path, int fmode, int cmode) 301 { 302 return (copen(fd, path, OPENMODE32(fmode), cmode)); 303 } 304 #endif /* _SYSCALL32_IMPL */ 305