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