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