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