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