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