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