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