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