1 /* $NetBSD: umap_vnops.c,v 1.24 2004/01/25 18:06:49 hannken Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * the UCLA Ficus project. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95 35 */ 36 37 /* 38 * Umap Layer 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: umap_vnops.c,v 1.24 2004/01/25 18:06:49 hannken Exp $"); 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/time.h> 47 #include <sys/vnode.h> 48 #include <sys/mount.h> 49 #include <sys/namei.h> 50 #include <sys/malloc.h> 51 #include <sys/buf.h> 52 #include <miscfs/umapfs/umap.h> 53 #include <miscfs/genfs/genfs.h> 54 #include <miscfs/genfs/layer_extern.h> 55 56 int umap_lookup __P((void *)); 57 int umap_getattr __P((void *)); 58 int umap_print __P((void *)); 59 int umap_rename __P((void *)); 60 61 /* 62 * Global vfs data structures 63 */ 64 /* 65 * XXX - strategy, bwrite are hand coded currently. They should 66 * go away with a merged buffer/block cache. 67 * 68 */ 69 int (**umap_vnodeop_p) __P((void *)); 70 const struct vnodeopv_entry_desc umap_vnodeop_entries[] = { 71 { &vop_default_desc, umap_bypass }, 72 73 { &vop_lookup_desc, umap_lookup }, 74 { &vop_getattr_desc, umap_getattr }, 75 { &vop_print_desc, umap_print }, 76 { &vop_rename_desc, umap_rename }, 77 78 { &vop_lock_desc, layer_lock }, 79 { &vop_unlock_desc, layer_unlock }, 80 { &vop_islocked_desc, layer_islocked }, 81 { &vop_fsync_desc, layer_fsync }, 82 { &vop_inactive_desc, layer_inactive }, 83 { &vop_reclaim_desc, layer_reclaim }, 84 { &vop_open_desc, layer_open }, 85 { &vop_setattr_desc, layer_setattr }, 86 { &vop_access_desc, layer_access }, 87 88 { &vop_bwrite_desc, layer_bwrite }, 89 { &vop_bmap_desc, layer_bmap }, 90 { &vop_getpages_desc, layer_getpages }, 91 { &vop_putpages_desc, layer_putpages }, 92 93 { NULL, NULL } 94 }; 95 const struct vnodeopv_desc umapfs_vnodeop_opv_desc = 96 { &umap_vnodeop_p, umap_vnodeop_entries }; 97 98 /* 99 * This is the 08-June-1999 bypass routine. 100 * See layer_vnops.c:layer_bypass for more details. 101 */ 102 int 103 umap_bypass(v) 104 void *v; 105 { 106 struct vop_generic_args /* { 107 struct vnodeop_desc *a_desc; 108 <other random data follows, presumably> 109 } */ *ap = v; 110 struct ucred **credpp = 0, *credp = 0; 111 struct ucred *savecredp = 0, *savecompcredp = 0; 112 struct ucred *compcredp = 0; 113 struct vnode **this_vp_p; 114 int error, error1; 115 int (**our_vnodeop_p) __P((void *)); 116 struct vnode *old_vps[VDESC_MAX_VPS], *vp0; 117 struct vnode **vps_p[VDESC_MAX_VPS]; 118 struct vnode ***vppp; 119 struct vnodeop_desc *descp = ap->a_desc; 120 int reles, i, flags; 121 struct componentname **compnamepp = 0; 122 123 #ifdef SAFETY 124 /* 125 * We require at least one vp. 126 */ 127 if (descp->vdesc_vp_offsets == NULL || 128 descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) 129 panic ("umap_bypass: no vp's in map.\n"); 130 #endif 131 vps_p[0] = VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[0], 132 ap); 133 vp0 = *vps_p[0]; 134 flags = MOUNTTOUMAPMOUNT(vp0->v_mount)->umapm_flags; 135 our_vnodeop_p = vp0->v_op; 136 137 if (flags & LAYERFS_MBYPASSDEBUG) 138 printf("umap_bypass: %s\n", descp->vdesc_name); 139 140 /* 141 * Map the vnodes going in. 142 * Later, we'll invoke the operation based on 143 * the first mapped vnode's operation vector. 144 */ 145 reles = descp->vdesc_flags; 146 for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 147 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 148 break; /* bail out at end of list */ 149 vps_p[i] = this_vp_p = 150 VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap); 151 152 /* 153 * We're not guaranteed that any but the first vnode 154 * are of our type. Check for and don't map any 155 * that aren't. (Must map first vp or vclean fails.) 156 */ 157 158 if (i && ((*this_vp_p)==NULL || 159 (*this_vp_p)->v_op != our_vnodeop_p)) { 160 old_vps[i] = NULL; 161 } else { 162 old_vps[i] = *this_vp_p; 163 *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p); 164 if (reles & 1) 165 VREF(*this_vp_p); 166 } 167 168 } 169 170 /* 171 * Fix the credentials. (That's the purpose of this layer.) 172 */ 173 174 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { 175 176 credpp = VOPARG_OFFSETTO(struct ucred**, 177 descp->vdesc_cred_offset, ap); 178 179 /* Save old values */ 180 181 savecredp = *credpp; 182 if (savecredp != NOCRED) 183 *credpp = crdup(savecredp); 184 credp = *credpp; 185 186 if ((flags & LAYERFS_MBYPASSDEBUG) && credp->cr_uid != 0) 187 printf("umap_bypass: user was %d, group %d\n", 188 credp->cr_uid, credp->cr_gid); 189 190 /* Map all ids in the credential structure. */ 191 192 umap_mapids(vp0->v_mount, credp); 193 194 if ((flags & LAYERFS_MBYPASSDEBUG) && credp->cr_uid != 0) 195 printf("umap_bypass: user now %d, group %d\n", 196 credp->cr_uid, credp->cr_gid); 197 } 198 199 /* BSD often keeps a credential in the componentname structure 200 * for speed. If there is one, it better get mapped, too. 201 */ 202 203 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { 204 205 compnamepp = VOPARG_OFFSETTO(struct componentname**, 206 descp->vdesc_componentname_offset, ap); 207 208 savecompcredp = (*compnamepp)->cn_cred; 209 if (savecompcredp != NOCRED) 210 (*compnamepp)->cn_cred = crdup(savecompcredp); 211 compcredp = (*compnamepp)->cn_cred; 212 213 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) 214 printf("umap_bypass: component credit user was %d, group %d\n", 215 compcredp->cr_uid, compcredp->cr_gid); 216 217 /* Map all ids in the credential structure. */ 218 219 umap_mapids(vp0->v_mount, compcredp); 220 221 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) 222 printf("umap_bypass: component credit user now %d, group %d\n", 223 compcredp->cr_uid, compcredp->cr_gid); 224 } 225 226 /* 227 * Call the operation on the lower layer 228 * with the modified argument structure. 229 */ 230 error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); 231 232 /* 233 * Maintain the illusion of call-by-value 234 * by restoring vnodes in the argument structure 235 * to their original value. 236 */ 237 reles = descp->vdesc_flags; 238 for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 239 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 240 break; /* bail out at end of list */ 241 if (old_vps[i]) { 242 *(vps_p[i]) = old_vps[i]; 243 if (reles & VDESC_VP0_WILLUNLOCK) 244 LAYERFS_UPPERUNLOCK(*(vps_p[i]), 0, error1); 245 if (reles & VDESC_VP0_WILLRELE) 246 vrele(*(vps_p[i])); 247 }; 248 }; 249 250 /* 251 * Map the possible out-going vpp 252 * (Assumes that the lower layer always returns 253 * a VREF'ed vpp unless it gets an error.) 254 */ 255 if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && 256 !(descp->vdesc_flags & VDESC_NOMAP_VPP) && 257 !error) { 258 if (descp->vdesc_flags & VDESC_VPP_WILLRELE) 259 goto out; 260 vppp = VOPARG_OFFSETTO(struct vnode***, 261 descp->vdesc_vpp_offset, ap); 262 error = layer_node_create(old_vps[0]->v_mount, **vppp, *vppp); 263 }; 264 265 out: 266 /* 267 * Free duplicate cred structure and restore old one. 268 */ 269 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { 270 if ((flags & LAYERFS_MBYPASSDEBUG) && credp && 271 credp->cr_uid != 0) 272 printf("umap_bypass: returning-user was %d\n", 273 credp->cr_uid); 274 275 if (savecredp != NOCRED) { 276 crfree(credp); 277 *credpp = savecredp; 278 if ((flags & LAYERFS_MBYPASSDEBUG) && credpp && 279 (*credpp)->cr_uid != 0) 280 printf("umap_bypass: returning-user now %d\n\n", 281 savecredp->cr_uid); 282 } 283 } 284 285 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { 286 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && 287 compcredp->cr_uid != 0) 288 printf("umap_bypass: returning-component-user was %d\n", 289 compcredp->cr_uid); 290 291 if (savecompcredp != NOCRED) { 292 crfree(compcredp); 293 (*compnamepp)->cn_cred = savecompcredp; 294 if ((flags & LAYERFS_MBYPASSDEBUG) && savecompcredp && 295 savecompcredp->cr_uid != 0) 296 printf("umap_bypass: returning-component-user now %d\n", 297 savecompcredp->cr_uid); 298 } 299 } 300 301 return (error); 302 } 303 304 /* 305 * This is based on the 08-June-1999 bypass routine. 306 * See layer_vnops.c:layer_bypass for more details. 307 */ 308 int 309 umap_lookup(v) 310 void *v; 311 { 312 struct vop_lookup_args /* { 313 struct vnodeop_desc *a_desc; 314 struct vnode * a_dvp; 315 struct vnode ** a_vpp; 316 struct componentname * a_cnp; 317 } */ *ap = v; 318 struct componentname *cnp = ap->a_cnp; 319 struct ucred *savecompcredp = NULL; 320 struct ucred *compcredp = NULL; 321 struct vnode *dvp, *vp, *ldvp; 322 struct mount *mp; 323 int error; 324 int i, flags, cnf = cnp->cn_flags; 325 326 dvp = ap->a_dvp; 327 mp = dvp->v_mount; 328 329 if ((cnf & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 330 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 331 return (EROFS); 332 333 flags = MOUNTTOUMAPMOUNT(mp)->umapm_flags; 334 ldvp = UMAPVPTOLOWERVP(dvp); 335 336 if (flags & LAYERFS_MBYPASSDEBUG) 337 printf("umap_lookup\n"); 338 339 /* 340 * Fix the credentials. (That's the purpose of this layer.) 341 * 342 * BSD often keeps a credential in the componentname structure 343 * for speed. If there is one, it better get mapped, too. 344 */ 345 346 if ((savecompcredp = cnp->cn_cred)) { 347 compcredp = crdup(savecompcredp); 348 cnp->cn_cred = compcredp; 349 350 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) 351 printf("umap_lookup: component credit user was %d, group %d\n", 352 compcredp->cr_uid, compcredp->cr_gid); 353 354 /* Map all ids in the credential structure. */ 355 umap_mapids(mp, compcredp); 356 } 357 358 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) 359 printf("umap_lookup: component credit user now %d, group %d\n", 360 compcredp->cr_uid, compcredp->cr_gid); 361 362 ap->a_dvp = ldvp; 363 error = VCALL(ldvp, ap->a_desc->vdesc_offset, ap); 364 vp = *ap->a_vpp; 365 366 if (error == EJUSTRETURN && (cnf & ISLASTCN) && 367 (dvp->v_mount->mnt_flag & MNT_RDONLY) && 368 (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) 369 error = EROFS; 370 371 /* Do locking fixup as appropriate. See layer_lookup() for info */ 372 if ((cnp->cn_flags & PDIRUNLOCK)) { 373 LAYERFS_UPPERUNLOCK(dvp, 0, i); 374 } 375 if (ldvp == vp) { 376 *ap->a_vpp = dvp; 377 VREF(dvp); 378 vrele(vp); 379 } else if (vp != NULL) { 380 error = layer_node_create(mp, vp, ap->a_vpp); 381 } 382 383 /* 384 * Free duplicate cred structure and restore old one. 385 */ 386 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && 387 compcredp->cr_uid != 0) 388 printf("umap_lookup: returning-component-user was %d\n", 389 compcredp->cr_uid); 390 391 if (savecompcredp != NOCRED) { 392 crfree(compcredp); 393 cnp->cn_cred = savecompcredp; 394 if ((flags & LAYERFS_MBYPASSDEBUG) && savecompcredp && 395 savecompcredp->cr_uid != 0) 396 printf("umap_lookup: returning-component-user now %d\n", 397 savecompcredp->cr_uid); 398 } 399 400 return (error); 401 } 402 403 /* 404 * We handle getattr to change the fsid. 405 */ 406 int 407 umap_getattr(v) 408 void *v; 409 { 410 struct vop_getattr_args /* { 411 struct vnode *a_vp; 412 struct vattr *a_vap; 413 struct ucred *a_cred; 414 struct proc *a_p; 415 } */ *ap = v; 416 uid_t uid; 417 gid_t gid; 418 int error, tmpid, nentries, gnentries, flags; 419 u_long (*mapdata)[2]; 420 u_long (*gmapdata)[2]; 421 struct vnode **vp1p; 422 const struct vnodeop_desc *descp = ap->a_desc; 423 424 if ((error = umap_bypass(ap)) != 0) 425 return (error); 426 /* Requires that arguments be restored. */ 427 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 428 429 flags = MOUNTTOUMAPMOUNT(ap->a_vp->v_mount)->umapm_flags; 430 /* 431 * Umap needs to map the uid and gid returned by a stat 432 * into the proper values for this site. This involves 433 * finding the returned uid in the mapping information, 434 * translating it into the uid on the other end, 435 * and filling in the proper field in the vattr 436 * structure pointed to by ap->a_vap. The group 437 * is easier, since currently all groups will be 438 * translate to the NULLGROUP. 439 */ 440 441 /* Find entry in map */ 442 443 uid = ap->a_vap->va_uid; 444 gid = ap->a_vap->va_gid; 445 if ((flags & LAYERFS_MBYPASSDEBUG)) 446 printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid, 447 gid); 448 449 vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap); 450 nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries; 451 mapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata); 452 gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries; 453 gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata); 454 455 /* Reverse map the uid for the vnode. Since it's a reverse 456 map, we can't use umap_mapids() to do it. */ 457 458 tmpid = umap_reverse_findid(uid, mapdata, nentries); 459 460 if (tmpid != -1) { 461 ap->a_vap->va_uid = (uid_t) tmpid; 462 if ((flags & LAYERFS_MBYPASSDEBUG)) 463 printf("umap_getattr: original uid = %d\n", uid); 464 } else 465 ap->a_vap->va_uid = (uid_t) NOBODY; 466 467 /* Reverse map the gid for the vnode. */ 468 469 tmpid = umap_reverse_findid(gid, gmapdata, gnentries); 470 471 if (tmpid != -1) { 472 ap->a_vap->va_gid = (gid_t) tmpid; 473 if ((flags & LAYERFS_MBYPASSDEBUG)) 474 printf("umap_getattr: original gid = %d\n", gid); 475 } else 476 ap->a_vap->va_gid = (gid_t) NULLGROUP; 477 478 return (0); 479 } 480 481 int 482 umap_print(v) 483 void *v; 484 { 485 struct vop_print_args /* { 486 struct vnode *a_vp; 487 } */ *ap = v; 488 struct vnode *vp = ap->a_vp; 489 printf("\ttag VT_UMAPFS, vp=%p, lowervp=%p\n", vp, 490 UMAPVPTOLOWERVP(vp)); 491 return (0); 492 } 493 494 int 495 umap_rename(v) 496 void *v; 497 { 498 struct vop_rename_args /* { 499 struct vnode *a_fdvp; 500 struct vnode *a_fvp; 501 struct componentname *a_fcnp; 502 struct vnode *a_tdvp; 503 struct vnode *a_tvp; 504 struct componentname *a_tcnp; 505 } */ *ap = v; 506 int error, flags; 507 struct componentname *compnamep; 508 struct ucred *compcredp, *savecompcredp; 509 struct vnode *vp; 510 511 /* 512 * Rename is irregular, having two componentname structures. 513 * We need to map the cre in the second structure, 514 * and then bypass takes care of the rest. 515 */ 516 517 vp = ap->a_fdvp; 518 flags = MOUNTTOUMAPMOUNT(vp->v_mount)->umapm_flags; 519 compnamep = ap->a_tcnp; 520 compcredp = compnamep->cn_cred; 521 522 savecompcredp = compcredp; 523 compcredp = compnamep->cn_cred = crdup(savecompcredp); 524 525 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) 526 printf("umap_rename: rename component credit user was %d, group %d\n", 527 compcredp->cr_uid, compcredp->cr_gid); 528 529 /* Map all ids in the credential structure. */ 530 531 umap_mapids(vp->v_mount, compcredp); 532 533 if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) 534 printf("umap_rename: rename component credit user now %d, group %d\n", 535 compcredp->cr_uid, compcredp->cr_gid); 536 537 error = umap_bypass(ap); 538 539 /* Restore the additional mapped componentname cred structure. */ 540 541 crfree(compcredp); 542 compnamep->cn_cred = savecompcredp; 543 544 return error; 545 } 546