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