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