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 2010 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 #include <sys/param.h> 36 #include <sys/isa_defs.h> 37 #include <sys/types.h> 38 #include <sys/sysmacros.h> 39 #include <sys/user.h> 40 #include <sys/systm.h> 41 #include <sys/errno.h> 42 #include <sys/fcntl.h> 43 #include <sys/stat.h> 44 #include <sys/vnode.h> 45 #include <sys/vfs.h> 46 #include <sys/file.h> 47 #include <sys/mode.h> 48 #include <sys/uio.h> 49 #include <sys/debug.h> 50 #include <c2/audit.h> 51 #include <sys/cmn_err.h> 52 53 /* 54 * Common code for openat(). Check permissions, allocate an open 55 * 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 uio_seg_t seg = UIO_USERSPACE; 70 char *open_filename = fname; 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 char startchar; 82 83 if (copyin(fname, &startchar, sizeof (char))) 84 return (set_errno(EFAULT)); 85 86 /* 87 * if startchar is / then startfd is ignored 88 */ 89 if (startchar == '/') 90 startvp = NULL; 91 else { 92 if ((startfp = getf(startfd)) == NULL) 93 return (set_errno(EBADF)); 94 startvp = startfp->f_vnode; 95 VN_HOLD(startvp); 96 releasef(startfd); 97 } 98 } 99 100 /* 101 * Handle openattrdirat request 102 */ 103 if (filemode & FXATTRDIROPEN) { 104 if (audit_active) 105 audit_setfsat_path(1); 106 107 if (error = lookupnameat(fname, seg, FOLLOW, 108 NULLVPP, &vp, startvp)) 109 return (set_errno(error)); 110 if (startvp) { 111 VN_RELE(startvp); 112 startvp = NULL; 113 } 114 115 startvp = vp; 116 } 117 118 /* 119 * Do we need to go into extended attribute space? 120 */ 121 if (filemode & (FXATTR|FXATTRDIROPEN)) { 122 vattr_t vattr; 123 124 /* 125 * Make sure we have a valid request. 126 * We must either have a real fd or AT_FDCWD 127 */ 128 129 if (startfd != AT_FDCWD && startvp == NULL) { 130 error = EINVAL; 131 goto out; 132 } 133 134 if (error = pn_get(fname, UIO_USERSPACE, &pn)) { 135 goto out; 136 } 137 138 if (startfd == AT_FDCWD && !(filemode & FXATTRDIROPEN)) { 139 mutex_enter(&p->p_lock); 140 startvp = PTOU(p)->u_cdir; 141 VN_HOLD(startvp); 142 mutex_exit(&p->p_lock); 143 } 144 145 /* 146 * In order to access hidden attribute directory the 147 * user must be able to stat() the file 148 */ 149 150 vattr.va_mask = AT_ALL; 151 if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) { 152 pn_free(&pn); 153 goto out; 154 } 155 156 if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 || 157 vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { 158 error = VOP_LOOKUP(startvp, "", &sdvp, &pn, 159 (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR : 160 LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(), 161 NULL, NULL, NULL); 162 } else { 163 error = EINVAL; 164 } 165 166 /* 167 * For openattrdirat use "." as filename to open 168 * as part of vn_openat() 169 */ 170 if (error == 0 && (filemode & FXATTRDIROPEN)) { 171 open_filename = "."; 172 seg = UIO_SYSSPACE; 173 } 174 175 pn_free(&pn); 176 if (error != 0) 177 goto out; 178 179 VN_RELE(startvp); 180 startvp = sdvp; 181 } 182 183 if ((filemode & (FREAD|FWRITE|FXATTRDIROPEN)) != 0) { 184 if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 185 filemode &= ~FNDELAY; 186 error = falloc((vnode_t *)NULL, filemode, &fp, &fd); 187 if (error == 0) { 188 if (audit_active) 189 audit_setfsat_path(1); 190 /* 191 * Last arg is a don't-care term if 192 * !(filemode & FCREAT). 193 */ 194 195 error = vn_openat(open_filename, seg, filemode, 196 (int)(createmode & MODEMASK), 197 &vp, CRCREAT, PTOU(curproc)->u_cmask, 198 startvp, fd); 199 200 if (startvp != NULL) 201 VN_RELE(startvp); 202 if (error == 0) { 203 if (audit_active) 204 audit_copen(fd, fp, vp); 205 if ((vp->v_flag & VDUP) == 0) { 206 fp->f_vnode = vp; 207 mutex_exit(&fp->f_tlock); 208 /* 209 * We must now fill in the slot 210 * falloc reserved. 211 */ 212 setf(fd, fp); 213 return (fd); 214 } else { 215 /* 216 * Special handling for /dev/fd. 217 * Give up the file pointer 218 * and dup the indicated file descriptor 219 * (in v_rdev). This is ugly, but I've 220 * seen worse. 221 */ 222 unfalloc(fp); 223 dupfd = getminor(vp->v_rdev); 224 type = vp->v_type; 225 mutex_enter(&vp->v_lock); 226 vp->v_flag &= ~VDUP; 227 mutex_exit(&vp->v_lock); 228 VN_RELE(vp); 229 if (type != VCHR) 230 return (set_errno(EINVAL)); 231 if ((fp = getf(dupfd)) == NULL) { 232 setf(fd, NULL); 233 return (set_errno(EBADF)); 234 } 235 mutex_enter(&fp->f_tlock); 236 fp->f_count++; 237 mutex_exit(&fp->f_tlock); 238 setf(fd, fp); 239 releasef(dupfd); 240 } 241 return (fd); 242 } else { 243 setf(fd, NULL); 244 unfalloc(fp); 245 return (set_errno(error)); 246 } 247 } 248 } else { 249 error = EINVAL; 250 } 251 out: 252 if (startvp != NULL) 253 VN_RELE(startvp); 254 return (set_errno(error)); 255 } 256 257 #define OPENMODE32(fmode) ((int)((fmode)-FOPEN)) 258 #define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX) 259 #define OPENMODEATTRDIR FXATTRDIROPEN 260 #ifdef _LP64 261 #define OPENMODE(fmode) OPENMODE64(fmode) 262 #else 263 #define OPENMODE OPENMODE32 264 #endif 265 266 /* 267 * Open a file. 268 */ 269 int 270 openat(int fd, char *path, int fmode, int cmode) 271 { 272 return (copen(fd, path, OPENMODE(fmode), cmode)); 273 } 274 275 int 276 open(char *path, int fmode, int cmode) 277 { 278 return (openat(AT_FDCWD, path, fmode, cmode)); 279 } 280 281 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 282 /* 283 * Open for large files in 32-bit environment. Sets the FOFFMAX flag. 284 */ 285 int 286 openat64(int fd, char *path, int fmode, int cmode) 287 { 288 return (copen(fd, path, OPENMODE64(fmode), cmode)); 289 } 290 291 int 292 open64(char *path, int fmode, int cmode) 293 { 294 return (openat64(AT_FDCWD, path, fmode, cmode)); 295 } 296 297 #endif /* _ILP32 || _SYSCALL32_IMPL */ 298 299 #ifdef _SYSCALL32_IMPL 300 /* 301 * Open for 32-bit compatibility on 64-bit kernel 302 */ 303 int 304 openat32(int fd, char *path, int fmode, int cmode) 305 { 306 return (copen(fd, path, OPENMODE32(fmode), cmode)); 307 } 308 309 int 310 open32(char *path, int fmode, int cmode) 311 { 312 return (openat32(AT_FDCWD, path, fmode, cmode)); 313 } 314 315 #endif /* _SYSCALL32_IMPL */ 316