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