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