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