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 68 struct amd_rddirres { 69 enum autofs_res rd_status; 70 u_long rd_bufsize; 71 nfsdirlist rd_dl; 72 }; 73 typedef struct amd_rddirres amd_rddirres; 74 75 /* 76 * VARIABLES: 77 */ 78 79 SVCXPRT *autofs_xprt = NULL; 80 81 /* forward declarations */ 82 bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp); 83 bool_t xdr_umntres(XDR *xdrs, umntres *objp); 84 bool_t xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp); 85 bool_t xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp); 86 bool_t xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp); 87 bool_t xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp); 88 static 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 94 bool_t xdr_postumntreq(XDR *xdrs, postumntreq *objp); 95 bool_t xdr_postumntres(XDR *xdrs, postumntres *objp); 96 bool_t xdr_postmountreq(XDR *xdrs, postmountreq *objp); 97 bool_t xdr_postmountres(XDR *xdrs, postmountres *objp); 98 #endif /* AUTOFS_POSTUMOUNT */ 99 100 /* 101 * AUTOFS XDR FUNCTIONS: 102 */ 103 104 bool_t 105 xdr_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 113 bool_t 114 xdr_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 122 bool_t 123 xdr_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 133 bool_t 134 xdr_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 146 bool_t 147 xdr_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 171 bool_t 172 xdr_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 191 bool_t 192 xdr_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 212 bool_t 213 xdr_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 224 bool_t 225 xdr_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 255 bool_t 256 xdr_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 271 bool_t 272 xdr_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 286 bool_t 287 xdr_postumntres(XDR *xdrs, postumntres *objp) 288 { 289 if (!xdr_int(xdrs, &objp->status)) 290 return (FALSE); 291 return (TRUE); 292 } 293 294 295 bool_t 296 xdr_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 312 bool_t 313 xdr_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 322 bool_t 323 xdr_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 331 bool_t 332 xdr_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 353 bool_t 354 xdr_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 374 bool_t 375 xdr_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 389 bool_t 390 xdr_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 406 bool_t 407 xdr_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 419 bool_t 420 xdr_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 */ 438 static bool_t 439 xdr_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 482 static bool_t 483 xdr_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 497 static int 498 autofs_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 546 static void 547 autofs_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 565 static int 566 autofs_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 627 out: 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 654 static void 655 autofs_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 693 static int 694 autofs_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 */ 760 static int 761 autofs_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 */ 781 static int 782 autofs_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 799 static int 800 autofs_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 831 out: 832 dlog("READDIR REPLY: status=%d", res->rd_status); 833 return 0; 834 } 835 836 837 /****************************************************************************/ 838 /* autofs program dispatcher */ 839 static void 840 autofs_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 963 int 964 autofs_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 1006 void 1007 autofs_mounted(am_node *mp) 1008 { 1009 /* We don't want any timeouts on autofs nodes */ 1010 mp->am_autofs_ttl = NEVER; 1011 } 1012 1013 1014 void 1015 autofs_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 1026 void 1027 autofs_get_mp(am_node *mp) 1028 { 1029 /* nothing to do */ 1030 } 1031 1032 1033 void 1034 autofs_release_mp(am_node *mp) 1035 { 1036 /* nothing to do */ 1037 } 1038 1039 1040 void 1041 autofs_add_fdset(fd_set *readfds) 1042 { 1043 /* nothing to do */ 1044 } 1045 1046 1047 int 1048 autofs_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 */ 1058 int 1059 create_autofs_service(void) 1060 { 1061 dlog("creating autofs service listener"); 1062 return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_2); 1063 } 1064 1065 1066 int 1067 destroy_autofs_service(void) 1068 { 1069 dlog("destroying autofs service listener"); 1070 return unregister_autofs_service(AUTOFS_CONFTYPE); 1071 } 1072 1073 1074 int 1075 autofs_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 1145 int 1146 autofs_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 1166 int 1167 autofs_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 1190 int 1191 autofs_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 1214 void 1215 autofs_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 1253 void 1254 autofs_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 1278 void 1279 autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh) 1280 { 1281 xsnprintf(opts, l, "%sdirect", 1282 fh->direct ? "" : "in"); 1283 } 1284 1285 1286 int 1287 autofs_compute_mount_flags(mntent_t *mntp) 1288 { 1289 /* Must use overlay mounts */ 1290 return MNT2_GEN_OPT_OVERLAY; 1291 } 1292 1293 1294 void 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