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