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