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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Portions Copyright 2007-2013 Apple Inc.
29 */
30
31#pragma ident	"@(#)autod_main.c	1.69	05/06/08 SMI"
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <signal.h>
37#include <fcntl.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <sys/ioctl.h>
41#include <stdarg.h>
42#include <sys/resource.h>
43#include <syslog.h>
44#include <errno.h>
45#include <string.h>
46#include <pthread.h>
47#include <locale.h>
48#include <vproc.h>
49#include <assert.h>
50#include <mach/mach.h>
51#include <servers/bootstrap.h>
52
53#include "automount.h"
54#include "automountd.h"
55#include "autofs_protServer.h"
56#include <arpa/inet.h>
57#include "deflt.h"
58#include <strings.h>
59#include "sysctl_fsid.h"
60
61#define MAXVAL(a, b)	((a) > (b) ? (a) : (b))
62#define AUTOFS_MAX_MSG_SIZE \
63	MAXVAL(sizeof (union __RequestUnion__autofs_subsystem), \
64	    sizeof (union __ReplyUnion__autofs_subsystem))
65
66static void usage(void);
67static void *automount_thread(void *);
68static void new_worker_thread(void);
69static void compute_new_timeout(struct timespec *);
70static void *shutdown_thread(void *);
71static void *timeout_thread(void *);
72static void *wait_for_flush_indication_thread(void *);
73static int do_mount_subtrigger(autofs_pathname, autofs_pathname,
74    autofs_pathname, autofs_opts, autofs_pathname, autofs_pathname,
75    autofs_component, uint32_t, uint32_t, int32_t, fsid_t *, boolean_t *);
76
77/*
78 * XXX - this limit is the same as Solaris, although we don't have the
79 * System V binary compatibility problem that limits their standard
80 * I/O library to a maximum of 256 FILE *'s.  (Now why that affects
81 * their automounter is another question....)
82 */
83#define	MAXTHREADS 64
84#define	SHUTDOWN_TIMEOUT  2     /* timeout gets set to this after TERM signal */
85#define	TIMEOUT RDDIR_CACHE_TIME  /* Hang around if caches might be valid */
86#define	APPLE_PREFIX  "com.apple." /* Bootstrap name prefix */
87#define	MAXLABEL	256	/* Max bootstrap name */
88
89static pthread_mutex_t numthreads_lock;
90static pthread_cond_t numthreads_cv;
91static int numthreads;
92static pthread_attr_t attr;	/* To create detached threads */
93static vproc_transaction_t vproc_transaction;
94static time_t timeout = TIMEOUT; /* Seconds to wait before exiting */
95static int bye = 0;		/* Force clean shutdown flag. */
96
97static sigset_t waitset;	/* Signals that we wait for */
98static sigset_t contset;	/* Signals that we don't exit from */
99
100static mach_port_t service_port_receive_right;
101
102static int autofs_fd;
103
104#define	RESOURCE_FACTOR 8
105
106struct autodir *dir_head;
107struct autodir *dir_tail;
108
109time_t timenow;
110int verbose = 0;
111int trace = 0;
112int automountd_nobrowse = 0;
113int automountd_nosuid = TRUE;
114char *automountd_defopts = NULL;
115
116/*
117 * This daemon is to be started by launchd, as such it follows the following
118 * launchd rules:
119 *	We don't:
120 *		call daemon(3)
121 *		call fork and having the parent process exit
122 *		change uids or gids.
123 *		set up the current working directory or chroot.
124 *		set the session id
125 *		change stdio to /dev/null.
126 *		call setrusage(2)
127 *		call setpriority(2)
128 *		Ignore SIGTERM.
129 *	We are launched on demand
130 *		and we catch SIGTERM and use vproc_transactions to exit cleanly.
131 *
132 * In practice daemonizing in the classic unix sense would probably be ok
133 * since we get invoked by traffic on a task_special_port, but we will play
134 * by the rules; it's even easier, to boot.
135 */
136
137
138int
139main(argc, argv)
140	int argc;
141	char *argv[];
142
143{
144	int c, error;
145	kern_return_t ret;
146	pthread_t thread, timeout_thr, shutdown_thr;
147	char *defval;
148	int defflags;
149	char bname[MAXLABEL] = { APPLE_PREFIX };
150	char *myname;
151
152	/*
153	 * If launchd is redirecting these two files they'll be block-
154	 * buffered, as they'll be pipes, or some other such non-tty,
155	 * sending data to launchd. Probably not what you want.
156	 */
157	setlinebuf(stdout);
158	setlinebuf(stderr);
159
160	/* Figure out our bootstrap name based on what we are called. */
161
162	myname = strrchr(argv[0], '/');
163	myname = myname ? myname + 1 : argv[0];
164	strlcat(bname, myname, sizeof(bname));
165
166	/*
167	 * Read in the values from config file first before we check
168	 * commandline options so the options override the file.
169	 */
170	if ((defopen(AUTOFSADMIN)) == 0) {
171		if ((defval = defread("AUTOMOUNTD_VERBOSE=")) != NULL) {
172			if (strncasecmp("true", defval, 4) == 0)
173				verbose = TRUE;
174			else
175				verbose = FALSE;
176		}
177		if ((defval = defread("AUTOMOUNTD_NOBROWSE=")) != NULL) {
178			if (strncasecmp("true", defval, 4) == 0)
179				automountd_nobrowse = TRUE;
180			else
181				automountd_nobrowse = FALSE;
182		}
183		if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) {
184			errno = 0;
185			trace = (int)strtol(defval, (char **)NULL, 10);
186			if (errno != 0)
187				trace = 0;
188		}
189		if ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) {
190			(void) putenv(strdup(defval));
191			defflags = defcntl(DC_GETFLAGS, 0);
192			TURNON(defflags, DC_NOREWIND);
193			defflags = defcntl(DC_SETFLAGS, defflags);
194			while ((defval = defread("AUTOMOUNTD_ENV=")) != NULL)
195				(void) putenv(strdup(defval));
196			(void) defcntl(DC_SETFLAGS, defflags);
197		}
198		if ((defval = defread("AUTOMOUNTD_MNTOPTS=")) != NULL
199		    && *defval != '\0') {
200			automountd_defopts = strdup(defval);
201			if (automountd_defopts == NULL) {
202				syslog(LOG_ERR, "Memory allocation failed: %m");
203				exit(2);
204			}
205		}
206		if ((defval = defread("AUTOMOUNTD_NOSUID=")) != NULL) {
207			if (strncasecmp("true", defval, 4) == 0)
208				automountd_nosuid = TRUE;
209			else
210				automountd_nosuid = FALSE;
211		}
212
213		/* close defaults file */
214		defopen(NULL);
215	}
216
217	while ((c = getopt(argc, argv, "vnTo:D:")) != EOF) {
218		switch (c) {
219		case 'v':
220			verbose++;
221			break;
222		case 'n':
223			automountd_nobrowse++;
224			break;
225		case 'T':
226			trace++;
227			break;
228		case 'o':
229			if (automountd_defopts != NULL)
230				free(automountd_defopts);
231			automountd_defopts = strdup(optarg);
232			break;
233		case 'D':
234			(void) putenv(optarg);
235			break;
236		default:
237			usage();
238		}
239	}
240
241	openlog(myname, LOG_PID, LOG_DAEMON);
242	(void) setlocale(LC_ALL, "");
243
244	if (trace > 0)
245		trace_prt(1, "%s running", myname);
246
247	/*
248	 * This is platform-dependent; for now, we just say
249	 * "macintosh" - I guess we could do something to
250	 * distinguish x86 from PowerPC.
251	 */
252	if (getenv("ARCH") == NULL)
253		(void) putenv("ARCH=macintosh");
254	if (getenv("CPU") == NULL) {
255#if defined(__ppc__)
256		(void) putenv("CPU=powerpc");
257#elif defined(__i386__) || defined(__x86_64__)
258		/*
259		 * At least on Solaris, "CPU" appears to be the
260		 * narrowest ISA the machine supports, with
261		 * "NATISA" being the widest, so "CPU" is "i386"
262		 * even on x86-64.
263		 */
264		(void) putenv("CPU=i386");
265#else
266#error "can't determine processor type");
267#endif
268	}
269
270	/*
271	 * We catch
272	 *
273	 *	SIGINT - if we get one, we just drive on;
274	 *	SIGHUP - if we get one, we log a message
275	 *		 so the user knows that it doesn't
276	 *		 do anything useful, and drive on;
277	 *	SIGTERM - we quit.
278	 */
279	sigemptyset(&waitset);
280	sigaddset(&waitset, SIGINT);
281	sigaddset(&waitset, SIGHUP);
282	contset = waitset;
283	sigaddset(&waitset, SIGTERM);
284	pthread_sigmask(SIG_BLOCK, &waitset, NULL);
285
286	/*
287	 * We create most threads as detached threads, so any Mach
288	 * resources they have are reclaimed when they terminate.
289	 */
290	(void) pthread_attr_init(&attr);
291	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
292
293	(void) pthread_mutex_init(&numthreads_lock, NULL);
294	(void) pthread_cond_init(&numthreads_cv, NULL);
295	(void) pthread_rwlock_init(&cache_lock, NULL);
296	(void) pthread_rwlock_init(&rddir_cache_lock, NULL);
297
298	/*
299	 * initialize the name services, use NULL arguments to ensure
300	 * we don't initialize the stack of files used in file service
301	 *
302	 * XXX - do we need to do something equivalent here?
303	 */
304#if 0
305	(void) ns_setup(NULL, NULL);
306#endif
307
308	/*
309	 * Attempt to open the autofs device to establish ourselves
310	 * as an automounter;
311	 *
312	 * We hold it open as long as we're running; if we exit,
313	 * that'll close it, so autofs will forget that we were
314	 * the automounter.
315	 *
316	 * This device also delivers notifications that we should
317	 * flush our caches.
318	 */
319	autofs_fd = open("/dev/" AUTOFS_DEVICE, O_RDONLY);
320	if (autofs_fd == -1) {
321		syslog(LOG_ERR, "Can't open /dev/autofs: %s",
322		    strerror(errno));
323		exit(2);
324	}
325
326	/*
327	 * Check in with launchd to get the receive right.
328	 * N.B. Since we're using a task special port, if launchd
329	 * does not have the receive right we can't get it.
330	 * And since we should always be started by launchd
331	 * this should always succeed.
332	 */
333	ret = bootstrap_check_in(bootstrap_port, bname, &service_port_receive_right);
334	if (ret != BOOTSTRAP_SUCCESS) {
335		syslog(LOG_ERR, "Could not get receive right for %s: %s (%d)\n",
336				bname, bootstrap_strerror(ret), ret);
337		exit(EXIT_FAILURE);
338	}
339
340	/* Create signal handling thread */
341	error = pthread_create(&shutdown_thr, &attr, shutdown_thread, NULL);
342	if (error) {
343		syslog(LOG_ERR, "unable to create shutdown thread: %s", strerror(error));
344		exit(EXIT_FAILURE);
345	}
346
347	/* Create time out thread */
348	error = pthread_create(&timeout_thr, NULL, timeout_thread, NULL);
349	if (error) {
350		syslog(LOG_ERR, "unable to create time out thread: %s", strerror(error));
351		exit(EXIT_FAILURE);
352	}
353
354	/*
355	 * Create cache_cleanup thread
356	 */
357	error = pthread_create(&thread, &attr, cache_cleanup, NULL);
358	if (error) {
359		syslog(LOG_ERR, "unable to create cache_cleanup thread: %s",
360		    strerror(error));
361		exit(1);
362	}
363
364	/*
365	 * Create wait-for-cache-flush-indication thread.
366	 */
367	error = pthread_create(&thread, &attr, wait_for_flush_indication_thread,
368	    NULL);
369	if (error) {
370		syslog(LOG_ERR, "unable to create wait-for-flush-indication thread: %s",
371		    strerror(error));
372		exit(1);
373	}
374
375	/*
376	 * Start a worker thread to listen for a message.
377	 * Then just spin.
378	 *
379	 * This is a bit ugly.  If there were a version of mach_msg_server()
380	 * that spun off a thread before calling the dispatch routine,
381	 * and had that thread handle the message, we could have this
382	 * thread run that routine, with workers created as messages arrive.
383	 */
384	new_worker_thread();
385
386	/* Wait for time out */
387	pthread_join(timeout_thr, NULL);
388
389	pthread_attr_destroy(&attr);
390
391	/*
392	 * Wake up the "wait for flush indication" thread.
393	 */
394	if (ioctl(autofs_fd, AUTOFS_NOTIFYCHANGE, 0) == -1)
395		pr_msg("AUTOFS_NOTIFYCHANGE failed: %m");
396
397	if (trace > 0)
398		trace_prt(1, "%s exited", myname);
399
400	return (EXIT_SUCCESS);
401}
402
403static void
404usage(void)
405{
406	(void) fprintf(stderr, "Usage: automountd\n"
407		"\t[-o opts]\t\t(default mount options)\n"
408		"\t[-T]\t\t(trace requests)\n"
409		"\t[-v]\t\t(verbose error msgs)\n"
410		"\t[-D n=s]\t(define env variable)\n");
411	exit(1);
412	/* NOTREACHED */
413}
414
415/*
416 * Receive one message and process it.
417 */
418static void *
419automount_thread(__unused void *arg)
420{
421	kern_return_t ret;
422
423	pthread_setname_np("upcall receiver");
424	ret = mach_msg_server_once(autofs_server, AUTOFS_MAX_MSG_SIZE,
425	    service_port_receive_right,
426	    MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
427	if (ret != KERN_SUCCESS) {
428		syslog(LOG_ERR, "automounter mach_msg_server_once failed: %s",
429		    mach_error_string(ret));
430	}
431	return NULL;
432}
433
434/*
435 * Wait until we have fewer than the maximum number of worker threads,
436 * and then create one running automount_thread().
437 *
438 * Called by the dispatch routines just before processing a message,
439 * so we're listening for messages even while processing a message,
440 * as long as we aren't out of threads.
441 */
442static void
443new_worker_thread(void)
444{
445	pthread_t thread;
446	int error;
447
448	(void) pthread_mutex_lock(&numthreads_lock);
449	while (bye == 0 && numthreads >= MAXTHREADS)
450		(void) pthread_cond_wait(&numthreads_cv, &numthreads_lock);
451	if (bye)
452		goto out;
453	numthreads++;
454	error = pthread_create(&thread, &attr, automount_thread, NULL);
455	if (error) {
456		syslog(LOG_ERR, "unable to create worker thread: %s",
457		    strerror(error));
458		numthreads--;
459	}
460	if (numthreads == 2)
461		vproc_transaction = vproc_transaction_begin(NULL);
462out:
463	(void) pthread_mutex_unlock(&numthreads_lock);
464}
465
466/*
467 * This worker thread is terminating; reduce the count of worker threads,
468 * and, if it's dropped below the maximum, wake up anybody waiting for
469 * it to drop below the maximum.
470 *
471 * Called by the dispatch routines just before returning.
472 */
473static void
474end_worker_thread(void)
475{
476	(void) pthread_mutex_lock(&numthreads_lock);
477	numthreads--;
478	if (numthreads == 1)
479		vproc_transaction_end(NULL, vproc_transaction);
480	if (numthreads < MAXTHREADS)
481		pthread_cond_signal(&numthreads_cv);
482	(void) pthread_mutex_unlock(&numthreads_lock);
483}
484
485/*
486 * Thread that handles signals for us and will tell the timeout thread to
487 * shut us down if we get a signal that we don't continue for. We set a global
488 * variable bye and the timeout value to SHUTDOWN_TIMEOUT and wake every
489 * body up. Threads blocked in new_worker_thread will see bye is set and exit.
490 * We set timeout to SHUTDOWN_TIMEOUT for the timeout thread, so that threads
491 * executing dispatch routines have an opportunity to finish.
492 *
493 * If there are no worker threads running, as indicated by vproc_transaction
494 * then launchd will signal with SIGKILL instead of SIGTERM so we'll exit
495 * immediately rather than wait for the shutdown timeout.
496 */
497static void*
498shutdown_thread(__unused void *arg)
499{
500	int sig;
501
502	pthread_setname_np("shutdown");
503	do {
504		sigwait(&waitset, &sig);
505		switch (sig) {
506		case SIGHUP:
507			/*
508			 * The old automounter supported a SIGHUP
509			 * to allow it to resynchronize internal
510			 * state with the /etc/mnttab.
511			 * This is no longer relevant, but we
512			 * need to catch the signal and warn
513			 * the user.
514			 */
515
516			syslog(LOG_ERR, "SIGHUP received: ignored");
517			break;
518		}
519	} while (sigismember(&contset, sig));
520
521	pthread_mutex_lock(&numthreads_lock);
522	bye = 1;
523	/*
524	 * Wait a little bit for dispatch threads to complete.
525	 */
526	timeout = SHUTDOWN_TIMEOUT;
527	/*
528	 * Force the timeout_thread and all the rest to to wake up and exit.
529	 */
530	pthread_cond_broadcast(&numthreads_cv);
531	pthread_mutex_unlock(&numthreads_lock);
532
533	return (NULL);
534}
535
536static void
537compute_new_timeout(struct timespec *new)
538{
539	struct timeval current;
540
541	gettimeofday(&current, NULL);
542	new->tv_sec = current.tv_sec + timeout;
543	new->tv_nsec = 1000 * current.tv_usec;
544}
545
546static void*
547timeout_thread(__unused void *arg)
548{
549	int rv = 0;
550	struct timespec exittime;
551
552	pthread_setname_np("timeout");
553	(void) pthread_mutex_lock(&numthreads_lock);
554
555	/*
556	 * Wait until the timer given to pthread_cond_timedwait()
557	 * expires (which causes it to return ETIMEDOUT rather
558	 * than 0) and we have no worker threads running, or
559	 * until bye was set to 1 by the shutdown thread (telling
560	 * us to terminate) and the timer expires (we shut down
561	 * after SHUTDOWN_TIMEOUT in that case).
562	 */
563	while ((rv == 0 || numthreads > 1) && bye < 2) {
564		compute_new_timeout(&exittime);
565		/*
566		 * If the shutdown thread has told us to exit (bye == 1),
567		 * then increment bye so that we will exit after
568		 * SHUTDOWN_TIMEOUT.
569		 */
570		if (bye)
571			bye++;
572		rv = pthread_cond_timedwait(&numthreads_cv,
573					&numthreads_lock, &exittime);
574	}
575
576	(void) pthread_mutex_unlock(&numthreads_lock);
577
578	return (NULL);
579}
580
581static void *
582wait_for_flush_indication_thread(__unused void *arg)
583{
584	/*
585	 * This thread waits for an indication that we should flush
586	 * our caches.  It quits if bye >= 1, meaning we're shutting
587	 * down.
588	 */
589	pthread_setname_np("wait for flush indication");
590	for (;;) {
591		/*
592		 * Check whether we're shutting down.
593		 */
594		pthread_mutex_lock(&numthreads_lock);
595		if (bye >= 1) {
596			pthread_mutex_unlock(&numthreads_lock);
597			break;
598		}
599		pthread_mutex_unlock(&numthreads_lock);
600
601		if (ioctl(autofs_fd, AUTOFS_WAITFORFLUSH, 0) == -1) {
602			if (errno != EINTR) {
603				syslog(LOG_ERR,
604				    "AUTOFS_WAITFORFLUSH failed: %s",
605				    strerror(errno));
606			}
607		} else
608			flush_caches();
609	}
610	return (NULL);
611}
612
613kern_return_t
614autofs_readdir(__unused mach_port_t server, autofs_pathname rda_map,
615    int64_t rda_offset, uint32_t rda_count, int *status, int64_t *rddir_offset,
616    boolean_t *rddir_eof, byte_buffer *rddir_entries,
617    mach_msg_type_number_t *rddir_entriesCnt, security_token_t token)
618{
619	new_worker_thread();
620
621	pthread_setname_np("readdir worker");
622
623	/*
624	 * Reject this if the sender wasn't root
625	 * (all messages from the kernel will be from root).
626	 */
627	if (token.val[0] != 0) {
628		*status  = EPERM;
629		end_worker_thread();
630		return KERN_SUCCESS;
631	}
632
633	if (trace > 0)
634		trace_prt(1, "READDIR REQUEST   : %s @ %llu\n", rda_map, rda_offset);
635
636	*status = do_readdir(rda_map, rda_offset, rda_count, rddir_offset,
637	    rddir_eof, rddir_entries, rddir_entriesCnt);
638
639	if (trace > 0)
640		trace_prt(1, "READDIR REPLY	: status=%d\n", *status);
641
642	end_worker_thread();
643
644	return KERN_SUCCESS;
645}
646
647kern_return_t
648autofs_readsubdir(__unused mach_port_t server, autofs_pathname rda_map,
649    autofs_component rda_name, mach_msg_type_number_t rda_nameCnt,
650    autofs_pathname rda_subdir, autofs_opts rda_mntopts,
651    uint32_t rda_parentino, int64_t rda_offset, uint32_t rda_count,
652    int *status, int64_t *rddir_offset, boolean_t *rddir_eof,
653    byte_buffer *rddir_entries, mach_msg_type_number_t *rddir_entriesCnt,
654    security_token_t token)
655{
656	char *key;
657
658	new_worker_thread();
659
660	/*
661	 * Reject this if the sender wasn't root
662	 * (all messages from the kernel will be from root).
663	 */
664	if (token.val[0] != 0) {
665		*status  = EPERM;
666		end_worker_thread();
667		return KERN_SUCCESS;
668	}
669
670	/*
671	 * The name component is a counted string; make a
672	 * null-terminated string out of it.
673	 */
674	if (rda_nameCnt < 1 || rda_nameCnt > MAXNAMLEN) {
675		*status = ENOENT;
676		end_worker_thread();
677		return KERN_SUCCESS;
678	}
679	key = malloc(rda_nameCnt + 1);
680	if (key == NULL) {
681		*status = ENOMEM;
682		end_worker_thread();
683		return KERN_SUCCESS;
684	}
685	memcpy(key, rda_name, rda_nameCnt);
686	key[rda_nameCnt] = '\0';
687
688	if (trace > 0)
689		trace_prt(1, "READSUBDIR REQUEST : name=%s[%s] map=%s @ %llu\n",
690		key, rda_subdir, rda_map, rda_offset);
691
692	*status = do_readsubdir(rda_map, key, rda_subdir, rda_mntopts,
693	    rda_parentino, rda_offset, rda_count, rddir_offset, rddir_eof,
694	    rddir_entries, rddir_entriesCnt);
695	free(key);
696
697	if (trace > 0)
698		trace_prt(1, "READSUBDIR REPLY   : status=%d\n", *status);
699
700	end_worker_thread();
701
702	return KERN_SUCCESS;
703}
704
705kern_return_t
706autofs_unmount(__unused mach_port_t server, fsid_t mntpnt_fsid,
707    autofs_pathname mntresource, autofs_pathname mntpnt,
708    autofs_component fstype, autofs_opts mntopts, int *status,
709    security_token_t token)
710{
711	new_worker_thread();
712
713	pthread_setname_np("unmount worker");
714
715	/*
716	 * Reject this if the sender wasn't root
717	 * (all messages from the kernel will be from root).
718	 */
719	if (token.val[0] != 0) {
720		*status  = EPERM;
721		end_worker_thread();
722		return KERN_SUCCESS;
723	}
724
725	if (trace > 0) {
726		trace_prt(1, "UNMOUNT REQUEST: resource=%s fstype=%s mntpnt=%s mntopts=%s\n",
727			mntresource, fstype, mntpnt, mntopts);
728	}
729
730	*status = do_unmount1(mntpnt_fsid, mntresource, mntpnt, fstype,
731	    mntopts);
732
733	if (trace > 0)
734		trace_prt(1, "UNMOUNT REPLY: status=%d\n", *status);
735
736	end_worker_thread();
737
738	return KERN_SUCCESS;
739}
740
741kern_return_t
742autofs_lookup(__unused mach_port_t server, autofs_pathname map,
743    autofs_pathname path, autofs_component name, mach_msg_type_number_t nameCnt,
744    autofs_pathname subdir, autofs_opts opts, boolean_t isdirect,
745    uint32_t sendereuid, int *err, int *node_type, boolean_t *lu_verbose,
746    security_token_t token)
747{
748	char *key;
749
750	new_worker_thread();
751
752	pthread_setname_np("lookup worker");
753
754	/*
755	 * Reject this if the sender wasn't root
756	 * (all messages from the kernel will be from root).
757	 */
758	if (token.val[0] != 0) {
759		*err = EPERM;
760		*node_type = 0;
761		*lu_verbose = 0;
762		end_worker_thread();
763		return KERN_SUCCESS;
764	}
765
766	/*
767	 * The name component is a counted string; make a
768	 * null-terminated string out of it.
769	 */
770	if (nameCnt < 1 || nameCnt > MAXNAMLEN) {
771		*err = ENOENT;
772		*node_type = 0;
773		*lu_verbose = 0;
774		end_worker_thread();
775		return KERN_SUCCESS;
776	}
777	key = malloc(nameCnt + 1);
778	if (key == NULL) {
779		*err = ENOMEM;
780		*node_type = 0;
781		*lu_verbose = 0;
782		end_worker_thread();
783		return KERN_SUCCESS;
784	}
785	memcpy(key, name, nameCnt);
786	key[nameCnt] = '\0';
787
788	if (trace > 0) {
789		trace_prt(1, "LOOKUP REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d uid=%u\n",
790			key, subdir, map, opts, path, isdirect, sendereuid);
791	}
792
793	*err = do_lookup1(map, key, subdir, opts, isdirect, sendereuid,
794	    node_type);
795	*lu_verbose = verbose;
796	free(key);
797
798	if (trace > 0)
799		trace_prt(1, "LOOKUP REPLY  : status=%d\n", *err);
800
801	end_worker_thread();
802
803	return KERN_SUCCESS;
804}
805
806kern_return_t
807autofs_mount(__unused mach_port_t server, autofs_pathname map,
808    autofs_pathname path, autofs_component name, mach_msg_type_number_t nameCnt,
809    autofs_pathname subdir, autofs_opts opts, boolean_t isdirect,
810    boolean_t issubtrigger, fsid_t mntpnt_fsid, uint32_t sendereuid,
811    int32_t asid, int *mr_type, fsid_t *fsidp, uint32_t *retflags,
812    byte_buffer *actions, mach_msg_type_number_t *actionsCnt, int *err,
813    boolean_t *mr_verbose, security_token_t token)
814{
815	char *key;
816	int status;
817	static time_t prevmsg = 0;
818
819	new_worker_thread();
820
821	pthread_setname_np("mount worker");
822
823	*retflags = 0;	/* what we call sets retflags as needed */
824
825	/*
826	 * Reject this if the sender wasn't root
827	 * (all messages from the kernel will be from root).
828	 */
829	if (token.val[0] != 0) {
830		*mr_type = AUTOFS_DONE;
831		*err  = EPERM;
832		*mr_verbose = 0;
833		end_worker_thread();
834		return KERN_SUCCESS;
835	}
836
837	/*
838	 * The name component is a counted string; make a
839	 * null-terminated string out of it.
840	 */
841	if (nameCnt < 1 || nameCnt > MAXNAMLEN) {
842		*mr_type = AUTOFS_DONE;
843		*err = ENOENT;
844		*mr_verbose = 0;
845		end_worker_thread();
846		return KERN_SUCCESS;
847	}
848	key = malloc(nameCnt + 1);
849	if (key == NULL) {
850		*mr_type = AUTOFS_DONE;
851		*err = ENOMEM;
852		*mr_verbose = 0;
853		end_worker_thread();
854		return KERN_SUCCESS;
855	}
856	memcpy(key, name, nameCnt);
857	key[nameCnt] = '\0';
858
859	if (trace > 0) {
860		trace_prt(1, "MOUNT  REQUEST: name=%s [%s] map=%s opts=%s path=%s direct=%d\n",
861			key, subdir, map, opts, path, isdirect);
862	}
863
864	status = do_mount1(map, key, subdir, opts, path, isdirect,
865	    issubtrigger, mntpnt_fsid, sendereuid, asid, fsidp,
866	    retflags, actions, actionsCnt);
867
868	if (status == 0 && *actionsCnt != 0)
869		*mr_type = AUTOFS_ACTION;
870	else
871		*mr_type = AUTOFS_DONE;
872
873	*err = status;
874	*mr_verbose = verbose;
875
876	if (trace > 0) {
877		switch (*mr_type) {
878		case AUTOFS_ACTION:
879			trace_prt(1, "MOUNT  REPLY  : status=%d, AUTOFS_ACTION\n", status);
880			break;
881		case AUTOFS_DONE:
882			trace_prt(1, "MOUNT  REPLY  : status=%d, AUTOFS_DONE\n", status);
883			break;
884		default:
885			trace_prt(1, "MOUNT  REPLY  : status=%d, UNKNOWN\n", status);
886		}
887	}
888
889	/*
890	 * Report a failed mount.
891	 * Failed mounts can come in bursts of dozens of
892	 * these messages - so limit to one in 5 sec interval.
893	 */
894	if (status && prevmsg < time((time_t) NULL)) {
895		prevmsg = time((time_t) NULL) + 5;
896		if (isdirect) {
897			/* direct mount */
898			syslog(LOG_ERR, "mount of %s%s failed: %s", path,
899				issubtrigger ? "" : subdir, strerror(status));
900		} else {
901			/* indirect mount */
902			syslog(LOG_ERR,
903				"mount of %s/%s%s failed: %s", path, key,
904				issubtrigger ? "" : subdir, strerror(status));
905		}
906	}
907	free(key);
908
909	end_worker_thread();
910
911	return KERN_SUCCESS;
912}
913
914kern_return_t
915autofs_mount_subtrigger(__unused mach_port_t server,
916    autofs_pathname mntpt, autofs_pathname submntpt,
917    autofs_pathname path, autofs_opts opts,
918    autofs_pathname map, autofs_pathname subdir,
919    autofs_component key, uint32_t flags, uint32_t mntflags,
920    int32_t direct, fsid_t *fsidp, boolean_t *top_level, int *err,
921    security_token_t token)
922{
923	new_worker_thread();
924
925	pthread_setname_np("mount-subtrigger worker");
926
927	/*
928	 * Reject this if the sender wasn't root
929	 * (all messages from the kernel will be from root).
930	 */
931	if (token.val[0] != 0) {
932		*err = EPERM;
933		end_worker_thread();
934		return KERN_SUCCESS;
935	}
936
937	*err = do_mount_subtrigger(mntpt, submntpt, path, opts, map, subdir,
938	    key, flags, mntflags, direct, fsidp, top_level);
939
940	if (*err)
941		syslog(LOG_ERR, "subtrigger mount on %s failed: %s", mntpt,
942		    strerror(*err));
943
944	end_worker_thread();
945
946	return KERN_SUCCESS;
947}
948
949static int
950do_mount_subtrigger(autofs_pathname mntpt, autofs_pathname submntpt,
951    autofs_pathname path, autofs_opts opts,
952    autofs_pathname map, autofs_pathname subdir,
953    autofs_component key, uint32_t flags, uint32_t mntflags,
954    int32_t direct, fsid_t *fsidp, boolean_t *top_level)
955{
956	struct stat statb;
957	struct autofs_args mnt_args;
958	struct statfs buf;
959	int err;
960
961	/*
962	 * Check whether this is a symlink; Solaris does this entirely
963	 * in the kernel, and looks up the trigger mount point with
964	 * a no-follow lookup, but we can't do that, so we have to
965	 * check this ourselves.
966	 *
967	 * (We don't want to be tricked by sneaky servers into mounting
968	 * a trigger on top of, for example, "/etc".)
969	 *
970	 * XXX - will this still happen?  These mounts will only be
971	 * done as a result of a planted trigger; will vfs_addtrigger(),
972	 * which takes a relative path as an argument and won't cross
973	 * mount points, handle that?  Should vfs_addtrigger() not follow
974	 * symlinks?  Or is it sufficient that it won't leave the file
975	 * system that was just mounted?
976	 */
977	if (lstat(mntpt, &statb) == 0) {
978		if (S_ISLNK(statb.st_mode)) {
979			syslog(LOG_ERR, "%s symbolic link: not a valid mountpoint - mount failed",
980			    mntpt);
981			return (ENOENT);
982		}
983	}
984
985	mnt_args.version = AUTOFS_ARGSVERSION;
986	mnt_args.path = path;
987	mnt_args.opts = opts;
988	mnt_args.map = map;
989	mnt_args.subdir = subdir;
990	mnt_args.key = key;
991	mnt_args.mntflags = mntflags;
992	mnt_args.direct = direct;
993	mnt_args.mount_type = MOUNT_TYPE_SUBTRIGGER;		/* special trigger submount */
994	/*
995	 * XXX - subtriggers are always direct maps, right?
996	 */
997	if (direct)
998		mnt_args.node_type = NT_TRIGGER;
999	else
1000		mnt_args.node_type = 0;	/* not a trigger */
1001
1002	if (mount(MNTTYPE_AUTOFS, mntpt, flags|MNT_AUTOMOUNTED|MNT_DONTBROWSE,
1003	    &mnt_args) == -1)
1004		return (errno);
1005	/*
1006	 * XXX - what if somebody unmounts the mount out from under us?
1007	 */
1008	if (statfs(mntpt, &buf) == -1) {
1009		err = errno;
1010		/*
1011		 * XXX - if the unmount fails, we're screwed - we can't
1012		 * succeed, and we can't undo the mount.
1013		 * It "shouldn't happen", though - but it could, if,
1014		 * for example, we're mounting on a soft-mounted NFS
1015		 * mount and it times out.
1016		 */
1017		unmount(mntpt, MNT_FORCE);
1018		return (err);
1019	}
1020	*fsidp = buf.f_fsid;
1021	*top_level = (strcmp(submntpt, ".") == 0);
1022	return (0);
1023}
1024
1025kern_return_t
1026autofs_mount_url(__unused mach_port_t server, autofs_pathname url,
1027    autofs_pathname mountpoint, autofs_opts opts, fsid_t mntpnt_fsid,
1028    uint32_t sendereuid, int32_t asid, fsid_t *fsidp,
1029    uint32_t *retflags, int *err, security_token_t token)
1030{
1031	int status;
1032
1033	new_worker_thread();
1034
1035	pthread_setname_np("mount-url worker");
1036
1037	*retflags = 0;	/* what we call sets retflags as needed */
1038
1039	/*
1040	 * Reject this if the sender wasn't root
1041	 * (all messages from the kernel will be from root).
1042	 */
1043	if (token.val[0] != 0) {
1044		*err  = EPERM;
1045		end_worker_thread();
1046		return KERN_SUCCESS;
1047	}
1048
1049	if (trace > 0) {
1050		trace_prt(1, "MOUNT_URL REQUEST: url=%s mountpoint=%s\n", url, mountpoint);
1051	}
1052
1053	status = mount_generic(url, "url", opts, 0, mountpoint, FALSE,
1054	    TRUE, mntpnt_fsid, sendereuid, asid, fsidp, retflags);
1055
1056	*err = status;
1057
1058	if (trace > 0) {
1059		trace_prt(1, "MOUNT_URL REPLY    : status=%d\n", status);
1060	}
1061
1062	if (status && verbose)
1063		syslog(LOG_ERR, "mount of %s on %s failed", url, mountpoint);
1064
1065	end_worker_thread();
1066
1067	return KERN_SUCCESS;
1068}
1069
1070#define SMBREMOUNTSERVER_PATH	"/System/Library/Extensions/autofs.kext/Contents/Resources/smbremountserver"
1071
1072kern_return_t
1073autofs_smb_remount_server(__unused mach_port_t server, byte_buffer blob,
1074			  mach_msg_type_number_t blobCnt, au_asid_t asid,
1075			  security_token_t token)
1076{
1077	int pipefds[2];
1078	int child_pid;
1079	int res;
1080	uint32_t byte_count;
1081	ssize_t bytes_written;
1082	int stat_loc;
1083
1084	new_worker_thread();
1085
1086	pthread_setname_np("smb-remount-server worker");
1087
1088	/*
1089	 * Reject this if the sender wasn't root
1090	 * (all messages from the kernel will be from root).
1091	 */
1092	if (token.val[0] != 0) {
1093		end_worker_thread();
1094		return KERN_SUCCESS;
1095	}
1096
1097	if (trace > 0) {
1098		trace_prt(1, "SMB_REMOUNT_SERVER REQUEST:\n");
1099	}
1100
1101	/*
1102	 * This is a bit ugly; we have to do the SMBRemountServer()
1103	 * call in a subprocess, for reasons listed in the comment
1104	 * in smbremountserver.c.
1105	 */
1106
1107	/*
1108	 * Set up a pipe over which we send the blob to the subprocess.
1109	 */
1110	if (pipe(pipefds) == -1) {
1111		syslog(LOG_ERR, "Can't create pipe to smbremountserver: %m");
1112		goto done;
1113	}
1114
1115
1116	switch ((child_pid = fork())) {
1117	case -1:
1118		/*
1119		 * Fork failure.  Close the pipe,
1120		 * log an error, and quit.
1121		 */
1122		close(pipefds[0]);
1123		close(pipefds[1]);
1124		syslog(LOG_ERR, "Cannot fork: %m");
1125		break;
1126
1127	case 0:
1128		/*
1129		 * Child.
1130		 *
1131		 * We make the read side of the pipe our standard
1132		 * input.
1133		 *
1134		 * We leave the rest of our environment as it is; we assume
1135		 * that launchd has made the right thing happen for us,
1136		 * and that this is also the right thing for the processes
1137		 * we run.
1138		 *
1139		 * Join the passed in audit session so we will have access to credentials
1140		 */
1141		if (join_session(asid))
1142			_exit(EPERM);
1143
1144		if (dup2(pipefds[0], 0) == -1) {
1145			res = errno;
1146			syslog(LOG_ERR, "Cannot dup2: %m");
1147			_exit(res);
1148		}
1149		close(pipefds[0]);
1150		close(pipefds[1]);
1151		(void) execl(SMBREMOUNTSERVER_PATH, SMBREMOUNTSERVER_PATH,
1152			     NULL);
1153		res = errno;
1154		syslog(LOG_ERR, "exec %s: %m", SMBREMOUNTSERVER_PATH);
1155		_exit(res);
1156
1157	default:
1158		/*
1159		 * Parent.
1160		 *
1161		 * Close the read side of the pipe.
1162		 */
1163		close(pipefds[0]);
1164
1165		/*
1166		 * Send the size of the blob down the pipe, in host
1167		 * byte order.
1168		 */
1169		byte_count = blobCnt;
1170		bytes_written = write(pipefds[1], &byte_count,
1171				      sizeof byte_count);
1172		if (bytes_written == -1) {
1173			syslog(LOG_ERR, "Write of byte count to pipe failed: %m");
1174			close(pipefds[1]);
1175			goto done;
1176		}
1177		if ((size_t)bytes_written != sizeof byte_count) {
1178			syslog(LOG_ERR, "Write of byte count to pipe wrote only %zd of %zu bytes",
1179			       bytes_written, sizeof byte_count);
1180			close(pipefds[1]);
1181			goto done;
1182		}
1183
1184		/*
1185		 * Send the blob itself.
1186		 */
1187		bytes_written = write(pipefds[1], blob, byte_count);
1188		if (bytes_written == -1) {
1189			syslog(LOG_ERR, "Write of blob to pipe failed: %m");
1190			close(pipefds[1]);
1191			goto done;
1192		}
1193		if (bytes_written != (ssize_t)byte_count) {
1194			syslog(LOG_ERR, "Write of blob to pipe wrote only %zd of %u bytes",
1195			       bytes_written, byte_count);
1196			close(pipefds[1]);
1197			goto done;
1198		}
1199
1200		/*
1201		 * Close the pipe, so the subprocess knows there's nothing
1202		 * more to read.
1203		 */
1204		close(pipefds[1]);
1205
1206		/*
1207		 * Now wait for the child to finish.
1208		 */
1209		while (waitpid(child_pid, &stat_loc, WUNTRACED) < 0) {
1210			if (errno == EINTR)
1211				continue;
1212			syslog(LOG_ERR, "waitpid %d failed - error %d", child_pid, errno);
1213			goto done;
1214		}
1215
1216		if (WIFSIGNALED(stat_loc)) {
1217			syslog(LOG_ERR, "SMBRemountServer subprocess terminated with %s",
1218			       strsignal(WTERMSIG(stat_loc)));
1219		} else if (WIFSTOPPED(stat_loc)) {
1220			syslog(LOG_ERR, "SMBRemountServer subprocess stopped with %s",
1221			       strsignal(WSTOPSIG(stat_loc)));
1222		} else if (!WIFEXITED(stat_loc)) {
1223			syslog(LOG_ERR, "SMBRemountServer subprocess got unknown status 0x%08x",
1224			       stat_loc);
1225		}
1226		break;
1227	}
1228
1229done:
1230
1231	if (trace > 0) {
1232		trace_prt(1, "SMB_REMOUNT_SERVER REPLY\n");
1233	}
1234
1235	end_worker_thread();
1236
1237	return KERN_SUCCESS;
1238}
1239
1240/*
1241 * Used for reporting messages from code
1242 * shared with automount command.
1243 * Calls vsyslog to log the message.
1244 *
1245 * Print an error.
1246 * Works like printf (fmt string and variable args)
1247 * except that it will subsititute an error message
1248 * for a "%m" string (like syslog).
1249 */
1250void
1251pr_msg(const char *fmt, ...)
1252{
1253	va_list ap;
1254
1255#if 0
1256	fmt = gettext(fmt);
1257#endif
1258
1259	va_start(ap, fmt);
1260	(void) vsyslog(LOG_ERR, fmt, ap);
1261	va_end(ap);
1262}
1263