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