autofs_solaris_v2_v3.c revision 1.1.1.2
1/* $NetBSD: autofs_solaris_v2_v3.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_v2_v3.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/* 58 * MACROS: 59 */ 60#ifndef AUTOFS_NULL 61# define AUTOFS_NULL NULLPROC 62#endif /* not AUTOFS_NULL */ 63 64/* 65 * STRUCTURES: 66 */ 67 68struct amd_rddirres { 69 enum autofs_res rd_status; 70 u_long rd_bufsize; 71 nfsdirlist rd_dl; 72}; 73typedef struct amd_rddirres amd_rddirres; 74 75/* 76 * VARIABLES: 77 */ 78 79SVCXPRT *autofs_xprt = NULL; 80 81/* forward declarations */ 82bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp); 83bool_t xdr_umntres(XDR *xdrs, umntres *objp); 84bool_t xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp); 85bool_t xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp); 86bool_t xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp); 87bool_t xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp); 88static bool_t xdr_amd_rddirres(XDR *xdrs, amd_rddirres *objp); 89 90/* 91 * These exist only in the AutoFS V2 protocol. 92 */ 93#ifdef AUTOFS_POSTUNMOUNT 94bool_t xdr_postumntreq(XDR *xdrs, postumntreq *objp); 95bool_t xdr_postumntres(XDR *xdrs, postumntres *objp); 96bool_t xdr_postmountreq(XDR *xdrs, postmountreq *objp); 97bool_t xdr_postmountres(XDR *xdrs, postmountres *objp); 98#endif /* AUTOFS_POSTUMOUNT */ 99 100/* 101 * AUTOFS XDR FUNCTIONS: 102 */ 103 104bool_t 105xdr_autofs_stat(XDR *xdrs, autofs_stat *objp) 106{ 107 if (!xdr_enum(xdrs, (enum_t *)objp)) 108 return (FALSE); 109 return (TRUE); 110} 111 112 113bool_t 114xdr_autofs_action(XDR *xdrs, autofs_action *objp) 115{ 116 if (!xdr_enum(xdrs, (enum_t *)objp)) 117 return (FALSE); 118 return (TRUE); 119} 120 121 122bool_t 123xdr_linka(XDR *xdrs, linka *objp) 124{ 125 if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN)) 126 return (FALSE); 127 if (!xdr_string(xdrs, &objp->link, AUTOFS_MAXPATHLEN)) 128 return (FALSE); 129 return (TRUE); 130} 131 132 133bool_t 134xdr_autofs_netbuf(XDR *xdrs, struct netbuf *objp) 135{ 136 bool_t dummy; 137 138 if (!xdr_u_long(xdrs, (u_long *) &objp->maxlen)) 139 return (FALSE); 140 dummy = xdr_bytes(xdrs, (char **)&(objp->buf), 141 (u_int *)&(objp->len), objp->maxlen); 142 return (dummy); 143} 144 145 146bool_t 147xdr_autofs_args(XDR *xdrs, autofs_args *objp) 148{ 149 if (!xdr_autofs_netbuf(xdrs, &objp->addr)) 150 return (FALSE); 151 if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN)) 152 return (FALSE); 153 if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN)) 154 return (FALSE); 155 if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN)) 156 return (FALSE); 157 if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN)) 158 return (FALSE); 159 if (!xdr_string(xdrs, &objp->key, AUTOFS_MAXCOMPONENTLEN)) 160 return (FALSE); 161 if (!xdr_int(xdrs, &objp->mount_to)) 162 return (FALSE); 163 if (!xdr_int(xdrs, &objp->rpc_to)) 164 return (FALSE); 165 if (!xdr_int(xdrs, &objp->direct)) 166 return (FALSE); 167 return (TRUE); 168} 169 170 171bool_t 172xdr_mounta(XDR *xdrs, struct mounta *objp) 173{ 174 if (!xdr_string(xdrs, &objp->spec, AUTOFS_MAXPATHLEN)) 175 return (FALSE); 176 if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN)) 177 return (FALSE); 178 if (!xdr_int(xdrs, &objp->flags)) 179 return (FALSE); 180 if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN)) 181 return (FALSE); 182 if (!xdr_pointer(xdrs, (char **)&objp->dataptr, sizeof(autofs_args), 183 (XDRPROC_T_TYPE) xdr_autofs_args)) 184 return (FALSE); 185 if (!xdr_int(xdrs, &objp->datalen)) 186 return (FALSE); 187 return (TRUE); 188} 189 190 191bool_t 192xdr_action_list_entry(XDR *xdrs, action_list_entry *objp) 193{ 194 if (!xdr_autofs_action(xdrs, &objp->action)) 195 return (FALSE); 196 switch (objp->action) { 197 case AUTOFS_MOUNT_RQ: 198 if (!xdr_mounta(xdrs, &objp->action_list_entry_u.mounta)) 199 return (FALSE); 200 break; 201 case AUTOFS_LINK_RQ: 202 if (!xdr_linka(xdrs, &objp->action_list_entry_u.linka)) 203 return (FALSE); 204 break; 205 default: 206 break; 207 } 208 return (TRUE); 209} 210 211 212bool_t 213xdr_action_list(XDR *xdrs, action_list *objp) 214{ 215 if (!xdr_action_list_entry(xdrs, &objp->action)) 216 return (FALSE); 217 if (!xdr_pointer(xdrs, (char **)&objp->next, sizeof(action_list), 218 (XDRPROC_T_TYPE) xdr_action_list)) 219 return (FALSE); 220 return (TRUE); 221} 222 223 224bool_t 225xdr_umntrequest(XDR *xdrs, umntrequest *objp) 226{ 227 if (amuDebug(D_XDRTRACE)) 228 plog(XLOG_DEBUG, "xdr_umntrequest:"); 229 230 if (!xdr_bool_t(xdrs, &objp->isdirect)) 231 return (FALSE); 232#ifdef HAVE_STRUCT_UMNTREQUEST_DEVID 233 if (!xdr_dev_t(xdrs, &objp->devid)) 234 return (FALSE); 235 if (!xdr_dev_t(xdrs, &objp->rdevid)) 236 return (FALSE); 237#else /* not HAVE_STRUCT_UMNTREQUEST_DEVID */ 238 if (!xdr_string(xdrs, &objp->mntresource, AUTOFS_MAXPATHLEN)) 239 return (FALSE); 240 if (!xdr_string(xdrs, &objp->mntpnt, AUTOFS_MAXPATHLEN)) 241 return (FALSE); 242 if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN)) 243 return (FALSE); 244 if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN)) 245 return (FALSE); 246#endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */ 247 if (!xdr_pointer(xdrs, (char **) &objp->next, sizeof(umntrequest), 248 (XDRPROC_T_TYPE) xdr_umntrequest)) 249 return (FALSE); 250 251 return (TRUE); 252} 253 254 255bool_t 256xdr_umntres(XDR *xdrs, umntres *objp) 257{ 258 if (amuDebug(D_XDRTRACE)) 259 plog(XLOG_DEBUG, "xdr_mntres:"); 260 261 if (!xdr_int(xdrs, &objp->status)) 262 return (FALSE); 263 return (TRUE); 264} 265 266 267/* 268 * These exist only in the AutoFS V2 protocol. 269 */ 270#ifdef AUTOFS_POSTUNMOUNT 271bool_t 272xdr_postumntreq(XDR *xdrs, postumntreq *objp) 273{ 274 if (!xdr_dev_t(xdrs, &objp->devid)) 275 return (FALSE); 276 if (!xdr_dev_t(xdrs, &objp->rdevid)) 277 return (FALSE); 278 if (!xdr_pointer(xdrs, (char **)&objp->next, 279 sizeof(struct postumntreq), 280 (XDRPROC_T_TYPE) xdr_postumntreq)) 281 return (FALSE); 282 return (TRUE); 283} 284 285 286bool_t 287xdr_postumntres(XDR *xdrs, postumntres *objp) 288{ 289 if (!xdr_int(xdrs, &objp->status)) 290 return (FALSE); 291 return (TRUE); 292} 293 294 295bool_t 296xdr_postmountreq(XDR *xdrs, postmountreq *objp) 297{ 298 if (!xdr_string(xdrs, &objp->special, AUTOFS_MAXPATHLEN)) 299 return (FALSE); 300 if (!xdr_string(xdrs, &objp->mountp, AUTOFS_MAXPATHLEN)) 301 return (FALSE); 302 if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN)) 303 return (FALSE); 304 if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN)) 305 return (FALSE); 306 if (!xdr_dev_t(xdrs, &objp->devid)) 307 return (FALSE); 308 return (TRUE); 309} 310 311 312bool_t 313xdr_postmountres(XDR *xdrs, postmountres *objp) 314{ 315 if (!xdr_int(xdrs, &objp->status)) 316 return (FALSE); 317 return (TRUE); 318} 319#endif /* AUTOFS_POSTUNMOUNT */ 320 321 322bool_t 323xdr_autofs_res(XDR *xdrs, autofs_res *objp) 324{ 325 if (!xdr_enum(xdrs, (enum_t *)objp)) 326 return (FALSE); 327 return (TRUE); 328} 329 330 331bool_t 332xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp) 333{ 334 if (amuDebug(D_XDRTRACE)) 335 plog(XLOG_DEBUG, "xdr_autofs_lookupargs:"); 336 337 if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN)) 338 return (FALSE); 339 if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN)) 340 return (FALSE); 341 if (!xdr_string(xdrs, &objp->name, AUTOFS_MAXCOMPONENTLEN)) 342 return (FALSE); 343 if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN)) 344 return (FALSE); 345 if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN)) 346 return (FALSE); 347 if (!xdr_bool_t(xdrs, &objp->isdirect)) 348 return (FALSE); 349 return (TRUE); 350} 351 352 353bool_t 354xdr_mount_result_type(XDR *xdrs, mount_result_type *objp) 355{ 356 if (!xdr_autofs_stat(xdrs, &objp->status)) 357 return (FALSE); 358 switch (objp->status) { 359 case AUTOFS_ACTION: 360 if (!xdr_pointer(xdrs, 361 (char **)&objp->mount_result_type_u.list, 362 sizeof(action_list), (XDRPROC_T_TYPE) xdr_action_list)) 363 return (FALSE); 364 break; 365 case AUTOFS_DONE: 366 if (!xdr_int(xdrs, &objp->mount_result_type_u.error)) 367 return (FALSE); 368 break; 369 } 370 return (TRUE); 371} 372 373 374bool_t 375xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp) 376{ 377 if (amuDebug(D_XDRTRACE)) 378 plog(XLOG_DEBUG, "xdr_mntres:"); 379 380 if (!xdr_mount_result_type(xdrs, &objp->mr_type)) 381 return (FALSE); 382 if (!xdr_int(xdrs, &objp->mr_verbose)) 383 return (FALSE); 384 385 return (TRUE); 386} 387 388 389bool_t 390xdr_lookup_result_type(XDR *xdrs, lookup_result_type *objp) 391{ 392 if (!xdr_autofs_action(xdrs, &objp->action)) 393 return (FALSE); 394 switch (objp->action) { 395 case AUTOFS_LINK_RQ: 396 if (!xdr_linka(xdrs, &objp->lookup_result_type_u.lt_linka)) 397 return (FALSE); 398 break; 399 default: 400 break; 401 } 402 return (TRUE); 403} 404 405 406bool_t 407xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp) 408{ 409 if (!xdr_autofs_res(xdrs, &objp->lu_res)) 410 return (FALSE); 411 if (!xdr_lookup_result_type(xdrs, &objp->lu_type)) 412 return (FALSE); 413 if (!xdr_int(xdrs, &objp->lu_verbose)) 414 return (FALSE); 415 return (TRUE); 416} 417 418 419bool_t 420xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp) 421{ 422 if (!xdr_string(xdrs, &objp->rda_map, AUTOFS_MAXPATHLEN)) 423 return (FALSE); 424 if (!xdr_u_int(xdrs, (u_int *) &objp->rda_offset)) 425 return (FALSE); 426 if (!xdr_u_int(xdrs, (u_int *) &objp->rda_count)) 427 return (FALSE); 428 return (TRUE); 429} 430 431 432/* 433 * ENCODE ONLY 434 * 435 * Solaris automountd uses struct autofsrddir to pass the results. 436 * We use the traditional nfsreaddirres and do the conversion ourselves. 437 */ 438static bool_t 439xdr_amd_putrddirres(XDR *xdrs, nfsdirlist *dp, ulong reqsize) 440{ 441 nfsentry *ep; 442 char *name; 443 u_int namlen; 444 bool_t true = TRUE; 445 bool_t false = FALSE; 446 int entrysz; 447 int tofit; 448 int bufsize; 449 u_long ino, off; 450 451 bufsize = 1 * BYTES_PER_XDR_UNIT; 452 for (ep = dp->dl_entries; ep; ep = ep->ne_nextentry) { 453 name = ep->ne_name; 454 namlen = strlen(name); 455 ino = (u_long) ep->ne_fileid; 456 off = (u_long) ep->ne_cookie + AUTOFS_DAEMONCOOKIE; 457 entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT + 458 roundup(namlen, BYTES_PER_XDR_UNIT); 459 tofit = entrysz + 2 * BYTES_PER_XDR_UNIT; 460 if (bufsize + tofit > reqsize) { 461 dp->dl_eof = FALSE; 462 break; 463 } 464 if (!xdr_bool(xdrs, &true) || 465 !xdr_u_long(xdrs, &ino) || 466 !xdr_bytes(xdrs, &name, &namlen, AUTOFS_MAXPATHLEN) || 467 !xdr_u_long(xdrs, &off)) { 468 return (FALSE); 469 } 470 bufsize += entrysz; 471 } 472 if (!xdr_bool(xdrs, &false)) { 473 return (FALSE); 474 } 475 if (!xdr_bool(xdrs, &dp->dl_eof)) { 476 return (FALSE); 477 } 478 return (TRUE); 479} 480 481 482static bool_t 483xdr_amd_rddirres(XDR *xdrs, amd_rddirres *objp) 484{ 485 if (!xdr_enum(xdrs, (enum_t *)&objp->rd_status)) 486 return (FALSE); 487 if (objp->rd_status != AUTOFS_OK) 488 return (TRUE); 489 return (xdr_amd_putrddirres(xdrs, &objp->rd_dl, objp->rd_bufsize)); 490} 491 492 493/* 494 * AUTOFS RPC methods 495 */ 496 497static int 498autofs_lookup_2_req(autofs_lookupargs *m, 499 autofs_lookupres *res, 500 struct authunix_parms *cred, 501 SVCXPRT *transp) 502{ 503 int err; 504 am_node *mp, *new_mp; 505 mntfs *mf; 506 507 dlog("LOOKUP REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d", 508 m->name, m->subdir, m->map, m->opts, 509 m->path, m->isdirect); 510 511 /* find the effective uid/gid from RPC request */ 512 xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid); 513 xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid); 514 515 mp = find_ap(m->path); 516 if (!mp) { 517 plog(XLOG_ERROR, "map %s not found", m->path); 518 err = AUTOFS_NOENT; 519 goto out; 520 } 521 522 mf = mp->am_mnt; 523 new_mp = mf->mf_ops->lookup_child(mp, m->name, &err, VLOOK_LOOKUP); 524 if (!new_mp) { 525 err = AUTOFS_NOENT; 526 goto out; 527 } 528 529 if (err == 0) { 530 plog(XLOG_ERROR, "autofs requests to mount an already mounted node???"); 531 } else { 532 free_map(new_mp); 533 } 534 err = AUTOFS_OK; 535 res->lu_type.action = AUTOFS_NONE; 536 537 out: 538 res->lu_res = err; 539 res->lu_verbose = 1; 540 541 dlog("LOOKUP REPLY: status=%d", res->lu_res); 542 return 0; 543} 544 545 546static void 547autofs_lookup_2_free(autofs_lookupres *res) 548{ 549 struct linka link; 550 551 if ((res->lu_res == AUTOFS_OK) && 552 (res->lu_type.action == AUTOFS_LINK_RQ)) { 553 /* 554 * Free link information 555 */ 556 link = res->lu_type.lookup_result_type_u.lt_linka; 557 if (link.dir) 558 XFREE(link.dir); 559 if (link.link) 560 XFREE(link.link); 561 } 562} 563 564 565static int 566autofs_mount_2_req(autofs_lookupargs *m, 567 autofs_mountres *res, 568 struct authunix_parms *cred, 569 SVCXPRT *transp) 570{ 571 int err = AUTOFS_OK; 572 am_node *mp, *new_mp; 573 mntfs *mf; 574 575 dlog("MOUNT REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d", 576 m->name, m->subdir, m->map, m->opts, 577 m->path, m->isdirect); 578 579 /* find the effective uid/gid from RPC request */ 580 xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid); 581 xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid); 582 583 mp = find_ap(m->path); 584 if (!mp) { 585 plog(XLOG_ERROR, "map %s not found", m->path); 586 res->mr_type.status = AUTOFS_DONE; 587 res->mr_type.mount_result_type_u.error = AUTOFS_NOENT; 588 goto out; 589 } 590 591 mf = mp->am_mnt; 592 new_mp = mf->mf_ops->lookup_child(mp, m->name + m->isdirect, &err, VLOOK_CREATE); 593 if (new_mp && err < 0) { 594 /* new_mp->am_transp = transp; */ 595 new_mp = mf->mf_ops->mount_child(new_mp, &err); 596 } 597 if (new_mp == NULL) { 598 if (err < 0) { 599 /* we're working on it */ 600 amd_stats.d_drops++; 601 return 1; 602 } 603 res->mr_type.status = AUTOFS_DONE; 604 res->mr_type.mount_result_type_u.error = AUTOFS_NOENT; 605 goto out; 606 } 607 608 if (gopt.flags & CFM_AUTOFS_USE_LOFS || 609 new_mp->am_mnt->mf_flags & MFF_ON_AUTOFS) { 610 res->mr_type.status = AUTOFS_DONE; 611 res->mr_type.mount_result_type_u.error = AUTOFS_OK; 612 } else { 613 struct action_list *list = malloc(sizeof(struct action_list)); 614 char *target; 615 if (new_mp->am_link) 616 target = new_mp->am_link; 617 else 618 target = new_mp->am_mnt->mf_mount; 619 list->action.action = AUTOFS_LINK_RQ; 620 list->action.action_list_entry_u.linka.dir = strdup(new_mp->am_name); 621 list->action.action_list_entry_u.linka.link = strdup(target); 622 list->next = NULL; 623 res->mr_type.status = AUTOFS_ACTION; 624 res->mr_type.mount_result_type_u.list = list; 625 } 626 627out: 628 res->mr_verbose = 1; 629 630 switch (res->mr_type.status) { 631 case AUTOFS_ACTION: 632 dlog("MOUNT REPLY: status=%d, AUTOFS_ACTION", err); 633 break; 634 case AUTOFS_DONE: 635 dlog("MOUNT REPLY: status=%d, AUTOFS_DONE", err); 636 break; 637 default: 638 dlog("MOUNT REPLY: status=%d, UNKNOWN(%d)", err, res->mr_type.status); 639 } 640 641 if (err) { 642 if (m->isdirect) { 643 /* direct mount */ 644 plog(XLOG_ERROR, "mount of %s failed", m->path); 645 } else { 646 /* indirect mount */ 647 plog(XLOG_ERROR, "mount of %s/%s failed", m->path, m->name); 648 } 649 } 650 return 0; 651} 652 653 654static void 655autofs_mount_2_free(struct autofs_mountres *res) 656{ 657 if (res->mr_type.status == AUTOFS_ACTION && 658 res->mr_type.mount_result_type_u.list != NULL) { 659 autofs_action action; 660 dlog("freeing action list"); 661 action = res->mr_type.mount_result_type_u.list->action.action; 662 if (action == AUTOFS_LINK_RQ) { 663 /* 664 * Free link information 665 */ 666 struct linka *link; 667 link = &(res->mr_type.mount_result_type_u.list->action.action_list_entry_u.linka); 668 if (link->dir) 669 XFREE(link->dir); 670 if (link->link) 671 XFREE(link->link); 672 } else if (action == AUTOFS_MOUNT_RQ) { 673 struct mounta *mnt; 674 mnt = &(res->mr_type.mount_result_type_u.list->action.action_list_entry_u.mounta); 675 if (mnt->spec) 676 XFREE(mnt->spec); 677 if (mnt->dir) 678 XFREE(mnt->dir); 679 if (mnt->fstype) 680 XFREE(mnt->fstype); 681 if (mnt->dataptr) 682 XFREE(mnt->dataptr); 683#ifdef HAVE_MOUNTA_OPTPTR 684 if (mnt->optptr) 685 XFREE(mnt->optptr); 686#endif /* HAVE_MOUNTA_OPTPTR */ 687 } 688 XFREE(res->mr_type.mount_result_type_u.list); 689 } 690} 691 692 693static int 694autofs_unmount_2_req(umntrequest *ul, 695 umntres *res, 696 struct authunix_parms *cred, 697 SVCXPRT *transp) 698{ 699 int mapno, err; 700 am_node *mp = NULL; 701 702#ifdef HAVE_STRUCT_UMNTREQUEST_DEVID 703 dlog("UNMOUNT REQUEST: dev=%lx rdev=%lx %s", 704 (u_long) ul->devid, 705 (u_long) ul->rdevid, 706 ul->isdirect ? "direct" : "indirect"); 707#else /* not HAVE_STRUCT_UMNTREQUEST_DEVID */ 708 dlog("UNMOUNT REQUEST: mntresource='%s' mntpnt='%s' fstype='%s' mntopts='%s' %s", 709 ul->mntresource, 710 ul->mntpnt, 711 ul->fstype, 712 ul->mntopts, 713 ul->isdirect ? "direct" : "indirect"); 714#endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */ 715 716 /* by default, and if not found, succeed */ 717 res->status = 0; 718 719#ifdef HAVE_STRUCT_UMNTREQUEST_DEVID 720 for (mp = get_first_exported_ap(&mapno); 721 mp; 722 mp = get_next_exported_ap(&mapno)) { 723 if (mp->am_dev == ul->devid && 724 mp->am_rdev == ul->rdevid) 725 break; 726 } 727#else /* not HAVE_STRUCT_UMNTREQUEST_DEVID */ 728 mp = find_ap(ul->mntpnt); 729#endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */ 730 731 if (mp) { 732 /* save RPC context */ 733 if (!mp->am_transp && transp) { 734 mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); 735 *(mp->am_transp) = *transp; 736 } 737 738 mapno = mp->am_mapno; 739 err = unmount_mp(mp); 740 741 if (err) 742 /* backgrounded, don't reply yet */ 743 return 1; 744 745 if (get_exported_ap(mapno)) 746 /* unmounting failed, tell the kernel */ 747 res->status = 1; 748 } 749 750 dlog("UNMOUNT REPLY: status=%d", res->status); 751 return 0; 752} 753 754 755/* 756 * These exist only in the AutoFS V2 protocol. 757 */ 758#ifdef AUTOFS_POSTUNMOUNT 759/* XXX not implemented */ 760static int 761autofs_postunmount_2_req(postumntreq *req, 762 postumntres *res, 763 struct authunix_parms *cred, 764 SVCXPRT *transp) 765{ 766 postumntreq *ul = req; 767 768 dlog("POSTUNMOUNT REQUEST: dev=%lx rdev=%lx", 769 (u_long) ul->devid, 770 (u_long) ul->rdevid); 771 772 /* succeed unconditionally */ 773 res->status = 0; 774 775 dlog("POSTUNMOUNT REPLY: status=%d", res->status); 776 return 0; 777} 778 779 780/* XXX not implemented */ 781static int 782autofs_postmount_2_req(postmountreq *req, 783 postmountres *res, 784 struct authunix_parms *cred, 785 SVCXPRT *transp) 786{ 787 dlog("POSTMOUNT REQUEST: %s\tdev=%lx\tspecial=%s %s", 788 req->mountp, (u_long) req->devid, req->special, req->mntopts); 789 790 /* succeed unconditionally */ 791 res->status = 0; 792 793 dlog("POSTMOUNT REPLY: status=%d", res->status); 794 return 0; 795} 796#endif /* AUTOFS_POSTUNMOUNT */ 797 798 799static int 800autofs_readdir_2_req(struct autofs_rddirargs *req, 801 struct amd_rddirres *res, 802 struct authunix_parms *cred, 803 SVCXPRT *transp) 804{ 805 am_node *mp; 806 int err; 807 static nfsentry e_res[MAX_READDIR_ENTRIES]; 808 809 dlog("READDIR REQUEST: %s @ %d", 810 req->rda_map, (int) req->rda_offset); 811 812 mp = find_ap(req->rda_map); 813 if (!mp) { 814 plog(XLOG_ERROR, "map %s not found", req->rda_map); 815 res->rd_status = AUTOFS_NOENT; 816 goto out; 817 } 818 819 mp->am_stats.s_readdir++; 820 req->rda_offset -= AUTOFS_DAEMONCOOKIE; 821 err = mp->am_mnt->mf_ops->readdir(mp, (char *)&req->rda_offset, 822 &res->rd_dl, e_res, req->rda_count); 823 if (err) { 824 res->rd_status = AUTOFS_ECOMM; 825 goto out; 826 } 827 828 res->rd_status = AUTOFS_OK; 829 res->rd_bufsize = req->rda_count; 830 831out: 832 dlog("READDIR REPLY: status=%d", res->rd_status); 833 return 0; 834} 835 836 837/****************************************************************************/ 838/* autofs program dispatcher */ 839static void 840autofs_program_2(struct svc_req *rqstp, SVCXPRT *transp) 841{ 842 union { 843 autofs_lookupargs autofs_mount_2_arg; 844 autofs_lookupargs autofs_lookup_2_arg; 845 umntrequest autofs_umount_2_arg; 846 autofs_rddirargs autofs_readdir_2_arg; 847#ifdef AUTOFS_POSTUNMOUNT 848 postmountreq autofs_postmount_2_arg; 849 postumntreq autofs_postumnt_2_arg; 850#endif /* AUTOFS_POSTUNMOUNT */ 851 } argument; 852 853 union { 854 autofs_mountres mount_res; 855 autofs_lookupres lookup_res; 856 umntres umount_res; 857 amd_rddirres readdir_res; 858#ifdef AUTOFS_POSTUNMOUNT 859 postumntres postumnt_res; 860 postmountres postmnt_res; 861#endif /* AUTOFS_POSTUNMOUNT */ 862 } result; 863 int ret; 864 865 bool_t (*xdr_argument)(); 866 bool_t (*xdr_result)(); 867 int (*local)(); 868 void (*local_free)() = NULL; 869 870 current_transp = transp; 871 872 switch (rqstp->rq_proc) { 873 874 case AUTOFS_NULL: 875 svc_sendreply(transp, 876 (XDRPROC_T_TYPE) xdr_void, 877 (SVC_IN_ARG_TYPE) NULL); 878 return; 879 880 case AUTOFS_LOOKUP: 881 xdr_argument = xdr_autofs_lookupargs; 882 xdr_result = xdr_autofs_lookupres; 883 local = autofs_lookup_2_req; 884 local_free = autofs_lookup_2_free; 885 break; 886 887 case AUTOFS_MOUNT: 888 xdr_argument = xdr_autofs_lookupargs; 889 xdr_result = xdr_autofs_mountres; 890 local = autofs_mount_2_req; 891 local_free = autofs_mount_2_free; 892 break; 893 894 case AUTOFS_UNMOUNT: 895 xdr_argument = xdr_umntrequest; 896 xdr_result = xdr_umntres; 897 local = autofs_unmount_2_req; 898 break; 899 900/* 901 * These exist only in the AutoFS V2 protocol. 902 */ 903#ifdef AUTOFS_POSTUNMOUNT 904 case AUTOFS_POSTUNMOUNT: 905 xdr_argument = xdr_postumntreq; 906 xdr_result = xdr_postumntres; 907 local = autofs_postunmount_2_req; 908 break; 909 910 case AUTOFS_POSTMOUNT: 911 xdr_argument = xdr_postmountreq; 912 xdr_result = xdr_postmountres; 913 local = autofs_postmount_2_req; 914 break; 915#endif /* AUTOFS_POSTUNMOUNT */ 916 917 case AUTOFS_READDIR: 918 xdr_argument = xdr_autofs_rddirargs; 919 xdr_result = xdr_amd_rddirres; 920 local = autofs_readdir_2_req; 921 break; 922 923 default: 924 svcerr_noproc(transp); 925 return; 926 } 927 928 memset((char *) &argument, 0, sizeof(argument)); 929 if (!svc_getargs(transp, 930 (XDRPROC_T_TYPE) xdr_argument, 931 (SVC_IN_ARG_TYPE) &argument)) { 932 plog(XLOG_ERROR, "AUTOFS xdr decode failed for %d %d %d", 933 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc); 934 svcerr_decode(transp); 935 return; 936 } 937 938 memset((char *)&result, 0, sizeof(result)); 939 ret = (*local) (&argument, &result, rqstp->rq_clntcred, transp); 940 941 current_transp = NULL; 942 943 /* send reply only if the RPC method returned 0 */ 944 if (!ret) { 945 if (!svc_sendreply(transp, 946 (XDRPROC_T_TYPE) xdr_result, 947 (SVC_IN_ARG_TYPE) &result)) { 948 svcerr_systemerr(transp); 949 } 950 } 951 952 if (!svc_freeargs(transp, 953 (XDRPROC_T_TYPE) xdr_argument, 954 (SVC_IN_ARG_TYPE) &argument)) { 955 plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_2"); 956 } 957 958 if (local_free) 959 (*local_free)(&result); 960} 961 962 963int 964autofs_get_fh(am_node *mp) 965{ 966 autofs_fh_t *fh; 967 char buf[MAXHOSTNAMELEN]; 968 mntfs *mf = mp->am_mnt; 969 struct utsname utsname; 970 971 plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path); 972 fh = ALLOC(autofs_fh_t); 973 memset((voidp) fh, 0, sizeof(autofs_fh_t)); /* Paranoid */ 974 975 /* 976 * SET MOUNT ARGS 977 */ 978 if (uname(&utsname) < 0) { 979 xstrlcpy(buf, "localhost.autofs", sizeof(buf)); 980 } else { 981 xstrlcpy(buf, utsname.nodename, sizeof(buf)); 982 xstrlcat(buf, ".autofs", sizeof(buf)); 983 } 984#ifdef HAVE_AUTOFS_ARGS_T_ADDR 985 fh->addr.buf = strdup(buf); 986 fh->addr.len = fh->addr.maxlen = strlen(buf); 987#endif /* HAVE_AUTOFS_ARGS_T_ADDR */ 988 989 fh->direct = ((mf->mf_ops->autofs_fs_flags & FS_DIRECT) == FS_DIRECT); 990 fh->rpc_to = 1; /* XXX: arbitrary */ 991 fh->mount_to = mp->am_timeo; 992 fh->path = mp->am_path; 993 fh->opts = ""; /* XXX: arbitrary */ 994 fh->map = mp->am_path; /* this is what we get back in readdir */ 995 fh->subdir = ""; 996 if (fh->direct) 997 fh->key = mp->am_name; 998 else 999 fh->key = ""; 1000 1001 mp->am_autofs_fh = fh; 1002 return 0; 1003} 1004 1005 1006void 1007autofs_mounted(am_node *mp) 1008{ 1009 /* We don't want any timeouts on autofs nodes */ 1010 mp->am_autofs_ttl = NEVER; 1011} 1012 1013 1014void 1015autofs_release_fh(am_node *mp) 1016{ 1017 autofs_fh_t *fh = mp->am_autofs_fh; 1018#ifdef HAVE_AUTOFS_ARGS_T_ADDR 1019 XFREE(fh->addr.buf); 1020#endif /* HAVE_AUTOFS_ARGS_T_ADDR */ 1021 XFREE(fh); 1022 mp->am_autofs_fh = NULL; 1023} 1024 1025 1026void 1027autofs_get_mp(am_node *mp) 1028{ 1029 /* nothing to do */ 1030} 1031 1032 1033void 1034autofs_release_mp(am_node *mp) 1035{ 1036 /* nothing to do */ 1037} 1038 1039 1040void 1041autofs_add_fdset(fd_set *readfds) 1042{ 1043 /* nothing to do */ 1044} 1045 1046 1047int 1048autofs_handle_fdset(fd_set *readfds, int nsel) 1049{ 1050 /* nothing to do */ 1051 return nsel; 1052} 1053 1054 1055/* 1056 * Create the autofs service for amd 1057 */ 1058int 1059create_autofs_service(void) 1060{ 1061 dlog("creating autofs service listener"); 1062 return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_2); 1063} 1064 1065 1066int 1067destroy_autofs_service(void) 1068{ 1069 dlog("destroying autofs service listener"); 1070 return unregister_autofs_service(AUTOFS_CONFTYPE); 1071} 1072 1073 1074int 1075autofs_mount_fs(am_node *mp, mntfs *mf) 1076{ 1077 int err = 0; 1078 char *target, *target2 = NULL; 1079 struct stat buf; 1080 1081 /* 1082 * For sublinks, we could end up here with an already mounted f/s. 1083 * Don't do anything in that case. 1084 */ 1085 if (!(mf->mf_flags & MFF_MOUNTED)) 1086 err = mf->mf_ops->mount_fs(mp, mf); 1087 1088 if (err || mf->mf_flags & MFF_ON_AUTOFS) 1089 /* Nothing else to do */ 1090 return err; 1091 1092 if (!(gopt.flags & CFM_AUTOFS_USE_LOFS)) 1093 /* Symlinks will be requested in autofs_mount_succeeded */ 1094 return 0; 1095 1096 if (mp->am_link) 1097 target = mp->am_link; 1098 else 1099 target = mf->mf_mount; 1100 1101 if (target[0] != '/') 1102 target2 = str3cat(NULL, mp->am_parent->am_path, "/", target); 1103 else 1104 target2 = strdup(target); 1105 1106 plog(XLOG_INFO, "autofs: converting from link to lofs (%s -> %s)", mp->am_path, target2); 1107 1108 /* 1109 * we need to stat() the destination, because the bind mount does not 1110 * follow symlinks and/or allow for non-existent destinations. 1111 * we fall back to symlinks if there are problems. 1112 * 1113 * we need to temporarily change pgrp, otherwise our stat() won't 1114 * trigger whatever cascading mounts are needed. 1115 * 1116 * WARNING: we will deadlock if this function is called from the master 1117 * amd process and it happens to trigger another auto mount. Therefore, 1118 * this function should be called only from a child amd process, or 1119 * at the very least it should not be called from the parent unless we 1120 * know for sure that it won't cause a recursive mount. We refuse to 1121 * cause the recursive mount anyway if called from the parent amd. 1122 */ 1123 if (!foreground) { 1124 if ((err = stat(target2, &buf))) 1125 goto out; 1126 } 1127 if ((err = lstat(target2, &buf))) 1128 goto out; 1129 1130 if ((err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1))) { 1131 errno = err; 1132 goto out; 1133 } 1134 1135 out: 1136 if (target2) 1137 XFREE(target2); 1138 1139 if (err) 1140 return errno; 1141 return 0; 1142} 1143 1144 1145int 1146autofs_umount_fs(am_node *mp, mntfs *mf) 1147{ 1148 int err = 0; 1149 if (!(mf->mf_flags & MFF_ON_AUTOFS) && 1150 gopt.flags & CFM_AUTOFS_USE_LOFS) { 1151 err = UMOUNT_FS(mp->am_path, mnttab_file_name, 1); 1152 if (err) 1153 return err; 1154 } 1155 1156 /* 1157 * Multiple sublinks could reference this f/s. 1158 * Don't actually unmount it unless we're holding the last reference. 1159 */ 1160 if (mf->mf_refc == 1) 1161 err = mf->mf_ops->umount_fs(mp, mf); 1162 return err; 1163} 1164 1165 1166int 1167autofs_umount_succeeded(am_node *mp) 1168{ 1169 umntres res; 1170 SVCXPRT *transp = mp->am_transp; 1171 1172 if (transp) { 1173 res.status = 0; 1174 1175 if (!svc_sendreply(transp, 1176 (XDRPROC_T_TYPE) xdr_umntres, 1177 (SVC_IN_ARG_TYPE) &res)) 1178 svcerr_systemerr(transp); 1179 1180 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 1181 XFREE(transp); 1182 mp->am_transp = NULL; 1183 } 1184 1185 plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path); 1186 return 0; 1187} 1188 1189 1190int 1191autofs_umount_failed(am_node *mp) 1192{ 1193 umntres res; 1194 SVCXPRT *transp = mp->am_transp; 1195 1196 if (transp) { 1197 res.status = 1; 1198 1199 if (!svc_sendreply(transp, 1200 (XDRPROC_T_TYPE) xdr_umntres, 1201 (SVC_IN_ARG_TYPE) &res)) 1202 svcerr_systemerr(transp); 1203 1204 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 1205 XFREE(transp); 1206 mp->am_transp = NULL; 1207 } 1208 1209 plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path); 1210 return 0; 1211} 1212 1213 1214void 1215autofs_mount_succeeded(am_node *mp) 1216{ 1217 SVCXPRT *transp = mp->am_transp; 1218 struct stat stb; 1219 1220 /* 1221 * Store dev and rdev -- but not for symlinks 1222 */ 1223 if (gopt.flags & CFM_AUTOFS_USE_LOFS || 1224 mp->am_mnt->mf_flags & MFF_ON_AUTOFS) { 1225 if (!lstat(mp->am_path, &stb)) { 1226 mp->am_dev = stb.st_dev; 1227 mp->am_rdev = stb.st_rdev; 1228 } 1229 /* don't expire the entries -- the kernel will do it for us */ 1230 mp->am_flags |= AMF_NOTIMEOUT; 1231 } 1232 1233 if (transp) { 1234 autofs_mountres res; 1235 res.mr_type.status = AUTOFS_DONE; 1236 res.mr_type.mount_result_type_u.error = AUTOFS_OK; 1237 res.mr_verbose = 1; 1238 1239 if (!svc_sendreply(transp, 1240 (XDRPROC_T_TYPE) xdr_autofs_mountres, 1241 (SVC_IN_ARG_TYPE) &res)) 1242 svcerr_systemerr(transp); 1243 1244 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 1245 XFREE(transp); 1246 mp->am_transp = NULL; 1247 } 1248 1249 plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path); 1250} 1251 1252 1253void 1254autofs_mount_failed(am_node *mp) 1255{ 1256 SVCXPRT *transp = mp->am_transp; 1257 1258 if (transp) { 1259 autofs_mountres res; 1260 res.mr_type.status = AUTOFS_DONE; 1261 res.mr_type.mount_result_type_u.error = AUTOFS_NOENT; 1262 res.mr_verbose = 1; 1263 1264 if (!svc_sendreply(transp, 1265 (XDRPROC_T_TYPE) xdr_autofs_mountres, 1266 (SVC_IN_ARG_TYPE) &res)) 1267 svcerr_systemerr(transp); 1268 1269 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); 1270 XFREE(transp); 1271 mp->am_transp = NULL; 1272 } 1273 1274 plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path); 1275} 1276 1277 1278void 1279autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh) 1280{ 1281 xsnprintf(opts, l, "%sdirect", 1282 fh->direct ? "" : "in"); 1283} 1284 1285 1286int 1287autofs_compute_mount_flags(mntent_t *mntp) 1288{ 1289 /* Must use overlay mounts */ 1290 return MNT2_GEN_OPT_OVERLAY; 1291} 1292 1293 1294void autofs_timeout_mp(am_node *mp) 1295{ 1296 /* We don't want any timeouts on autofs nodes */ 1297 mp->am_autofs_ttl = NEVER; 1298} 1299