1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 26 #include <stdio.h> 27 #include <stdio_ext.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <signal.h> 31 #include <sys/types.h> 32 #include <memory.h> 33 #include <stropts.h> 34 #include <netconfig.h> 35 #include <stdarg.h> 36 #include <sys/resource.h> 37 #include <sys/systeminfo.h> 38 #include <syslog.h> 39 #include <errno.h> 40 #include <sys/sockio.h> 41 #include <rpc/xdr.h> 42 #include <net/if.h> 43 #include <netdir.h> 44 #include <string.h> 45 #include <thread.h> 46 #include <locale.h> 47 #include <door.h> 48 #include <limits.h> 49 #include "automount.h" 50 #include <sys/vfs.h> 51 #include <sys/mnttab.h> 52 #include <arpa/inet.h> 53 #include <rpcsvc/daemon_utils.h> 54 #include <deflt.h> 55 #include <strings.h> 56 #include <priv.h> 57 #include <tsol/label.h> 58 #include <sys/utsname.h> 59 #include <sys/thread.h> 60 #include <nfs/rnode.h> 61 #include <nfs/nfs.h> 62 #include <wait.h> 63 #include <libshare.h> 64 #include <libscf.h> 65 #include "smfcfg.h" 66 67 static void autofs_doorfunc(void *, char *, size_t, door_desc_t *, uint_t); 68 static void autofs_setdoor(int); 69 static void autofs_mntinfo_1_r(autofs_lookupargs *, autofs_mountres *); 70 static void autofs_mount_1_free_r(struct autofs_mountres *); 71 static void autofs_lookup_1_r(autofs_lookupargs *, autofs_lookupres *); 72 static void autofs_lookup_1_free_args(autofs_lookupargs *); 73 static void autofs_unmount_1_r(umntrequest *, umntres *); 74 static void autofs_unmount_1_free_args(umntrequest *); 75 static void autofs_readdir_1_r(autofs_rddirargs *, autofs_rddirres *); 76 static void autofs_readdir_1_free_r(struct autofs_rddirres *); 77 static int decode_args(xdrproc_t, autofs_door_args_t *, caddr_t *, int); 78 static bool_t encode_res(xdrproc_t, autofs_door_res_t **, caddr_t, int *); 79 static void usage(); 80 static void warn_hup(int); 81 static void free_action_list(); 82 static int start_autofs_svcs(); 83 static void automountd_wait_for_cleanup(pid_t); 84 85 /* 86 * Private autofs system call 87 */ 88 extern int _autofssys(int, void *); 89 90 #define CTIME_BUF_LEN 26 91 92 #define RESOURCE_FACTOR 8 93 #ifdef DEBUG 94 #define AUTOFS_DOOR "/var/run/autofs_door" 95 #endif /* DEBUG */ 96 97 static thread_key_t s_thr_key; 98 99 struct autodir *dir_head; 100 struct autodir *dir_tail; 101 char self[64]; 102 103 time_t timenow; 104 int verbose = 0; 105 int trace = 0; 106 int automountd_nobrowse = 0; 107 int did_fork_exec; 108 109 int 110 main(argc, argv) 111 int argc; 112 char *argv[]; 113 114 { 115 pid_t pid; 116 int c, error; 117 struct rlimit rlset; 118 char defval[6]; 119 int ret = 0, bufsz; 120 121 if (geteuid() != 0) { 122 (void) fprintf(stderr, "%s must be run as root\n", argv[0]); 123 exit(1); 124 } 125 126 /* 127 * Read in the values from SMF first before we check 128 * commandline options so the options override the file. 129 */ 130 bufsz = 6; 131 ret = autofs_smf_get_prop("automountd_verbose", defval, 132 DEFAULT_INSTANCE, SCF_TYPE_BOOLEAN, AUTOMOUNTD, &bufsz); 133 if (ret == SA_OK) { 134 if (strncasecmp("true", defval, 4) == 0) 135 verbose = TRUE; 136 else 137 verbose = FALSE; 138 } 139 bufsz = 6; 140 ret = autofs_smf_get_prop("nobrowse", defval, DEFAULT_INSTANCE, 141 SCF_TYPE_BOOLEAN, AUTOMOUNTD, &bufsz); 142 if (ret == SA_OK) { 143 if (strncasecmp("true", defval, 4) == 0) 144 automountd_nobrowse = TRUE; 145 else 146 automountd_nobrowse = FALSE; 147 } 148 bufsz = 6; 149 ret = autofs_smf_get_prop("trace", defval, DEFAULT_INSTANCE, 150 SCF_TYPE_INTEGER, AUTOMOUNTD, &bufsz); 151 if (ret == SA_OK) { 152 errno = 0; 153 trace = strtol(defval, (char **)NULL, 10); 154 if (errno != 0) 155 trace = 0; 156 } 157 put_automountd_env(); 158 159 while ((c = getopt(argc, argv, "vnTD:")) != EOF) { 160 switch (c) { 161 case 'v': 162 verbose++; 163 break; 164 case 'n': 165 automountd_nobrowse++; 166 break; 167 case 'T': 168 trace++; 169 break; 170 case 'D': 171 (void) putenv(optarg); 172 break; 173 default: 174 usage(); 175 } 176 } 177 178 if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) { 179 error = errno; 180 (void) fprintf(stderr, 181 "automountd: can't determine hostname, error: %d\n", 182 error); 183 exit(1); 184 } 185 186 #ifndef DEBUG 187 pid = fork(); 188 if (pid < 0) { 189 perror("cannot fork"); 190 exit(1); 191 } 192 if (pid) 193 exit(0); 194 #endif 195 196 (void) setsid(); 197 openlog("automountd", LOG_PID, LOG_DAEMON); 198 (void) setlocale(LC_ALL, ""); 199 200 /* 201 * Create the door_servers to manage fork/exec requests for 202 * mounts and executable automount maps 203 */ 204 if ((did_fork_exec = door_create(automountd_do_fork_exec, 205 NULL, 0)) == -1) { 206 syslog(LOG_ERR, "door_create failed: %m, Exiting."); 207 exit(errno); 208 } 209 if ((did_exec_map = door_create(automountd_do_exec_map, 210 NULL, 0)) == -1) { 211 syslog(LOG_ERR, "door_create failed: %m, Exiting."); 212 if (door_revoke(did_fork_exec) == -1) { 213 syslog(LOG_ERR, "failed to door_revoke(%d) %m", 214 did_fork_exec); 215 } 216 exit(errno); 217 } 218 /* 219 * Before we become multithreaded we fork allowing the parent 220 * to become a door server to handle all mount and unmount 221 * requests. This works around a potential hang in using 222 * fork1() within a multithreaded environment 223 */ 224 225 pid = fork1(); 226 if (pid < 0) { 227 syslog(LOG_ERR, 228 "can't fork the automountd mount process %m"); 229 if (door_revoke(did_fork_exec) == -1) { 230 syslog(LOG_ERR, "failed to door_revoke(%d) %m", 231 did_fork_exec); 232 } 233 if (door_revoke(did_exec_map) == -1) { 234 syslog(LOG_ERR, "failed to door_revoke(%d) %m", 235 did_exec_map); 236 } 237 exit(1); 238 } else if (pid > 0) { 239 /* this is the door server process */ 240 automountd_wait_for_cleanup(pid); 241 } 242 243 244 (void) rwlock_init(&cache_lock, USYNC_THREAD, NULL); 245 (void) rwlock_init(&autofs_rddir_cache_lock, USYNC_THREAD, NULL); 246 247 /* 248 * initialize the name services, use NULL arguments to ensure 249 * we don't initialize the stack of files used in file service 250 */ 251 (void) ns_setup(NULL, NULL); 252 253 /* 254 * we're using doors and its thread management now so we need to 255 * make sure we have more than the default of 256 file descriptors 256 * available. 257 */ 258 rlset.rlim_cur = RLIM_INFINITY; 259 rlset.rlim_max = RLIM_INFINITY; 260 if (setrlimit(RLIMIT_NOFILE, &rlset) == -1) 261 syslog(LOG_ERR, "setrlimit failed for %s: %s", AUTOMOUNTD, 262 strerror(errno)); 263 264 (void) enable_extended_FILE_stdio(-1, -1); 265 266 /* 267 * establish our lock on the lock file and write our pid to it. 268 * exit if some other process holds the lock, or if there's any 269 * error in writing/locking the file. 270 */ 271 pid = _enter_daemon_lock(AUTOMOUNTD); 272 switch (pid) { 273 case 0: 274 break; 275 case -1: 276 syslog(LOG_ERR, "error locking for %s: %m", AUTOMOUNTD); 277 exit(2); 278 default: 279 /* daemon was already running */ 280 exit(0); 281 } 282 283 /* 284 * If we coredump it'll be /core. 285 */ 286 if (chdir("/") < 0) 287 syslog(LOG_ERR, "chdir /: %m"); 288 289 /* 290 * Create cache_cleanup thread 291 */ 292 if (thr_create(NULL, 0, (void *(*)(void *))cache_cleanup, NULL, 293 THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) { 294 syslog(LOG_ERR, "unable to create cache_cleanup thread"); 295 exit(1); 296 } 297 298 /* other initializations */ 299 (void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL); 300 301 /* 302 * On a labeled system, allow read-down nfs mounts if privileged 303 * (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error 304 * and "mount equal label only" behavior will result. 305 */ 306 if (is_system_labeled()) { 307 (void) setpflags(NET_MAC_AWARE, 1); 308 (void) setpflags(NET_MAC_AWARE_INHERIT, 1); 309 } 310 311 (void) signal(SIGHUP, warn_hup); 312 313 /* start services */ 314 return (start_autofs_svcs()); 315 316 } 317 318 /* 319 * The old automounter supported a SIGHUP 320 * to allow it to resynchronize internal 321 * state with the /etc/mnttab. 322 * This is no longer relevant, but we 323 * need to catch the signal and warn 324 * the user. 325 */ 326 /* ARGSUSED */ 327 static void 328 warn_hup(i) 329 int i; 330 { 331 syslog(LOG_ERR, "SIGHUP received: ignored"); 332 (void) signal(SIGHUP, warn_hup); 333 } 334 335 static void 336 usage() 337 { 338 (void) fprintf(stderr, "Usage: automountd\n" 339 "\t[-T]\t\t(trace requests)\n" 340 "\t[-v]\t\t(verbose error msgs)\n" 341 "\t[-D n=s]\t(define env variable)\n"); 342 exit(1); 343 /* NOTREACHED */ 344 } 345 346 static void 347 autofs_readdir_1_r( 348 autofs_rddirargs *req, 349 autofs_rddirres *res) 350 { 351 if (trace > 0) 352 trace_prt(1, "READDIR REQUEST : %s @ %ld\n", 353 req->rda_map, req->rda_offset); 354 355 do_readdir(req, res); 356 if (trace > 0) 357 trace_prt(1, "READDIR REPLY : status=%d\n", res->rd_status); 358 } 359 360 static void 361 autofs_readdir_1_free_r(struct autofs_rddirres *res) 362 { 363 if (res->rd_status == AUTOFS_OK) { 364 if (res->rd_rddir.rddir_entries) 365 free(res->rd_rddir.rddir_entries); 366 } 367 } 368 369 370 /* ARGSUSED */ 371 static void 372 autofs_unmount_1_r( 373 umntrequest *m, 374 umntres *res) 375 { 376 struct umntrequest *ul; 377 378 if (trace > 0) { 379 char ctime_buf[CTIME_BUF_LEN]; 380 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 381 ctime_buf[0] = '\0'; 382 383 trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf); 384 for (ul = m; ul; ul = ul->next) 385 trace_prt(1, " resource=%s fstype=%s mntpnt=%s" 386 " mntopts=%s %s\n", 387 ul->mntresource, 388 ul->fstype, 389 ul->mntpnt, 390 ul->mntopts, 391 ul->isdirect ? "direct" : "indirect"); 392 } 393 394 395 res->status = do_unmount1(m); 396 397 if (trace > 0) 398 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status); 399 } 400 401 static void 402 autofs_lookup_1_r( 403 autofs_lookupargs *m, 404 autofs_lookupres *res) 405 { 406 autofs_action_t action; 407 struct linka link; 408 int status; 409 410 if (trace > 0) { 411 char ctime_buf[CTIME_BUF_LEN]; 412 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 413 ctime_buf[0] = '\0'; 414 415 trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf); 416 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 417 m->name, m->subdir, m->map, m->opts, m->path, m->isdirect); 418 } 419 420 bzero(&link, sizeof (struct linka)); 421 422 status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path, 423 (uint_t)m->isdirect, m->uid, &action, &link); 424 if (status == 0) { 425 /* 426 * Return action list to kernel. 427 */ 428 res->lu_res = AUTOFS_OK; 429 if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) { 430 res->lu_type.lookup_result_type_u.lt_linka = link; 431 } 432 } else { 433 /* 434 * Entry not found 435 */ 436 res->lu_res = AUTOFS_NOENT; 437 } 438 res->lu_verbose = verbose; 439 440 if (trace > 0) 441 trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res); 442 } 443 444 static void 445 autofs_mntinfo_1_r( 446 autofs_lookupargs *m, 447 autofs_mountres *res) 448 { 449 int status; 450 action_list *alp = NULL; 451 452 if (trace > 0) { 453 char ctime_buf[CTIME_BUF_LEN]; 454 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 455 ctime_buf[0] = '\0'; 456 457 trace_prt(1, "MOUNT REQUEST: %s", ctime_buf); 458 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 459 m->name, m->subdir, m->map, m->opts, m->path, m->isdirect); 460 } 461 462 status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path, 463 (uint_t)m->isdirect, m->uid, &alp, DOMOUNT_USER); 464 if (status != 0) { 465 /* 466 * An error occurred, free action list if allocated. 467 */ 468 if (alp != NULL) { 469 free_action_list(alp); 470 alp = NULL; 471 } 472 } 473 if (alp != NULL) { 474 /* 475 * Return action list to kernel. 476 */ 477 res->mr_type.status = AUTOFS_ACTION; 478 res->mr_type.mount_result_type_u.list = alp; 479 } else { 480 /* 481 * No work to do left for the kernel 482 */ 483 res->mr_type.status = AUTOFS_DONE; 484 res->mr_type.mount_result_type_u.error = status; 485 } 486 487 if (trace > 0) { 488 switch (res->mr_type.status) { 489 case AUTOFS_ACTION: 490 trace_prt(1, 491 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n", 492 status); 493 break; 494 case AUTOFS_DONE: 495 trace_prt(1, 496 "MOUNT REPLY : status=%d, AUTOFS_DONE\n", 497 status); 498 break; 499 default: 500 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n", 501 status); 502 } 503 } 504 505 if (status && verbose) { 506 if (m->isdirect) { 507 /* direct mount */ 508 syslog(LOG_ERR, "mount of %s failed", m->path); 509 } else { 510 /* indirect mount */ 511 syslog(LOG_ERR, 512 "mount of %s/%s failed", m->path, m->name); 513 } 514 } 515 } 516 517 static void 518 autofs_mount_1_free_r(struct autofs_mountres *res) 519 { 520 if (res->mr_type.status == AUTOFS_ACTION) { 521 if (trace > 2) 522 trace_prt(1, "freeing action list\n"); 523 free_action_list(res->mr_type.mount_result_type_u.list); 524 } 525 } 526 527 /* 528 * Used for reporting messages from code shared with automount command. 529 * Formats message into a buffer and calls syslog. 530 * 531 * Print an error. Works like printf (fmt string and variable args) 532 * except that it will subsititute an error message for a "%m" string 533 * (like syslog). 534 */ 535 void 536 pr_msg(const char *fmt, ...) 537 { 538 va_list ap; 539 char fmtbuff[BUFSIZ], buff[BUFSIZ]; 540 const char *p1; 541 char *p2; 542 543 p2 = fmtbuff; 544 fmt = gettext(fmt); 545 546 for (p1 = fmt; *p1; p1++) { 547 if (*p1 == '%' && *(p1 + 1) == 'm') { 548 (void) strcpy(p2, strerror(errno)); 549 p2 += strlen(p2); 550 p1++; 551 } else { 552 *p2++ = *p1; 553 } 554 } 555 if (p2 > fmtbuff && *(p2-1) != '\n') 556 *p2++ = '\n'; 557 *p2 = '\0'; 558 559 va_start(ap, fmt); 560 (void) vsprintf(buff, fmtbuff, ap); 561 va_end(ap); 562 syslog(LOG_ERR, buff); 563 } 564 565 static void 566 free_action_list(action_list *alp) 567 { 568 action_list *p, *next = NULL; 569 struct mounta *mp; 570 571 for (p = alp; p != NULL; p = next) { 572 switch (p->action.action) { 573 case AUTOFS_MOUNT_RQ: 574 mp = &(p->action.action_list_entry_u.mounta); 575 /* LINTED pointer alignment */ 576 if (mp->fstype) { 577 if (strcmp(mp->fstype, "autofs") == 0) { 578 free_autofs_args((autofs_args *) 579 mp->dataptr); 580 } else if (strncmp(mp->fstype, "nfs", 3) == 0) { 581 free_nfs_args((struct nfs_args *) 582 mp->dataptr); 583 } 584 } 585 mp->dataptr = NULL; 586 mp->datalen = 0; 587 free_mounta(mp); 588 break; 589 case AUTOFS_LINK_RQ: 590 syslog(LOG_ERR, 591 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 592 break; 593 default: 594 syslog(LOG_ERR, 595 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 596 break; 597 } 598 next = p->next; 599 free(p); 600 } 601 } 602 603 static void 604 autofs_lookup_1_free_args(autofs_lookupargs *args) 605 { 606 if (args->map) 607 free(args->map); 608 if (args->path) 609 free(args->path); 610 if (args->name) 611 free(args->name); 612 if (args->subdir) 613 free(args->subdir); 614 if (args->opts) 615 free(args->opts); 616 } 617 618 static void 619 autofs_unmount_1_free_args(umntrequest *args) 620 { 621 if (args->mntresource) 622 free(args->mntresource); 623 if (args->mntpnt) 624 free(args->mntpnt); 625 if (args->fstype) 626 free(args->fstype); 627 if (args->mntopts) 628 free(args->mntopts); 629 if (args->next) 630 autofs_unmount_1_free_args(args->next); 631 } 632 633 static void 634 autofs_setdoor(int did) 635 { 636 637 if (did < 0) { 638 did = 0; 639 } 640 641 (void) _autofssys(AUTOFS_SETDOOR, &did); 642 } 643 644 void * 645 autofs_get_buffer(size_t size) 646 { 647 autofs_tsd_t *tsd = NULL; 648 649 /* 650 * Make sure the buffer size is aligned 651 */ 652 (void) thr_getspecific(s_thr_key, (void **)&tsd); 653 if (tsd == NULL) { 654 tsd = (autofs_tsd_t *)malloc(sizeof (autofs_tsd_t)); 655 if (tsd == NULL) { 656 return (NULL); 657 } 658 tsd->atsd_buf = malloc(size); 659 if (tsd->atsd_buf != NULL) 660 tsd->atsd_len = size; 661 else 662 tsd->atsd_len = 0; 663 (void) thr_setspecific(s_thr_key, tsd); 664 } else { 665 if (tsd->atsd_buf && (tsd->atsd_len < size)) { 666 free(tsd->atsd_buf); 667 tsd->atsd_buf = malloc(size); 668 if (tsd->atsd_buf != NULL) 669 tsd->atsd_len = size; 670 else { 671 tsd->atsd_len = 0; 672 } 673 } 674 } 675 if (tsd->atsd_buf) { 676 bzero(tsd->atsd_buf, size); 677 return (tsd->atsd_buf); 678 } else { 679 syslog(LOG_ERR, 680 gettext("Can't Allocate tsd buffer, size %d"), size); 681 return (NULL); 682 } 683 } 684 685 /* 686 * Each request will automatically spawn a new thread with this 687 * as its entry point. 688 */ 689 /* ARGUSED */ 690 static void 691 autofs_doorfunc( 692 void *cookie, 693 char *argp, 694 size_t arg_size, 695 door_desc_t *dp, 696 uint_t n_desc) 697 { 698 char *res; 699 int res_size; 700 int which; 701 int error = 0; 702 int srsz = 0; 703 autofs_lookupargs *xdrargs; 704 autofs_lookupres lookup_res; 705 autofs_rddirargs *rddir_args; 706 autofs_rddirres rddir_res; 707 autofs_mountres mount_res; 708 umntrequest *umnt_args; 709 umntres umount_res; 710 autofs_door_res_t *door_res; 711 autofs_door_res_t failed_res; 712 713 if (arg_size < sizeof (autofs_door_args_t)) { 714 failed_res.res_status = EINVAL; 715 error = door_return((char *)&failed_res, 716 sizeof (autofs_door_res_t), NULL, 0); 717 /* 718 * If we got here the door_return() failed. 719 */ 720 syslog(LOG_ERR, "Bad argument, door_return failure %d", error); 721 return; 722 } 723 724 timenow = time((time_t *)NULL); 725 726 which = ((autofs_door_args_t *)argp)->cmd; 727 switch (which) { 728 case AUTOFS_LOOKUP: 729 if (error = decode_args(xdr_autofs_lookupargs, 730 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs, 731 sizeof (autofs_lookupargs))) { 732 syslog(LOG_ERR, 733 "error allocating lookup arguments buffer"); 734 failed_res.res_status = error; 735 failed_res.xdr_len = 0; 736 res = (caddr_t)&failed_res; 737 res_size = 0; 738 break; 739 } 740 bzero(&lookup_res, sizeof (autofs_lookupres)); 741 742 autofs_lookup_1_r(xdrargs, &lookup_res); 743 744 autofs_lookup_1_free_args(xdrargs); 745 free(xdrargs); 746 747 if (!encode_res(xdr_autofs_lookupres, &door_res, 748 (caddr_t)&lookup_res, &res_size)) { 749 syslog(LOG_ERR, 750 "error allocating lookup results buffer"); 751 failed_res.res_status = EINVAL; 752 failed_res.xdr_len = 0; 753 res = (caddr_t)&failed_res; 754 } else { 755 door_res->res_status = 0; 756 res = (caddr_t)door_res; 757 } 758 break; 759 760 case AUTOFS_MNTINFO: 761 if (error = decode_args(xdr_autofs_lookupargs, 762 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs, 763 sizeof (autofs_lookupargs))) { 764 syslog(LOG_ERR, 765 "error allocating lookup arguments buffer"); 766 failed_res.res_status = error; 767 failed_res.xdr_len = 0; 768 res = (caddr_t)&failed_res; 769 res_size = 0; 770 break; 771 } 772 773 autofs_mntinfo_1_r((autofs_lookupargs *)xdrargs, &mount_res); 774 775 autofs_lookup_1_free_args(xdrargs); 776 free(xdrargs); 777 778 /* 779 * Only reason we would get a NULL res is because 780 * we could not allocate a results buffer. Use 781 * a local one to return the error EAGAIN as has 782 * always been done when memory allocations fail. 783 */ 784 if (!encode_res(xdr_autofs_mountres, &door_res, 785 (caddr_t)&mount_res, &res_size)) { 786 syslog(LOG_ERR, 787 "error allocating mount results buffer"); 788 failed_res.res_status = EAGAIN; 789 failed_res.xdr_len = 0; 790 res = (caddr_t)&failed_res; 791 } else { 792 door_res->res_status = 0; 793 res = (caddr_t)door_res; 794 } 795 autofs_mount_1_free_r(&mount_res); 796 break; 797 798 case AUTOFS_UNMOUNT: 799 if (error = decode_args(xdr_umntrequest, 800 (autofs_door_args_t *)argp, 801 (caddr_t *)&umnt_args, sizeof (umntrequest))) { 802 syslog(LOG_ERR, 803 "error allocating unmount argument buffer"); 804 failed_res.res_status = error; 805 failed_res.xdr_len = 0; 806 res = (caddr_t)&failed_res; 807 res_size = sizeof (autofs_door_res_t); 808 break; 809 } 810 811 autofs_unmount_1_r(umnt_args, &umount_res); 812 813 error = umount_res.status; 814 815 autofs_unmount_1_free_args(umnt_args); 816 free(umnt_args); 817 818 if (!encode_res(xdr_umntres, &door_res, (caddr_t)&umount_res, 819 &res_size)) { 820 syslog(LOG_ERR, 821 "error allocating unmount results buffer"); 822 failed_res.res_status = EINVAL; 823 failed_res.xdr_len = 0; 824 res = (caddr_t)&failed_res; 825 res_size = sizeof (autofs_door_res_t); 826 } else { 827 door_res->res_status = 0; 828 res = (caddr_t)door_res; 829 } 830 break; 831 832 case AUTOFS_READDIR: 833 if (error = decode_args(xdr_autofs_rddirargs, 834 (autofs_door_args_t *)argp, 835 (caddr_t *)&rddir_args, 836 sizeof (autofs_rddirargs))) { 837 syslog(LOG_ERR, 838 "error allocating readdir argument buffer"); 839 failed_res.res_status = error; 840 failed_res.xdr_len = 0; 841 res = (caddr_t)&failed_res; 842 res_size = sizeof (autofs_door_res_t); 843 break; 844 } 845 846 autofs_readdir_1_r(rddir_args, &rddir_res); 847 848 free(rddir_args->rda_map); 849 free(rddir_args); 850 851 if (!encode_res(xdr_autofs_rddirres, &door_res, 852 (caddr_t)&rddir_res, &res_size)) { 853 syslog(LOG_ERR, 854 "error allocating readdir results buffer"); 855 failed_res.res_status = ENOMEM; 856 failed_res.xdr_len = 0; 857 res = (caddr_t)&failed_res; 858 res_size = sizeof (autofs_door_res_t); 859 } else { 860 door_res->res_status = 0; 861 res = (caddr_t)door_res; 862 } 863 autofs_readdir_1_free_r(&rddir_res); 864 break; 865 #ifdef MALLOC_DEBUG 866 case AUTOFS_DUMP_DEBUG: 867 check_leaks("/var/tmp/automountd.leak"); 868 error = door_return(NULL, 0, NULL, 0); 869 /* 870 * If we got here, door_return() failed 871 */ 872 syslog(LOG_ERR, "dump debug door_return failure %d", 873 error); 874 return; 875 #endif 876 case NULLPROC: 877 res = NULL; 878 res_size = 0; 879 break; 880 default: 881 failed_res.res_status = EINVAL; 882 res = (char *)&failed_res; 883 res_size = sizeof (autofs_door_res_t); 884 break; 885 } 886 887 srsz = res_size; 888 errno = 0; 889 error = door_return(res, res_size, NULL, 0); 890 891 if (errno == E2BIG) { 892 /* 893 * Failed due to encoded results being bigger than the 894 * kernel expected bufsize. Passing actual results size 895 * back down to kernel. 896 */ 897 failed_res.res_status = EOVERFLOW; 898 failed_res.xdr_len = srsz; 899 res = (caddr_t)&failed_res; 900 res_size = sizeof (autofs_door_res_t); 901 } else { 902 syslog(LOG_ERR, "door_return failed %d, buffer %p, " 903 "buffer size %d", error, (void *)res, res_size); 904 res = NULL; 905 res_size = 0; 906 } 907 (void) door_return(res, res_size, NULL, 0); 908 /* NOTREACHED */ 909 } 910 911 static int 912 start_autofs_svcs(void) 913 { 914 int doorfd; 915 #ifdef DEBUG 916 int dfd; 917 #endif 918 919 if ((doorfd = door_create(autofs_doorfunc, NULL, 920 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 921 syslog(LOG_ERR, gettext("Unable to create door\n")); 922 return (1); 923 } 924 925 #ifdef DEBUG 926 /* 927 * Create a file system path for the door 928 */ 929 if ((dfd = open(AUTOFS_DOOR, O_RDWR|O_CREAT|O_TRUNC, 930 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { 931 syslog(LOG_ERR, "Unable to open %s: %m\n", AUTOFS_DOOR); 932 (void) close(doorfd); 933 return (1); 934 } 935 936 /* 937 * stale associations clean up 938 */ 939 (void) fdetach(AUTOFS_DOOR); 940 941 /* 942 * Register in the namespace to the kernel to door_ki_open. 943 */ 944 if (fattach(doorfd, AUTOFS_DOOR) == -1) { 945 syslog(LOG_ERR, "Unable to fattach door %m\n", AUTOFS_DOOR); 946 (void) close(dfd); 947 (void) close(doorfd); 948 return (1); 949 } 950 #endif /* DEBUG */ 951 952 /* 953 * Pass door name to kernel for door_ki_open 954 */ 955 autofs_setdoor(doorfd); 956 957 (void) thr_keycreate(&s_thr_key, NULL); 958 959 /* 960 * Wait for incoming calls 961 */ 962 /*CONSTCOND*/ 963 while (1) 964 (void) pause(); 965 966 /* NOTREACHED */ 967 syslog(LOG_ERR, gettext("Door server exited")); 968 return (10); 969 } 970 971 static int 972 decode_args( 973 xdrproc_t xdrfunc, 974 autofs_door_args_t *argp, 975 caddr_t *xdrargs, 976 int size) 977 { 978 XDR xdrs; 979 980 caddr_t tmpargs = (caddr_t)&((autofs_door_args_t *)argp)->xdr_arg; 981 size_t arg_size = ((autofs_door_args_t *)argp)->xdr_len; 982 983 xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE); 984 985 *xdrargs = malloc(size); 986 if (*xdrargs == NULL) { 987 syslog(LOG_ERR, "error allocating arguments buffer"); 988 return (ENOMEM); 989 } 990 991 bzero(*xdrargs, size); 992 993 if (!(*xdrfunc)(&xdrs, *xdrargs)) { 994 free(*xdrargs); 995 *xdrargs = NULL; 996 syslog(LOG_ERR, "error decoding arguments"); 997 return (EINVAL); 998 } 999 1000 return (0); 1001 } 1002 1003 1004 static bool_t 1005 encode_res( 1006 xdrproc_t xdrfunc, 1007 autofs_door_res_t **results, 1008 caddr_t resp, 1009 int *size) 1010 { 1011 XDR xdrs; 1012 1013 *size = xdr_sizeof((*xdrfunc), resp); 1014 *results = autofs_get_buffer( 1015 sizeof (autofs_door_res_t) + *size); 1016 if (*results == NULL) { 1017 (*results)->res_status = ENOMEM; 1018 return (FALSE); 1019 } 1020 (*results)->xdr_len = *size; 1021 *size = sizeof (autofs_door_res_t) + (*results)->xdr_len; 1022 xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res), 1023 (*results)->xdr_len, XDR_ENCODE); 1024 if (!(*xdrfunc)(&xdrs, resp)) { 1025 (*results)->res_status = EINVAL; 1026 syslog(LOG_ERR, "error encoding results"); 1027 return (FALSE); 1028 } 1029 (*results)->res_status = 0; 1030 return (TRUE); 1031 } 1032 1033 static void 1034 automountd_wait_for_cleanup(pid_t pid) 1035 { 1036 int status; 1037 int child_exitval; 1038 1039 /* 1040 * Wait for the main automountd process to exit so we cleanup 1041 */ 1042 (void) waitpid(pid, &status, 0); 1043 1044 child_exitval = WEXITSTATUS(status); 1045 1046 /* 1047 * Shutdown the door server for mounting and unmounting 1048 * filesystems 1049 */ 1050 if (door_revoke(did_fork_exec) == -1) { 1051 syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_fork_exec); 1052 } 1053 if (door_revoke(did_exec_map) == -1) { 1054 syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_exec_map); 1055 } 1056 exit(child_exitval); 1057 } 1058