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