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