xref: /titanic_51/usr/src/cmd/fs.d/autofs/autod_main.c (revision fd715b005074c2741c17a3048ee8945b913a2ff6)
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