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