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