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