init.c revision 1.63
1/* $OpenBSD: init.c,v 1.63 2017/03/02 10:38:09 natano 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, sizeof(pbuf), RPP_ECHO_OFF); 565 if (clear == NULL || *clear == '\0') 566 _exit(0); 567 if (crypt_checkpass(clear, pp->pw_passwd) == 0) 568 ok = 1; 569 memset(clear, 0, strlen(clear)); 570 if (ok) 571 break; 572 warning("single-user login failed\n"); 573 } 574 } 575 endttyent(); 576 endpwent(); 577#endif /* SECURE */ 578 579#ifdef DEBUGSHELL 580 { 581 char altshell[128], *cp = altshell; 582 int num; 583 584#define SHREQUEST \ 585 "Enter pathname of shell or RETURN for sh: " 586 587 (void)write(STDERR_FILENO, 588 SHREQUEST, sizeof(SHREQUEST) - 1); 589 while ((num = read(STDIN_FILENO, cp, 1)) != -1 && 590 num != 0 && *cp != '\n' && cp < &altshell[127]) 591 cp++; 592 *cp = '\0'; 593 594 /* Copy in alternate shell */ 595 if (altshell[0] != '\0'){ 596 char *p; 597 598 /* Binary to exec */ 599 strlcpy(shell, altshell, sizeof shell); 600 601 /* argv[0] */ 602 p = strrchr(altshell, '/'); 603 if(p == NULL) p = altshell; 604 else p++; 605 606 name[0] = '-'; 607 strlcpy(&name[1], p, sizeof name -1); 608 } 609 } 610#endif /* DEBUGSHELL */ 611 612 /* 613 * Unblock signals. 614 * We catch all the interesting ones, 615 * and those are reset to SIG_DFL on exec. 616 */ 617 sigemptyset(&mask); 618 sigprocmask(SIG_SETMASK, &mask, NULL); 619 620 /* 621 * Fire off a shell. 622 * If the default one doesn't work, try the Bourne shell. 623 */ 624 argv[0] = name; 625 argv[1] = NULL; 626 setenv("PATH", _PATH_STDPATH, 1); 627 execv(shell, argv); 628 emergency("can't exec %s for single user: %m", shell); 629 630 argv[0] = "-sh"; 631 argv[1] = NULL; 632 execv(_PATH_BSHELL, argv); 633 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 634 sleep(STALL_TIMEOUT); 635 _exit(1); 636 } 637 638 if (pid == -1) { 639 /* 640 * We are seriously hosed. Do our best. 641 */ 642 emergency("can't fork single-user shell, trying again"); 643 while (waitpid(-1, NULL, WNOHANG) > 0) 644 continue; 645 return single_user; 646 } 647 648 requested_transition = 0; 649 do { 650 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 651 collect_child(wpid); 652 if (wpid == -1) { 653 if (errno == EINTR) 654 continue; 655 warning("wait for single-user shell failed: %m; restarting"); 656 return single_user; 657 } 658 if (wpid == pid && WIFSTOPPED(status)) { 659 warning("init: shell stopped, restarting\n"); 660 kill(pid, SIGCONT); 661 wpid = -1; 662 } 663 } while (wpid != pid && !requested_transition); 664 665 if (requested_transition) 666 return requested_transition; 667 668 if (!WIFEXITED(status)) { 669 if (WTERMSIG(status) == SIGKILL) { 670 /* 671 * reboot(8) killed shell? 672 */ 673 warning("single user shell terminated."); 674 sleep(STALL_TIMEOUT); 675 _exit(0); 676 } else { 677 warning("single user shell terminated, restarting"); 678 return single_user; 679 } 680 } 681 682 runcom_mode = FASTBOOT; 683 return runcom; 684} 685 686/* 687 * Run the system startup script. 688 */ 689state_t 690f_runcom(void) 691{ 692 pid_t pid, wpid; 693 int status; 694 char *argv[4]; 695 struct sigaction sa; 696 697 if ((pid = fork()) == 0) { 698 memset(&sa, 0, sizeof sa); 699 sigemptyset(&sa.sa_mask); 700 sa.sa_flags = 0; 701 sa.sa_handler = SIG_IGN; 702 (void) sigaction(SIGTSTP, &sa, NULL); 703 (void) sigaction(SIGHUP, &sa, NULL); 704 705 setctty(_PATH_CONSOLE); 706 707 argv[0] = "sh"; 708 argv[1] = _PATH_RUNCOM; 709 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : NULL; 710 argv[3] = NULL; 711 712 sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); 713 714 setprocresources(RESOURCE_RC); 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, NULL, WNOHANG) > 0) 725 continue; 726 sleep(STALL_TIMEOUT); 727 return 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 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 single_user; 765 } 766 767 if (WEXITSTATUS(status)) 768 return 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 read_ttys; 774} 775 776/* 777 * Compare session keys. 778 */ 779static int 780cmp_sessions(session_t *sp1, session_t *sp2) 781{ 782 if (sp1->se_process < sp2->se_process) 783 return (-1); 784 if (sp1->se_process > sp2->se_process) 785 return (1); 786 return (0); 787} 788 789/* 790 * Add a new login session. 791 */ 792void 793add_session(session_t *sp) 794{ 795 if (RB_INSERT(session_tree, &session_tree, sp) != NULL) 796 emergency("insert %d: %s", sp->se_process, strerror(errno)); 797} 798 799/* 800 * Delete an old login session. 801 */ 802void 803del_session(session_t *sp) 804{ 805 RB_REMOVE(session_tree, &session_tree, sp); 806} 807 808/* 809 * Look up a login session by pid. 810 */ 811session_t * 812find_session(pid_t pid) 813{ 814 struct init_session s; 815 816 s.se_process = pid; 817 return (RB_FIND(session_tree, &session_tree, &s)); 818} 819 820/* 821 * Construct an argument vector from a command line. 822 */ 823char ** 824construct_argv(char *command) 825{ 826 int argc = 0; 827 char **argv = calloc((strlen(command) + 1) / 2 + 1, sizeof (char *)); 828 static const char separators[] = " \t"; 829 830 if (argv == NULL) 831 return (0); 832 833 if ((argv[argc++] = strtok(command, separators)) == 0) { 834 free(argv); 835 return (0); 836 } 837 while ((argv[argc++] = strtok(NULL, separators))) 838 continue; 839 return (argv); 840} 841 842/* 843 * Deallocate a session descriptor. 844 */ 845void 846free_session(session_t *sp) 847{ 848 free(sp->se_device); 849 if (sp->se_getty) { 850 free(sp->se_getty); 851 free(sp->se_getty_argv); 852 } 853 if (sp->se_window) { 854 free(sp->se_window); 855 free(sp->se_window_argv); 856 } 857 free(sp); 858} 859 860/* 861 * Allocate a new session descriptor. 862 */ 863session_t * 864new_session(session_t *sprev, int session_index, struct ttyent *typ) 865{ 866 session_t *sp; 867 868 if ((typ->ty_status & TTY_ON) == 0 || 869 typ->ty_name == 0 || 870 typ->ty_getty == 0) 871 return (0); 872 873 sp = calloc(1, sizeof (session_t)); 874 if (sp == NULL) 875 err(1, "calloc"); 876 877 sp->se_flags = SE_PRESENT; 878 sp->se_index = session_index; 879 880 if (asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name) == -1) 881 err(1, "asprintf"); 882 883 if (setupargv(sp, typ) == 0) { 884 free_session(sp); 885 return (0); 886 } 887 888 sp->se_next = NULL; 889 if (sprev == NULL) { 890 sessions = sp; 891 sp->se_prev = NULL; 892 } else { 893 sprev->se_next = sp; 894 sp->se_prev = sprev; 895 } 896 897 return (sp); 898} 899 900/* 901 * Calculate getty and if useful window argv vectors. 902 */ 903int 904setupargv(session_t *sp, struct ttyent *typ) 905{ 906 if (sp->se_getty) { 907 free(sp->se_getty); 908 free(sp->se_getty_argv); 909 } 910 if (asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name) == -1) 911 err(1, "asprintf"); 912 sp->se_getty_argv = construct_argv(sp->se_getty); 913 if (sp->se_getty_argv == 0) { 914 warning("can't parse getty for port %s", sp->se_device); 915 free(sp->se_getty); 916 sp->se_getty = NULL; 917 return (0); 918 } 919 if (typ->ty_window) { 920 free(sp->se_window); 921 sp->se_window = strdup(typ->ty_window); 922 if (sp->se_window == NULL) { 923 warning("can't allocate window"); 924 return (0); 925 } 926 sp->se_window_argv = construct_argv(sp->se_window); 927 if (sp->se_window_argv == NULL) { 928 warning("can't parse window for port %s", 929 sp->se_device); 930 free(sp->se_window); 931 sp->se_window = NULL; 932 return (0); 933 } 934 } 935 return (1); 936} 937 938/* 939 * Walk the list of ttys and create sessions for each active line. 940 */ 941state_t 942f_read_ttys(void) 943{ 944 int session_index = 0; 945 session_t *sp, *snext; 946 struct ttyent *typ; 947 948 /* 949 * Destroy any previous session state. 950 * There shouldn't be any, but just in case... 951 */ 952 for (sp = sessions; sp; sp = snext) { 953 if (sp->se_process) 954 clear_session_logs(sp); 955 snext = sp->se_next; 956 free_session(sp); 957 } 958 sessions = NULL; 959 960 /* 961 * Allocate a session entry for each active port. 962 * Note that sp starts at 0. 963 */ 964 while ((typ = getttyent())) 965 if ((snext = new_session(sp, ++session_index, typ))) 966 sp = snext; 967 968 endttyent(); 969 970 return multi_user; 971} 972 973/* 974 * Start a window system running. 975 */ 976void 977start_window_system(session_t *sp) 978{ 979 pid_t pid; 980 sigset_t mask; 981 982 if ((pid = fork()) == -1) { 983 emergency("can't fork for window system on port %s: %m", 984 sp->se_device); 985 /* hope that getty fails and we can try again */ 986 return; 987 } 988 989 if (pid) 990 return; 991 992 sigemptyset(&mask); 993 sigprocmask(SIG_SETMASK, &mask, NULL); 994 995 if (setsid() < 0) 996 emergency("setsid failed (window) %m"); 997 998 setprocresources(RESOURCE_WINDOW); 999 1000 execv(sp->se_window_argv[0], sp->se_window_argv); 1001 stall("can't exec window system '%s' for port %s: %m", 1002 sp->se_window_argv[0], sp->se_device); 1003 _exit(1); 1004} 1005 1006/* 1007 * Start a login session running. 1008 * For first open, man-handle tty directly to determine if it 1009 * really exists. It is not efficient to spawn gettys on devices 1010 * that do not exist. 1011 */ 1012pid_t 1013start_getty(session_t *sp) 1014{ 1015 pid_t pid; 1016 sigset_t mask; 1017 time_t current_time = time(NULL); 1018 int p[2], new = 1; 1019 1020 if (sp->se_flags & SE_DEVEXISTS) 1021 new = 0; 1022 1023 if (new) { 1024 if (pipe(p) == -1) 1025 return (-1); 1026 } 1027 1028 /* 1029 * fork(), not vfork() -- we can't afford to block. 1030 */ 1031 if ((pid = fork()) == -1) { 1032 emergency("can't fork for getty on port %s: %m", sp->se_device); 1033 return (-1); 1034 } 1035 1036 if (pid) { 1037 if (new) { 1038 char c; 1039 1040 close(p[1]); 1041 if (read(p[0], &c, 1) != 1) { 1042 close(p[0]); 1043 return (-1); 1044 } 1045 close(p[0]); 1046 if (c == '1') 1047 sp->se_flags |= SE_DEVEXISTS; 1048 else 1049 sp->se_flags |= SE_SHUTDOWN; 1050 } 1051 return (pid); 1052 } 1053 if (new) { 1054 int fd; 1055 1056 close(p[0]); 1057 fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0666); 1058 if (fd == -1 && (errno == ENXIO || errno == ENOENT || 1059 errno == EISDIR)) { 1060 (void)write(p[1], "0", 1); 1061 close(p[1]); 1062 _exit(1); 1063 } 1064 (void)write(p[1], "1", 1); 1065 close(p[1]); 1066 close(fd); 1067 sleep(1); 1068 } 1069 1070 if (current_time > sp->se_started && 1071 current_time - sp->se_started < GETTY_SPACING) { 1072 warning("getty repeating too quickly on port %s, sleeping", 1073 sp->se_device); 1074 sleep(GETTY_SLEEP); 1075 } 1076 1077 if (sp->se_window) { 1078 start_window_system(sp); 1079 sleep(WINDOW_WAIT); 1080 } 1081 1082 sigemptyset(&mask); 1083 sigprocmask(SIG_SETMASK, &mask, NULL); 1084 1085 setprocresources(RESOURCE_GETTY); 1086 1087 execv(sp->se_getty_argv[0], sp->se_getty_argv); 1088 stall("can't exec getty '%s' for port %s: %m", 1089 sp->se_getty_argv[0], sp->se_device); 1090 _exit(1); 1091} 1092 1093/* 1094 * Collect exit status for a child. 1095 * If an exiting login, start a new login running. 1096 */ 1097void 1098collect_child(pid_t pid) 1099{ 1100 session_t *sp, *sprev, *snext; 1101 1102 if (sessions == NULL) 1103 return; 1104 1105 if ((sp = find_session(pid)) == NULL) 1106 return; 1107 1108 clear_session_logs(sp); 1109 login_fbtab(sp->se_device + sizeof(_PATH_DEV) - 1, 0, 0); 1110 del_session(sp); 1111 sp->se_process = 0; 1112 1113 if (sp->se_flags & SE_SHUTDOWN) { 1114 if ((sprev = sp->se_prev)) 1115 sprev->se_next = sp->se_next; 1116 else 1117 sessions = sp->se_next; 1118 if ((snext = sp->se_next)) 1119 snext->se_prev = sp->se_prev; 1120 free_session(sp); 1121 return; 1122 } 1123 1124 if ((pid = start_getty(sp)) == -1) { 1125 /* serious trouble */ 1126 requested_transition = clean_ttys; 1127 return; 1128 } 1129 1130 sp->se_process = pid; 1131 sp->se_started = time(NULL); 1132 add_session(sp); 1133} 1134 1135/* 1136 * Catch a signal and request a state transition. 1137 */ 1138void 1139transition_handler(int sig) 1140{ 1141 1142 switch (sig) { 1143 case SIGHUP: 1144 requested_transition = clean_ttys; 1145 break; 1146 case SIGINT: 1147 requested_transition = do_reboot; 1148 break; 1149 case SIGTERM: 1150 requested_transition = death; 1151 break; 1152 case SIGUSR1: 1153 requested_transition = nice_death; 1154 break; 1155 case SIGUSR2: 1156 requested_transition = hard_death; 1157 break; 1158 case SIGTSTP: 1159 requested_transition = catatonia; 1160 break; 1161 default: 1162 requested_transition = 0; 1163 break; 1164 } 1165} 1166 1167/* 1168 * Take the system multiuser. 1169 */ 1170state_t 1171f_multi_user(void) 1172{ 1173 pid_t pid; 1174 session_t *sp; 1175 1176 /* 1177 * If the administrator has not set the security level to -1 1178 * to indicate that the kernel should not run multiuser in secure 1179 * mode, and the run script has not set a higher level of security 1180 * than level 1, then put the kernel into secure mode. 1181 */ 1182 if (requested_transition != catatonia) { 1183 if (getsecuritylevel() == 0) 1184 setsecuritylevel(1); 1185 } 1186 1187 requested_transition = 0; 1188 1189 for (sp = sessions; sp; sp = sp->se_next) { 1190 if (sp->se_process) 1191 continue; 1192 if ((pid = start_getty(sp)) == -1) { 1193 /* serious trouble */ 1194 requested_transition = clean_ttys; 1195 break; 1196 } 1197 sp->se_process = pid; 1198 sp->se_started = time(NULL); 1199 add_session(sp); 1200 } 1201 1202 while (!requested_transition) 1203 if ((pid = waitpid(-1, NULL, 0)) != -1) 1204 collect_child(pid); 1205 1206 return requested_transition; 1207} 1208 1209/* 1210 * This is an n-squared algorithm. We hope it isn't run often... 1211 */ 1212state_t 1213f_clean_ttys(void) 1214{ 1215 session_t *sp, *sprev; 1216 struct ttyent *typ; 1217 int session_index = 0; 1218 int devlen; 1219 1220 for (sp = sessions; sp; sp = sp->se_next) 1221 sp->se_flags &= ~SE_PRESENT; 1222 1223 devlen = sizeof(_PATH_DEV) - 1; 1224 while ((typ = getttyent())) { 1225 ++session_index; 1226 1227 for (sprev = NULL, sp = sessions; sp; sprev = sp, sp = sp->se_next) 1228 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1229 break; 1230 1231 if (sp) { 1232 sp->se_flags |= SE_PRESENT; 1233 if (sp->se_index != session_index) { 1234 warning("port %s changed utmp index from %d to %d", 1235 sp->se_device, sp->se_index, 1236 session_index); 1237 sp->se_index = session_index; 1238 } 1239 if ((typ->ty_status & TTY_ON) == 0 || 1240 typ->ty_getty == 0) { 1241 sp->se_flags |= SE_SHUTDOWN; 1242 kill(sp->se_process, SIGHUP); 1243 continue; 1244 } 1245 sp->se_flags &= ~SE_SHUTDOWN; 1246 if (setupargv(sp, typ) == 0) { 1247 warning("can't parse getty for port %s", 1248 sp->se_device); 1249 sp->se_flags |= SE_SHUTDOWN; 1250 kill(sp->se_process, SIGHUP); 1251 } 1252 continue; 1253 } 1254 1255 new_session(sprev, session_index, typ); 1256 } 1257 1258 endttyent(); 1259 1260 for (sp = sessions; sp; sp = sp->se_next) 1261 if ((sp->se_flags & SE_PRESENT) == 0) { 1262 sp->se_flags |= SE_SHUTDOWN; 1263 kill(sp->se_process, SIGHUP); 1264 } 1265 1266 return multi_user; 1267} 1268 1269/* 1270 * Block further logins. 1271 */ 1272state_t 1273f_catatonia(void) 1274{ 1275 session_t *sp; 1276 1277 for (sp = sessions; sp; sp = sp->se_next) 1278 sp->se_flags |= SE_SHUTDOWN; 1279 1280 return multi_user; 1281} 1282 1283/* 1284 * Note SIGALRM. 1285 */ 1286void 1287alrm_handler(int sig) 1288{ 1289 clang = 1; 1290} 1291 1292int death_howto = RB_HALT; 1293 1294/* 1295 * Reboot the system. 1296 */ 1297state_t 1298f_do_reboot(void) 1299{ 1300 death_howto = RB_AUTOBOOT; 1301 return nice_death; 1302} 1303 1304/* 1305 * Bring the system down nicely, then we must powerdown because something 1306 * is very wrong. 1307 */ 1308state_t 1309f_hard_death(void) 1310{ 1311 death_howto |= RB_POWERDOWN; 1312 return nice_death; 1313} 1314 1315/* 1316 * Bring the system down to single user nicely, after run the shutdown script. 1317 */ 1318state_t 1319f_nice_death(void) 1320{ 1321 session_t *sp; 1322 int i; 1323 pid_t pid; 1324 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1325 int status; 1326 1327#ifdef CPU_LIDSUSPEND 1328 int mib[] = {CTL_MACHDEP, CPU_LIDACTION}; 1329 int lidaction = 0; 1330 1331 if ((death_howto & RB_POWERDOWN) && 1332 (sysctl(mib, 2, NULL, NULL, &lidaction, 1333 sizeof(lidaction)) == -1) && (errno != EOPNOTSUPP)) 1334 warning("cannot disable lid action"); 1335#endif 1336 1337 for (sp = sessions; sp; sp = sp->se_next) { 1338 sp->se_flags &= ~SE_PRESENT; 1339 sp->se_flags |= SE_SHUTDOWN; 1340 kill(sp->se_process, SIGHUP); 1341 } 1342 1343 /* terminate the accounting process */ 1344 acct(NULL); 1345 1346 /* NB: should send a message to the session logger to avoid blocking. */ 1347 logwtmp("~", "shutdown", ""); 1348 1349 if (access(_PATH_RUNCOM, R_OK) != -1) { 1350 struct sigaction sa; 1351 1352 switch ((pid = fork())) { 1353 case -1: 1354 break; 1355 case 0: 1356 1357 memset(&sa, 0, sizeof sa); 1358 sigemptyset(&sa.sa_mask); 1359 sa.sa_flags = 0; 1360 sa.sa_handler = SIG_IGN; 1361 (void) sigaction(SIGTSTP, &sa, NULL); 1362 (void) sigaction(SIGHUP, &sa, NULL); 1363 1364 setctty(_PATH_CONSOLE); 1365 1366 sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); 1367 1368 execl(_PATH_BSHELL, "sh", _PATH_RUNCOM, "shutdown", 1369 (char *)NULL); 1370 stall("can't exec %s for %s %s: %m", _PATH_BSHELL, 1371 _PATH_RUNCOM, "shutdown"); 1372 _exit(1); 1373 default: 1374 waitpid(pid, &status, 0); 1375 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) 1376 death_howto |= RB_POWERDOWN; 1377 } 1378 } 1379 1380 for (i = 0; i < 3; ++i) { 1381 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1382 goto die; 1383 1384 clang = 0; 1385 alarm(DEATH_WATCH); 1386 do { 1387 if ((pid = waitpid(-1, NULL, 0)) != -1) 1388 collect_child(pid); 1389 } while (clang == 0 && errno != ECHILD); 1390 1391 if (errno == ECHILD) 1392 goto die; 1393 } 1394 1395 warning("some processes would not die; ps axl advised"); 1396 1397die: 1398 reboot(death_howto); 1399 1400 /* ... and if that fails.. oh well */ 1401 return single_user; 1402} 1403 1404/* 1405 * Bring the system down to single user. 1406 */ 1407state_t 1408f_death(void) 1409{ 1410 session_t *sp; 1411 int i; 1412 pid_t pid; 1413 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1414 1415 /* terminate the accounting process */ 1416 acct(NULL); 1417 1418 for (sp = sessions; sp; sp = sp->se_next) 1419 sp->se_flags |= SE_SHUTDOWN; 1420 1421 /* NB: should send a message to the session logger to avoid blocking. */ 1422 logwtmp("~", "shutdown", ""); 1423 1424 for (i = 0; i < 3; ++i) { 1425 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1426 return single_user; 1427 1428 clang = 0; 1429 alarm(DEATH_WATCH); 1430 do { 1431 if ((pid = waitpid(-1, NULL, 0)) != -1) 1432 collect_child(pid); 1433 } while (clang == 0 && errno != ECHILD); 1434 1435 if (errno == ECHILD) 1436 return single_user; 1437 } 1438 1439 warning("some processes would not die; ps axl advised"); 1440 1441 return single_user; 1442} 1443 1444#ifdef LOGIN_CAP 1445void 1446setprocresources(char *class) 1447{ 1448 login_cap_t *lc; 1449 1450 if ((lc = login_getclass(class)) != NULL) { 1451 setusercontext(lc, NULL, 0, 1452 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK); 1453 login_close(lc); 1454 } 1455} 1456#endif 1457