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