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