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