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