1 /* $NetBSD: init.c,v 1.24 1997/03/14 00:44:35 mycroft 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.24 1997/03/14 00:44:35 mycroft 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 #include <util.h> 69 70 #ifdef __STDC__ 71 #include <stdarg.h> 72 #else 73 #include <varargs.h> 74 #endif 75 76 #ifdef SECURE 77 #include <pwd.h> 78 #endif 79 80 #include "pathnames.h" 81 82 /* 83 * Sleep times; used to prevent thrashing. 84 */ 85 #define GETTY_SPACING 5 /* N secs minimum getty spacing */ 86 #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ 87 #define WINDOW_WAIT 3 /* wait N secs after starting window */ 88 #define STALL_TIMEOUT 30 /* wait N secs after warning */ 89 #define DEATH_WATCH 10 /* wait N secs for procs to die */ 90 91 void handle __P((sig_t, ...)); 92 void delset __P((sigset_t *, ...)); 93 94 void stall __P((char *, ...)); 95 void warning __P((char *, ...)); 96 void emergency __P((char *, ...)); 97 void disaster __P((int)); 98 void badsys __P((int)); 99 100 /* 101 * We really need a recursive typedef... 102 * The following at least guarantees that the return type of (*state_t)() 103 * is sufficiently wide to hold a function pointer. 104 */ 105 typedef long (*state_func_t) __P((void)); 106 typedef state_func_t (*state_t) __P((void)); 107 108 state_func_t single_user __P((void)); 109 state_func_t runcom __P((void)); 110 state_func_t read_ttys __P((void)); 111 state_func_t multi_user __P((void)); 112 state_func_t clean_ttys __P((void)); 113 state_func_t catatonia __P((void)); 114 state_func_t death __P((void)); 115 116 enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; 117 118 void transition __P((state_t)); 119 #ifndef LETS_GET_SMALL 120 state_t requested_transition = runcom; 121 #else /* LETS_GET_SMALL */ 122 state_t requested_transition = single_user; 123 #endif /* LETS_GET_SMALL */ 124 125 void setctty __P((char *)); 126 127 typedef struct init_session { 128 int se_index; /* index of entry in ttys file */ 129 pid_t se_process; /* controlling process */ 130 time_t se_started; /* used to avoid thrashing */ 131 int se_flags; /* status of session */ 132 #define SE_SHUTDOWN 0x1 /* session won't be restarted */ 133 #define SE_PRESENT 0x2 /* session is in /etc/ttys */ 134 char *se_device; /* filename of port */ 135 char *se_getty; /* what to run on that port */ 136 char **se_getty_argv; /* pre-parsed argument array */ 137 char *se_window; /* window system (started only once) */ 138 char **se_window_argv; /* pre-parsed argument array */ 139 struct init_session *se_prev; 140 struct init_session *se_next; 141 } session_t; 142 143 void free_session __P((session_t *)); 144 session_t *new_session __P((session_t *, int, struct ttyent *)); 145 session_t *sessions; 146 147 char **construct_argv __P((char *)); 148 void start_window_system __P((session_t *)); 149 void collect_child __P((pid_t)); 150 pid_t start_getty __P((session_t *)); 151 void transition_handler __P((int)); 152 void alrm_handler __P((int)); 153 void setsecuritylevel __P((int)); 154 int getsecuritylevel __P((void)); 155 int setupargv __P((session_t *, struct ttyent *)); 156 int clang; 157 158 void clear_session_logs __P((session_t *)); 159 160 int start_session_db __P((void)); 161 void add_session __P((session_t *)); 162 void del_session __P((session_t *)); 163 session_t *find_session __P((pid_t)); 164 DB *session_db; 165 166 /* 167 * The mother of all processes. 168 */ 169 int 170 main(argc, argv) 171 int argc; 172 char **argv; 173 { 174 int c; 175 struct sigaction sa; 176 sigset_t mask; 177 178 #ifndef LETS_GET_SMALL 179 /* Dispose of random users. */ 180 if (getuid() != 0) { 181 (void)fprintf(stderr, "init: %s\n", strerror(EPERM)); 182 exit (1); 183 } 184 185 /* System V users like to reexec init. */ 186 if (getpid() != 1) { 187 (void)fprintf(stderr, "init: already running\n"); 188 exit (1); 189 } 190 191 /* 192 * Note that this does NOT open a file... 193 * Does 'init' deserve its own facility number? 194 */ 195 openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 196 #endif /* LETS_GET_SMALL */ 197 198 /* 199 * Create an initial session. 200 */ 201 if (setsid() < 0) 202 warning("initial setsid() failed: %m"); 203 204 /* 205 * Establish an initial user so that programs running 206 * single user do not freak out and die (like passwd). 207 */ 208 if (setlogin("root") < 0) 209 warning("setlogin() failed: %m"); 210 211 #ifndef LETS_GET_SMALL 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 #else /* LETS_GET_SMALL */ 232 requested_transition = single_user; 233 #endif /* LETS_GET_SMALL */ 234 235 /* 236 * We catch or block signals rather than ignore them, 237 * so that they get reset on exec. 238 */ 239 handle(badsys, SIGSYS, 0); 240 handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, 241 SIGBUS, SIGXCPU, SIGXFSZ, 0); 242 handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0); 243 handle(alrm_handler, SIGALRM, 0); 244 sigfillset(&mask); 245 delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, 246 SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0); 247 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 248 sigemptyset(&sa.sa_mask); 249 sa.sa_flags = 0; 250 sa.sa_handler = SIG_IGN; 251 (void) sigaction(SIGTTIN, &sa, (struct sigaction *)0); 252 (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0); 253 254 /* 255 * Paranoia. 256 */ 257 close(0); 258 close(1); 259 close(2); 260 261 /* 262 * Start the state machine. 263 */ 264 transition(requested_transition); 265 266 /* 267 * Should never reach here. 268 */ 269 return 1; 270 } 271 272 /* 273 * Associate a function with a signal handler. 274 */ 275 void 276 #ifdef __STDC__ 277 handle(sig_t handler, ...) 278 #else 279 handle(va_alist) 280 va_dcl 281 #endif 282 { 283 int sig; 284 struct sigaction sa; 285 int mask_everything; 286 va_list ap; 287 #ifndef __STDC__ 288 sig_t handler; 289 290 va_start(ap); 291 handler = va_arg(ap, sig_t); 292 #else 293 va_start(ap, handler); 294 #endif 295 296 sa.sa_handler = handler; 297 sigfillset(&mask_everything); 298 299 while (sig = va_arg(ap, int)) { 300 sa.sa_mask = mask_everything; 301 /* XXX SA_RESTART? */ 302 sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0; 303 sigaction(sig, &sa, (struct sigaction *) 0); 304 } 305 va_end(ap); 306 } 307 308 /* 309 * Delete a set of signals from a mask. 310 */ 311 void 312 #ifdef __STDC__ 313 delset(sigset_t *maskp, ...) 314 #else 315 delset(va_alist) 316 va_dcl 317 #endif 318 { 319 int sig; 320 va_list ap; 321 #ifndef __STDC__ 322 sigset_t *maskp; 323 324 va_start(ap); 325 maskp = va_arg(ap, sigset_t *); 326 #else 327 va_start(ap, maskp); 328 #endif 329 330 while (sig = va_arg(ap, int)) 331 sigdelset(maskp, sig); 332 va_end(ap); 333 } 334 335 /* 336 * Log a message and sleep for a while (to give someone an opportunity 337 * to read it and to save log or hardcopy output if the problem is chronic). 338 * NB: should send a message to the session logger to avoid blocking. 339 */ 340 void 341 #ifdef __STDC__ 342 stall(char *message, ...) 343 #else 344 stall(va_alist) 345 va_dcl 346 #endif 347 { 348 va_list ap; 349 #ifndef __STDC__ 350 char *message; 351 352 va_start(ap); 353 message = va_arg(ap, char *); 354 #else 355 va_start(ap, message); 356 #endif 357 358 vsyslog(LOG_ALERT, message, ap); 359 va_end(ap); 360 closelog(); 361 sleep(STALL_TIMEOUT); 362 } 363 364 /* 365 * Like stall(), but doesn't sleep. 366 * If cpp had variadic macros, the two functions could be #defines for another. 367 * NB: should send a message to the session logger to avoid blocking. 368 */ 369 void 370 #ifdef __STDC__ 371 warning(char *message, ...) 372 #else 373 warning(va_alist) 374 va_dcl 375 #endif 376 { 377 va_list ap; 378 #ifndef __STDC__ 379 char *message; 380 381 va_start(ap); 382 message = va_arg(ap, char *); 383 #else 384 va_start(ap, message); 385 #endif 386 387 vsyslog(LOG_ALERT, message, ap); 388 va_end(ap); 389 closelog(); 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 closelog(); 417 } 418 419 /* 420 * Catch a SIGSYS signal. 421 * 422 * These may arise if a system does not support sysctl. 423 * We tolerate up to 25 of these, then throw in the towel. 424 */ 425 void 426 badsys(sig) 427 int sig; 428 { 429 static int badcount = 0; 430 431 if (badcount++ < 25) 432 return; 433 disaster(sig); 434 } 435 436 /* 437 * Catch an unexpected signal. 438 */ 439 void 440 disaster(sig) 441 int sig; 442 { 443 emergency("fatal signal: %s", strsignal(sig)); 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 *pp->pw_passwd != '\0') { 592 write(2, banner, sizeof banner - 1); 593 for (;;) { 594 clear = getpass("Password:"); 595 if (clear == 0 || *clear == '\0') 596 _exit(0); 597 password = crypt(clear, pp->pw_passwd); 598 memset(clear, 0, _PASSWORD_LEN); 599 if (strcmp(password, pp->pw_passwd) == 0) 600 break; 601 warning("single-user login failed\n"); 602 } 603 } 604 endttyent(); 605 endpwent(); 606 #endif /* SECURE */ 607 608 #ifdef DEBUGSHELL 609 { 610 char altshell[128], *cp = altshell; 611 int num; 612 613 #define SHREQUEST \ 614 "Enter pathname of shell or RETURN for sh: " 615 (void)write(STDERR_FILENO, 616 SHREQUEST, sizeof(SHREQUEST) - 1); 617 while ((num = read(STDIN_FILENO, cp, 1)) != -1 && 618 num != 0 && *cp != '\n' && cp < &altshell[127]) 619 cp++; 620 *cp = '\0'; 621 if (altshell[0] != '\0') 622 shell = altshell; 623 } 624 #endif /* DEBUGSHELL */ 625 626 /* 627 * Unblock signals. 628 * We catch all the interesting ones, 629 * and those are reset to SIG_DFL on exec. 630 */ 631 sigemptyset(&mask); 632 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 633 634 /* 635 * Fire off a shell. 636 * If the default one doesn't work, try the Bourne shell. 637 */ 638 argv[0] = "-sh"; 639 argv[1] = 0; 640 setenv("PATH", _PATH_STDPATH, 1); 641 execv(shell, argv); 642 emergency("can't exec %s for single user: %m", shell); 643 execv(_PATH_BSHELL, argv); 644 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 645 sleep(STALL_TIMEOUT); 646 _exit(1); 647 } 648 649 if (pid == -1) { 650 /* 651 * We are seriously hosed. Do our best. 652 */ 653 emergency("can't fork single-user shell, trying again"); 654 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 655 continue; 656 return (state_func_t) single_user; 657 } 658 659 requested_transition = 0; 660 do { 661 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 662 collect_child(wpid); 663 if (wpid == -1) { 664 if (errno == EINTR) 665 continue; 666 warning("wait for single-user shell failed: %m; restarting"); 667 return (state_func_t) single_user; 668 } 669 if (wpid == pid && WIFSTOPPED(status)) { 670 warning("init: shell stopped, restarting\n"); 671 kill(pid, SIGCONT); 672 wpid = -1; 673 } 674 } while (wpid != pid && !requested_transition); 675 676 if (requested_transition) 677 return (state_func_t) requested_transition; 678 679 if (!WIFEXITED(status)) { 680 if (WTERMSIG(status) == SIGKILL) { 681 /* 682 * reboot(8) killed shell? 683 */ 684 warning("single user shell terminated."); 685 sleep(STALL_TIMEOUT); 686 _exit(0); 687 } else { 688 warning("single user shell terminated, restarting"); 689 return (state_func_t) single_user; 690 } 691 } 692 693 runcom_mode = FASTBOOT; 694 #ifndef LETS_GET_SMALL 695 return (state_func_t) runcom; 696 #else /* LETS_GET_SMALL */ 697 return (state_func_t) single_user; 698 #endif /* LETS_GET_SMALL */ 699 } 700 701 #ifndef LETS_GET_SMALL 702 /* 703 * Run the system startup script. 704 */ 705 state_func_t 706 runcom() 707 { 708 pid_t pid, wpid; 709 int status; 710 char *argv[4]; 711 struct sigaction sa; 712 713 if ((pid = fork()) == 0) { 714 sigemptyset(&sa.sa_mask); 715 sa.sa_flags = 0; 716 sa.sa_handler = SIG_IGN; 717 (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 718 (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 719 720 setctty(_PATH_CONSOLE); 721 722 argv[0] = "sh"; 723 argv[1] = _PATH_RUNCOM; 724 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 725 argv[3] = 0; 726 727 sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 728 729 execv(_PATH_BSHELL, argv); 730 stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 731 _exit(1); /* force single user mode */ 732 } 733 734 if (pid == -1) { 735 emergency("can't fork for %s on %s: %m", 736 _PATH_BSHELL, _PATH_RUNCOM); 737 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 738 continue; 739 sleep(STALL_TIMEOUT); 740 return (state_func_t) single_user; 741 } 742 743 /* 744 * Copied from single_user(). This is a bit paranoid. 745 */ 746 do { 747 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 748 collect_child(wpid); 749 if (wpid == -1) { 750 if (errno == EINTR) 751 continue; 752 warning("wait for %s on %s failed: %m; going to single user mode", 753 _PATH_BSHELL, _PATH_RUNCOM); 754 return (state_func_t) single_user; 755 } 756 if (wpid == pid && WIFSTOPPED(status)) { 757 warning("init: %s on %s stopped, restarting\n", 758 _PATH_BSHELL, _PATH_RUNCOM); 759 kill(pid, SIGCONT); 760 wpid = -1; 761 } 762 } while (wpid != pid); 763 764 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && 765 requested_transition == catatonia) { 766 /* /etc/rc executed /sbin/reboot; wait for the end quietly */ 767 sigset_t s; 768 769 sigfillset(&s); 770 for (;;) 771 sigsuspend(&s); 772 } 773 774 if (!WIFEXITED(status)) { 775 warning("%s on %s terminated abnormally, going to single user mode", 776 _PATH_BSHELL, _PATH_RUNCOM); 777 return (state_func_t) single_user; 778 } 779 780 if (WEXITSTATUS(status)) 781 return (state_func_t) single_user; 782 783 runcom_mode = AUTOBOOT; /* the default */ 784 /* NB: should send a message to the session logger to avoid blocking. */ 785 logwtmp("~", "reboot", ""); 786 return (state_func_t) read_ttys; 787 } 788 789 /* 790 * Open the session database. 791 * 792 * NB: We could pass in the size here; is it necessary? 793 */ 794 int 795 start_session_db() 796 { 797 if (session_db && (*session_db->close)(session_db)) 798 emergency("session database close: %s", strerror(errno)); 799 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 800 emergency("session database open: %s", strerror(errno)); 801 return (1); 802 } 803 return (0); 804 805 } 806 807 /* 808 * Add a new login session. 809 */ 810 void 811 add_session(sp) 812 session_t *sp; 813 { 814 DBT key; 815 DBT data; 816 817 key.data = &sp->se_process; 818 key.size = sizeof sp->se_process; 819 data.data = &sp; 820 data.size = sizeof sp; 821 822 if ((*session_db->put)(session_db, &key, &data, 0)) 823 emergency("insert %d: %s", sp->se_process, strerror(errno)); 824 } 825 826 /* 827 * Delete an old login session. 828 */ 829 void 830 del_session(sp) 831 session_t *sp; 832 { 833 DBT key; 834 835 key.data = &sp->se_process; 836 key.size = sizeof sp->se_process; 837 838 if ((*session_db->del)(session_db, &key, 0)) 839 emergency("delete %d: %s", sp->se_process, strerror(errno)); 840 } 841 842 /* 843 * Look up a login session by pid. 844 */ 845 session_t * 846 #ifdef __STDC__ 847 find_session(pid_t pid) 848 #else 849 find_session(pid) 850 pid_t pid; 851 #endif 852 { 853 DBT key; 854 DBT data; 855 session_t *ret; 856 857 key.data = &pid; 858 key.size = sizeof pid; 859 if ((*session_db->get)(session_db, &key, &data, 0) != 0) 860 return 0; 861 memcpy(&ret, data.data, sizeof(ret)); 862 return ret; 863 } 864 865 /* 866 * Construct an argument vector from a command line. 867 */ 868 char ** 869 construct_argv(command) 870 char *command; 871 { 872 register int argc = 0; 873 register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 874 * sizeof (char *)); 875 static const char separators[] = " \t"; 876 877 if ((argv[argc++] = strtok(command, separators)) == 0) 878 return 0; 879 while (argv[argc++] = strtok((char *) 0, separators)) 880 continue; 881 return argv; 882 } 883 884 /* 885 * Deallocate a session descriptor. 886 */ 887 void 888 free_session(sp) 889 register session_t *sp; 890 { 891 free(sp->se_device); 892 if (sp->se_getty) { 893 free(sp->se_getty); 894 free(sp->se_getty_argv); 895 } 896 if (sp->se_window) { 897 free(sp->se_window); 898 free(sp->se_window_argv); 899 } 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 memset(sp, 0, sizeof *sp); 921 922 sp->se_flags = SE_PRESENT; 923 sp->se_index = session_index; 924 925 sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name)); 926 (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); 927 928 if (setupargv(sp, typ) == 0) { 929 free_session(sp); 930 return (0); 931 } 932 933 sp->se_next = 0; 934 if (sprev == 0) { 935 sessions = sp; 936 sp->se_prev = 0; 937 } else { 938 sprev->se_next = sp; 939 sp->se_prev = sprev; 940 } 941 942 return sp; 943 } 944 945 /* 946 * Calculate getty and if useful window argv vectors. 947 */ 948 int 949 setupargv(sp, typ) 950 session_t *sp; 951 struct ttyent *typ; 952 { 953 954 if (sp->se_getty) { 955 free(sp->se_getty); 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 = construct_argv(sp->se_getty); 961 if (sp->se_getty_argv == 0) { 962 warning("can't parse getty for port %s", sp->se_device); 963 free(sp->se_getty); 964 sp->se_getty = 0; 965 return (0); 966 } 967 if (typ->ty_window) { 968 if (sp->se_window) 969 free(sp->se_window); 970 sp->se_window = strdup(typ->ty_window); 971 sp->se_window_argv = construct_argv(sp->se_window); 972 if (sp->se_window_argv == 0) { 973 warning("can't parse window for port %s", 974 sp->se_device); 975 free(sp->se_window); 976 sp->se_window = 0; 977 return (0); 978 } 979 } 980 return (1); 981 } 982 983 /* 984 * Walk the list of ttys and create sessions for each active line. 985 */ 986 state_func_t 987 read_ttys() 988 { 989 int session_index = 0; 990 register session_t *sp, *snext; 991 register struct ttyent *typ; 992 993 /* 994 * Destroy any previous session state. 995 * There shouldn't be any, but just in case... 996 */ 997 for (sp = sessions; sp; sp = snext) { 998 if (sp->se_process) 999 clear_session_logs(sp); 1000 snext = sp->se_next; 1001 free_session(sp); 1002 } 1003 sessions = 0; 1004 if (start_session_db()) 1005 return (state_func_t) single_user; 1006 1007 /* 1008 * Allocate a session entry for each active port. 1009 * Note that sp starts at 0. 1010 */ 1011 while (typ = getttyent()) 1012 if (snext = new_session(sp, ++session_index, typ)) 1013 sp = snext; 1014 1015 endttyent(); 1016 1017 return (state_func_t) multi_user; 1018 } 1019 1020 /* 1021 * Start a window system running. 1022 */ 1023 void 1024 start_window_system(sp) 1025 session_t *sp; 1026 { 1027 pid_t pid; 1028 sigset_t mask; 1029 1030 if ((pid = fork()) == -1) { 1031 emergency("can't fork for window system on port %s: %m", 1032 sp->se_device); 1033 /* hope that getty fails and we can try again */ 1034 return; 1035 } 1036 1037 if (pid) 1038 return; 1039 1040 sigemptyset(&mask); 1041 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1042 1043 if (setsid() < 0) 1044 emergency("setsid failed (window) %m"); 1045 1046 execv(sp->se_window_argv[0], sp->se_window_argv); 1047 stall("can't exec window system '%s' for port %s: %m", 1048 sp->se_window_argv[0], sp->se_device); 1049 _exit(1); 1050 } 1051 1052 /* 1053 * Start a login session running. 1054 */ 1055 pid_t 1056 start_getty(sp) 1057 session_t *sp; 1058 { 1059 pid_t pid; 1060 sigset_t mask; 1061 time_t current_time = time((time_t *) 0); 1062 1063 /* 1064 * fork(), not vfork() -- we can't afford to block. 1065 */ 1066 if ((pid = fork()) == -1) { 1067 emergency("can't fork for getty on port %s: %m", sp->se_device); 1068 return -1; 1069 } 1070 1071 if (pid) 1072 return pid; 1073 1074 if (current_time > sp->se_started && 1075 current_time - sp->se_started < GETTY_SPACING) { 1076 warning("getty repeating too quickly on port %s, sleeping", 1077 sp->se_device); 1078 sleep((unsigned) GETTY_SLEEP); 1079 } 1080 1081 if (sp->se_window) { 1082 start_window_system(sp); 1083 sleep(WINDOW_WAIT); 1084 } 1085 1086 sigemptyset(&mask); 1087 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1088 1089 execv(sp->se_getty_argv[0], sp->se_getty_argv); 1090 stall("can't exec getty '%s' for port %s: %m", 1091 sp->se_getty_argv[0], sp->se_device); 1092 _exit(1); 1093 } 1094 #endif /* LETS_GET_SMALL */ 1095 1096 /* 1097 * Collect exit status for a child. 1098 * If an exiting login, start a new login running. 1099 */ 1100 void 1101 #ifdef __STDC__ 1102 collect_child(pid_t pid) 1103 #else 1104 collect_child(pid) 1105 pid_t pid; 1106 #endif 1107 { 1108 #ifndef LETS_GET_SMALL 1109 register session_t *sp, *sprev, *snext; 1110 1111 if (! sessions) 1112 return; 1113 1114 if (! (sp = find_session(pid))) 1115 return; 1116 1117 clear_session_logs(sp); 1118 del_session(sp); 1119 sp->se_process = 0; 1120 1121 if (sp->se_flags & SE_SHUTDOWN) { 1122 if (sprev = sp->se_prev) 1123 sprev->se_next = sp->se_next; 1124 else 1125 sessions = sp->se_next; 1126 if (snext = sp->se_next) 1127 snext->se_prev = sp->se_prev; 1128 free_session(sp); 1129 return; 1130 } 1131 1132 if ((pid = start_getty(sp)) == -1) { 1133 /* serious trouble */ 1134 requested_transition = clean_ttys; 1135 return; 1136 } 1137 1138 sp->se_process = pid; 1139 sp->se_started = time((time_t *) 0); 1140 add_session(sp); 1141 #endif /* LETS_GET_SMALL */ 1142 } 1143 1144 /* 1145 * Catch a signal and request a state transition. 1146 */ 1147 void 1148 transition_handler(sig) 1149 int sig; 1150 { 1151 1152 switch (sig) { 1153 #ifndef LETS_GET_SMALL 1154 case SIGHUP: 1155 requested_transition = clean_ttys; 1156 break; 1157 case SIGTERM: 1158 requested_transition = death; 1159 break; 1160 case SIGTSTP: 1161 requested_transition = catatonia; 1162 break; 1163 #endif /* LETS_GET_SMALL */ 1164 default: 1165 requested_transition = 0; 1166 break; 1167 } 1168 } 1169 1170 #ifndef LETS_GET_SMALL 1171 /* 1172 * Take the system multiuser. 1173 */ 1174 state_func_t 1175 multi_user() 1176 { 1177 pid_t pid; 1178 register session_t *sp; 1179 1180 requested_transition = 0; 1181 1182 /* 1183 * If the administrator has not set the security level to -1 1184 * to indicate that the kernel should not run multiuser in secure 1185 * mode, and the run script has not set a higher level of security 1186 * than level 1, then put the kernel into secure mode. 1187 */ 1188 if (getsecuritylevel() == 0) 1189 setsecuritylevel(1); 1190 1191 for (sp = sessions; sp; sp = sp->se_next) { 1192 if (sp->se_process) 1193 continue; 1194 if ((pid = start_getty(sp)) == -1) { 1195 /* serious trouble */ 1196 requested_transition = clean_ttys; 1197 break; 1198 } 1199 sp->se_process = pid; 1200 sp->se_started = time((time_t *) 0); 1201 add_session(sp); 1202 } 1203 1204 while (!requested_transition) 1205 if ((pid = waitpid(-1, (int *) 0, 0)) != -1) 1206 collect_child(pid); 1207 1208 return (state_func_t) requested_transition; 1209 } 1210 1211 /* 1212 * This is an n-squared algorithm. We hope it isn't run often... 1213 */ 1214 state_func_t 1215 clean_ttys() 1216 { 1217 register session_t *sp, *sprev; 1218 register struct ttyent *typ; 1219 register int session_index = 0; 1220 register int devlen; 1221 1222 for (sp = sessions; sp; sp = sp->se_next) 1223 sp->se_flags &= ~SE_PRESENT; 1224 1225 devlen = sizeof(_PATH_DEV) - 1; 1226 while (typ = getttyent()) { 1227 ++session_index; 1228 1229 for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) 1230 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1231 break; 1232 1233 if (sp) { 1234 sp->se_flags |= SE_PRESENT; 1235 if (sp->se_index != session_index) { 1236 warning("port %s changed utmp index from %d to %d", 1237 sp->se_device, sp->se_index, 1238 session_index); 1239 sp->se_index = session_index; 1240 } 1241 if ((typ->ty_status & TTY_ON) == 0 || 1242 typ->ty_getty == 0) { 1243 sp->se_flags |= SE_SHUTDOWN; 1244 kill(sp->se_process, SIGHUP); 1245 continue; 1246 } 1247 sp->se_flags &= ~SE_SHUTDOWN; 1248 if (setupargv(sp, typ) == 0) { 1249 warning("can't parse getty for port %s", 1250 sp->se_device); 1251 sp->se_flags |= SE_SHUTDOWN; 1252 kill(sp->se_process, SIGHUP); 1253 } 1254 continue; 1255 } 1256 1257 new_session(sprev, session_index, typ); 1258 } 1259 1260 endttyent(); 1261 1262 for (sp = sessions; sp; sp = sp->se_next) 1263 if ((sp->se_flags & SE_PRESENT) == 0) { 1264 sp->se_flags |= SE_SHUTDOWN; 1265 kill(sp->se_process, SIGHUP); 1266 } 1267 1268 return (state_func_t) multi_user; 1269 } 1270 1271 /* 1272 * Block further logins. 1273 */ 1274 state_func_t 1275 catatonia() 1276 { 1277 register session_t *sp; 1278 1279 for (sp = sessions; sp; sp = sp->se_next) 1280 sp->se_flags |= SE_SHUTDOWN; 1281 1282 return (state_func_t) multi_user; 1283 } 1284 #endif /* LETS_GET_SMALL */ 1285 1286 /* 1287 * Note SIGALRM. 1288 */ 1289 void 1290 alrm_handler(sig) 1291 int sig; 1292 { 1293 clang = 1; 1294 } 1295 1296 #ifndef LETS_GET_SMALL 1297 /* 1298 * Bring the system down to single user. 1299 */ 1300 state_func_t 1301 death() 1302 { 1303 register session_t *sp; 1304 register int i; 1305 pid_t pid; 1306 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1307 1308 for (sp = sessions; sp; sp = sp->se_next) 1309 sp->se_flags |= SE_SHUTDOWN; 1310 1311 /* NB: should send a message to the session logger to avoid blocking. */ 1312 logwtmp("~", "shutdown", ""); 1313 1314 for (i = 0; i < 3; ++i) { 1315 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1316 return (state_func_t) single_user; 1317 1318 clang = 0; 1319 alarm(DEATH_WATCH); 1320 do 1321 if ((pid = waitpid(-1, (int *)0, 0)) != -1) 1322 collect_child(pid); 1323 while (clang == 0 && errno != ECHILD); 1324 1325 if (errno == ECHILD) 1326 return (state_func_t) single_user; 1327 } 1328 1329 warning("some processes would not die; ps axl advised"); 1330 1331 return (state_func_t) single_user; 1332 } 1333 #endif /* LETS_GET_SMALL */ 1334