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