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