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
main(argc,argv)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
warn_hup(i)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
usage()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
autofs_readdir_1_r(autofs_rddirargs * req,autofs_rddirres * res)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
autofs_readdir_1_free_r(struct autofs_rddirres * res)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
autofs_unmount_1_r(umntrequest * m,umntres * res)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
autofs_lookup_1_r(autofs_lookupargs * m,autofs_lookupres * res)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
autofs_mntinfo_1_r(autofs_lookupargs * m,autofs_mountres * res)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
autofs_mount_1_free_r(struct autofs_mountres * res)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
pr_msg(const char * fmt,...)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
free_action_list(action_list * alp)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
autofs_lookup_1_free_args(autofs_lookupargs * args)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
autofs_unmount_1_free_args(umntrequest * args)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
autofs_setdoor(int did)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 *
autofs_get_buffer(size_t size)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
autofs_doorfunc(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
start_autofs_svcs(void)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
decode_args(xdrproc_t xdrfunc,autofs_door_args_t * argp,caddr_t * xdrargs,int size)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
encode_res(xdrproc_t xdrfunc,autofs_door_res_t ** results,caddr_t resp,int * size)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
automountd_wait_for_cleanup(pid_t pid)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