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