1 /* $NetBSD: autofs_solaris_v1.c,v 1.1.1.2 2009/03/20 20:26:51 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1999-2003 Ion Badulescu 5 * Copyright (c) 1997-2009 Erez Zadok 6 * Copyright (c) 1990 Jan-Simon Pendry 7 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 8 * Copyright (c) 1990 The Regents of the University of California. 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to Berkeley by 12 * Jan-Simon Pendry at Imperial College, London. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgment: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * 43 * File: am-utils/conf/autofs/autofs_solaris_v1.c 44 * 45 */ 46 47 /* 48 * Automounter filesystem 49 */ 50 51 #ifdef HAVE_CONFIG_H 52 # include <config.h> 53 #endif /* HAVE_CONFIG_H */ 54 #include <am_defs.h> 55 #include <amd.h> 56 57 #ifdef HAVE_FS_AUTOFS 58 59 /* 60 * MACROS: 61 */ 62 #ifndef AUTOFS_NULL 63 # define AUTOFS_NULL NULLPROC 64 #endif /* not AUTOFS_NULL */ 65 66 /* 67 * STRUCTURES: 68 */ 69 70 /* 71 * VARIABLES: 72 */ 73 74 /* forward declarations */ 75 # ifndef HAVE_XDR_MNTREQUEST 76 bool_t xdr_mntrequest(XDR *xdrs, mntrequest *objp); 77 # endif /* not HAVE_XDR_MNTREQUEST */ 78 # ifndef HAVE_XDR_MNTRES 79 bool_t xdr_mntres(XDR *xdrs, mntres *objp); 80 # endif /* not HAVE_XDR_MNTRES */ 81 # ifndef HAVE_XDR_UMNTREQUEST 82 bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp); 83 # endif /* not HAVE_XDR_UMNTREQUEST */ 84 # ifndef HAVE_XDR_UMNTRES 85 bool_t xdr_umntres(XDR *xdrs, umntres *objp); 86 # endif /* not HAVE_XDR_UMNTRES */ 87 static int autofs_mount_1_req(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred, SVCXPRT *transp); 88 static int autofs_unmount_1_req(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred, SVCXPRT *transp); 89 90 /**************************************************************************** 91 *** VARIABLES *** 92 ****************************************************************************/ 93 94 /**************************************************************************** 95 *** FUNCTIONS *** 96 ****************************************************************************/ 97 98 /* 99 * AUTOFS XDR FUNCTIONS: 100 */ 101 102 #ifndef HAVE_XDR_MNTREQUEST 103 bool_t 104 xdr_mntrequest(XDR *xdrs, mntrequest *objp) 105 { 106 if (amuDebug(D_XDRTRACE)) 107 plog(XLOG_DEBUG, "xdr_mntrequest:"); 108 109 if (!xdr_string(xdrs, &objp->name, A_MAXNAME)) 110 return (FALSE); 111 112 if (!xdr_string(xdrs, &objp->map, A_MAXNAME)) 113 return (FALSE); 114 115 if (!xdr_string(xdrs, &objp->opts, A_MAXOPTS)) 116 return (FALSE); 117 118 if (!xdr_string(xdrs, &objp->path, A_MAXPATH)) 119 return (FALSE); 120 121 return (TRUE); 122 } 123 #endif /* not HAVE_XDR_MNTREQUEST */ 124 125 126 #ifndef HAVE_XDR_MNTRES 127 bool_t 128 xdr_mntres(XDR *xdrs, mntres *objp) 129 { 130 if (amuDebug(D_XDRTRACE)) 131 plog(XLOG_DEBUG, "xdr_mntres:"); 132 133 if (!xdr_int(xdrs, &objp->status)) 134 return (FALSE); 135 136 return (TRUE); 137 } 138 # endif /* not HAVE_XDR_MNTRES */ 139 140 141 #ifndef HAVE_XDR_UMNTREQUEST 142 bool_t 143 xdr_umntrequest(XDR *xdrs, umntrequest *objp) 144 { 145 if (amuDebug(D_XDRTRACE)) 146 plog(XLOG_DEBUG, "xdr_umntrequest:"); 147 148 if (!xdr_int(xdrs, (int *) &objp->isdirect)) 149 return (FALSE); 150 151 if (!xdr_u_int(xdrs, (u_int *) &objp->devid)) 152 return (FALSE); 153 154 #ifdef HAVE_UMNTREQUEST_RDEVID 155 if (!xdr_u_long(xdrs, &objp->rdevid)) 156 return (FALSE); 157 #endif /* HAVE_UMNTREQUEST_RDEVID */ 158 159 if (!xdr_pointer(xdrs, (char **) &objp->next, sizeof(umntrequest), (XDRPROC_T_TYPE) xdr_umntrequest)) 160 return (FALSE); 161 162 return (TRUE); 163 } 164 #endif /* not HAVE_XDR_UMNTREQUEST */ 165 166 167 #ifndef HAVE_XDR_UMNTRES 168 bool_t 169 xdr_umntres(XDR *xdrs, umntres *objp) 170 { 171 if (amuDebug(D_XDRTRACE)) 172 plog(XLOG_DEBUG, "xdr_mntres:"); 173 174 if (!xdr_int(xdrs, &objp->status)) 175 return (FALSE); 176 177 return (TRUE); 178 } 179 #endif /* not HAVE_XDR_UMNTRES */ 180 181 182 /* 183 * AUTOFS RPC methods 184 */ 185 186 static int 187 autofs_mount_1_req(struct mntrequest *m, 188 struct mntres *res, 189 struct authunix_parms *cred, 190 SVCXPRT *transp) 191 { 192 int err = 0; 193 int isdirect = 0; 194 am_node *mp, *ap; 195 mntfs *mf; 196 197 dlog("MOUNT REQUEST: name=%s map=%s opts=%s path=%s", 198 m->name, m->map, m->opts, m->path); 199 200 /* find the effective uid/gid from RPC request */ 201 xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid); 202 xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid); 203 204 mp = find_ap(m->path); 205 if (!mp) { 206 plog(XLOG_ERROR, "map %s not found", m->path); 207 err = ENOENT; 208 goto out; 209 } 210 211 mf = mp->am_mnt; 212 isdirect = (mf->mf_fsflags & FS_DIRECT) ? 1 : 0; 213 ap = mf->mf_ops->lookup_child(mp, m->name + isdirect, &err, VLOOK_CREATE); 214 if (ap && err < 0) 215 ap = mf->mf_ops->mount_child(ap, &err); 216 if (ap == NULL) { 217 if (err < 0) { 218 /* we're working on it */ 219 amd_stats.d_drops++; 220 return 1; 221 } 222 err = ENOENT; 223 goto out; 224 } 225 226 out: 227 if (err) { 228 if (isdirect) { 229 /* direct mount */ 230 plog(XLOG_ERROR, "mount of %s failed", m->path); 231 } else { 232 /* indirect mount */ 233 plog(XLOG_ERROR, "mount of %s/%s failed", m->path, m->name); 234 } 235 } 236 237 dlog("MOUNT REPLY: status=%d (%s)", err, strerror(err)); 238 239 res->status = err; 240 return 0; 241 } 242 243 244 static int 245 autofs_unmount_1_req(struct umntrequest *ul, 246 struct umntres *res, 247 struct authunix_parms *cred, 248 SVCXPRT *transp) 249 { 250 int mapno, err; 251 am_node *mp = NULL; 252 253 dlog("UNMOUNT REQUEST: dev=%lx rdev=%lx %s", 254 (u_long) ul->devid, 255 (u_long) ul->rdevid, 256 ul->isdirect ? "direct" : "indirect"); 257 258 /* by default, and if not found, succeed */ 259 res->status = 0; 260 261 for (mapno = 0; ; mapno++) { 262 mp = get_exported_ap(mapno); 263 if (!mp) 264 break; 265 if (mp->am_dev == ul->devid && 266 (ul->rdevid == 0 || mp->am_rdev == ul->rdevid)) 267 break; 268 } 269 270 if (mp) { 271 /* save RPC context */ 272 if (!mp->am_transp && transp) { 273 mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); 274 *(mp->am_transp) = *transp; 275 } 276 277 mapno = mp->am_mapno; 278 err = unmount_mp(mp); 279 280 if (err) 281 /* backgrounded, don't reply yet */ 282 return 1; 283 284 if (get_exported_ap(mapno)) 285 /* unmounting failed, tell the kernel */ 286 res->status = 1; 287 } 288 289 dlog("UNMOUNT REPLY: status=%d", res->status); 290 return 0; 291 } 292 293 294 /****************************************************************************/ 295 /* autofs program dispatcher */ 296 static void 297 autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp) 298 { 299 union { 300 mntrequest autofs_mount_1_arg; 301 umntrequest autofs_umount_1_arg; 302 } argument; 303 union { 304 mntres mount_res; 305 umntres umount_res; 306 } result; 307 int ret; 308 309 bool_t (*xdr_argument)(); 310 bool_t (*xdr_result)(); 311 int (*local)(); 312 313 current_transp = transp; 314 315 switch (rqstp->rq_proc) { 316 317 case AUTOFS_NULL: 318 svc_sendreply(transp, 319 (XDRPROC_T_TYPE) xdr_void, 320 (SVC_IN_ARG_TYPE) NULL); 321 return; 322 323 case AUTOFS_MOUNT: 324 xdr_argument = xdr_mntrequest; 325 xdr_result = xdr_mntres; 326 local = autofs_mount_1_req; 327 break; 328 329 case AUTOFS_UNMOUNT: 330 xdr_argument = xdr_umntrequest; 331 xdr_result = xdr_umntres; 332 local = autofs_unmount_1_req; 333 break; 334 335 default: 336 svcerr_noproc(transp); 337 return; 338 } 339 340 memset((char *) &argument, 0, sizeof(argument)); 341 if (!svc_getargs(transp, 342 (XDRPROC_T_TYPE) xdr_argument, 343 (SVC_IN_ARG_TYPE) &argument)) { 344 plog(XLOG_ERROR, 345 "AUTOFS xdr decode failed for %d %d %d", 346 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc); 347 svcerr_decode(transp); 348 return; 349 } 350 351 memset((char *)&result, 0, sizeof(result)); 352 ret = (*local) (&argument, &result, rqstp, transp); 353 354 current_transp = NULL; 355 356 /* send reply only if the RPC method returned 0 */ 357 if (!ret) { 358 if (!svc_sendreply(transp, 359 (XDRPROC_T_TYPE) xdr_result, 360 (SVC_IN_ARG_TYPE) &result)) { 361 svcerr_systemerr(transp); 362 } 363 } 364 365 if (!svc_freeargs(transp, 366 (XDRPROC_T_TYPE) xdr_argument, 367 (SVC_IN_ARG_TYPE) &argument)) { 368 plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_1"); 369 } 370 } 371 372 373 int 374 autofs_get_fh(am_node *mp) 375 { 376 autofs_fh_t *fh; 377 char buf[MAXHOSTNAMELEN]; 378 mntfs *mf = mp->am_mnt; 379 struct utsname utsname; 380 381 plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path); 382 fh = ALLOC(autofs_fh_t); 383 memset((voidp) fh, 0, sizeof(autofs_fh_t)); /* Paranoid */ 384 385 /* 386 * SET MOUNT ARGS 387 */ 388 if (uname(&utsname) < 0) { 389 xstrlcpy(buf, "localhost.autofs", sizeof(buf)); 390 } else { 391 xstrlcpy(buf, utsname.nodename, sizeof(buf)); 392 xstrlcat(buf, ".autofs", sizeof(buf)); 393 } 394 #ifdef HAVE_AUTOFS_ARGS_T_ADDR 395 fh->addr.buf = strdup(buf); 396 fh->addr.len = fh->addr.maxlen = strlen(buf); 397 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */ 398 399 fh->direct = (mf->mf_fsflags & FS_DIRECT) ? 1 : 0; 400 fh->rpc_to = 1; /* XXX: arbitrary */ 401 fh->mount_to = mp->am_timeo; 402 fh->path = mp->am_path; 403 fh->opts = ""; /* XXX: arbitrary */ 404 fh->map = mp->am_path; /* this is what we get back in readdir */ 405 406 mp->am_autofs_fh = fh; 407 return 0; 408 } 409 410 411 void 412 autofs_mounted(am_node *mp) 413 { 414 /* We don't want any timeouts on autofs nodes */ 415 mp->am_autofs_ttl = NEVER; 416 } 417 418 419 void 420 autofs_release_fh(am_node *mp) 421 { 422 autofs_fh_t *fh = mp->am_autofs_fh; 423 #ifdef HAVE_AUTOFS_ARGS_T_ADDR 424 XFREE(fh->addr.buf); 425 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */ 426 XFREE(fh); 427 mp->am_autofs_fh = NULL; 428 } 429 430 431 void 432 autofs_get_mp(am_node *mp) 433 { 434 /* nothing to do */ 435 } 436 437 438 void 439 autofs_release_mp(am_node *mp) 440 { 441 /* nothing to do */ 442 } 443 444 445 void 446 autofs_add_fdset(fd_set *readfds) 447 { 448 /* nothing to do */ 449 } 450 451 452 int 453 autofs_handle_fdset(fd_set *readfds, int nsel) 454 { 455 /* nothing to do */ 456 return nsel; 457 } 458 459 460 /* 461 * Create the autofs service for amd 462 */ 463 int 464 create_autofs_service(void) 465 { 466 dlog("creating autofs service listener"); 467 return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_1); 468 } 469 470 471 int 472 destroy_autofs_service(void) 473 { 474 dlog("destroying autofs service listener"); 475 return unregister_autofs_service(AUTOFS_CONFTYPE); 476 } 477 478 479 int 480 autofs_mount_fs(am_node *mp, mntfs *mf) 481 { 482 int err = 0; 483 char *target, *target2 = NULL; 484 char *space_hack = autofs_strdup_space_hack(mp->am_path); 485 struct stat buf; 486 487 if (mf->mf_flags & MFF_ON_AUTOFS) { 488 if ((err = mkdir(space_hack, 0555))) 489 goto out; 490 } 491 492 /* 493 * For sublinks, we could end up here with an already mounted f/s. 494 * Don't do anything in that case. 495 */ 496 if (!(mf->mf_flags & MFF_MOUNTED)) 497 err = mf->mf_ops->mount_fs(mp, mf); 498 499 if (err) { 500 if (mf->mf_flags & MFF_ON_AUTOFS) 501 rmdir(space_hack); 502 errno = err; 503 goto out; 504 } 505 506 /* 507 * Autofs v1 doesn't support symlinks, 508 * so we ignore the CFM_AUTOFS_USE_LOFS flag 509 */ 510 if (mf->mf_flags & MFF_ON_AUTOFS) 511 /* Nothing to do */ 512 goto out; 513 514 if (mp->am_link) 515 target = mp->am_link; 516 else 517 target = mf->mf_mount; 518 519 if (target[0] != '/') 520 target2 = str3cat(NULL, mp->am_parent->am_path, "/", target); 521 else 522 target2 = strdup(target); 523 524 plog(XLOG_INFO, "autofs: converting from link to lofs (%s -> %s)", mp->am_path, target2); 525 /* 526 * we need to stat() the destination, because the bind mount does not 527 * follow symlinks and/or allow for non-existent destinations. 528 * 529 * WARNING: we will deadlock if this function is called from the master 530 * amd process and it happens to trigger another auto mount. Therefore, 531 * this function should be called only from a child amd process, or 532 * at the very least it should not be called from the parent unless we 533 * know for sure that it won't cause a recursive mount. We refuse to 534 * cause the recursive mount anyway if called from the parent amd. 535 */ 536 if (!foreground) { 537 if ((err = stat(target2, &buf))) 538 goto out; 539 } 540 if ((err = lstat(target2, &buf))) 541 goto out; 542 543 if ((err = mkdir(space_hack, 0555))) 544 goto out; 545 546 if ((err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1))) { 547 errno = err; 548 goto out; 549 } 550 551 out: 552 XFREE(space_hack); 553 if (target2) 554 XFREE(target2); 555 556 if (err) 557 return errno; 558 return 0; 559 } 560 561 562 int 563 autofs_umount_fs(am_node *mp, mntfs *mf) 564 { 565 int err = 0; 566 char *space_hack = autofs_strdup_space_hack(mp->am_path); 567 568 /* 569 * Autofs v1 doesn't support symlinks, 570 * so we ignore the CFM_AUTOFS_USE_LOFS flag 571 */ 572 if (!(mf->mf_flags & MFF_ON_AUTOFS)) { 573 err = UMOUNT_FS(mp->am_path, mnttab_file_name, 1); 574 if (err) 575 goto out; 576 rmdir(space_hack); 577 } 578 579 /* 580 * Multiple sublinks could reference this f/s. 581 * Don't actually unmount it unless we're holding the last reference. 582 */ 583 if (mf->mf_refc == 1) { 584 if ((err = mf->mf_ops->umount_fs(mp, mf))) 585 goto out; 586 587 if (mf->mf_flags & MFF_ON_AUTOFS) 588 rmdir(space_hack); 589 } 590 591 out: 592 XFREE(space_hack); 593 return err; 594 } 595 596 597 int 598 autofs_umount_succeeded(am_node *mp) 599 { 600 umntres res; 601 SVCXPRT *transp = mp->am_transp; 602 603 if (transp) { 604 res.status = 0; 605 606 if (!svc_sendreply(transp, 607 (XDRPROC_T_TYPE) xdr_umntres, 608 (SVC_IN_ARG_TYPE) &res)) 609 svcerr_systemerr(transp); 610 611 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 612 XFREE(transp); 613 mp->am_transp = NULL; 614 } 615 616 plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path); 617 return 0; 618 } 619 620 621 int 622 autofs_umount_failed(am_node *mp) 623 { 624 umntres res; 625 SVCXPRT *transp = mp->am_transp; 626 627 if (transp) { 628 res.status = 1; 629 630 if (!svc_sendreply(transp, 631 (XDRPROC_T_TYPE) xdr_umntres, 632 (SVC_IN_ARG_TYPE) &res)) 633 svcerr_systemerr(transp); 634 635 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 636 XFREE(transp); 637 mp->am_transp = NULL; 638 } 639 640 plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path); 641 return 0; 642 } 643 644 645 void 646 autofs_mount_succeeded(am_node *mp) 647 { 648 SVCXPRT *transp = mp->am_transp; 649 struct stat stb; 650 char *space_hack; 651 652 if (transp) { 653 /* this was a mount request */ 654 mntres res; 655 res.status = 0; 656 657 if (!svc_sendreply(transp, 658 (XDRPROC_T_TYPE) xdr_mntres, 659 (SVC_IN_ARG_TYPE) &res)) 660 svcerr_systemerr(transp); 661 662 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 663 XFREE(transp); 664 mp->am_transp = NULL; 665 } 666 667 space_hack = autofs_strdup_space_hack(mp->am_path); 668 if (!lstat(space_hack, &stb)) { 669 mp->am_dev = stb.st_dev; 670 mp->am_rdev = stb.st_rdev; 671 } 672 XFREE(space_hack); 673 /* don't expire the entries -- the kernel will do it for us */ 674 mp->am_flags |= AMF_NOTIMEOUT; 675 676 plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path); 677 } 678 679 680 void 681 autofs_mount_failed(am_node *mp) 682 { 683 SVCXPRT *transp = mp->am_transp; 684 685 if (transp) { 686 /* this was a mount request */ 687 mntres res; 688 res.status = ENOENT; 689 690 if (!svc_sendreply(transp, 691 (XDRPROC_T_TYPE) xdr_mntres, 692 (SVC_IN_ARG_TYPE) &res)) 693 svcerr_systemerr(transp); 694 695 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 696 XFREE(transp); 697 mp->am_transp = NULL; 698 } 699 700 plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path); 701 } 702 703 704 void 705 autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh) 706 { 707 xsnprintf(opts, l, "%sdirect", 708 fh->direct ? "" : "in"); 709 } 710 711 712 int 713 autofs_compute_mount_flags(mntent_t *mntp) 714 { 715 /* Must use overlay mounts */ 716 return MNT2_GEN_OPT_OVERLAY; 717 } 718 719 720 void autofs_timeout_mp(am_node *mp) 721 { 722 /* We don't want any timeouts on autofs nodes */ 723 mp->am_autofs_ttl = NEVER; 724 } 725 #endif /* HAVE_FS_AUTOFS */ 726