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