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