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 2008 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", res->rd_status); 350 } 351 352 static void 353 autofs_readdir_1_free_r(struct autofs_rddirres *res) 354 { 355 if (res->rd_status == AUTOFS_OK) { 356 if (res->rd_rddir.rddir_entries) 357 free(res->rd_rddir.rddir_entries); 358 } 359 } 360 361 362 /* ARGSUSED */ 363 static void 364 autofs_unmount_1_r( 365 umntrequest *m, 366 umntres *res) 367 { 368 struct umntrequest *ul; 369 370 if (trace > 0) { 371 char ctime_buf[CTIME_BUF_LEN]; 372 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 373 ctime_buf[0] = '\0'; 374 375 trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf); 376 for (ul = m; ul; ul = ul->next) 377 trace_prt(1, " resource=%s fstype=%s mntpnt=%s" 378 " mntopts=%s %s\n", 379 ul->mntresource, 380 ul->fstype, 381 ul->mntpnt, 382 ul->mntopts, 383 ul->isdirect ? "direct" : "indirect"); 384 } 385 386 387 res->status = do_unmount1(m); 388 389 if (trace > 0) 390 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status); 391 } 392 393 static void 394 autofs_lookup_1_r( 395 autofs_lookupargs *m, 396 autofs_lookupres *res) 397 { 398 autofs_action_t action; 399 struct linka link; 400 int status; 401 402 if (trace > 0) { 403 char ctime_buf[CTIME_BUF_LEN]; 404 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 405 ctime_buf[0] = '\0'; 406 407 trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf); 408 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 409 m->name, m->subdir, m->map, m->opts, m->path, m->isdirect); 410 } 411 412 bzero(&link, sizeof (struct linka)); 413 414 status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path, 415 (uint_t)m->isdirect, m->uid, &action, &link); 416 if (status == 0) { 417 /* 418 * Return action list to kernel. 419 */ 420 res->lu_res = AUTOFS_OK; 421 if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) { 422 res->lu_type.lookup_result_type_u.lt_linka = link; 423 } 424 } else { 425 /* 426 * Entry not found 427 */ 428 res->lu_res = AUTOFS_NOENT; 429 } 430 res->lu_verbose = verbose; 431 432 if (trace > 0) 433 trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res); 434 } 435 436 static void 437 autofs_mntinfo_1_r( 438 autofs_lookupargs *m, 439 autofs_mountres *res) 440 { 441 int status; 442 action_list *alp = NULL; 443 444 if (trace > 0) { 445 char ctime_buf[CTIME_BUF_LEN]; 446 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 447 ctime_buf[0] = '\0'; 448 449 trace_prt(1, "MOUNT REQUEST: %s", ctime_buf); 450 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 451 m->name, m->subdir, m->map, m->opts, m->path, m->isdirect); 452 } 453 454 status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path, 455 (uint_t)m->isdirect, m->uid, &alp, DOMOUNT_USER); 456 if (status != 0) { 457 /* 458 * An error occurred, free action list if allocated. 459 */ 460 if (alp != NULL) { 461 free_action_list(alp); 462 alp = NULL; 463 } 464 } 465 if (alp != NULL) { 466 /* 467 * Return action list to kernel. 468 */ 469 res->mr_type.status = AUTOFS_ACTION; 470 res->mr_type.mount_result_type_u.list = alp; 471 } else { 472 /* 473 * No work to do left for the kernel 474 */ 475 res->mr_type.status = AUTOFS_DONE; 476 res->mr_type.mount_result_type_u.error = status; 477 } 478 479 if (trace > 0) { 480 switch (res->mr_type.status) { 481 case AUTOFS_ACTION: 482 trace_prt(1, 483 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n", 484 status); 485 break; 486 case AUTOFS_DONE: 487 trace_prt(1, 488 "MOUNT REPLY : status=%d, AUTOFS_DONE\n", 489 status); 490 break; 491 default: 492 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n", 493 status); 494 } 495 } 496 497 if (status && verbose) { 498 if (m->isdirect) { 499 /* direct mount */ 500 syslog(LOG_ERR, "mount of %s failed", m->path); 501 } else { 502 /* indirect mount */ 503 syslog(LOG_ERR, 504 "mount of %s/%s failed", m->path, m->name); 505 } 506 } 507 } 508 509 static void 510 autofs_mount_1_free_r(struct autofs_mountres *res) 511 { 512 if (res->mr_type.status == AUTOFS_ACTION) { 513 if (trace > 2) 514 trace_prt(1, "freeing action list\n"); 515 free_action_list(res->mr_type.mount_result_type_u.list); 516 } 517 } 518 519 /* 520 * Used for reporting messages from code shared with automount command. 521 * Formats message into a buffer and calls syslog. 522 * 523 * Print an error. Works like printf (fmt string and variable args) 524 * except that it will subsititute an error message for a "%m" string 525 * (like syslog). 526 */ 527 void 528 pr_msg(const char *fmt, ...) 529 { 530 va_list ap; 531 char fmtbuff[BUFSIZ], buff[BUFSIZ]; 532 const char *p1; 533 char *p2; 534 535 p2 = fmtbuff; 536 fmt = gettext(fmt); 537 538 for (p1 = fmt; *p1; p1++) { 539 if (*p1 == '%' && *(p1 + 1) == 'm') { 540 (void) strcpy(p2, strerror(errno)); 541 p2 += strlen(p2); 542 p1++; 543 } else { 544 *p2++ = *p1; 545 } 546 } 547 if (p2 > fmtbuff && *(p2-1) != '\n') 548 *p2++ = '\n'; 549 *p2 = '\0'; 550 551 va_start(ap, fmt); 552 (void) vsprintf(buff, fmtbuff, ap); 553 va_end(ap); 554 syslog(LOG_ERR, buff); 555 } 556 557 static void 558 free_action_list(action_list *alp) 559 { 560 action_list *p, *next = NULL; 561 struct mounta *mp; 562 563 for (p = alp; p != NULL; p = next) { 564 switch (p->action.action) { 565 case AUTOFS_MOUNT_RQ: 566 mp = &(p->action.action_list_entry_u.mounta); 567 /* LINTED pointer alignment */ 568 if (mp->fstype) { 569 if (strcmp(mp->fstype, "autofs") == 0) { 570 free_autofs_args((autofs_args *) 571 mp->dataptr); 572 } else if (strncmp(mp->fstype, "nfs", 3) == 0) { 573 free_nfs_args((struct nfs_args *) 574 mp->dataptr); 575 } 576 } 577 mp->dataptr = NULL; 578 mp->datalen = 0; 579 free_mounta(mp); 580 break; 581 case AUTOFS_LINK_RQ: 582 syslog(LOG_ERR, 583 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 584 break; 585 default: 586 syslog(LOG_ERR, 587 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 588 break; 589 } 590 next = p->next; 591 free(p); 592 } 593 } 594 595 static void 596 autofs_lookup_1_free_args(autofs_lookupargs *args) 597 { 598 if (args->map) 599 free(args->map); 600 if (args->path) 601 free(args->path); 602 if (args->name) 603 free(args->name); 604 if (args->subdir) 605 free(args->subdir); 606 if (args->opts) 607 free(args->opts); 608 } 609 610 static void 611 autofs_unmount_1_free_args(umntrequest *args) 612 { 613 if (args->mntresource) 614 free(args->mntresource); 615 if (args->mntpnt) 616 free(args->mntpnt); 617 if (args->fstype) 618 free(args->fstype); 619 if (args->mntopts) 620 free(args->mntopts); 621 if (args->next) 622 autofs_unmount_1_free_args(args->next); 623 } 624 625 static void 626 autofs_setdoor(int did) 627 { 628 629 if (did < 0) { 630 did = 0; 631 } 632 633 (void) _autofssys(AUTOFS_SETDOOR, &did); 634 } 635 636 void * 637 autofs_get_buffer(size_t size) 638 { 639 autofs_tsd_t *tsd = NULL; 640 641 /* 642 * Make sure the buffer size is aligned 643 */ 644 (void) thr_getspecific(s_thr_key, (void **)&tsd); 645 if (tsd == NULL) { 646 tsd = (autofs_tsd_t *)malloc(sizeof (autofs_tsd_t)); 647 if (tsd == NULL) { 648 return (NULL); 649 } 650 tsd->atsd_buf = malloc(size); 651 if (tsd->atsd_buf != NULL) 652 tsd->atsd_len = size; 653 else 654 tsd->atsd_len = 0; 655 (void) thr_setspecific(s_thr_key, tsd); 656 } else { 657 if (tsd->atsd_buf && (tsd->atsd_len < size)) { 658 free(tsd->atsd_buf); 659 tsd->atsd_buf = malloc(size); 660 if (tsd->atsd_buf != NULL) 661 tsd->atsd_len = size; 662 else { 663 tsd->atsd_len = 0; 664 } 665 } 666 } 667 if (tsd->atsd_buf) { 668 bzero(tsd->atsd_buf, size); 669 return (tsd->atsd_buf); 670 } else { 671 syslog(LOG_ERR, 672 gettext("Can't Allocate tsd buffer, size %d"), size); 673 return (NULL); 674 } 675 } 676 677 /* 678 * Each request will automatically spawn a new thread with this 679 * as its entry point. 680 */ 681 /* ARGUSED */ 682 static void 683 autofs_doorfunc( 684 void *cookie, 685 char *argp, 686 size_t arg_size, 687 door_desc_t *dp, 688 uint_t n_desc) 689 { 690 char *res; 691 int res_size; 692 int which; 693 int error = 0; 694 int srsz = 0; 695 autofs_lookupargs *xdrargs; 696 autofs_lookupres lookup_res; 697 autofs_rddirargs *rddir_args; 698 autofs_rddirres rddir_res; 699 autofs_mountres mount_res; 700 umntrequest *umnt_args; 701 umntres umount_res; 702 autofs_door_res_t *door_res; 703 autofs_door_res_t failed_res; 704 705 if (arg_size < sizeof (autofs_door_args_t)) { 706 failed_res.res_status = EINVAL; 707 error = door_return((char *)&failed_res, 708 sizeof (autofs_door_res_t), NULL, 0); 709 /* 710 * If we got here the door_return() failed. 711 */ 712 syslog(LOG_ERR, "Bad argument, door_return failure %d", error); 713 return; 714 } 715 716 timenow = time((time_t *)NULL); 717 718 which = ((autofs_door_args_t *)argp)->cmd; 719 switch (which) { 720 case AUTOFS_LOOKUP: 721 if (error = decode_args(xdr_autofs_lookupargs, 722 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs, 723 sizeof (autofs_lookupargs))) { 724 syslog(LOG_ERR, 725 "error allocating lookup arguments buffer"); 726 failed_res.res_status = error; 727 failed_res.xdr_len = 0; 728 res = (caddr_t)&failed_res; 729 res_size = 0; 730 break; 731 } 732 bzero(&lookup_res, sizeof (autofs_lookupres)); 733 734 autofs_lookup_1_r(xdrargs, &lookup_res); 735 736 autofs_lookup_1_free_args(xdrargs); 737 free(xdrargs); 738 739 if (!encode_res(xdr_autofs_lookupres, &door_res, 740 (caddr_t)&lookup_res, &res_size)) { 741 syslog(LOG_ERR, 742 "error allocating lookup results buffer"); 743 failed_res.res_status = EINVAL; 744 failed_res.xdr_len = 0; 745 res = (caddr_t)&failed_res; 746 } else { 747 door_res->res_status = 0; 748 res = (caddr_t)door_res; 749 } 750 break; 751 752 case AUTOFS_MNTINFO: 753 if (error = decode_args(xdr_autofs_lookupargs, 754 (autofs_door_args_t *)argp, (caddr_t *)&xdrargs, 755 sizeof (autofs_lookupargs))) { 756 syslog(LOG_ERR, 757 "error allocating lookup arguments buffer"); 758 failed_res.res_status = error; 759 failed_res.xdr_len = 0; 760 res = (caddr_t)&failed_res; 761 res_size = 0; 762 break; 763 } 764 765 autofs_mntinfo_1_r((autofs_lookupargs *)xdrargs, &mount_res); 766 767 autofs_lookup_1_free_args(xdrargs); 768 free(xdrargs); 769 770 /* 771 * Only reason we would get a NULL res is because 772 * we could not allocate a results buffer. Use 773 * a local one to return the error EAGAIN as has 774 * always been done when memory allocations fail. 775 */ 776 if (!encode_res(xdr_autofs_mountres, &door_res, 777 (caddr_t)&mount_res, &res_size)) { 778 syslog(LOG_ERR, 779 "error allocating mount results buffer"); 780 failed_res.res_status = EAGAIN; 781 failed_res.xdr_len = 0; 782 res = (caddr_t)&failed_res; 783 } else { 784 door_res->res_status = 0; 785 res = (caddr_t)door_res; 786 } 787 autofs_mount_1_free_r(&mount_res); 788 break; 789 790 case AUTOFS_UNMOUNT: 791 if (error = decode_args(xdr_umntrequest, 792 (autofs_door_args_t *)argp, 793 (caddr_t *)&umnt_args, sizeof (umntrequest))) { 794 syslog(LOG_ERR, 795 "error allocating unmount argument buffer"); 796 failed_res.res_status = error; 797 failed_res.xdr_len = 0; 798 res = (caddr_t)&failed_res; 799 res_size = sizeof (autofs_door_res_t); 800 break; 801 } 802 803 autofs_unmount_1_r(umnt_args, &umount_res); 804 805 error = umount_res.status; 806 807 autofs_unmount_1_free_args(umnt_args); 808 free(umnt_args); 809 810 if (!encode_res(xdr_umntres, &door_res, (caddr_t)&umount_res, 811 &res_size)) { 812 syslog(LOG_ERR, 813 "error allocating unmount results buffer"); 814 failed_res.res_status = EINVAL; 815 failed_res.xdr_len = 0; 816 res = (caddr_t)&failed_res; 817 res_size = sizeof (autofs_door_res_t); 818 } else { 819 door_res->res_status = 0; 820 res = (caddr_t)door_res; 821 } 822 break; 823 824 case AUTOFS_READDIR: 825 if (error = decode_args(xdr_autofs_rddirargs, 826 (autofs_door_args_t *)argp, 827 (caddr_t *)&rddir_args, 828 sizeof (autofs_rddirargs))) { 829 syslog(LOG_ERR, 830 "error allocating readdir argument buffer"); 831 failed_res.res_status = error; 832 failed_res.xdr_len = 0; 833 res = (caddr_t)&failed_res; 834 res_size = sizeof (autofs_door_res_t); 835 break; 836 } 837 838 autofs_readdir_1_r(rddir_args, &rddir_res); 839 840 free(rddir_args->rda_map); 841 free(rddir_args); 842 843 if (!encode_res(xdr_autofs_rddirres, &door_res, 844 (caddr_t)&rddir_res, &res_size)) { 845 syslog(LOG_ERR, 846 "error allocating readdir results buffer"); 847 failed_res.res_status = ENOMEM; 848 failed_res.xdr_len = 0; 849 res = (caddr_t)&failed_res; 850 res_size = sizeof (autofs_door_res_t); 851 } else { 852 door_res->res_status = 0; 853 res = (caddr_t)door_res; 854 } 855 autofs_readdir_1_free_r(&rddir_res); 856 break; 857 #ifdef MALLOC_DEBUG 858 case AUTOFS_DUMP_DEBUG: 859 check_leaks("/var/tmp/automountd.leak"); 860 error = door_return(NULL, 0, NULL, 0); 861 /* 862 * If we got here, door_return() failed 863 */ 864 syslog(LOG_ERR, "dump debug door_return failure %d", 865 error); 866 return; 867 #endif 868 case NULLPROC: 869 res = NULL; 870 res_size = 0; 871 break; 872 default: 873 failed_res.res_status = EINVAL; 874 res = (char *)&failed_res; 875 res_size = sizeof (autofs_door_res_t); 876 break; 877 } 878 879 srsz = res_size; 880 errno = 0; 881 error = door_return(res, res_size, NULL, 0); 882 883 if (errno == E2BIG) { 884 /* 885 * Failed due to encoded results being bigger than the 886 * kernel expected bufsize. Passing actual results size 887 * back down to kernel. 888 */ 889 failed_res.res_status = EOVERFLOW; 890 failed_res.xdr_len = srsz; 891 res = (caddr_t)&failed_res; 892 res_size = sizeof (autofs_door_res_t); 893 } else { 894 syslog(LOG_ERR, "door_return failed %d, buffer %p, " 895 "buffer size %d", error, (void *)res, res_size); 896 res = NULL; 897 res_size = 0; 898 } 899 (void) door_return(res, res_size, NULL, 0); 900 /* NOTREACHED */ 901 } 902 903 static int 904 start_autofs_svcs(void) 905 { 906 int doorfd; 907 #ifdef DEBUG 908 int dfd; 909 #endif 910 911 if ((doorfd = door_create(autofs_doorfunc, NULL, 912 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 913 syslog(LOG_ERR, gettext("Unable to create door\n")); 914 return (1); 915 } 916 917 #ifdef DEBUG 918 /* 919 * Create a file system path for the door 920 */ 921 if ((dfd = open(AUTOFS_DOOR, O_RDWR|O_CREAT|O_TRUNC, 922 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { 923 syslog(LOG_ERR, "Unable to open %s: %m\n", AUTOFS_DOOR); 924 (void) close(doorfd); 925 return (1); 926 } 927 928 /* 929 * stale associations clean up 930 */ 931 (void) fdetach(AUTOFS_DOOR); 932 933 /* 934 * Register in the namespace to the kernel to door_ki_open. 935 */ 936 if (fattach(doorfd, AUTOFS_DOOR) == -1) { 937 syslog(LOG_ERR, "Unable to fattach door %m\n", AUTOFS_DOOR); 938 (void) close(dfd); 939 (void) close(doorfd); 940 return (1); 941 } 942 #endif /* DEBUG */ 943 944 /* 945 * Pass door name to kernel for door_ki_open 946 */ 947 autofs_setdoor(doorfd); 948 949 (void) thr_keycreate(&s_thr_key, NULL); 950 951 /* 952 * Wait for incoming calls 953 */ 954 /*CONSTCOND*/ 955 while (1) 956 (void) pause(); 957 958 /* NOTREACHED */ 959 syslog(LOG_ERR, gettext("Door server exited")); 960 return (10); 961 } 962 963 static int 964 decode_args( 965 xdrproc_t xdrfunc, 966 autofs_door_args_t *argp, 967 caddr_t *xdrargs, 968 int size) 969 { 970 XDR xdrs; 971 972 caddr_t tmpargs = (caddr_t)&((autofs_door_args_t *)argp)->xdr_arg; 973 size_t arg_size = ((autofs_door_args_t *)argp)->xdr_len; 974 975 xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE); 976 977 *xdrargs = malloc(size); 978 if (*xdrargs == NULL) { 979 syslog(LOG_ERR, "error allocating arguments buffer"); 980 return (ENOMEM); 981 } 982 983 bzero(*xdrargs, size); 984 985 if (!(*xdrfunc)(&xdrs, *xdrargs)) { 986 free(*xdrargs); 987 *xdrargs = NULL; 988 syslog(LOG_ERR, "error decoding arguments"); 989 return (EINVAL); 990 } 991 992 return (0); 993 } 994 995 996 static bool_t 997 encode_res( 998 xdrproc_t xdrfunc, 999 autofs_door_res_t **results, 1000 caddr_t resp, 1001 int *size) 1002 { 1003 XDR xdrs; 1004 1005 *size = xdr_sizeof((*xdrfunc), resp); 1006 *results = autofs_get_buffer( 1007 sizeof (autofs_door_res_t) + *size); 1008 if (*results == NULL) { 1009 (*results)->res_status = ENOMEM; 1010 return (FALSE); 1011 } 1012 (*results)->xdr_len = *size; 1013 *size = sizeof (autofs_door_res_t) + (*results)->xdr_len; 1014 xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res), 1015 (*results)->xdr_len, XDR_ENCODE); 1016 if (!(*xdrfunc)(&xdrs, resp)) { 1017 (*results)->res_status = EINVAL; 1018 syslog(LOG_ERR, "error encoding results"); 1019 return (FALSE); 1020 } 1021 (*results)->res_status = 0; 1022 return (TRUE); 1023 } 1024 1025 static void 1026 automountd_wait_for_cleanup(pid_t pid) 1027 { 1028 int status; 1029 int child_exitval; 1030 1031 /* 1032 * Wait for the main automountd process to exit so we cleanup 1033 */ 1034 (void) waitpid(pid, &status, 0); 1035 1036 child_exitval = WEXITSTATUS(status); 1037 1038 /* 1039 * Shutdown the door server for mounting and unmounting 1040 * filesystems 1041 */ 1042 if (door_revoke(did_fork_exec) == -1) { 1043 syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_fork_exec); 1044 } 1045 if (door_revoke(did_exec_map) == -1) { 1046 syslog(LOG_ERR, "failed to door_revoke(%d) %m", did_exec_map); 1047 } 1048 exit(child_exitval); 1049 } 1050