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