init.c revision 1.14
1/*	$OpenBSD: init.c,v 1.14 1998/05/04 06:37:02 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.14 1998/05/04 06:37:02 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	sigemptyset(&sa.sa_mask);
241	sa.sa_flags = 0;
242	sa.sa_handler = SIG_IGN;
243	(void) sigaction(SIGTTIN, &sa, NULL);
244	(void) sigaction(SIGTTOU, &sa, NULL);
245
246	/*
247	 * Paranoia.
248	 */
249	close(0);
250	close(1);
251	close(2);
252
253	/*
254	 * Start the state machine.
255	 */
256	transition(requested_transition);
257
258	/*
259	 * Should never reach here.
260	 */
261	return 1;
262}
263
264/*
265 * Associate a function with a signal handler.
266 */
267void
268#ifdef __STDC__
269handle(sig_t handler, ...)
270#else
271handle(va_alist)
272	va_dcl
273#endif
274{
275	int sig;
276	struct sigaction sa;
277	sigset_t mask_everything;
278	va_list ap;
279#ifndef __STDC__
280	sig_t handler;
281
282	va_start(ap);
283	handler = va_arg(ap, sig_t);
284#else
285	va_start(ap, handler);
286#endif
287
288	sa.sa_handler = handler;
289	sigfillset(&mask_everything);
290
291	while ((sig = va_arg(ap, int))) {
292		sa.sa_mask = mask_everything;
293		/* XXX SA_RESTART? */
294		sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
295		sigaction(sig, &sa, NULL);
296	}
297	va_end(ap);
298}
299
300/*
301 * Delete a set of signals from a mask.
302 */
303void
304#ifdef __STDC__
305delset(sigset_t *maskp, ...)
306#else
307delset(va_alist)
308	va_dcl
309#endif
310{
311	int sig;
312	va_list ap;
313#ifndef __STDC__
314	sigset_t *maskp;
315
316	va_start(ap);
317	maskp = va_arg(ap, sigset_t *);
318#else
319	va_start(ap, maskp);
320#endif
321
322	while ((sig = va_arg(ap, int)))
323		sigdelset(maskp, sig);
324	va_end(ap);
325}
326
327/*
328 * Log a message and sleep for a while (to give someone an opportunity
329 * to read it and to save log or hardcopy output if the problem is chronic).
330 * NB: should send a message to the session logger to avoid blocking.
331 */
332void
333#ifdef __STDC__
334stall(char *message, ...)
335#else
336stall(va_alist)
337	va_dcl
338#endif
339{
340	va_list ap;
341#ifndef __STDC__
342	char *message;
343
344	va_start(ap);
345	message = va_arg(ap, char *);
346#else
347	va_start(ap, message);
348#endif
349
350	vsyslog(LOG_ALERT, message, ap);
351	va_end(ap);
352	closelog();
353	sleep(STALL_TIMEOUT);
354}
355
356/*
357 * Like stall(), but doesn't sleep.
358 * If cpp had variadic macros, the two functions could be #defines for another.
359 * NB: should send a message to the session logger to avoid blocking.
360 */
361void
362#ifdef __STDC__
363warning(char *message, ...)
364#else
365warning(va_alist)
366	va_dcl
367#endif
368{
369	va_list ap;
370#ifndef __STDC__
371	char *message;
372
373	va_start(ap);
374	message = va_arg(ap, char *);
375#else
376	va_start(ap, message);
377#endif
378
379	vsyslog(LOG_ALERT, message, ap);
380	va_end(ap);
381	closelog();
382}
383
384/*
385 * Log an emergency message.
386 * NB: should send a message to the session logger to avoid blocking.
387 */
388void
389#ifdef __STDC__
390emergency(char *message, ...)
391#else
392emergency(va_alist)
393	va_dcl
394#endif
395{
396	va_list ap;
397#ifndef __STDC__
398	char *message;
399
400	va_start(ap);
401	message = va_arg(ap, char *);
402#else
403	va_start(ap, message);
404#endif
405
406	vsyslog(LOG_EMERG, message, ap);
407	va_end(ap);
408	closelog();
409}
410
411/*
412 * Catch a SIGSYS signal.
413 *
414 * These may arise if a system does not support sysctl.
415 * We tolerate up to 25 of these, then throw in the towel.
416 */
417void
418badsys(sig)
419	int sig;
420{
421	static int badcount = 0;
422
423	if (badcount++ < 25)
424		return;
425	disaster(sig);
426}
427
428/*
429 * Catch an unexpected signal.
430 */
431void
432disaster(sig)
433	int sig;
434{
435	emergency("fatal signal: %s", strsignal(sig));
436
437	sleep(STALL_TIMEOUT);
438	_exit(sig);		/* reboot */
439}
440
441/*
442 * Get the security level of the kernel.
443 */
444int
445getsecuritylevel()
446{
447#ifdef KERN_SECURELVL
448	int name[2], curlevel;
449	size_t len;
450	extern int errno;
451
452	name[0] = CTL_KERN;
453	name[1] = KERN_SECURELVL;
454	len = sizeof curlevel;
455	if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
456		emergency("cannot get kernel security level: %s",
457		    strerror(errno));
458		return (-1);
459	}
460	return (curlevel);
461#else
462	return (-1);
463#endif
464}
465
466/*
467 * Set the security level of the kernel.
468 */
469void
470setsecuritylevel(newlevel)
471	int newlevel;
472{
473#ifdef KERN_SECURELVL
474	int name[2], curlevel;
475	extern int errno;
476
477	curlevel = getsecuritylevel();
478	if (newlevel == curlevel)
479		return;
480	name[0] = CTL_KERN;
481	name[1] = KERN_SECURELVL;
482	if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
483		emergency(
484		    "cannot change kernel security level from %d to %d: %s",
485		    curlevel, newlevel, strerror(errno));
486		return;
487	}
488#ifdef SECURE
489	warning("kernel security level changed from %d to %d",
490	    curlevel, newlevel);
491#endif
492#endif
493}
494
495/*
496 * Change states in the finite state machine.
497 * The initial state is passed as an argument.
498 */
499void
500transition(s)
501	state_t s;
502{
503	for (;;)
504		s = (state_t) (*s)();
505}
506
507/*
508 * Close out the accounting files for a login session.
509 * NB: should send a message to the session logger to avoid blocking.
510 */
511void
512clear_session_logs(sp)
513	session_t *sp;
514{
515	char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
516
517	if (logout(line))
518		logwtmp(line, "", "");
519}
520
521/*
522 * Start a session and allocate a controlling terminal.
523 * Only called by children of init after forking.
524 */
525void
526setctty(name)
527	char *name;
528{
529	int fd;
530
531	(void) revoke(name);
532	sleep (2);			/* leave DTR low */
533	if ((fd = open(name, O_RDWR)) == -1) {
534		stall("can't open %s: %m", name);
535		_exit(1);
536	}
537	if (login_tty(fd) == -1) {
538		stall("can't get %s for controlling terminal: %m", name);
539		_exit(1);
540	}
541}
542
543/*
544 * Bring the system up single user.
545 */
546state_func_t
547single_user()
548{
549	pid_t pid, wpid;
550	int status;
551	sigset_t mask;
552	char shell[MAXPATHLEN];		/* Allocate space here */
553	char name[MAXPATHLEN];		/* Name (argv[0]) of shell */
554	char *argv[2];
555#ifdef SECURE
556	struct ttyent *typ;
557	struct passwd *pp;
558	static const char banner[] =
559		"Enter root password, or ^D to go multi-user\n";
560	char *clear, *password;
561#endif
562
563	/* Init shell and name */
564	strcpy(shell, _PATH_BSHELL);
565	strcpy(name, "-sh");
566
567	/*
568	 * If the kernel is in secure mode, downgrade it to insecure mode.
569	 */
570	if (getsecuritylevel() > 0)
571		setsecuritylevel(0);
572
573	if ((pid = fork()) == 0) {
574		/*
575		 * Start the single user session.
576		 */
577		setctty(_PATH_CONSOLE);
578
579#ifdef SECURE
580		/*
581		 * Check the root password.
582		 * We don't care if the console is 'on' by default;
583		 * it's the only tty that can be 'off' and 'secure'.
584		 */
585		typ = getttynam("console");
586		pp = getpwnam("root");
587		if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp &&
588		    *pp->pw_passwd) {
589			write(2, banner, sizeof banner - 1);
590			for (;;) {
591				clear = getpass("Password:");
592				if (clear == 0 || *clear == '\0')
593					_exit(0);
594				password = crypt(clear, pp->pw_passwd);
595				memset(clear, 0, _PASSWORD_LEN);
596				if (strcmp(password, pp->pw_passwd) == 0)
597					break;
598				warning("single-user login failed\n");
599			}
600		}
601		endttyent();
602		endpwent();
603#endif /* SECURE */
604
605#ifdef DEBUGSHELL
606		{
607			char altshell[128], *cp = altshell;
608			int num;
609
610#define	SHREQUEST \
611	"Enter pathname of shell or RETURN for sh: "
612			(void)write(STDERR_FILENO,
613			    SHREQUEST, sizeof(SHREQUEST) - 1);
614			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
615			    num != 0 && *cp != '\n' && cp < &altshell[127])
616					cp++;
617			*cp = '\0';
618
619			/* Copy in alternate shell */
620			if (altshell[0] != '\0'){
621				char *p;
622
623				/* Binary to exec */
624				strcpy(shell, altshell);
625
626				/* argv[0] */
627				p = strrchr(altshell, '/');
628				if(p == NULL) p = altshell;
629				else p++;
630
631				name[0] = '-';
632				strcpy(&name[1], p);
633			}
634		}
635#endif /* DEBUGSHELL */
636
637		/*
638		 * Unblock signals.
639		 * We catch all the interesting ones,
640		 * and those are reset to SIG_DFL on exec.
641		 */
642		sigemptyset(&mask);
643		sigprocmask(SIG_SETMASK, &mask, NULL);
644
645		/*
646		 * Fire off a shell.
647		 * If the default one doesn't work, try the Bourne shell.
648		 */
649		argv[0] = name;
650		argv[1] = NULL;
651		setenv("PATH", _PATH_STDPATH, 1);
652		execv(shell, argv);
653		emergency("can't exec %s for single user: %m", shell);
654
655		argv[0] = "-sh";
656		argv[1] = NULL;
657		execv(_PATH_BSHELL, argv);
658		emergency("can't exec %s for single user: %m", _PATH_BSHELL);
659		sleep(STALL_TIMEOUT);
660		_exit(1);
661	}
662
663	if (pid == -1) {
664		/*
665		 * We are seriously hosed.  Do our best.
666		 */
667		emergency("can't fork single-user shell, trying again");
668		while (waitpid(-1, NULL, WNOHANG) > 0)
669			continue;
670		return (state_func_t) single_user;
671	}
672
673	requested_transition = 0;
674	do {
675		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
676			collect_child(wpid);
677		if (wpid == -1) {
678			if (errno == EINTR)
679				continue;
680			warning("wait for single-user shell failed: %m; restarting");
681			return (state_func_t) single_user;
682		}
683		if (wpid == pid && WIFSTOPPED(status)) {
684			warning("init: shell stopped, restarting\n");
685			kill(pid, SIGCONT);
686			wpid = -1;
687		}
688	} while (wpid != pid && !requested_transition);
689
690	if (requested_transition)
691		return (state_func_t) requested_transition;
692
693	if (!WIFEXITED(status)) {
694		if (WTERMSIG(status) == SIGKILL) {
695			/*
696			 *  reboot(8) killed shell?
697			 */
698			warning("single user shell terminated.");
699			sleep(STALL_TIMEOUT);
700			_exit(0);
701		} else {
702			warning("single user shell terminated, restarting");
703			return (state_func_t) single_user;
704		}
705	}
706
707	runcom_mode = FASTBOOT;
708	return (state_func_t) runcom;
709}
710
711/*
712 * Run the system startup script.
713 */
714state_func_t
715runcom()
716{
717	pid_t pid, wpid;
718	int status;
719	char *argv[4];
720	struct sigaction sa;
721
722	if ((pid = fork()) == 0) {
723		sigemptyset(&sa.sa_mask);
724		sa.sa_flags = 0;
725		sa.sa_handler = SIG_IGN;
726		(void) sigaction(SIGTSTP, &sa, NULL);
727		(void) sigaction(SIGHUP, &sa, NULL);
728
729		setctty(_PATH_CONSOLE);
730
731		argv[0] = "sh";
732		argv[1] = _PATH_RUNCOM;
733		argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0;
734		argv[3] = 0;
735
736		sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
737
738		execv(_PATH_BSHELL, argv);
739		stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM);
740		_exit(1);	/* force single user mode */
741	}
742
743	if (pid == -1) {
744		emergency("can't fork for %s on %s: %m",
745			_PATH_BSHELL, _PATH_RUNCOM);
746		while (waitpid(-1, NULL, WNOHANG) > 0)
747			continue;
748		sleep(STALL_TIMEOUT);
749		return (state_func_t) single_user;
750	}
751
752	/*
753	 * Copied from single_user().  This is a bit paranoid.
754	 */
755	do {
756		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
757			collect_child(wpid);
758		if (wpid == -1) {
759			if (errno == EINTR)
760				continue;
761			warning("wait for %s on %s failed: %m; going to single user mode",
762				_PATH_BSHELL, _PATH_RUNCOM);
763			return (state_func_t) single_user;
764		}
765		if (wpid == pid && WIFSTOPPED(status)) {
766			warning("init: %s on %s stopped, restarting\n",
767				_PATH_BSHELL, _PATH_RUNCOM);
768			kill(pid, SIGCONT);
769			wpid = -1;
770		}
771	} while (wpid != pid);
772
773	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
774	    requested_transition == catatonia) {
775		/* /etc/rc executed /sbin/reboot; wait for the end quietly */
776		sigset_t s;
777
778		sigfillset(&s);
779		for (;;)
780			sigsuspend(&s);
781	}
782
783	if (!WIFEXITED(status)) {
784		warning("%s on %s terminated abnormally, going to single user mode",
785			_PATH_BSHELL, _PATH_RUNCOM);
786		return (state_func_t) single_user;
787	}
788
789	if (WEXITSTATUS(status))
790		return (state_func_t) single_user;
791
792	runcom_mode = AUTOBOOT;		/* the default */
793	/* NB: should send a message to the session logger to avoid blocking. */
794	logwtmp("~", "reboot", "");
795	return (state_func_t) read_ttys;
796}
797
798/*
799 * Open the session database.
800 *
801 * NB: We could pass in the size here; is it necessary?
802 */
803int
804start_session_db()
805{
806	if (session_db && (*session_db->close)(session_db))
807		emergency("session database close: %s", strerror(errno));
808	if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
809		emergency("session database open: %s", strerror(errno));
810		return (1);
811	}
812	return (0);
813
814}
815
816/*
817 * Add a new login session.
818 */
819void
820add_session(sp)
821	session_t *sp;
822{
823	DBT key;
824	DBT data;
825
826	key.data = &sp->se_process;
827	key.size = sizeof sp->se_process;
828	data.data = &sp;
829	data.size = sizeof sp;
830
831	if ((*session_db->put)(session_db, &key, &data, 0))
832		emergency("insert %d: %s", sp->se_process, strerror(errno));
833}
834
835/*
836 * Delete an old login session.
837 */
838void
839del_session(sp)
840	session_t *sp;
841{
842	DBT key;
843
844	key.data = &sp->se_process;
845	key.size = sizeof sp->se_process;
846
847	if ((*session_db->del)(session_db, &key, 0))
848		emergency("delete %d: %s", sp->se_process, strerror(errno));
849}
850
851/*
852 * Look up a login session by pid.
853 */
854session_t *
855#ifdef __STDC__
856find_session(pid_t pid)
857#else
858find_session(pid)
859	pid_t pid;
860#endif
861{
862	DBT key;
863	DBT data;
864	session_t *ret;
865
866	key.data = &pid;
867	key.size = sizeof pid;
868	if ((*session_db->get)(session_db, &key, &data, 0) != 0)
869		return 0;
870	memcpy(&ret, data.data, sizeof(ret));
871	return ret;
872}
873
874/*
875 * Construct an argument vector from a command line.
876 */
877char **
878construct_argv(command)
879	char *command;
880{
881	register int argc = 0;
882	register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1)
883						* sizeof (char *));
884	static const char separators[] = " \t";
885
886	if ((argv[argc++] = strtok(command, separators)) == 0)
887		return 0;
888	while ((argv[argc++] = strtok(NULL, separators)))
889		continue;
890	return argv;
891}
892
893/*
894 * Deallocate a session descriptor.
895 */
896void
897free_session(sp)
898	register session_t *sp;
899{
900	free(sp->se_device);
901	if (sp->se_getty) {
902		free(sp->se_getty);
903		free(sp->se_getty_argv);
904	}
905	if (sp->se_window) {
906		free(sp->se_window);
907		free(sp->se_window_argv);
908	}
909	free(sp);
910}
911
912/*
913 * Allocate a new session descriptor.
914 */
915session_t *
916new_session(sprev, session_index, typ)
917	session_t *sprev;
918	int session_index;
919	register struct ttyent *typ;
920{
921	register session_t *sp;
922
923	if ((typ->ty_status & TTY_ON) == 0 ||
924	    typ->ty_name == 0 ||
925	    typ->ty_getty == 0)
926		return 0;
927
928	sp = (session_t *) malloc(sizeof (session_t));
929	memset(sp, 0, sizeof *sp);
930
931	sp->se_flags = SE_PRESENT;
932	sp->se_index = session_index;
933
934	sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
935	(void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
936
937	if (setupargv(sp, typ) == 0) {
938		free_session(sp);
939		return (0);
940	}
941
942	sp->se_next = 0;
943	if (sprev == 0) {
944		sessions = sp;
945		sp->se_prev = 0;
946	} else {
947		sprev->se_next = sp;
948		sp->se_prev = sprev;
949	}
950
951	return sp;
952}
953
954/*
955 * Calculate getty and if useful window argv vectors.
956 */
957int
958setupargv(sp, typ)
959	session_t *sp;
960	struct ttyent *typ;
961{
962
963	if (sp->se_getty) {
964		free(sp->se_getty);
965		free(sp->se_getty_argv);
966	}
967	sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2);
968	(void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
969	sp->se_getty_argv = construct_argv(sp->se_getty);
970	if (sp->se_getty_argv == 0) {
971		warning("can't parse getty for port %s", sp->se_device);
972		free(sp->se_getty);
973		sp->se_getty = 0;
974		return (0);
975	}
976	if (typ->ty_window) {
977		if (sp->se_window)
978			free(sp->se_window);
979		sp->se_window = strdup(typ->ty_window);
980		sp->se_window_argv = construct_argv(sp->se_window);
981		if (sp->se_window_argv == 0) {
982			warning("can't parse window for port %s",
983				sp->se_device);
984			free(sp->se_window);
985			sp->se_window = 0;
986			return (0);
987		}
988	}
989	return (1);
990}
991
992/*
993 * Walk the list of ttys and create sessions for each active line.
994 */
995state_func_t
996read_ttys()
997{
998	int session_index = 0;
999	register session_t *sp, *snext;
1000	register struct ttyent *typ;
1001
1002	/*
1003	 * Destroy any previous session state.
1004	 * There shouldn't be any, but just in case...
1005	 */
1006	for (sp = sessions; sp; sp = snext) {
1007		if (sp->se_process)
1008			clear_session_logs(sp);
1009		snext = sp->se_next;
1010		free_session(sp);
1011	}
1012	sessions = 0;
1013	if (start_session_db())
1014		return (state_func_t) single_user;
1015
1016	/*
1017	 * Allocate a session entry for each active port.
1018	 * Note that sp starts at 0.
1019	 */
1020	while ((typ = getttyent()))
1021		if ((snext = new_session(sp, ++session_index, typ)))
1022			sp = snext;
1023
1024	endttyent();
1025
1026	return (state_func_t) multi_user;
1027}
1028
1029/*
1030 * Start a window system running.
1031 */
1032void
1033start_window_system(sp)
1034	session_t *sp;
1035{
1036	pid_t pid;
1037	sigset_t mask;
1038
1039	if ((pid = fork()) == -1) {
1040		emergency("can't fork for window system on port %s: %m",
1041			sp->se_device);
1042		/* hope that getty fails and we can try again */
1043		return;
1044	}
1045
1046	if (pid)
1047		return;
1048
1049	sigemptyset(&mask);
1050	sigprocmask(SIG_SETMASK, &mask, NULL);
1051
1052	if (setsid() < 0)
1053		emergency("setsid failed (window) %m");
1054
1055	execv(sp->se_window_argv[0], sp->se_window_argv);
1056	stall("can't exec window system '%s' for port %s: %m",
1057		sp->se_window_argv[0], sp->se_device);
1058	_exit(1);
1059}
1060
1061/*
1062 * Start a login session running.
1063 * For first open, man-handle tty directly to determine if it
1064 * really exists. It is not efficient to spawn gettys on devices
1065 * that do not exist.
1066 */
1067pid_t
1068start_getty(sp)
1069	session_t *sp;
1070{
1071	pid_t pid;
1072	sigset_t mask;
1073	time_t current_time = time(NULL);
1074	int p[2], new = 1;
1075
1076	if (sp->se_flags & SE_DEVEXISTS)
1077		new = 0;
1078
1079	if (new) {
1080		if (pipe(p) == -1)
1081			return -1;
1082	}
1083
1084	/*
1085	 * fork(), not vfork() -- we can't afford to block.
1086	 */
1087	if ((pid = fork()) == -1) {
1088		emergency("can't fork for getty on port %s: %m", sp->se_device);
1089		return -1;
1090	}
1091
1092	if (pid) {
1093		if (new) {
1094			char c;
1095
1096			close(p[1]);
1097			if (read(p[0], &c, 1) != 1) {
1098				close(p[0]);
1099				return -1;
1100			}
1101			close(p[0]);
1102			if (c == '1')
1103				sp->se_flags |= SE_DEVEXISTS;
1104			else
1105				sp->se_flags |= SE_SHUTDOWN;
1106		}
1107		return pid;
1108	}
1109	if (new) {
1110		int fd;
1111
1112		close(p[0]);
1113		fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0666);
1114		if (fd == -1 && (errno == ENXIO || errno == ENOENT ||
1115		    errno == EISDIR)) {
1116			(void)write(p[1], "0", 1);
1117			close(p[1]);
1118			_exit(1);
1119		}
1120		(void)write(p[1], "1", 1);
1121		close(p[1]);
1122		close(fd);
1123		sleep(1);
1124	}
1125
1126	if (current_time > sp->se_started &&
1127	    current_time - sp->se_started < GETTY_SPACING) {
1128		warning("getty repeating too quickly on port %s, sleeping",
1129		        sp->se_device);
1130		sleep((unsigned) GETTY_SLEEP);
1131	}
1132
1133	if (sp->se_window) {
1134		start_window_system(sp);
1135		sleep(WINDOW_WAIT);
1136	}
1137
1138	sigemptyset(&mask);
1139	sigprocmask(SIG_SETMASK, &mask, NULL);
1140
1141	execv(sp->se_getty_argv[0], sp->se_getty_argv);
1142	stall("can't exec getty '%s' for port %s: %m",
1143		sp->se_getty_argv[0], sp->se_device);
1144	_exit(1);
1145}
1146
1147/*
1148 * Collect exit status for a child.
1149 * If an exiting login, start a new login running.
1150 */
1151void
1152#ifdef __STDC__
1153collect_child(pid_t pid)
1154#else
1155collect_child(pid)
1156	pid_t pid;
1157#endif
1158{
1159	register session_t *sp, *sprev, *snext;
1160
1161	if (! sessions)
1162		return;
1163
1164	if (! (sp = find_session(pid)))
1165		return;
1166
1167	clear_session_logs(sp);
1168	login_fbtab(sp->se_device + sizeof(_PATH_DEV) - 1, 0, 0);
1169	del_session(sp);
1170	sp->se_process = 0;
1171
1172	if (sp->se_flags & SE_SHUTDOWN) {
1173		if ((sprev = sp->se_prev))
1174			sprev->se_next = sp->se_next;
1175		else
1176			sessions = sp->se_next;
1177		if ((snext = sp->se_next))
1178			snext->se_prev = sp->se_prev;
1179		free_session(sp);
1180		return;
1181	}
1182
1183	if ((pid = start_getty(sp)) == -1) {
1184		/* serious trouble */
1185		requested_transition = clean_ttys;
1186		return;
1187	}
1188
1189	sp->se_process = pid;
1190	sp->se_started = time(NULL);
1191	add_session(sp);
1192}
1193
1194/*
1195 * Catch a signal and request a state transition.
1196 */
1197void
1198transition_handler(sig)
1199	int sig;
1200{
1201
1202	switch (sig) {
1203	case SIGHUP:
1204		requested_transition = clean_ttys;
1205		break;
1206	case SIGTERM:
1207		requested_transition = death;
1208		break;
1209	case SIGTSTP:
1210		requested_transition = catatonia;
1211		break;
1212	default:
1213		requested_transition = 0;
1214		break;
1215	}
1216}
1217
1218/*
1219 * Take the system multiuser.
1220 */
1221state_func_t
1222multi_user()
1223{
1224	pid_t pid;
1225	register session_t *sp;
1226
1227	requested_transition = 0;
1228
1229	/*
1230	 * If the administrator has not set the security level to -1
1231	 * to indicate that the kernel should not run multiuser in secure
1232	 * mode, and the run script has not set a higher level of security
1233	 * than level 1, then put the kernel into secure mode.
1234	 */
1235	if (getsecuritylevel() == 0)
1236		setsecuritylevel(1);
1237
1238	for (sp = sessions; sp; sp = sp->se_next) {
1239		if (sp->se_process)
1240			continue;
1241		if ((pid = start_getty(sp)) == -1) {
1242			/* serious trouble */
1243			requested_transition = clean_ttys;
1244			break;
1245		}
1246		sp->se_process = pid;
1247		sp->se_started = time(NULL);
1248		add_session(sp);
1249	}
1250
1251	while (!requested_transition)
1252		if ((pid = waitpid(-1, NULL, 0)) != -1)
1253			collect_child(pid);
1254
1255	return (state_func_t) requested_transition;
1256}
1257
1258/*
1259 * This is an n-squared algorithm.  We hope it isn't run often...
1260 */
1261state_func_t
1262clean_ttys()
1263{
1264	register session_t *sp, *sprev;
1265	register struct ttyent *typ;
1266	register int session_index = 0;
1267	register int devlen;
1268
1269	for (sp = sessions; sp; sp = sp->se_next)
1270		sp->se_flags &= ~SE_PRESENT;
1271
1272	devlen = sizeof(_PATH_DEV) - 1;
1273	while ((typ = getttyent())) {
1274		++session_index;
1275
1276		for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1277			if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1278				break;
1279
1280		if (sp) {
1281			sp->se_flags |= SE_PRESENT;
1282			if (sp->se_index != session_index) {
1283				warning("port %s changed utmp index from %d to %d",
1284				       sp->se_device, sp->se_index,
1285				       session_index);
1286				sp->se_index = session_index;
1287			}
1288			if ((typ->ty_status & TTY_ON) == 0 ||
1289			    typ->ty_getty == 0) {
1290				sp->se_flags |= SE_SHUTDOWN;
1291				kill(sp->se_process, SIGHUP);
1292				continue;
1293			}
1294			sp->se_flags &= ~SE_SHUTDOWN;
1295			if (setupargv(sp, typ) == 0) {
1296				warning("can't parse getty for port %s",
1297					sp->se_device);
1298				sp->se_flags |= SE_SHUTDOWN;
1299				kill(sp->se_process, SIGHUP);
1300			}
1301			continue;
1302		}
1303
1304		new_session(sprev, session_index, typ);
1305	}
1306
1307	endttyent();
1308
1309	for (sp = sessions; sp; sp = sp->se_next)
1310		if ((sp->se_flags & SE_PRESENT) == 0) {
1311			sp->se_flags |= SE_SHUTDOWN;
1312			kill(sp->se_process, SIGHUP);
1313		}
1314
1315	return (state_func_t) multi_user;
1316}
1317
1318/*
1319 * Block further logins.
1320 */
1321state_func_t
1322catatonia()
1323{
1324	register session_t *sp;
1325
1326	for (sp = sessions; sp; sp = sp->se_next)
1327		sp->se_flags |= SE_SHUTDOWN;
1328
1329	return (state_func_t) multi_user;
1330}
1331
1332/*
1333 * Note SIGALRM.
1334 */
1335void
1336alrm_handler(sig)
1337	int sig;
1338{
1339	clang = 1;
1340}
1341
1342/*
1343 * Bring the system down to single user.
1344 */
1345state_func_t
1346death()
1347{
1348	register session_t *sp;
1349	register int i;
1350	pid_t pid;
1351	static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1352
1353	for (sp = sessions; sp; sp = sp->se_next)
1354		sp->se_flags |= SE_SHUTDOWN;
1355
1356	/* NB: should send a message to the session logger to avoid blocking. */
1357	logwtmp("~", "shutdown", "");
1358
1359	for (i = 0; i < 3; ++i) {
1360		if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1361			return (state_func_t) single_user;
1362
1363		clang = 0;
1364		alarm(DEATH_WATCH);
1365		do
1366			if ((pid = waitpid(-1, NULL, 0)) != -1)
1367				collect_child(pid);
1368		while (clang == 0 && errno != ECHILD);
1369
1370		if (errno == ECHILD)
1371			return (state_func_t) single_user;
1372	}
1373
1374	warning("some processes would not die; ps axl advised");
1375
1376	return (state_func_t) single_user;
1377}
1378