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