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