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 /* 23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 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 51 /* 52 * Common code for openat(). Check permissions, allocate an open 53 * file structure, and call the device open routine (if any). 54 */ 55 56 static int 57 copen(int startfd, char *fname, int filemode, int createmode) 58 { 59 struct pathname pn; 60 vnode_t *vp, *sdvp; 61 file_t *fp, *startfp; 62 enum vtype type; 63 int error; 64 int fd, dupfd; 65 vnode_t *startvp; 66 proc_t *p = curproc; 67 uio_seg_t seg = UIO_USERSPACE; 68 char *open_filename = fname; 69 uint32_t auditing = AU_AUDITING(); 70 char startchar; 71 72 if (startfd == AT_FDCWD) { 73 /* 74 * Regular open() 75 */ 76 startvp = NULL; 77 } else { 78 /* 79 * We're here via openat() 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 /* 99 * Handle __openattrdirat() requests 100 */ 101 if (filemode & FXATTRDIROPEN) { 102 if (auditing && (startvp != NULL)) 103 audit_setfsat_path(1); 104 105 if (error = lookupnameat(fname, seg, FOLLOW, 106 NULLVPP, &vp, startvp)) 107 return (set_errno(error)); 108 if (startvp != NULL) 109 VN_RELE(startvp); 110 111 startvp = vp; 112 } 113 114 /* 115 * Do we need to go into extended attribute space? 116 */ 117 if (filemode & FXATTR) { 118 if (startfd == AT_FDCWD) { 119 if (copyin(fname, &startchar, sizeof (char))) 120 return (set_errno(EFAULT)); 121 122 /* 123 * If startchar == '/' then no extended attributes 124 * are looked up. 125 */ 126 if (startchar == '/') { 127 startvp = NULL; 128 } else { 129 mutex_enter(&p->p_lock); 130 startvp = PTOU(p)->u_cdir; 131 VN_HOLD(startvp); 132 mutex_exit(&p->p_lock); 133 } 134 } 135 136 /* 137 * Make sure we have a valid extended attribute request. 138 * We must either have a real fd or AT_FDCWD and a relative 139 * pathname. 140 */ 141 if (startvp == NULL) { 142 goto noxattr; 143 } 144 } 145 146 if (filemode & (FXATTR|FXATTRDIROPEN)) { 147 vattr_t vattr; 148 149 if (error = pn_get(fname, UIO_USERSPACE, &pn)) { 150 goto out; 151 } 152 153 /* 154 * In order to access hidden attribute directory the 155 * user must be able to stat() the file 156 */ 157 vattr.va_mask = AT_ALL; 158 if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) { 159 pn_free(&pn); 160 goto out; 161 } 162 163 if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 || 164 vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { 165 error = VOP_LOOKUP(startvp, "", &sdvp, &pn, 166 (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR : 167 LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(), 168 NULL, NULL, NULL); 169 } else { 170 error = EINVAL; 171 } 172 173 /* 174 * For __openattrdirat() use "." as filename to open 175 * as part of vn_openat() 176 */ 177 if (error == 0 && (filemode & FXATTRDIROPEN)) { 178 open_filename = "."; 179 seg = UIO_SYSSPACE; 180 } 181 182 pn_free(&pn); 183 if (error != 0) 184 goto out; 185 186 VN_RELE(startvp); 187 startvp = sdvp; 188 } 189 190 noxattr: 191 if ((filemode & (FREAD|FWRITE|FXATTRDIROPEN)) != 0) { 192 if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 193 filemode &= ~FNDELAY; 194 error = falloc((vnode_t *)NULL, filemode, &fp, &fd); 195 if (error == 0) { 196 if (auditing && (startvp != NULL)) 197 audit_setfsat_path(1); 198 /* 199 * Last arg is a don't-care term if 200 * !(filemode & FCREAT). 201 */ 202 error = vn_openat(open_filename, seg, filemode, 203 (int)(createmode & MODEMASK), 204 &vp, CRCREAT, PTOU(curproc)->u_cmask, 205 startvp, fd); 206 207 if (startvp != NULL) 208 VN_RELE(startvp); 209 if (error == 0) { 210 if ((vp->v_flag & VDUP) == 0) { 211 fp->f_vnode = vp; 212 mutex_exit(&fp->f_tlock); 213 /* 214 * We must now fill in the slot 215 * falloc reserved. 216 */ 217 setf(fd, fp); 218 return (fd); 219 } else { 220 /* 221 * Special handling for /dev/fd. 222 * Give up the file pointer 223 * and dup the indicated file descriptor 224 * (in v_rdev). This is ugly, but I've 225 * seen worse. 226 */ 227 unfalloc(fp); 228 dupfd = getminor(vp->v_rdev); 229 type = vp->v_type; 230 mutex_enter(&vp->v_lock); 231 vp->v_flag &= ~VDUP; 232 mutex_exit(&vp->v_lock); 233 VN_RELE(vp); 234 if (type != VCHR) 235 return (set_errno(EINVAL)); 236 if ((fp = getf(dupfd)) == NULL) { 237 setf(fd, NULL); 238 return (set_errno(EBADF)); 239 } 240 mutex_enter(&fp->f_tlock); 241 fp->f_count++; 242 mutex_exit(&fp->f_tlock); 243 setf(fd, fp); 244 releasef(dupfd); 245 } 246 return (fd); 247 } else { 248 setf(fd, NULL); 249 unfalloc(fp); 250 return (set_errno(error)); 251 } 252 } 253 } else { 254 error = EINVAL; 255 } 256 out: 257 if (startvp != NULL) 258 VN_RELE(startvp); 259 return (set_errno(error)); 260 } 261 262 #define OPENMODE32(fmode) ((int)((fmode)-FOPEN)) 263 #define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX) 264 #define OPENMODEATTRDIR FXATTRDIROPEN 265 #ifdef _LP64 266 #define OPENMODE(fmode) OPENMODE64(fmode) 267 #else 268 #define OPENMODE OPENMODE32 269 #endif 270 271 /* 272 * Open a file. 273 */ 274 int 275 openat(int fd, char *path, int fmode, int cmode) 276 { 277 return (copen(fd, path, OPENMODE(fmode), cmode)); 278 } 279 280 int 281 open(char *path, int fmode, int cmode) 282 { 283 return (openat(AT_FDCWD, path, fmode, cmode)); 284 } 285 286 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 287 /* 288 * Open for large files in 32-bit environment. Sets the FOFFMAX flag. 289 */ 290 int 291 openat64(int fd, char *path, int fmode, int cmode) 292 { 293 return (copen(fd, path, OPENMODE64(fmode), cmode)); 294 } 295 296 int 297 open64(char *path, int fmode, int cmode) 298 { 299 return (openat64(AT_FDCWD, path, fmode, cmode)); 300 } 301 302 #endif /* _ILP32 || _SYSCALL32_IMPL */ 303 304 #ifdef _SYSCALL32_IMPL 305 /* 306 * Open for 32-bit compatibility on 64-bit kernel 307 */ 308 int 309 openat32(int fd, char *path, int fmode, int cmode) 310 { 311 return (copen(fd, path, OPENMODE32(fmode), cmode)); 312 } 313 314 int 315 open32(char *path, int fmode, int cmode) 316 { 317 return (openat32(AT_FDCWD, path, fmode, cmode)); 318 } 319 320 #endif /* _SYSCALL32_IMPL */ 321