init.c revision 26594
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Donn Seeley at Berkeley Software Design, Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *		$Id$
37 */
38
39#ifndef lint
40static char copyright[] =
41"@(#) Copyright (c) 1991, 1993\n\
42	The Regents of the University of California.  All rights reserved.\n";
43#endif /* not lint */
44
45#ifndef lint
46static char sccsid[] = "@(#)init.c	8.1 (Berkeley) 7/15/93";
47#endif /* not lint */
48
49#include <sys/param.h>
50#include <sys/mount.h>
51#include <sys/sysctl.h>
52#include <sys/wait.h>
53
54#include <db.h>
55#include <errno.h>
56#include <fcntl.h>
57#include <signal.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <syslog.h>
62#include <time.h>
63#include <ttyent.h>
64#include <unistd.h>
65#include <sys/reboot.h>
66#include <err.h>
67
68#ifdef __STDC__
69#include <stdarg.h>
70#else
71#include <varargs.h>
72#endif
73
74#ifdef SECURE
75#include <pwd.h>
76#endif
77
78#ifdef LOGIN_CAP
79#include <login_cap.h>
80#endif
81
82#include "pathnames.h"
83
84/*
85 * Until the mythical util.h arrives...
86 */
87extern int login_tty __P((int));
88extern int logout __P((const char *));
89extern void logwtmp __P((const char *, const char *, const char *));
90
91/*
92 * Sleep times; used to prevent thrashing.
93 */
94#define	GETTY_SPACING		 5	/* N secs minimum getty spacing */
95#define	GETTY_SLEEP		30	/* sleep N secs after spacing problem */
96#define GETTY_NSPACE             3      /* max. spacing count to bring reaction */
97#define	WINDOW_WAIT		 3	/* wait N secs after starting window */
98#define	STALL_TIMEOUT		30	/* wait N secs after warning */
99#define	DEATH_WATCH		10	/* wait N secs for procs to die */
100#define RESOURCE_RC		"daemon"
101#define RESOURCE_WINDOW 	"default"
102#define RESOURCE_GETTY		"default"
103
104void handle __P((sig_t, ...));
105void delset __P((sigset_t *, ...));
106
107void stall __P((char *, ...));
108void warning __P((char *, ...));
109void emergency __P((char *, ...));
110void disaster __P((int));
111void badsys __P((int));
112
113/*
114 * We really need a recursive typedef...
115 * The following at least guarantees that the return type of (*state_t)()
116 * is sufficiently wide to hold a function pointer.
117 */
118typedef long (*state_func_t) __P((void));
119typedef state_func_t (*state_t) __P((void));
120
121state_func_t single_user __P((void));
122state_func_t runcom __P((void));
123state_func_t read_ttys __P((void));
124state_func_t multi_user __P((void));
125state_func_t clean_ttys __P((void));
126state_func_t catatonia __P((void));
127state_func_t death __P((void));
128
129enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
130#define FALSE	0
131#define TRUE	1
132
133int Reboot = FALSE;
134
135int devfs;
136
137void transition __P((state_t));
138state_t requested_transition = runcom;
139
140void setctty __P((char *));
141
142typedef struct init_session {
143	int	se_index;		/* index of entry in ttys file */
144	pid_t	se_process;		/* controlling process */
145	time_t	se_started;		/* used to avoid thrashing */
146	int	se_flags;		/* status of session */
147#define	SE_SHUTDOWN	0x1		/* session won't be restarted */
148	int     se_nspace;              /* spacing count */
149	char	*se_device;		/* filename of port */
150	char	*se_getty;		/* what to run on that port */
151	char    *se_getty_argv_space;   /* pre-parsed argument array space */
152	char	**se_getty_argv;	/* pre-parsed argument array */
153	char	*se_window;		/* window system (started only once) */
154	char    *se_window_argv_space;  /* pre-parsed argument array space */
155	char	**se_window_argv;	/* pre-parsed argument array */
156	char    *se_type;               /* default terminal type */
157	struct	init_session *se_prev;
158	struct	init_session *se_next;
159} session_t;
160
161void free_session __P((session_t *));
162session_t *new_session __P((session_t *, int, struct ttyent *));
163session_t *sessions;
164
165char **construct_argv __P((char *));
166void start_window_system __P((session_t *));
167void collect_child __P((pid_t));
168pid_t start_getty __P((session_t *));
169void transition_handler __P((int));
170void alrm_handler __P((int));
171void setsecuritylevel __P((int));
172int getsecuritylevel __P((void));
173int setupargv __P((session_t *, struct ttyent *));
174#ifdef LOGIN_CAP
175void setprocresources __P((const char *));
176#endif
177int clang;
178
179void clear_session_logs __P((session_t *));
180
181int start_session_db __P((void));
182void add_session __P((session_t *));
183void del_session __P((session_t *));
184session_t *find_session __P((pid_t));
185DB *session_db;
186
187/*
188 * The mother of all processes.
189 */
190int
191main(argc, argv)
192	int argc;
193	char **argv;
194{
195	int c;
196	struct sigaction sa;
197	sigset_t mask;
198
199
200	/* Dispose of random users. */
201	if (getuid() != 0)
202		errx(1, "%s", strerror(EPERM));
203
204	/* System V users like to reexec init. */
205	if (getpid() != 1)
206		errx(1, "already running");
207
208	/*
209	 * Note that this does NOT open a file...
210	 * Does 'init' deserve its own facility number?
211	 */
212	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
213
214	/*
215	 * Create an initial session.
216	 */
217	if (setsid() < 0)
218		warning("initial setsid() failed: %m");
219
220	/*
221	 * Establish an initial user so that programs running
222	 * single user do not freak out and die (like passwd).
223	 */
224	if (setlogin("root") < 0)
225		warning("setlogin() failed: %m");
226
227	/*
228	 * This code assumes that we always get arguments through flags,
229	 * never through bits set in some random machine register.
230	 */
231	while ((c = getopt(argc, argv, "dsf")) != -1)
232		switch (c) {
233		case 'd':
234			devfs = 1;
235			break;
236		case 's':
237			requested_transition = single_user;
238			break;
239		case 'f':
240			runcom_mode = FASTBOOT;
241			break;
242		default:
243			warning("unrecognized flag '-%c'", c);
244			break;
245		}
246
247	if (optind != argc)
248		warning("ignoring excess arguments");
249
250	if (devfs) {
251		mount("devfs", "/dev", MNT_NOEXEC|MNT_RDONLY, 0);
252	}
253
254	/*
255	 * We catch or block signals rather than ignore them,
256	 * so that they get reset on exec.
257	 */
258	handle(badsys, SIGSYS, 0);
259	handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
260	       SIGBUS, SIGXCPU, SIGXFSZ, 0);
261	handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, 0);
262	handle(alrm_handler, SIGALRM, 0);
263	sigfillset(&mask);
264	delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
265		SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, 0);
266	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
267	sigemptyset(&sa.sa_mask);
268	sa.sa_flags = 0;
269	sa.sa_handler = SIG_IGN;
270	(void) sigaction(SIGTTIN, &sa, (struct sigaction *)0);
271	(void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
272
273	/*
274	 * Paranoia.
275	 */
276	close(0);
277	close(1);
278	close(2);
279
280	/*
281	 * Start the state machine.
282	 */
283	transition(requested_transition);
284
285	/*
286	 * Should never reach here.
287	 */
288	return 1;
289}
290
291/*
292 * Associate a function with a signal handler.
293 */
294void
295#ifdef __STDC__
296handle(sig_t handler, ...)
297#else
298handle(va_alist)
299	va_dcl
300#endif
301{
302	int sig;
303	struct sigaction sa;
304	int mask_everything;
305	va_list ap;
306#ifndef __STDC__
307	sig_t handler;
308
309	va_start(ap);
310	handler = va_arg(ap, sig_t);
311#else
312	va_start(ap, handler);
313#endif
314
315	sa.sa_handler = handler;
316	sigfillset(&mask_everything);
317
318	while (sig = va_arg(ap, int)) {
319		sa.sa_mask = mask_everything;
320		/* XXX SA_RESTART? */
321		sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
322		sigaction(sig, &sa, (struct sigaction *) 0);
323	}
324	va_end(ap);
325}
326
327/*
328 * Delete a set of signals from a mask.
329 */
330void
331#ifdef __STDC__
332delset(sigset_t *maskp, ...)
333#else
334delset(va_alist)
335	va_dcl
336#endif
337{
338	int sig;
339	va_list ap;
340#ifndef __STDC__
341	sigset_t *maskp;
342
343	va_start(ap);
344	maskp = va_arg(ap, sigset_t *);
345#else
346	va_start(ap, maskp);
347#endif
348
349	while (sig = va_arg(ap, int))
350		sigdelset(maskp, sig);
351	va_end(ap);
352}
353
354/*
355 * Log a message and sleep for a while (to give someone an opportunity
356 * to read it and to save log or hardcopy output if the problem is chronic).
357 * NB: should send a message to the session logger to avoid blocking.
358 */
359void
360#ifdef __STDC__
361stall(char *message, ...)
362#else
363stall(va_alist)
364	va_dcl
365#endif
366{
367	va_list ap;
368#ifndef __STDC__
369	char *message;
370
371	va_start(ap);
372	message = va_arg(ap, char *);
373#else
374	va_start(ap, message);
375#endif
376
377	vsyslog(LOG_ALERT, message, ap);
378	va_end(ap);
379	sleep(STALL_TIMEOUT);
380}
381
382/*
383 * Like stall(), but doesn't sleep.
384 * If cpp had variadic macros, the two functions could be #defines for another.
385 * NB: should send a message to the session logger to avoid blocking.
386 */
387void
388#ifdef __STDC__
389warning(char *message, ...)
390#else
391warning(va_alist)
392	va_dcl
393#endif
394{
395	va_list ap;
396#ifndef __STDC__
397	char *message;
398
399	va_start(ap);
400	message = va_arg(ap, char *);
401#else
402	va_start(ap, message);
403#endif
404
405	vsyslog(LOG_ALERT, message, ap);
406	va_end(ap);
407}
408
409/*
410 * Log an emergency message.
411 * NB: should send a message to the session logger to avoid blocking.
412 */
413void
414#ifdef __STDC__
415emergency(char *message, ...)
416#else
417emergency(va_alist)
418	va_dcl
419#endif
420{
421	va_list ap;
422#ifndef __STDC__
423	char *message;
424
425	va_start(ap);
426	message = va_arg(ap, char *);
427#else
428	va_start(ap, message);
429#endif
430
431	vsyslog(LOG_EMERG, message, ap);
432	va_end(ap);
433}
434
435/*
436 * Catch a SIGSYS signal.
437 *
438 * These may arise if a system does not support sysctl.
439 * We tolerate up to 25 of these, then throw in the towel.
440 */
441void
442badsys(sig)
443	int sig;
444{
445	static int badcount = 0;
446
447	if (badcount++ < 25)
448		return;
449	disaster(sig);
450}
451
452/*
453 * Catch an unexpected signal.
454 */
455void
456disaster(sig)
457	int sig;
458{
459	emergency("fatal signal: %s",
460		sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal");
461
462	sleep(STALL_TIMEOUT);
463	_exit(sig);		/* reboot */
464}
465
466/*
467 * Get the security level of the kernel.
468 */
469int
470getsecuritylevel()
471{
472#ifdef KERN_SECURELVL
473	int name[2], curlevel;
474	size_t len;
475	extern int errno;
476
477	name[0] = CTL_KERN;
478	name[1] = KERN_SECURELVL;
479	len = sizeof curlevel;
480	if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
481		emergency("cannot get kernel security level: %s",
482		    strerror(errno));
483		return (-1);
484	}
485	return (curlevel);
486#else
487	return (-1);
488#endif
489}
490
491/*
492 * Set the security level of the kernel.
493 */
494void
495setsecuritylevel(newlevel)
496	int newlevel;
497{
498#ifdef KERN_SECURELVL
499	int name[2], curlevel;
500	extern int errno;
501
502	curlevel = getsecuritylevel();
503	if (newlevel == curlevel)
504		return;
505	name[0] = CTL_KERN;
506	name[1] = KERN_SECURELVL;
507	if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
508		emergency(
509		    "cannot change kernel security level from %d to %d: %s",
510		    curlevel, newlevel, strerror(errno));
511		return;
512	}
513#ifdef SECURE
514	warning("kernel security level changed from %d to %d",
515	    curlevel, newlevel);
516#endif
517#endif
518}
519
520/*
521 * Change states in the finite state machine.
522 * The initial state is passed as an argument.
523 */
524void
525transition(s)
526	state_t s;
527{
528	for (;;)
529		s = (state_t) (*s)();
530}
531
532/*
533 * Close out the accounting files for a login session.
534 * NB: should send a message to the session logger to avoid blocking.
535 */
536void
537clear_session_logs(sp)
538	session_t *sp;
539{
540	char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
541
542	if (logout(line))
543		logwtmp(line, "", "");
544}
545
546/*
547 * Start a session and allocate a controlling terminal.
548 * Only called by children of init after forking.
549 */
550void
551setctty(name)
552	char *name;
553{
554	int fd;
555
556	(void) revoke(name);
557	if ((fd = open(name, O_RDWR)) == -1) {
558		stall("can't open %s: %m", name);
559		_exit(1);
560	}
561	if (login_tty(fd) == -1) {
562		stall("can't get %s for controlling terminal: %m", name);
563		_exit(1);
564	}
565}
566
567/*
568 * Bring the system up single user.
569 */
570state_func_t
571single_user()
572{
573	pid_t pid, wpid;
574	int status;
575	sigset_t mask;
576	char *shell = _PATH_BSHELL;
577	char *argv[2];
578#ifdef SECURE
579	struct ttyent *typ;
580	struct passwd *pp;
581	static const char banner[] =
582		"Enter root password, or ^D to go multi-user\n";
583	char *clear, *password;
584#endif
585
586	/*
587	 * If the kernel is in secure mode, downgrade it to insecure mode.
588	 */
589	if (getsecuritylevel() > 0)
590		setsecuritylevel(0);
591
592	if (Reboot) {
593		/* Instead of going single user, let's halt the machine */
594		sync();
595		alarm(2);
596		pause();
597		reboot(RB_AUTOBOOT);
598		_exit(0);
599	}
600
601	if ((pid = fork()) == 0) {
602		/*
603		 * Start the single user session.
604		 */
605		setctty(_PATH_CONSOLE);
606
607#ifdef SECURE
608		/*
609		 * Check the root password.
610		 * We don't care if the console is 'on' by default;
611		 * it's the only tty that can be 'off' and 'secure'.
612		 */
613		typ = getttynam("console");
614		pp = getpwnam("root");
615		if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp && *pp->pw_passwd) {
616			write(2, banner, sizeof banner - 1);
617			for (;;) {
618				clear = getpass("Password:");
619				if (clear == 0 || *clear == '\0')
620					_exit(0);
621				password = crypt(clear, pp->pw_passwd);
622				bzero(clear, _PASSWORD_LEN);
623				if (strcmp(password, pp->pw_passwd) == 0)
624					break;
625				warning("single-user login failed\n");
626			}
627		}
628		endttyent();
629		endpwent();
630#endif /* SECURE */
631
632#ifdef DEBUGSHELL
633		{
634			char altshell[128], *cp = altshell;
635			int num;
636
637#define	SHREQUEST \
638	"Enter pathname of shell or RETURN for sh: "
639			(void)write(STDERR_FILENO,
640			    SHREQUEST, sizeof(SHREQUEST) - 1);
641			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
642			    num != 0 && *cp != '\n' && cp < &altshell[127])
643					cp++;
644			*cp = '\0';
645			if (altshell[0] != '\0')
646				shell = altshell;
647		}
648#endif /* DEBUGSHELL */
649
650		/*
651		 * Unblock signals.
652		 * We catch all the interesting ones,
653		 * and those are reset to SIG_DFL on exec.
654		 */
655		sigemptyset(&mask);
656		sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
657
658		/*
659		 * Fire off a shell.
660		 * If the default one doesn't work, try the Bourne shell.
661		 */
662		argv[0] = "-sh";
663		argv[1] = 0;
664		execv(shell, argv);
665		emergency("can't exec %s for single user: %m", shell);
666		execv(_PATH_BSHELL, argv);
667		emergency("can't exec %s for single user: %m", _PATH_BSHELL);
668		sleep(STALL_TIMEOUT);
669		_exit(1);
670	}
671
672	if (pid == -1) {
673		/*
674		 * We are seriously hosed.  Do our best.
675		 */
676		emergency("can't fork single-user shell, trying again");
677		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
678			continue;
679		return (state_func_t) single_user;
680	}
681
682	requested_transition = 0;
683	do {
684		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
685			collect_child(wpid);
686		if (wpid == -1) {
687			if (errno == EINTR)
688				continue;
689			warning("wait for single-user shell failed: %m; restarting");
690			return (state_func_t) single_user;
691		}
692		if (wpid == pid && WIFSTOPPED(status)) {
693			warning("init: shell stopped, restarting\n");
694			kill(pid, SIGCONT);
695			wpid = -1;
696		}
697	} while (wpid != pid && !requested_transition);
698
699	if (requested_transition)
700		return (state_func_t) requested_transition;
701
702	if (!WIFEXITED(status)) {
703		if (WTERMSIG(status) == SIGKILL) {
704			/*
705			 *  reboot(8) killed shell?
706			 */
707			warning("single user shell terminated.");
708			sleep(STALL_TIMEOUT);
709			_exit(0);
710		} else {
711			warning("single user shell terminated, restarting");
712			return (state_func_t) single_user;
713		}
714	}
715
716	runcom_mode = FASTBOOT;
717	return (state_func_t) runcom;
718}
719
720/*
721 * Run the system startup script.
722 */
723state_func_t
724runcom()
725{
726	pid_t pid, wpid;
727	int status;
728	char *argv[4];
729	struct sigaction sa;
730
731	if ((pid = fork()) == 0) {
732		sigemptyset(&sa.sa_mask);
733		sa.sa_flags = 0;
734		sa.sa_handler = SIG_IGN;
735		(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
736		(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
737
738		setctty(_PATH_CONSOLE);
739
740		argv[0] = "sh";
741		argv[1] = _PATH_RUNCOM;
742		argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0;
743		argv[3] = 0;
744
745		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
746
747#ifdef LOGIN_CAP
748		setprocresources(RESOURCE_RC);
749#endif
750		execv(_PATH_BSHELL, argv);
751		stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM);
752		_exit(1);	/* force single user mode */
753	}
754
755	if (pid == -1) {
756		emergency("can't fork for %s on %s: %m",
757			_PATH_BSHELL, _PATH_RUNCOM);
758		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
759			continue;
760		sleep(STALL_TIMEOUT);
761		return (state_func_t) single_user;
762	}
763
764	/*
765	 * Copied from single_user().  This is a bit paranoid.
766	 */
767	do {
768		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
769			collect_child(wpid);
770		if (wpid == -1) {
771			if (errno == EINTR)
772				continue;
773			warning("wait for %s on %s failed: %m; going to single user mode",
774				_PATH_BSHELL, _PATH_RUNCOM);
775			return (state_func_t) single_user;
776		}
777		if (wpid == pid && WIFSTOPPED(status)) {
778			warning("init: %s on %s stopped, restarting\n",
779				_PATH_BSHELL, _PATH_RUNCOM);
780			kill(pid, SIGCONT);
781			wpid = -1;
782		}
783	} while (wpid != pid);
784
785	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
786	    requested_transition == catatonia) {
787		/* /etc/rc executed /sbin/reboot; wait for the end quietly */
788		sigset_t s;
789
790		sigfillset(&s);
791		for (;;)
792			sigsuspend(&s);
793	}
794
795	if (!WIFEXITED(status)) {
796		warning("%s on %s terminated abnormally, going to single user mode",
797			_PATH_BSHELL, _PATH_RUNCOM);
798		return (state_func_t) single_user;
799	}
800
801	if (WEXITSTATUS(status))
802		return (state_func_t) single_user;
803
804	runcom_mode = AUTOBOOT;		/* the default */
805	/* NB: should send a message to the session logger to avoid blocking. */
806	logwtmp("~", "reboot", "");
807	return (state_func_t) read_ttys;
808}
809
810/*
811 * Open the session database.
812 *
813 * NB: We could pass in the size here; is it necessary?
814 */
815int
816start_session_db()
817{
818	if (session_db && (*session_db->close)(session_db))
819		emergency("session database close: %s", strerror(errno));
820	if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
821		emergency("session database open: %s", strerror(errno));
822		return (1);
823	}
824	return (0);
825
826}
827
828/*
829 * Add a new login session.
830 */
831void
832add_session(sp)
833	session_t *sp;
834{
835	DBT key;
836	DBT data;
837
838	key.data = &sp->se_process;
839	key.size = sizeof sp->se_process;
840	data.data = &sp;
841	data.size = sizeof sp;
842
843	if ((*session_db->put)(session_db, &key, &data, 0))
844		emergency("insert %d: %s", sp->se_process, strerror(errno));
845}
846
847/*
848 * Delete an old login session.
849 */
850void
851del_session(sp)
852	session_t *sp;
853{
854	DBT key;
855
856	key.data = &sp->se_process;
857	key.size = sizeof sp->se_process;
858
859	if ((*session_db->del)(session_db, &key, 0))
860		emergency("delete %d: %s", sp->se_process, strerror(errno));
861}
862
863/*
864 * Look up a login session by pid.
865 */
866session_t *
867#ifdef __STDC__
868find_session(pid_t pid)
869#else
870find_session(pid)
871	pid_t pid;
872#endif
873{
874	DBT key;
875	DBT data;
876	session_t *ret;
877
878	key.data = &pid;
879	key.size = sizeof pid;
880	if ((*session_db->get)(session_db, &key, &data, 0) != 0)
881		return 0;
882	bcopy(data.data, (char *)&ret, sizeof(ret));
883	return ret;
884}
885
886/*
887 * Construct an argument vector from a command line.
888 */
889char **
890construct_argv(command)
891	char *command;
892{
893	char *strk (char *);
894	register int argc = 0;
895	register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1)
896						* sizeof (char *));
897
898	if ((argv[argc++] = strk(command)) == 0)
899		return 0;
900	while (argv[argc++] = strk((char *) 0))
901		continue;
902	return argv;
903}
904
905/*
906 * Deallocate a session descriptor.
907 */
908void
909free_session(sp)
910	register session_t *sp;
911{
912	free(sp->se_device);
913	if (sp->se_getty) {
914		free(sp->se_getty);
915		free(sp->se_getty_argv_space);
916		free(sp->se_getty_argv);
917	}
918	if (sp->se_window) {
919		free(sp->se_window);
920		free(sp->se_window_argv_space);
921		free(sp->se_window_argv);
922	}
923	if (sp->se_type)
924		free(sp->se_type);
925	free(sp);
926}
927
928/*
929 * Allocate a new session descriptor.
930 */
931session_t *
932new_session(sprev, session_index, typ)
933	session_t *sprev;
934	int session_index;
935	register struct ttyent *typ;
936{
937	register session_t *sp;
938
939	if ((typ->ty_status & TTY_ON) == 0 ||
940	    typ->ty_name == 0 ||
941	    typ->ty_getty == 0)
942		return 0;
943
944	sp = (session_t *) malloc(sizeof (session_t));
945	bzero(sp, sizeof *sp);
946
947	sp->se_index = session_index;
948
949	sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
950	(void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
951
952	if (setupargv(sp, typ) == 0) {
953		free_session(sp);
954		return (0);
955	}
956
957	sp->se_next = 0;
958	if (sprev == 0) {
959		sessions = sp;
960		sp->se_prev = 0;
961	} else {
962		sprev->se_next = sp;
963		sp->se_prev = sprev;
964	}
965
966	return sp;
967}
968
969/*
970 * Calculate getty and if useful window argv vectors.
971 */
972int
973setupargv(sp, typ)
974	session_t *sp;
975	struct ttyent *typ;
976{
977
978	if (sp->se_getty) {
979		free(sp->se_getty);
980		free(sp->se_getty_argv_space);
981		free(sp->se_getty_argv);
982	}
983	sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2);
984	(void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
985	sp->se_getty_argv_space = strdup(sp->se_getty);
986	sp->se_getty_argv = construct_argv(sp->se_getty_argv_space);
987	if (sp->se_getty_argv == 0) {
988		warning("can't parse getty for port %s", sp->se_device);
989		free(sp->se_getty);
990		free(sp->se_getty_argv_space);
991		sp->se_getty = sp->se_getty_argv_space = 0;
992		return (0);
993	}
994	if (sp->se_window) {
995			free(sp->se_window);
996		free(sp->se_window_argv_space);
997		free(sp->se_window_argv);
998	}
999	sp->se_window = sp->se_window_argv_space = 0;
1000	sp->se_window_argv = 0;
1001	if (typ->ty_window) {
1002		sp->se_window = strdup(typ->ty_window);
1003		sp->se_window_argv_space = strdup(sp->se_window);
1004		sp->se_window_argv = construct_argv(sp->se_window_argv_space);
1005		if (sp->se_window_argv == 0) {
1006			warning("can't parse window for port %s",
1007				sp->se_device);
1008			free(sp->se_window_argv_space);
1009			free(sp->se_window);
1010			sp->se_window = sp->se_window_argv_space = 0;
1011			return (0);
1012		}
1013	}
1014	if (sp->se_type)
1015		free(sp->se_type);
1016	sp->se_type = typ->ty_type ? strdup(typ->ty_type) : 0;
1017	return (1);
1018}
1019
1020/*
1021 * Walk the list of ttys and create sessions for each active line.
1022 */
1023state_func_t
1024read_ttys()
1025{
1026	int session_index = 0;
1027	register session_t *sp, *snext;
1028	register struct ttyent *typ;
1029
1030	/*
1031	 * Destroy any previous session state.
1032	 * There shouldn't be any, but just in case...
1033	 */
1034	for (sp = sessions; sp; sp = snext) {
1035		if (sp->se_process)
1036			clear_session_logs(sp);
1037		snext = sp->se_next;
1038		free_session(sp);
1039	}
1040	sessions = 0;
1041	if (start_session_db())
1042		return (state_func_t) single_user;
1043
1044	/*
1045	 * Allocate a session entry for each active port.
1046	 * Note that sp starts at 0.
1047	 */
1048	while (typ = getttyent())
1049		if (snext = new_session(sp, ++session_index, typ))
1050			sp = snext;
1051
1052	endttyent();
1053
1054	return (state_func_t) multi_user;
1055}
1056
1057/*
1058 * Start a window system running.
1059 */
1060void
1061start_window_system(sp)
1062	session_t *sp;
1063{
1064	pid_t pid;
1065	sigset_t mask;
1066	char term[64], *env[2];
1067
1068	if ((pid = fork()) == -1) {
1069		emergency("can't fork for window system on port %s: %m",
1070			sp->se_device);
1071		/* hope that getty fails and we can try again */
1072		return;
1073	}
1074
1075	if (pid)
1076		return;
1077
1078	sigemptyset(&mask);
1079	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1080
1081	if (setsid() < 0)
1082		emergency("setsid failed (window) %m");
1083
1084#ifdef LOGIN_CAP
1085	setprocresources(RESOURCE_WINDOW);
1086#endif
1087	if (sp->se_type) {
1088		/* Don't use malloc after fork */
1089		strcpy(term, "TERM=");
1090		strncat(term, sp->se_type, sizeof(term) - 6);
1091		env[0] = term;
1092		env[1] = 0;
1093	}
1094	else
1095		env[0] = 0;
1096	execve(sp->se_window_argv[0], sp->se_window_argv, env);
1097	stall("can't exec window system '%s' for port %s: %m",
1098		sp->se_window_argv[0], sp->se_device);
1099	_exit(1);
1100}
1101
1102/*
1103 * Start a login session running.
1104 */
1105pid_t
1106start_getty(sp)
1107	session_t *sp;
1108{
1109	pid_t pid;
1110	sigset_t mask;
1111	time_t current_time = time((time_t *) 0);
1112	int too_quick = 0;
1113	char term[64], *env[2];
1114
1115	if (current_time >= sp->se_started &&
1116	    current_time - sp->se_started < GETTY_SPACING) {
1117		if (++sp->se_nspace > GETTY_NSPACE) {
1118			sp->se_nspace = 0;
1119			too_quick = 1;
1120		}
1121	} else
1122		sp->se_nspace = 0;
1123
1124	/*
1125	 * fork(), not vfork() -- we can't afford to block.
1126	 */
1127	if ((pid = fork()) == -1) {
1128		emergency("can't fork for getty on port %s: %m", sp->se_device);
1129		return -1;
1130	}
1131
1132	if (pid)
1133		return pid;
1134
1135	if (too_quick) {
1136		warning("getty repeating too quickly on port %s, sleeping %d secs",
1137			sp->se_device, GETTY_SLEEP);
1138		sleep((unsigned) GETTY_SLEEP);
1139	}
1140
1141	if (sp->se_window) {
1142		start_window_system(sp);
1143		sleep(WINDOW_WAIT);
1144	}
1145
1146	sigemptyset(&mask);
1147	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1148
1149#ifdef LOGIN_CAP
1150	setprocresources(RESOURCE_GETTY);
1151#endif
1152	if (sp->se_type) {
1153		/* Don't use malloc after fork */
1154		strcpy(term, "TERM=");
1155		strncat(term, sp->se_type, sizeof(term) - 6);
1156		env[0] = term;
1157		env[1] = 0;
1158	}
1159	else
1160		env[0] = 0;
1161	execve(sp->se_getty_argv[0], sp->se_getty_argv, env);
1162	stall("can't exec getty '%s' for port %s: %m",
1163		sp->se_getty_argv[0], sp->se_device);
1164	_exit(1);
1165}
1166
1167/*
1168 * Collect exit status for a child.
1169 * If an exiting login, start a new login running.
1170 */
1171void
1172#ifdef __STDC__
1173collect_child(pid_t pid)
1174#else
1175collect_child(pid)
1176	pid_t pid;
1177#endif
1178{
1179	register session_t *sp, *sprev, *snext;
1180
1181	if (! sessions)
1182		return;
1183
1184	if (! (sp = find_session(pid)))
1185		return;
1186
1187	clear_session_logs(sp);
1188	del_session(sp);
1189	sp->se_process = 0;
1190
1191	if (sp->se_flags & SE_SHUTDOWN) {
1192		if (sprev = sp->se_prev)
1193			sprev->se_next = sp->se_next;
1194		else
1195			sessions = sp->se_next;
1196		if (snext = sp->se_next)
1197			snext->se_prev = sp->se_prev;
1198		free_session(sp);
1199		return;
1200	}
1201
1202	if ((pid = start_getty(sp)) == -1) {
1203		/* serious trouble */
1204		requested_transition = clean_ttys;
1205		return;
1206	}
1207
1208	sp->se_process = pid;
1209	sp->se_started = time((time_t *) 0);
1210	add_session(sp);
1211}
1212
1213/*
1214 * Catch a signal and request a state transition.
1215 */
1216void
1217transition_handler(sig)
1218	int sig;
1219{
1220
1221	switch (sig) {
1222	case SIGHUP:
1223		requested_transition = clean_ttys;
1224		break;
1225	case SIGINT:
1226		Reboot = TRUE;
1227	case SIGTERM:
1228		requested_transition = death;
1229		break;
1230	case SIGTSTP:
1231		requested_transition = catatonia;
1232		break;
1233	default:
1234		requested_transition = 0;
1235		break;
1236	}
1237}
1238
1239/*
1240 * Take the system multiuser.
1241 */
1242state_func_t
1243multi_user()
1244{
1245	pid_t pid;
1246	register session_t *sp;
1247
1248	requested_transition = 0;
1249
1250	/*
1251	 * If the administrator has not set the security level to -1
1252	 * to indicate that the kernel should not run multiuser in secure
1253	 * mode, and the run script has not set a higher level of security
1254	 * than level 1, then put the kernel into secure mode.
1255	 */
1256	if (getsecuritylevel() == 0)
1257		setsecuritylevel(1);
1258
1259	for (sp = sessions; sp; sp = sp->se_next) {
1260		if (sp->se_process)
1261			continue;
1262		if ((pid = start_getty(sp)) == -1) {
1263			/* serious trouble */
1264			requested_transition = clean_ttys;
1265			break;
1266		}
1267		sp->se_process = pid;
1268		sp->se_started = time((time_t *) 0);
1269		add_session(sp);
1270	}
1271
1272	while (!requested_transition)
1273		if ((pid = waitpid(-1, (int *) 0, 0)) != -1)
1274			collect_child(pid);
1275
1276	return (state_func_t) requested_transition;
1277}
1278
1279/*
1280 * This is an n-squared algorithm.  We hope it isn't run often...
1281 */
1282state_func_t
1283clean_ttys()
1284{
1285	register session_t *sp, *sprev;
1286	register struct ttyent *typ;
1287	register int session_index = 0;
1288	register int devlen;
1289	char *old_getty, *old_window, *old_type;
1290
1291	if (! sessions)
1292		return (state_func_t) multi_user;
1293
1294	devlen = sizeof(_PATH_DEV) - 1;
1295	while (typ = getttyent()) {
1296		++session_index;
1297
1298		for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1299			if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1300				break;
1301
1302		if (sp) {
1303			if (sp->se_index != session_index) {
1304				warning("port %s changed utmp index from %d to %d",
1305				       sp->se_device, sp->se_index,
1306				       session_index);
1307				sp->se_index = session_index;
1308			}
1309			if ((typ->ty_status & TTY_ON) == 0 ||
1310			    typ->ty_getty == 0) {
1311				sp->se_flags |= SE_SHUTDOWN;
1312				kill(sp->se_process, SIGHUP);
1313				continue;
1314			}
1315			sp->se_flags &= ~SE_SHUTDOWN;
1316			old_getty = sp->se_getty ? strdup(sp->se_getty) : 0;
1317			old_window = sp->se_window ? strdup(sp->se_window) : 0;
1318			old_type = sp->se_type ? strdup(sp->se_type) : 0;
1319			if (setupargv(sp, typ) == 0) {
1320				warning("can't parse getty for port %s",
1321					sp->se_device);
1322				sp->se_flags |= SE_SHUTDOWN;
1323				kill(sp->se_process, SIGHUP);
1324			}
1325			else if (   !old_getty
1326				 || !old_type && sp->se_type
1327				 || old_type && !sp->se_type
1328				 || !old_window && sp->se_window
1329				 || old_window && !sp->se_window
1330				 || strcmp(old_getty, sp->se_getty) != 0
1331				 || old_window && strcmp(old_window, sp->se_window) != 0
1332				 || old_type && strcmp(old_type, sp->se_type) != 0
1333				) {
1334				/* Don't set SE_SHUTDOWN here */
1335				sp->se_nspace = 0;
1336				sp->se_started = 0;
1337				kill(sp->se_process, SIGHUP);
1338			}
1339			if (old_getty)
1340				free(old_getty);
1341			if (old_getty)
1342				free(old_window);
1343			if (old_type)
1344				free(old_type);
1345			continue;
1346		}
1347
1348		new_session(sprev, session_index, typ);
1349	}
1350
1351	endttyent();
1352
1353	return (state_func_t) multi_user;
1354}
1355
1356/*
1357 * Block further logins.
1358 */
1359state_func_t
1360catatonia()
1361{
1362	register session_t *sp;
1363
1364	for (sp = sessions; sp; sp = sp->se_next)
1365		sp->se_flags |= SE_SHUTDOWN;
1366
1367	return (state_func_t) multi_user;
1368}
1369
1370/*
1371 * Note SIGALRM.
1372 */
1373void
1374alrm_handler(sig)
1375	int sig;
1376{
1377	clang = 1;
1378}
1379
1380/*
1381 * Bring the system down to single user.
1382 */
1383state_func_t
1384death()
1385{
1386	register session_t *sp;
1387	register int i;
1388	pid_t pid;
1389	static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1390
1391	for (sp = sessions; sp; sp = sp->se_next)
1392		sp->se_flags |= SE_SHUTDOWN;
1393
1394	/* NB: should send a message to the session logger to avoid blocking. */
1395	logwtmp("~", "shutdown", "");
1396
1397	for (i = 0; i < 3; ++i) {
1398		if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1399			return (state_func_t) single_user;
1400
1401		clang = 0;
1402		alarm(DEATH_WATCH);
1403		do
1404			if ((pid = waitpid(-1, (int *)0, 0)) != -1)
1405				collect_child(pid);
1406		while (clang == 0 && errno != ECHILD);
1407
1408		if (errno == ECHILD)
1409			return (state_func_t) single_user;
1410	}
1411
1412	warning("some processes would not die; ps axl advised");
1413
1414	return (state_func_t) single_user;
1415}
1416char *
1417strk (char *p)
1418{
1419    static char *t;
1420    char *q;
1421    int c;
1422
1423    if (p)
1424	t = p;
1425    if (!t)
1426	return 0;
1427
1428    c = *t;
1429    while (c == ' ' || c == '\t' )
1430	c = *++t;
1431    if (!c) {
1432	t = 0;
1433	return 0;
1434    }
1435    q = t;
1436    if (c == '\'') {
1437	c = *++t;
1438	q = t;
1439	while (c && c != '\'')
1440	    c = *++t;
1441	if (!c)  /* unterminated string */
1442	    q = t = 0;
1443	else
1444	    *t++ = 0;
1445    } else {
1446	while (c && c != ' ' && c != '\t' )
1447	    c = *++t;
1448	*t++ = 0;
1449	if (!c)
1450	    t = 0;
1451    }
1452    return q;
1453}
1454
1455#ifdef LOGIN_CAP
1456void
1457setprocresources(cname)
1458	const char *cname;
1459{
1460	login_cap_t *lc;
1461	if ((lc = login_getclassbyname(cname, (char*)NULL)) != NULL) {
1462		setusercontext(lc, (struct passwd*)NULL, 0, LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
1463		login_close(lc);
1464	}
1465}
1466#endif
1467