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