init.c revision 1.35
1/* $OpenBSD: init.c,v 1.35 2004/03/16 01:11:09 tedu 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.35 2004/03/16 01:11:09 tedu 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 427 curlevel = getsecuritylevel(); 428 if (newlevel == curlevel) 429 return; 430 name[0] = CTL_KERN; 431 name[1] = KERN_SECURELVL; 432 if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { 433 emergency( 434 "cannot change kernel security level from %d to %d: %s", 435 curlevel, newlevel, strerror(errno)); 436 return; 437 } 438#ifdef SECURE 439 warning("kernel security level changed from %d to %d", 440 curlevel, newlevel); 441#endif 442#endif 443} 444 445/* 446 * Change states in the finite state machine. 447 * The initial state is passed as an argument. 448 */ 449void 450transition(state_t s) 451{ 452 for (;;) 453 s = (state_t) (*s)(); 454} 455 456/* 457 * Close out the accounting files for a login session. 458 * NB: should send a message to the session logger to avoid blocking. 459 */ 460void 461clear_session_logs(session_t *sp) 462{ 463 char *line = sp->se_device + sizeof(_PATH_DEV) - 1; 464 465 if (logout(line)) 466 logwtmp(line, "", ""); 467} 468 469/* 470 * Start a session and allocate a controlling terminal. 471 * Only called by children of init after forking. 472 */ 473void 474setctty(char *name) 475{ 476 int fd; 477 478 (void) revoke(name); 479 sleep(2); /* leave DTR low */ 480 if ((fd = open(name, O_RDWR)) == -1) { 481 stall("can't open %s: %m", name); 482 _exit(1); 483 } 484 if (login_tty(fd) == -1) { 485 stall("can't get %s for controlling terminal: %m", name); 486 _exit(1); 487 } 488} 489 490/* 491 * Bring the system up single user. 492 */ 493state_func_t 494single_user(void) 495{ 496 pid_t pid, wpid; 497 int status; 498 sigset_t mask; 499 char shell[MAXPATHLEN]; /* Allocate space here */ 500 char name[MAXPATHLEN]; /* Name (argv[0]) of shell */ 501 char *argv[2]; 502#ifdef SECURE 503 struct ttyent *typ; 504 struct passwd *pp; 505 static const char banner[] = 506 "Enter root password, or ^D to go multi-user\n"; 507 char *clear, *password; 508#endif 509 510 /* Init shell and name */ 511 strlcpy(shell, _PATH_BSHELL, sizeof shell); 512 strlcpy(name, "-sh", sizeof name); 513 514 /* 515 * If the kernel is in secure mode, downgrade it to insecure mode. 516 */ 517 if (getsecuritylevel() > 0) 518 setsecuritylevel(0); 519 520 if ((pid = fork()) == 0) { 521 /* 522 * Start the single user session. 523 */ 524 setctty(_PATH_CONSOLE); 525 526#ifdef SECURE 527 /* 528 * Check the root password. 529 * We don't care if the console is 'on' by default; 530 * it's the only tty that can be 'off' and 'secure'. 531 */ 532 typ = getttynam("console"); 533 pp = getpwnam("root"); 534 if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp && 535 *pp->pw_passwd) { 536 write(STDERR_FILENO, banner, sizeof banner - 1); 537 for (;;) { 538 clear = getpass("Password:"); 539 if (clear == 0 || *clear == '\0') 540 _exit(0); 541 password = crypt(clear, pp->pw_passwd); 542 memset(clear, 0, _PASSWORD_LEN); 543 if (strcmp(password, pp->pw_passwd) == 0) 544 break; 545 warning("single-user login failed\n"); 546 } 547 } 548 endttyent(); 549 endpwent(); 550#endif /* SECURE */ 551 552#ifdef DEBUGSHELL 553 { 554 char altshell[128], *cp = altshell; 555 int num; 556 557#define SHREQUEST \ 558 "Enter pathname of shell or RETURN for sh: " 559 560 (void)write(STDERR_FILENO, 561 SHREQUEST, sizeof(SHREQUEST) - 1); 562 while ((num = read(STDIN_FILENO, cp, 1)) != -1 && 563 num != 0 && *cp != '\n' && cp < &altshell[127]) 564 cp++; 565 *cp = '\0'; 566 567 /* Copy in alternate shell */ 568 if (altshell[0] != '\0'){ 569 char *p; 570 571 /* Binary to exec */ 572 strlcpy(shell, altshell, sizeof shell); 573 574 /* argv[0] */ 575 p = strrchr(altshell, '/'); 576 if(p == NULL) p = altshell; 577 else p++; 578 579 name[0] = '-'; 580 strlcpy(&name[1], p, sizeof name -1); 581 } 582 } 583#endif /* DEBUGSHELL */ 584 585 /* 586 * Unblock signals. 587 * We catch all the interesting ones, 588 * and those are reset to SIG_DFL on exec. 589 */ 590 sigemptyset(&mask); 591 sigprocmask(SIG_SETMASK, &mask, NULL); 592 593 /* 594 * Fire off a shell. 595 * If the default one doesn't work, try the Bourne shell. 596 */ 597 argv[0] = name; 598 argv[1] = NULL; 599 setenv("PATH", _PATH_STDPATH, 1); 600 execv(shell, argv); 601 emergency("can't exec %s for single user: %m", shell); 602 603 argv[0] = "-sh"; 604 argv[1] = NULL; 605 execv(_PATH_BSHELL, argv); 606 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 607 sleep(STALL_TIMEOUT); 608 _exit(1); 609 } 610 611 if (pid == -1) { 612 /* 613 * We are seriously hosed. Do our best. 614 */ 615 emergency("can't fork single-user shell, trying again"); 616 while (waitpid(-1, NULL, WNOHANG) > 0) 617 continue; 618 return (state_func_t) single_user; 619 } 620 621 requested_transition = 0; 622 do { 623 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 624 collect_child(wpid); 625 if (wpid == -1) { 626 if (errno == EINTR) 627 continue; 628 warning("wait for single-user shell failed: %m; restarting"); 629 return (state_func_t) single_user; 630 } 631 if (wpid == pid && WIFSTOPPED(status)) { 632 warning("init: shell stopped, restarting\n"); 633 kill(pid, SIGCONT); 634 wpid = -1; 635 } 636 } while (wpid != pid && !requested_transition); 637 638 if (requested_transition) 639 return (state_func_t) requested_transition; 640 641 if (!WIFEXITED(status)) { 642 if (WTERMSIG(status) == SIGKILL) { 643 /* 644 * reboot(8) killed shell? 645 */ 646 warning("single user shell terminated."); 647 sleep(STALL_TIMEOUT); 648 _exit(0); 649 } else { 650 warning("single user shell terminated, restarting"); 651 return (state_func_t) single_user; 652 } 653 } 654 655 runcom_mode = FASTBOOT; 656 return (state_func_t) runcom; 657} 658 659/* 660 * Run the system startup script. 661 */ 662state_func_t 663runcom(void) 664{ 665 pid_t pid, wpid; 666 int status; 667 char *argv[4]; 668 struct sigaction sa; 669 670 if ((pid = fork()) == 0) { 671 memset(&sa, 0, sizeof sa); 672 sigemptyset(&sa.sa_mask); 673 sa.sa_flags = 0; 674 sa.sa_handler = SIG_IGN; 675 (void) sigaction(SIGTSTP, &sa, NULL); 676 (void) sigaction(SIGHUP, &sa, NULL); 677 678 setctty(_PATH_CONSOLE); 679 680 argv[0] = "sh"; 681 argv[1] = _PATH_RUNCOM; 682 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 683 argv[3] = 0; 684 685 sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); 686 687 setprocresources(RESOURCE_RC); 688 689 execv(_PATH_BSHELL, argv); 690 stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 691 _exit(1); /* force single user mode */ 692 } 693 694 if (pid == -1) { 695 emergency("can't fork for %s on %s: %m", 696 _PATH_BSHELL, _PATH_RUNCOM); 697 while (waitpid(-1, NULL, WNOHANG) > 0) 698 continue; 699 sleep(STALL_TIMEOUT); 700 return (state_func_t) single_user; 701 } 702 703 /* 704 * Copied from single_user(). This is a bit paranoid. 705 */ 706 do { 707 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 708 collect_child(wpid); 709 if (wpid == -1) { 710 if (errno == EINTR) 711 continue; 712 warning("wait for %s on %s failed: %m; going to single user mode", 713 _PATH_BSHELL, _PATH_RUNCOM); 714 return (state_func_t) single_user; 715 } 716 if (wpid == pid && WIFSTOPPED(status)) { 717 warning("init: %s on %s stopped, restarting\n", 718 _PATH_BSHELL, _PATH_RUNCOM); 719 kill(pid, SIGCONT); 720 wpid = -1; 721 } 722 } while (wpid != pid); 723 724 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && 725 requested_transition == catatonia) { 726 /* /etc/rc executed /sbin/reboot; wait for the end quietly */ 727 sigset_t s; 728 729 sigfillset(&s); 730 for (;;) 731 sigsuspend(&s); 732 } 733 734 if (!WIFEXITED(status)) { 735 warning("%s on %s terminated abnormally, going to single user mode", 736 _PATH_BSHELL, _PATH_RUNCOM); 737 return (state_func_t) single_user; 738 } 739 740 if (WEXITSTATUS(status)) 741 return (state_func_t) single_user; 742 743 runcom_mode = AUTOBOOT; /* the default */ 744 /* NB: should send a message to the session logger to avoid blocking. */ 745 logwtmp("~", "reboot", ""); 746 return (state_func_t) read_ttys; 747} 748 749/* 750 * Open the session database. 751 * 752 * NB: We could pass in the size here; is it necessary? 753 */ 754int 755start_session_db(void) 756{ 757 if (session_db && (*session_db->close)(session_db)) 758 emergency("session database close: %s", strerror(errno)); 759 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 760 emergency("session database open: %s", strerror(errno)); 761 return (1); 762 } 763 return (0); 764} 765 766/* 767 * Add a new login session. 768 */ 769void 770add_session(session_t *sp) 771{ 772 DBT key; 773 DBT data; 774 775 key.data = &sp->se_process; 776 key.size = sizeof sp->se_process; 777 data.data = &sp; 778 data.size = sizeof sp; 779 780 if ((*session_db->put)(session_db, &key, &data, 0)) 781 emergency("insert %d: %s", sp->se_process, strerror(errno)); 782} 783 784/* 785 * Delete an old login session. 786 */ 787void 788del_session(session_t *sp) 789{ 790 DBT key; 791 792 key.data = &sp->se_process; 793 key.size = sizeof sp->se_process; 794 795 if ((*session_db->del)(session_db, &key, 0)) 796 emergency("delete %d: %s", sp->se_process, strerror(errno)); 797} 798 799/* 800 * Look up a login session by pid. 801 */ 802session_t * 803find_session(pid_t pid) 804{ 805 DBT key; 806 DBT data; 807 session_t *ret; 808 809 key.data = &pid; 810 key.size = sizeof pid; 811 if ((*session_db->get)(session_db, &key, &data, 0) != 0) 812 return (0); 813 memcpy(&ret, data.data, sizeof(ret)); 814 return (ret); 815} 816 817/* 818 * Construct an argument vector from a command line. 819 */ 820char ** 821construct_argv(char *command) 822{ 823 int argc = 0; 824 char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) * 825 sizeof (char *)); 826 static const char separators[] = " \t"; 827 828 if ((argv[argc++] = strtok(command, separators)) == 0) 829 return (0); 830 while ((argv[argc++] = strtok(NULL, separators))) 831 continue; 832 return (argv); 833} 834 835/* 836 * Deallocate a session descriptor. 837 */ 838void 839free_session(session_t *sp) 840{ 841 free(sp->se_device); 842 if (sp->se_getty) { 843 free(sp->se_getty); 844 free(sp->se_getty_argv); 845 } 846 if (sp->se_window) { 847 free(sp->se_window); 848 free(sp->se_window_argv); 849 } 850 free(sp); 851} 852 853/* 854 * Allocate a new session descriptor. 855 */ 856session_t * 857new_session(session_t *sprev, int session_index, struct ttyent *typ) 858{ 859 session_t *sp; 860 size_t len; 861 862 if ((typ->ty_status & TTY_ON) == 0 || 863 typ->ty_name == 0 || 864 typ->ty_getty == 0) 865 return (0); 866 867 sp = (session_t *) malloc(sizeof (session_t)); 868 memset(sp, 0, sizeof *sp); 869 870 sp->se_flags = SE_PRESENT; 871 sp->se_index = session_index; 872 873 len = sizeof(_PATH_DEV) + strlen(typ->ty_name); 874 sp->se_device = malloc(len); 875 (void) snprintf(sp->se_device, len, "%s%s", _PATH_DEV, typ->ty_name); 876 877 if (setupargv(sp, typ) == 0) { 878 free_session(sp); 879 return (0); 880 } 881 882 sp->se_next = 0; 883 if (sprev == 0) { 884 sessions = sp; 885 sp->se_prev = 0; 886 } else { 887 sprev->se_next = sp; 888 sp->se_prev = sprev; 889 } 890 891 return (sp); 892} 893 894/* 895 * Calculate getty and if useful window argv vectors. 896 */ 897int 898setupargv(session_t *sp, struct ttyent *typ) 899{ 900 size_t len; 901 902 if (sp->se_getty) { 903 free(sp->se_getty); 904 free(sp->se_getty_argv); 905 } 906 len = strlen(typ->ty_getty) + strlen(typ->ty_name) + 2; 907 sp->se_getty = malloc(len); 908 (void) snprintf(sp->se_getty, len, "%s %s", typ->ty_getty, typ->ty_name); 909 sp->se_getty_argv = construct_argv(sp->se_getty); 910 if (sp->se_getty_argv == 0) { 911 warning("can't parse getty for port %s", sp->se_device); 912 free(sp->se_getty); 913 sp->se_getty = 0; 914 return (0); 915 } 916 if (typ->ty_window) { 917 if (sp->se_window) 918 free(sp->se_window); 919 sp->se_window = strdup(typ->ty_window); 920 if (sp->se_window == NULL) { 921 warning("can't allocate window"); 922 return (0); 923 } 924 sp->se_window_argv = construct_argv(sp->se_window); 925 if (sp->se_window_argv == NULL) { 926 warning("can't parse window for port %s", 927 sp->se_device); 928 free(sp->se_window); 929 sp->se_window = NULL; 930 return (0); 931 } 932 } 933 return (1); 934} 935 936/* 937 * Walk the list of ttys and create sessions for each active line. 938 */ 939state_func_t 940read_ttys(void) 941{ 942 int session_index = 0; 943 session_t *sp, *snext; 944 struct ttyent *typ; 945 946 /* 947 * Destroy any previous session state. 948 * There shouldn't be any, but just in case... 949 */ 950 for (sp = sessions; sp; sp = snext) { 951 if (sp->se_process) 952 clear_session_logs(sp); 953 snext = sp->se_next; 954 free_session(sp); 955 } 956 sessions = 0; 957 if (start_session_db()) 958 return (state_func_t) single_user; 959 960 /* 961 * Allocate a session entry for each active port. 962 * Note that sp starts at 0. 963 */ 964 while ((typ = getttyent())) 965 if ((snext = new_session(sp, ++session_index, typ))) 966 sp = snext; 967 968 endttyent(); 969 970 return (state_func_t) multi_user; 971} 972 973/* 974 * Start a window system running. 975 */ 976void 977start_window_system(session_t *sp) 978{ 979 pid_t pid; 980 sigset_t mask; 981 982 if ((pid = fork()) == -1) { 983 emergency("can't fork for window system on port %s: %m", 984 sp->se_device); 985 /* hope that getty fails and we can try again */ 986 return; 987 } 988 989 if (pid) 990 return; 991 992 sigemptyset(&mask); 993 sigprocmask(SIG_SETMASK, &mask, NULL); 994 995 if (setsid() < 0) 996 emergency("setsid failed (window) %m"); 997 998 setprocresources(RESOURCE_WINDOW); 999 1000 execv(sp->se_window_argv[0], sp->se_window_argv); 1001 stall("can't exec window system '%s' for port %s: %m", 1002 sp->se_window_argv[0], sp->se_device); 1003 _exit(1); 1004} 1005 1006/* 1007 * Start a login session running. 1008 * For first open, man-handle tty directly to determine if it 1009 * really exists. It is not efficient to spawn gettys on devices 1010 * that do not exist. 1011 */ 1012pid_t 1013start_getty(session_t *sp) 1014{ 1015 pid_t pid; 1016 sigset_t mask; 1017 time_t current_time = time(NULL); 1018 int p[2], new = 1; 1019 1020 if (sp->se_flags & SE_DEVEXISTS) 1021 new = 0; 1022 1023 if (new) { 1024 if (pipe(p) == -1) 1025 return (-1); 1026 } 1027 1028 /* 1029 * fork(), not vfork() -- we can't afford to block. 1030 */ 1031 if ((pid = fork()) == -1) { 1032 emergency("can't fork for getty on port %s: %m", sp->se_device); 1033 return (-1); 1034 } 1035 1036 if (pid) { 1037 if (new) { 1038 char c; 1039 1040 close(p[1]); 1041 if (read(p[0], &c, 1) != 1) { 1042 close(p[0]); 1043 return (-1); 1044 } 1045 close(p[0]); 1046 if (c == '1') 1047 sp->se_flags |= SE_DEVEXISTS; 1048 else 1049 sp->se_flags |= SE_SHUTDOWN; 1050 } 1051 return (pid); 1052 } 1053 if (new) { 1054 int fd; 1055 1056 close(p[0]); 1057 fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0666); 1058 if (fd == -1 && (errno == ENXIO || errno == ENOENT || 1059 errno == EISDIR)) { 1060 (void)write(p[1], "0", 1); 1061 close(p[1]); 1062 _exit(1); 1063 } 1064 (void)write(p[1], "1", 1); 1065 close(p[1]); 1066 close(fd); 1067 sleep(1); 1068 } 1069 1070 if (current_time > sp->se_started && 1071 current_time - sp->se_started < GETTY_SPACING) { 1072 warning("getty repeating too quickly on port %s, sleeping", 1073 sp->se_device); 1074 sleep((unsigned) GETTY_SLEEP); 1075 } 1076 1077 if (sp->se_window) { 1078 start_window_system(sp); 1079 sleep(WINDOW_WAIT); 1080 } 1081 1082 sigemptyset(&mask); 1083 sigprocmask(SIG_SETMASK, &mask, NULL); 1084 1085 setprocresources(RESOURCE_GETTY); 1086 1087 execv(sp->se_getty_argv[0], sp->se_getty_argv); 1088 stall("can't exec getty '%s' for port %s: %m", 1089 sp->se_getty_argv[0], sp->se_device); 1090 _exit(1); 1091} 1092 1093/* 1094 * Collect exit status for a child. 1095 * If an exiting login, start a new login running. 1096 */ 1097void 1098collect_child(pid_t pid) 1099{ 1100 session_t *sp, *sprev, *snext; 1101 1102 if (sessions == NULL) 1103 return; 1104 1105 if ((sp = find_session(pid)) == NULL) 1106 return; 1107 1108 clear_session_logs(sp); 1109 login_fbtab(sp->se_device + sizeof(_PATH_DEV) - 1, 0, 0); 1110 del_session(sp); 1111 sp->se_process = 0; 1112 1113 if (sp->se_flags & SE_SHUTDOWN) { 1114 if ((sprev = sp->se_prev)) 1115 sprev->se_next = sp->se_next; 1116 else 1117 sessions = sp->se_next; 1118 if ((snext = sp->se_next)) 1119 snext->se_prev = sp->se_prev; 1120 free_session(sp); 1121 return; 1122 } 1123 1124 if ((pid = start_getty(sp)) == -1) { 1125 /* serious trouble */ 1126 requested_transition = clean_ttys; 1127 return; 1128 } 1129 1130 sp->se_process = pid; 1131 sp->se_started = time(NULL); 1132 add_session(sp); 1133} 1134 1135/* 1136 * Catch a signal and request a state transition. 1137 */ 1138void 1139transition_handler(int sig) 1140{ 1141 1142 switch (sig) { 1143 case SIGHUP: 1144 requested_transition = clean_ttys; 1145 break; 1146 case SIGTERM: 1147 requested_transition = death; 1148 break; 1149 case SIGUSR1: 1150 requested_transition = nice_death; 1151 break; 1152 case SIGTSTP: 1153 requested_transition = catatonia; 1154 break; 1155 default: 1156 requested_transition = 0; 1157 break; 1158 } 1159} 1160 1161/* 1162 * Take the system multiuser. 1163 */ 1164state_func_t 1165multi_user(void) 1166{ 1167 pid_t pid; 1168 session_t *sp; 1169 1170 requested_transition = 0; 1171 1172 /* 1173 * If the administrator has not set the security level to -1 1174 * to indicate that the kernel should not run multiuser in secure 1175 * mode, and the run script has not set a higher level of security 1176 * than level 1, then put the kernel into secure mode. 1177 */ 1178 if (getsecuritylevel() == 0) 1179 setsecuritylevel(1); 1180 1181 for (sp = sessions; sp; sp = sp->se_next) { 1182 if (sp->se_process) 1183 continue; 1184 if ((pid = start_getty(sp)) == -1) { 1185 /* serious trouble */ 1186 requested_transition = clean_ttys; 1187 break; 1188 } 1189 sp->se_process = pid; 1190 sp->se_started = time(NULL); 1191 add_session(sp); 1192 } 1193 1194 while (!requested_transition) 1195 if ((pid = waitpid(-1, NULL, 0)) != -1) 1196 collect_child(pid); 1197 1198 return (state_func_t) requested_transition; 1199} 1200 1201/* 1202 * This is an n-squared algorithm. We hope it isn't run often... 1203 */ 1204state_func_t 1205clean_ttys(void) 1206{ 1207 session_t *sp, *sprev; 1208 struct ttyent *typ; 1209 int session_index = 0; 1210 int devlen; 1211 1212 for (sp = sessions; sp; sp = sp->se_next) 1213 sp->se_flags &= ~SE_PRESENT; 1214 1215 devlen = sizeof(_PATH_DEV) - 1; 1216 while ((typ = getttyent())) { 1217 ++session_index; 1218 1219 for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) 1220 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1221 break; 1222 1223 if (sp) { 1224 sp->se_flags |= SE_PRESENT; 1225 if (sp->se_index != session_index) { 1226 warning("port %s changed utmp index from %d to %d", 1227 sp->se_device, sp->se_index, 1228 session_index); 1229 sp->se_index = session_index; 1230 } 1231 if ((typ->ty_status & TTY_ON) == 0 || 1232 typ->ty_getty == 0) { 1233 sp->se_flags |= SE_SHUTDOWN; 1234 kill(sp->se_process, SIGHUP); 1235 continue; 1236 } 1237 sp->se_flags &= ~SE_SHUTDOWN; 1238 if (setupargv(sp, typ) == 0) { 1239 warning("can't parse getty for port %s", 1240 sp->se_device); 1241 sp->se_flags |= SE_SHUTDOWN; 1242 kill(sp->se_process, SIGHUP); 1243 } 1244 continue; 1245 } 1246 1247 new_session(sprev, session_index, typ); 1248 } 1249 1250 endttyent(); 1251 1252 for (sp = sessions; sp; sp = sp->se_next) 1253 if ((sp->se_flags & SE_PRESENT) == 0) { 1254 sp->se_flags |= SE_SHUTDOWN; 1255 kill(sp->se_process, SIGHUP); 1256 } 1257 1258 return (state_func_t) multi_user; 1259} 1260 1261/* 1262 * Block further logins. 1263 */ 1264state_func_t 1265catatonia(void) 1266{ 1267 session_t *sp; 1268 1269 for (sp = sessions; sp; sp = sp->se_next) 1270 sp->se_flags |= SE_SHUTDOWN; 1271 1272 return (state_func_t) multi_user; 1273} 1274 1275/* 1276 * Note SIGALRM. 1277 */ 1278void 1279alrm_handler(int sig) 1280{ 1281 clang = 1; 1282} 1283 1284/* 1285 * Bring the system down to single user nicely, after run the shutdown script. 1286 */ 1287state_func_t 1288nice_death(void) 1289{ 1290 session_t *sp; 1291 int i; 1292 pid_t pid; 1293 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1294 int howto = RB_HALT; 1295 int status; 1296 1297 for (sp = sessions; sp; sp = sp->se_next) { 1298 sp->se_flags &= ~SE_PRESENT; 1299 sp->se_flags |= SE_SHUTDOWN; 1300 kill(sp->se_process, SIGHUP); 1301 } 1302 1303 /* NB: should send a message to the session logger to avoid blocking. */ 1304 logwtmp("~", "shutdown", ""); 1305 1306 if (access(_PATH_RUNCOM, R_OK) != -1) { 1307 pid_t pid; 1308 struct sigaction sa; 1309 1310 switch ((pid = fork())) { 1311 case -1: 1312 break; 1313 case 0: 1314 1315 memset(&sa, 0, sizeof sa); 1316 sigemptyset(&sa.sa_mask); 1317 sa.sa_flags = 0; 1318 sa.sa_handler = SIG_IGN; 1319 (void) sigaction(SIGTSTP, &sa, NULL); 1320 (void) sigaction(SIGHUP, &sa, NULL); 1321 1322 setctty(_PATH_CONSOLE); 1323 1324 sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); 1325 1326 execl(_PATH_BSHELL, "sh", _PATH_RUNCOM, "shutdown", 1327 (char *)NULL); 1328 stall("can't exec %s for %s %s: %m", _PATH_BSHELL, 1329 _PATH_RUNCOM, "shutdown"); 1330 _exit(1); 1331 default: 1332 waitpid(pid, &status, 0); 1333 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) 1334 howto |= RB_POWERDOWN; 1335 } 1336 } 1337 1338 for (i = 0; i < 3; ++i) { 1339 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1340 goto die; 1341 1342 clang = 0; 1343 alarm(DEATH_WATCH); 1344 do { 1345 if ((pid = waitpid(-1, NULL, 0)) != -1) 1346 collect_child(pid); 1347 } while (clang == 0 && errno != ECHILD); 1348 1349 if (errno == ECHILD) 1350 goto die; 1351 } 1352 1353 warning("some processes would not die; ps axl advised"); 1354 1355die: 1356 reboot(howto); 1357 1358 /* ... and if that fails.. oh well */ 1359 return (state_func_t) single_user; 1360} 1361 1362/* 1363 * Bring the system down to single user. 1364 */ 1365state_func_t 1366death(void) 1367{ 1368 session_t *sp; 1369 int i; 1370 pid_t pid; 1371 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1372 1373 for (sp = sessions; sp; sp = sp->se_next) 1374 sp->se_flags |= SE_SHUTDOWN; 1375 1376 /* NB: should send a message to the session logger to avoid blocking. */ 1377 logwtmp("~", "shutdown", ""); 1378 1379 for (i = 0; i < 3; ++i) { 1380 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1381 return (state_func_t) single_user; 1382 1383 clang = 0; 1384 alarm(DEATH_WATCH); 1385 do { 1386 if ((pid = waitpid(-1, NULL, 0)) != -1) 1387 collect_child(pid); 1388 } while (clang == 0 && errno != ECHILD); 1389 1390 if (errno == ECHILD) 1391 return (state_func_t) single_user; 1392 } 1393 1394 warning("some processes would not die; ps axl advised"); 1395 1396 return (state_func_t) single_user; 1397} 1398 1399#ifdef LOGIN_CAP 1400void 1401setprocresources(char *class) 1402{ 1403 login_cap_t *lc; 1404 1405 if ((lc = login_getclass(class)) != NULL) { 1406 setusercontext(lc, NULL, 0, 1407 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK); 1408 login_close(lc); 1409 } 1410} 1411#endif 1412