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