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