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