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