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