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