1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * 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 38 char copyright[] = 39 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 40 All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 /*static char sccsid[] = "from: @(#)init.c 6.22 (Berkeley) 6/2/93";*/ 45 static char rcsid[] = "$Id: init.c,v 1.14 1994/04/26 19:56:22 pk Exp $"; 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #ifndef NOSYSCTL 50 #include <sys/sysctl.h> 51 #endif 52 #include <sys/wait.h> 53 54 #include <db.h> 55 #include <errno.h> 56 #include <fcntl.h> 57 #include <signal.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <syslog.h> 62 #include <time.h> 63 #include <ttyent.h> 64 #include <unistd.h> 65 66 #ifdef __STDC__ 67 #include <stdarg.h> 68 #else 69 #include <varargs.h> 70 #endif 71 72 #ifdef SECURE 73 #include <pwd.h> 74 #endif 75 76 #include "pathnames.h" 77 78 /* 79 * Until the mythical util.h arrives... 80 */ 81 extern int login_tty __P((int)); 82 extern int logout __P((const char *)); 83 extern void logwtmp __P((const char *, const char *, const char *)); 84 85 /* 86 * Sleep times; used to prevent thrashing. 87 */ 88 #define GETTY_SPACING 5 /* N secs minimum getty spacing */ 89 #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ 90 #define WINDOW_WAIT 3 /* wait N secs after starting window */ 91 #define STALL_TIMEOUT 30 /* wait N secs after warning */ 92 #define DEATH_WATCH 10 /* wait N secs for procs to die */ 93 94 void handle __P((sig_t, ...)); 95 void delset __P((sigset_t *, ...)); 96 97 void stall __P((char *, ...)); 98 void warning __P((char *, ...)); 99 void emergency __P((char *, ...)); 100 void disaster __P((int)); 101 void badsys __P((int)); 102 103 /* 104 * We really need a recursive typedef... 105 * The following at least guarantees that the return type of (*state_t)() 106 * is sufficiently wide to hold a function pointer. 107 */ 108 typedef long (*state_func_t) __P((void)); 109 typedef state_func_t (*state_t) __P((void)); 110 111 state_func_t single_user __P((void)); 112 state_func_t runcom __P((void)); 113 state_func_t read_ttys __P((void)); 114 state_func_t multi_user __P((void)); 115 state_func_t clean_ttys __P((void)); 116 state_func_t catatonia __P((void)); 117 state_func_t death __P((void)); 118 119 enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; 120 121 void transition __P((state_t)); 122 #ifndef LETS_GET_SMALL 123 state_t requested_transition = runcom; 124 #else /* LETS_GET_SMALL */ 125 state_t requested_transition = single_user; 126 #endif /* LETS_GET_SMALL */ 127 128 void setctty __P((char *)); 129 130 typedef struct init_session { 131 int se_index; /* index of entry in ttys file */ 132 pid_t se_process; /* controlling process */ 133 time_t se_started; /* used to avoid thrashing */ 134 int se_flags; /* status of session */ 135 #define SE_SHUTDOWN 0x1 /* session won't be restarted */ 136 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 145 void free_session __P((session_t *)); 146 session_t *new_session __P((session_t *, int, struct ttyent *)); 147 session_t *sessions; 148 149 char **construct_argv __P((char *)); 150 void start_window_system __P((session_t *)); 151 void collect_child __P((pid_t)); 152 pid_t start_getty __P((session_t *)); 153 void transition_handler __P((int)); 154 void alrm_handler __P((int)); 155 void setsecuritylevel __P((int)); 156 int getsecuritylevel __P((void)); 157 int setupargv __P((session_t *, struct ttyent *)); 158 int clang; 159 160 void clear_session_logs __P((session_t *)); 161 162 int start_session_db __P((void)); 163 void add_session __P((session_t *)); 164 void del_session __P((session_t *)); 165 session_t *find_session __P((pid_t)); 166 DB *session_db; 167 168 /* 169 * The mother of all processes. 170 */ 171 int 172 main(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, (sigset_t *) 0); 250 sigemptyset(&sa.sa_mask); 251 sa.sa_flags = 0; 252 sa.sa_handler = SIG_IGN; 253 (void) sigaction(SIGTTIN, &sa, (struct sigaction *)0); 254 (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0); 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 */ 277 void 278 #ifdef __STDC__ 279 handle(sig_t handler, ...) 280 #else 281 handle(va_alist) 282 va_dcl 283 #endif 284 { 285 int sig; 286 struct sigaction sa; 287 int 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, (struct sigaction *) 0); 306 } 307 va_end(ap); 308 } 309 310 /* 311 * Delete a set of signals from a mask. 312 */ 313 void 314 #ifdef __STDC__ 315 delset(sigset_t *maskp, ...) 316 #else 317 delset(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 */ 342 void 343 #ifdef __STDC__ 344 stall(char *message, ...) 345 #else 346 stall(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 sleep(STALL_TIMEOUT); 363 } 364 365 /* 366 * Like stall(), but doesn't sleep. 367 * If cpp had variadic macros, the two functions could be #defines for another. 368 * NB: should send a message to the session logger to avoid blocking. 369 */ 370 void 371 #ifdef __STDC__ 372 warning(char *message, ...) 373 #else 374 warning(va_alist) 375 va_dcl 376 #endif 377 { 378 va_list ap; 379 #ifndef __STDC__ 380 char *message; 381 382 va_start(ap); 383 message = va_arg(ap, char *); 384 #else 385 va_start(ap, message); 386 #endif 387 388 vsyslog(LOG_ALERT, message, ap); 389 va_end(ap); 390 } 391 392 /* 393 * Log an emergency message. 394 * NB: should send a message to the session logger to avoid blocking. 395 */ 396 void 397 #ifdef __STDC__ 398 emergency(char *message, ...) 399 #else 400 emergency(va_alist) 401 va_dcl 402 #endif 403 { 404 va_list ap; 405 #ifndef __STDC__ 406 char *message; 407 408 va_start(ap); 409 message = va_arg(ap, char *); 410 #else 411 va_start(ap, message); 412 #endif 413 414 vsyslog(LOG_EMERG, message, ap); 415 va_end(ap); 416 } 417 418 /* 419 * Catch a SIGSYS signal. 420 * 421 * These may arise if a system does not support sysctl. 422 * We tolerate up to 25 of these, then throw in the towel. 423 */ 424 void 425 badsys(sig) 426 int sig; 427 { 428 static int badcount = 0; 429 430 if (badcount++ < 25) 431 return; 432 disaster(sig); 433 } 434 435 /* 436 * Catch an unexpected signal. 437 */ 438 void 439 disaster(sig) 440 int sig; 441 { 442 emergency("fatal signal: %s", 443 sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal"); 444 445 sleep(STALL_TIMEOUT); 446 _exit(sig); /* reboot */ 447 } 448 449 /* 450 * Get the security level of the kernel. 451 */ 452 int 453 getsecuritylevel() 454 { 455 #ifdef KERN_SECURELVL 456 int name[2], curlevel; 457 size_t len; 458 extern int errno; 459 460 name[0] = CTL_KERN; 461 name[1] = KERN_SECURELVL; 462 len = sizeof curlevel; 463 if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { 464 emergency("cannot get kernel security level: %s", 465 strerror(errno)); 466 return (-1); 467 } 468 return (curlevel); 469 #else 470 return (-1); 471 #endif 472 } 473 474 /* 475 * Set the security level of the kernel. 476 */ 477 void 478 setsecuritylevel(newlevel) 479 int newlevel; 480 { 481 #ifdef KERN_SECURELVL 482 int name[2], curlevel; 483 extern int errno; 484 485 curlevel = getsecuritylevel(); 486 if (newlevel == curlevel) 487 return; 488 name[0] = CTL_KERN; 489 name[1] = KERN_SECURELVL; 490 if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { 491 emergency( 492 "cannot change kernel security level from %d to %d: %s", 493 curlevel, newlevel, strerror(errno)); 494 return; 495 } 496 #ifdef SECURE 497 warning("kernel security level changed from %d to %d", 498 curlevel, newlevel); 499 #endif 500 #endif 501 } 502 503 /* 504 * Change states in the finite state machine. 505 * The initial state is passed as an argument. 506 */ 507 void 508 transition(s) 509 state_t s; 510 { 511 for (;;) 512 s = (state_t) (*s)(); 513 } 514 515 /* 516 * Close out the accounting files for a login session. 517 * NB: should send a message to the session logger to avoid blocking. 518 */ 519 void 520 clear_session_logs(sp) 521 session_t *sp; 522 { 523 char *line = sp->se_device + sizeof(_PATH_DEV) - 1; 524 525 if (logout(line)) 526 logwtmp(line, "", ""); 527 } 528 529 /* 530 * Start a session and allocate a controlling terminal. 531 * Only called by children of init after forking. 532 */ 533 void 534 setctty(name) 535 char *name; 536 { 537 int fd; 538 539 (void) revoke(name); 540 sleep (2); /* leave DTR low */ 541 if ((fd = open(name, O_RDWR)) == -1) { 542 stall("can't open %s: %m", name); 543 _exit(1); 544 } 545 if (login_tty(fd) == -1) { 546 stall("can't get %s for controlling terminal: %m", name); 547 _exit(1); 548 } 549 } 550 551 /* 552 * Bring the system up single user. 553 */ 554 state_func_t 555 single_user() 556 { 557 pid_t pid, wpid; 558 int status; 559 sigset_t mask; 560 char *shell = _PATH_BSHELL; 561 char *argv[2]; 562 #ifdef SECURE 563 struct ttyent *typ; 564 struct passwd *pp; 565 static const char banner[] = 566 "Enter root password, or ^D to go multi-user\n"; 567 char *clear, *password; 568 #endif 569 570 /* 571 * If the kernel is in secure mode, downgrade it to insecure mode. 572 */ 573 if (getsecuritylevel() > 0) 574 setsecuritylevel(0); 575 576 if ((pid = fork()) == 0) { 577 /* 578 * Start the single user session. 579 */ 580 setctty(_PATH_CONSOLE); 581 582 #ifdef SECURE 583 /* 584 * Check the root password. 585 * We don't care if the console is 'on' by default; 586 * it's the only tty that can be 'off' and 'secure'. 587 */ 588 typ = getttynam("console"); 589 pp = getpwnam("root"); 590 if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) { 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 bzero(clear, _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 if (altshell[0] != '\0') 621 shell = altshell; 622 } 623 #endif /* DEBUGSHELL */ 624 625 /* 626 * Unblock signals. 627 * We catch all the interesting ones, 628 * and those are reset to SIG_DFL on exec. 629 */ 630 sigemptyset(&mask); 631 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 632 633 /* 634 * Fire off a shell. 635 * If the default one doesn't work, try the Bourne shell. 636 */ 637 argv[0] = "-sh"; 638 argv[1] = 0; 639 execv(shell, argv); 640 emergency("can't exec %s for single user: %m", shell); 641 execv(_PATH_BSHELL, argv); 642 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 643 sleep(STALL_TIMEOUT); 644 _exit(1); 645 } 646 647 if (pid == -1) { 648 /* 649 * We are seriously hosed. Do our best. 650 */ 651 emergency("can't fork single-user shell, trying again"); 652 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 653 continue; 654 return (state_func_t) single_user; 655 } 656 657 requested_transition = 0; 658 do { 659 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 660 collect_child(wpid); 661 if (wpid == -1) { 662 if (errno == EINTR) 663 continue; 664 warning("wait for single-user shell failed: %m; restarting"); 665 return (state_func_t) single_user; 666 } 667 if (wpid == pid && WIFSTOPPED(status)) { 668 warning("init: shell stopped, restarting\n"); 669 kill(pid, SIGCONT); 670 wpid = -1; 671 } 672 } while (wpid != pid && !requested_transition); 673 674 if (requested_transition) 675 return (state_func_t) requested_transition; 676 677 if (!WIFEXITED(status)) { 678 if (WTERMSIG(status) == SIGKILL) { 679 /* 680 * reboot(8) killed shell? 681 */ 682 warning("single user shell terminated."); 683 sleep(STALL_TIMEOUT); 684 _exit(0); 685 } else { 686 warning("single user shell terminated, restarting"); 687 return (state_func_t) single_user; 688 } 689 } 690 691 runcom_mode = FASTBOOT; 692 #ifndef LETS_GET_SMALL 693 return (state_func_t) runcom; 694 #else /* LETS_GET_SMALL */ 695 return (state_func_t) single_user; 696 #endif /* LETS_GET_SMALL */ 697 } 698 699 #ifndef LETS_GET_SMALL 700 /* 701 * Run the system startup script. 702 */ 703 state_func_t 704 runcom() 705 { 706 pid_t pid, wpid; 707 int status; 708 char *argv[4]; 709 struct sigaction sa; 710 711 if ((pid = fork()) == 0) { 712 sigemptyset(&sa.sa_mask); 713 sa.sa_flags = 0; 714 sa.sa_handler = SIG_IGN; 715 (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 716 (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 717 718 setctty(_PATH_CONSOLE); 719 720 argv[0] = "sh"; 721 argv[1] = _PATH_RUNCOM; 722 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 723 argv[3] = 0; 724 725 sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 726 727 execv(_PATH_BSHELL, argv); 728 stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 729 _exit(1); /* force single user mode */ 730 } 731 732 if (pid == -1) { 733 emergency("can't fork for %s on %s: %m", 734 _PATH_BSHELL, _PATH_RUNCOM); 735 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 736 continue; 737 sleep(STALL_TIMEOUT); 738 return (state_func_t) single_user; 739 } 740 741 /* 742 * Copied from single_user(). This is a bit paranoid. 743 */ 744 do { 745 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 746 collect_child(wpid); 747 if (wpid == -1) { 748 if (errno == EINTR) 749 continue; 750 warning("wait for %s on %s failed: %m; going to single user mode", 751 _PATH_BSHELL, _PATH_RUNCOM); 752 return (state_func_t) single_user; 753 } 754 if (wpid == pid && WIFSTOPPED(status)) { 755 warning("init: %s on %s stopped, restarting\n", 756 _PATH_BSHELL, _PATH_RUNCOM); 757 kill(pid, SIGCONT); 758 wpid = -1; 759 } 760 } while (wpid != pid); 761 762 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && 763 requested_transition == catatonia) { 764 /* /etc/rc executed /sbin/reboot; wait for the end quietly */ 765 sigset_t s; 766 767 sigfillset(&s); 768 for (;;) 769 sigsuspend(&s); 770 } 771 772 if (!WIFEXITED(status)) { 773 warning("%s on %s terminated abnormally, going to single user mode", 774 _PATH_BSHELL, _PATH_RUNCOM); 775 return (state_func_t) single_user; 776 } 777 778 if (WEXITSTATUS(status)) 779 return (state_func_t) single_user; 780 781 runcom_mode = AUTOBOOT; /* the default */ 782 /* NB: should send a message to the session logger to avoid blocking. */ 783 logwtmp("~", "reboot", ""); 784 return (state_func_t) read_ttys; 785 } 786 787 /* 788 * Open the session database. 789 * 790 * NB: We could pass in the size here; is it necessary? 791 */ 792 int 793 start_session_db() 794 { 795 if (session_db && (*session_db->close)(session_db)) 796 emergency("session database close: %s", strerror(errno)); 797 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 798 emergency("session database open: %s", strerror(errno)); 799 return (1); 800 } 801 return (0); 802 803 } 804 805 /* 806 * Add a new login session. 807 */ 808 void 809 add_session(sp) 810 session_t *sp; 811 { 812 DBT key; 813 DBT data; 814 815 key.data = &sp->se_process; 816 key.size = sizeof sp->se_process; 817 data.data = &sp; 818 data.size = sizeof sp; 819 820 if ((*session_db->put)(session_db, &key, &data, 0)) 821 emergency("insert %d: %s", sp->se_process, strerror(errno)); 822 } 823 824 /* 825 * Delete an old login session. 826 */ 827 void 828 del_session(sp) 829 session_t *sp; 830 { 831 DBT key; 832 833 key.data = &sp->se_process; 834 key.size = sizeof sp->se_process; 835 836 if ((*session_db->del)(session_db, &key, 0)) 837 emergency("delete %d: %s", sp->se_process, strerror(errno)); 838 } 839 840 /* 841 * Look up a login session by pid. 842 */ 843 session_t * 844 #ifdef __STDC__ 845 find_session(pid_t pid) 846 #else 847 find_session(pid) 848 pid_t pid; 849 #endif 850 { 851 DBT key; 852 DBT data; 853 session_t *ret; 854 855 key.data = &pid; 856 key.size = sizeof pid; 857 if ((*session_db->get)(session_db, &key, &data, 0) != 0) 858 return 0; 859 bcopy(data.data, (char *)&ret, sizeof(ret)); 860 return ret; 861 } 862 863 /* 864 * Construct an argument vector from a command line. 865 */ 866 char ** 867 construct_argv(command) 868 char *command; 869 { 870 register int argc = 0; 871 register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 872 * sizeof (char *)); 873 static const char separators[] = " \t"; 874 875 if ((argv[argc++] = strtok(command, separators)) == 0) 876 return 0; 877 while (argv[argc++] = strtok((char *) 0, separators)) 878 continue; 879 return argv; 880 } 881 882 /* 883 * Deallocate a session descriptor. 884 */ 885 void 886 free_session(sp) 887 register session_t *sp; 888 { 889 free(sp->se_device); 890 if (sp->se_getty) { 891 free(sp->se_getty); 892 free(sp->se_getty_argv); 893 } 894 if (sp->se_window) { 895 free(sp->se_window); 896 free(sp->se_window_argv); 897 } 898 free(sp); 899 } 900 901 /* 902 * Allocate a new session descriptor. 903 */ 904 session_t * 905 new_session(sprev, session_index, typ) 906 session_t *sprev; 907 int session_index; 908 register struct ttyent *typ; 909 { 910 register session_t *sp; 911 912 if ((typ->ty_status & TTY_ON) == 0 || 913 typ->ty_name == 0 || 914 typ->ty_getty == 0) 915 return 0; 916 917 sp = (session_t *) malloc(sizeof (session_t)); 918 bzero(sp, sizeof *sp); 919 920 sp->se_index = session_index; 921 922 sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name)); 923 (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); 924 925 if (setupargv(sp, typ) == 0) { 926 free_session(sp); 927 return (0); 928 } 929 930 sp->se_next = 0; 931 if (sprev == 0) { 932 sessions = sp; 933 sp->se_prev = 0; 934 } else { 935 sprev->se_next = sp; 936 sp->se_prev = sprev; 937 } 938 939 return sp; 940 } 941 942 /* 943 * Calculate getty and if useful window argv vectors. 944 */ 945 int 946 setupargv(sp, typ) 947 session_t *sp; 948 struct ttyent *typ; 949 { 950 951 if (sp->se_getty) { 952 free(sp->se_getty); 953 free(sp->se_getty_argv); 954 } 955 sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2); 956 (void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name); 957 sp->se_getty_argv = construct_argv(sp->se_getty); 958 if (sp->se_getty_argv == 0) { 959 warning("can't parse getty for port %s", sp->se_device); 960 free(sp->se_getty); 961 sp->se_getty = 0; 962 return (0); 963 } 964 if (typ->ty_window) { 965 if (sp->se_window) 966 free(sp->se_window); 967 sp->se_window = strdup(typ->ty_window); 968 sp->se_window_argv = construct_argv(sp->se_window); 969 if (sp->se_window_argv == 0) { 970 warning("can't parse window for port %s", 971 sp->se_device); 972 free(sp->se_window); 973 sp->se_window = 0; 974 return (0); 975 } 976 } 977 return (1); 978 } 979 980 /* 981 * Walk the list of ttys and create sessions for each active line. 982 */ 983 state_func_t 984 read_ttys() 985 { 986 int session_index = 0; 987 register session_t *sp, *snext; 988 register struct ttyent *typ; 989 990 /* 991 * Destroy any previous session state. 992 * There shouldn't be any, but just in case... 993 */ 994 for (sp = sessions; sp; sp = snext) { 995 if (sp->se_process) 996 clear_session_logs(sp); 997 snext = sp->se_next; 998 free_session(sp); 999 } 1000 sessions = 0; 1001 if (start_session_db()) 1002 return (state_func_t) single_user; 1003 1004 /* 1005 * Allocate a session entry for each active port. 1006 * Note that sp starts at 0. 1007 */ 1008 while (typ = getttyent()) 1009 if (snext = new_session(sp, ++session_index, typ)) 1010 sp = snext; 1011 1012 endttyent(); 1013 1014 return (state_func_t) multi_user; 1015 } 1016 1017 /* 1018 * Start a window system running. 1019 */ 1020 void 1021 start_window_system(sp) 1022 session_t *sp; 1023 { 1024 pid_t pid; 1025 sigset_t mask; 1026 1027 if ((pid = fork()) == -1) { 1028 emergency("can't fork for window system on port %s: %m", 1029 sp->se_device); 1030 /* hope that getty fails and we can try again */ 1031 return; 1032 } 1033 1034 if (pid) 1035 return; 1036 1037 sigemptyset(&mask); 1038 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1039 1040 if (setsid() < 0) 1041 emergency("setsid failed (window) %m"); 1042 1043 execv(sp->se_window_argv[0], sp->se_window_argv); 1044 stall("can't exec window system '%s' for port %s: %m", 1045 sp->se_window_argv[0], sp->se_device); 1046 _exit(1); 1047 } 1048 1049 /* 1050 * Start a login session running. 1051 */ 1052 pid_t 1053 start_getty(sp) 1054 session_t *sp; 1055 { 1056 pid_t pid; 1057 sigset_t mask; 1058 time_t current_time = time((time_t *) 0); 1059 1060 /* 1061 * fork(), not vfork() -- we can't afford to block. 1062 */ 1063 if ((pid = fork()) == -1) { 1064 emergency("can't fork for getty on port %s: %m", sp->se_device); 1065 return -1; 1066 } 1067 1068 if (pid) 1069 return pid; 1070 1071 if (current_time > sp->se_started && 1072 current_time - sp->se_started < GETTY_SPACING) { 1073 warning("getty repeating too quickly on port %s, sleeping", 1074 sp->se_device); 1075 sleep((unsigned) GETTY_SLEEP); 1076 } 1077 1078 if (sp->se_window) { 1079 start_window_system(sp); 1080 sleep(WINDOW_WAIT); 1081 } 1082 1083 sigemptyset(&mask); 1084 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1085 1086 execv(sp->se_getty_argv[0], sp->se_getty_argv); 1087 stall("can't exec getty '%s' for port %s: %m", 1088 sp->se_getty_argv[0], sp->se_device); 1089 _exit(1); 1090 } 1091 #endif /* LETS_GET_SMALL */ 1092 1093 /* 1094 * Collect exit status for a child. 1095 * If an exiting login, start a new login running. 1096 */ 1097 void 1098 #ifdef __STDC__ 1099 collect_child(pid_t pid) 1100 #else 1101 collect_child(pid) 1102 pid_t pid; 1103 #endif 1104 { 1105 #ifndef LETS_GET_SMALL 1106 register session_t *sp, *sprev, *snext; 1107 1108 if (! sessions) 1109 return; 1110 1111 if (! (sp = find_session(pid))) 1112 return; 1113 1114 clear_session_logs(sp); 1115 del_session(sp); 1116 sp->se_process = 0; 1117 1118 if (sp->se_flags & SE_SHUTDOWN) { 1119 if (sprev = sp->se_prev) 1120 sprev->se_next = sp->se_next; 1121 else 1122 sessions = sp->se_next; 1123 if (snext = sp->se_next) 1124 snext->se_prev = sp->se_prev; 1125 free_session(sp); 1126 return; 1127 } 1128 1129 if ((pid = start_getty(sp)) == -1) { 1130 /* serious trouble */ 1131 requested_transition = clean_ttys; 1132 return; 1133 } 1134 1135 sp->se_process = pid; 1136 sp->se_started = time((time_t *) 0); 1137 add_session(sp); 1138 #endif /* LETS_GET_SMALL */ 1139 } 1140 1141 /* 1142 * Catch a signal and request a state transition. 1143 */ 1144 void 1145 transition_handler(sig) 1146 int sig; 1147 { 1148 1149 switch (sig) { 1150 #ifndef LETS_GET_SMALL 1151 case SIGHUP: 1152 requested_transition = clean_ttys; 1153 break; 1154 case SIGTERM: 1155 requested_transition = death; 1156 break; 1157 case SIGTSTP: 1158 requested_transition = catatonia; 1159 break; 1160 #endif /* LETS_GET_SMALL */ 1161 default: 1162 requested_transition = 0; 1163 break; 1164 } 1165 } 1166 1167 #ifndef LETS_GET_SMALL 1168 /* 1169 * Take the system multiuser. 1170 */ 1171 state_func_t 1172 multi_user() 1173 { 1174 pid_t pid; 1175 register session_t *sp; 1176 1177 requested_transition = 0; 1178 1179 /* 1180 * If the administrator has not set the security level to -1 1181 * to indicate that the kernel should not run multiuser in secure 1182 * mode, and the run script has not set a higher level of security 1183 * than level 1, then put the kernel into secure mode. 1184 */ 1185 if (getsecuritylevel() == 0) 1186 setsecuritylevel(1); 1187 1188 for (sp = sessions; sp; sp = sp->se_next) { 1189 if (sp->se_process) 1190 continue; 1191 if ((pid = start_getty(sp)) == -1) { 1192 /* serious trouble */ 1193 requested_transition = clean_ttys; 1194 break; 1195 } 1196 sp->se_process = pid; 1197 sp->se_started = time((time_t *) 0); 1198 add_session(sp); 1199 } 1200 1201 while (!requested_transition) 1202 if ((pid = waitpid(-1, (int *) 0, 0)) != -1) 1203 collect_child(pid); 1204 1205 return (state_func_t) requested_transition; 1206 } 1207 1208 /* 1209 * This is an n-squared algorithm. We hope it isn't run often... 1210 */ 1211 state_func_t 1212 clean_ttys() 1213 { 1214 register session_t *sp, *sprev; 1215 register struct ttyent *typ; 1216 register int session_index = 0; 1217 register int devlen; 1218 1219 devlen = sizeof(_PATH_DEV) - 1; 1220 while (typ = getttyent()) { 1221 ++session_index; 1222 1223 for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) 1224 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1225 break; 1226 1227 if (sp) { 1228 if (sp->se_index != session_index) { 1229 warning("port %s changed utmp index from %d to %d", 1230 sp->se_device, sp->se_index, 1231 session_index); 1232 sp->se_index = session_index; 1233 } 1234 if ((typ->ty_status & TTY_ON) == 0 || 1235 typ->ty_getty == 0) { 1236 sp->se_flags |= SE_SHUTDOWN; 1237 kill(sp->se_process, SIGHUP); 1238 continue; 1239 } 1240 sp->se_flags &= ~SE_SHUTDOWN; 1241 if (setupargv(sp, typ) == 0) { 1242 warning("can't parse getty for port %s", 1243 sp->se_device); 1244 sp->se_flags |= SE_SHUTDOWN; 1245 kill(sp->se_process, SIGHUP); 1246 } 1247 continue; 1248 } 1249 1250 new_session(sprev, session_index, typ); 1251 } 1252 1253 endttyent(); 1254 1255 return (state_func_t) multi_user; 1256 } 1257 1258 /* 1259 * Block further logins. 1260 */ 1261 state_func_t 1262 catatonia() 1263 { 1264 register session_t *sp; 1265 1266 for (sp = sessions; sp; sp = sp->se_next) 1267 sp->se_flags |= SE_SHUTDOWN; 1268 1269 return (state_func_t) multi_user; 1270 } 1271 #endif /* LETS_GET_SMALL */ 1272 1273 /* 1274 * Note SIGALRM. 1275 */ 1276 void 1277 alrm_handler(sig) 1278 int sig; 1279 { 1280 clang = 1; 1281 } 1282 1283 #ifndef LETS_GET_SMALL 1284 /* 1285 * Bring the system down to single user. 1286 */ 1287 state_func_t 1288 death() 1289 { 1290 register session_t *sp; 1291 register int i; 1292 pid_t pid; 1293 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1294 1295 for (sp = sessions; sp; sp = sp->se_next) 1296 sp->se_flags |= SE_SHUTDOWN; 1297 1298 /* NB: should send a message to the session logger to avoid blocking. */ 1299 logwtmp("~", "shutdown", ""); 1300 1301 for (i = 0; i < 3; ++i) { 1302 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1303 return (state_func_t) single_user; 1304 1305 clang = 0; 1306 alarm(DEATH_WATCH); 1307 do 1308 if ((pid = waitpid(-1, (int *)0, 0)) != -1) 1309 collect_child(pid); 1310 while (clang == 0 && errno != ECHILD); 1311 1312 if (errno == ECHILD) 1313 return (state_func_t) single_user; 1314 } 1315 1316 warning("some processes would not die; ps axl advised"); 1317 1318 return (state_func_t) single_user; 1319 } 1320 #endif /* LETS_GET_SMALL */ 1321