init.c revision 1.47
1/* $OpenBSD: init.c,v 1.47 2012/10/11 22:21:29 halex 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 = (session_t *) malloc(sizeof (session_t)); 864 memset(sp, 0, sizeof *sp); 865 866 sp->se_flags = SE_PRESENT; 867 sp->se_index = session_index; 868 869 if (asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name) == -1) 870 err(1, "asprintf"); 871 872 if (setupargv(sp, typ) == 0) { 873 free_session(sp); 874 return (0); 875 } 876 877 sp->se_next = 0; 878 if (sprev == 0) { 879 sessions = sp; 880 sp->se_prev = 0; 881 } else { 882 sprev->se_next = sp; 883 sp->se_prev = sprev; 884 } 885 886 return (sp); 887} 888 889/* 890 * Calculate getty and if useful window argv vectors. 891 */ 892int 893setupargv(session_t *sp, struct ttyent *typ) 894{ 895 if (sp->se_getty) { 896 free(sp->se_getty); 897 free(sp->se_getty_argv); 898 } 899 if (asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name) == -1) 900 err(1, "asprintf"); 901 sp->se_getty_argv = construct_argv(sp->se_getty); 902 if (sp->se_getty_argv == 0) { 903 warning("can't parse getty for port %s", sp->se_device); 904 free(sp->se_getty); 905 sp->se_getty = 0; 906 return (0); 907 } 908 if (typ->ty_window) { 909 if (sp->se_window) 910 free(sp->se_window); 911 sp->se_window = strdup(typ->ty_window); 912 if (sp->se_window == NULL) { 913 warning("can't allocate window"); 914 return (0); 915 } 916 sp->se_window_argv = construct_argv(sp->se_window); 917 if (sp->se_window_argv == NULL) { 918 warning("can't parse window for port %s", 919 sp->se_device); 920 free(sp->se_window); 921 sp->se_window = NULL; 922 return (0); 923 } 924 } 925 return (1); 926} 927 928/* 929 * Walk the list of ttys and create sessions for each active line. 930 */ 931state_func_t 932read_ttys(void) 933{ 934 int session_index = 0; 935 session_t *sp, *snext; 936 struct ttyent *typ; 937 938 /* 939 * Destroy any previous session state. 940 * There shouldn't be any, but just in case... 941 */ 942 for (sp = sessions; sp; sp = snext) { 943 if (sp->se_process) 944 clear_session_logs(sp); 945 snext = sp->se_next; 946 free_session(sp); 947 } 948 sessions = 0; 949 if (start_session_db()) 950 return (state_func_t) single_user; 951 952 /* 953 * Allocate a session entry for each active port. 954 * Note that sp starts at 0. 955 */ 956 while ((typ = getttyent())) 957 if ((snext = new_session(sp, ++session_index, typ))) 958 sp = snext; 959 960 endttyent(); 961 962 return (state_func_t) multi_user; 963} 964 965/* 966 * Start a window system running. 967 */ 968void 969start_window_system(session_t *sp) 970{ 971 pid_t pid; 972 sigset_t mask; 973 974 if ((pid = fork()) == -1) { 975 emergency("can't fork for window system on port %s: %m", 976 sp->se_device); 977 /* hope that getty fails and we can try again */ 978 return; 979 } 980 981 if (pid) 982 return; 983 984 sigemptyset(&mask); 985 sigprocmask(SIG_SETMASK, &mask, NULL); 986 987 if (setsid() < 0) 988 emergency("setsid failed (window) %m"); 989 990 setprocresources(RESOURCE_WINDOW); 991 992 execv(sp->se_window_argv[0], sp->se_window_argv); 993 stall("can't exec window system '%s' for port %s: %m", 994 sp->se_window_argv[0], sp->se_device); 995 _exit(1); 996} 997 998/* 999 * Start a login session running. 1000 * For first open, man-handle tty directly to determine if it 1001 * really exists. It is not efficient to spawn gettys on devices 1002 * that do not exist. 1003 */ 1004pid_t 1005start_getty(session_t *sp) 1006{ 1007 pid_t pid; 1008 sigset_t mask; 1009 time_t current_time = time(NULL); 1010 int p[2], new = 1; 1011 1012 if (sp->se_flags & SE_DEVEXISTS) 1013 new = 0; 1014 1015 if (new) { 1016 if (pipe(p) == -1) 1017 return (-1); 1018 } 1019 1020 /* 1021 * fork(), not vfork() -- we can't afford to block. 1022 */ 1023 if ((pid = fork()) == -1) { 1024 emergency("can't fork for getty on port %s: %m", sp->se_device); 1025 return (-1); 1026 } 1027 1028 if (pid) { 1029 if (new) { 1030 char c; 1031 1032 close(p[1]); 1033 if (read(p[0], &c, 1) != 1) { 1034 close(p[0]); 1035 return (-1); 1036 } 1037 close(p[0]); 1038 if (c == '1') 1039 sp->se_flags |= SE_DEVEXISTS; 1040 else 1041 sp->se_flags |= SE_SHUTDOWN; 1042 } 1043 return (pid); 1044 } 1045 if (new) { 1046 int fd; 1047 1048 close(p[0]); 1049 fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0666); 1050 if (fd == -1 && (errno == ENXIO || errno == ENOENT || 1051 errno == EISDIR)) { 1052 (void)write(p[1], "0", 1); 1053 close(p[1]); 1054 _exit(1); 1055 } 1056 (void)write(p[1], "1", 1); 1057 close(p[1]); 1058 close(fd); 1059 sleep(1); 1060 } 1061 1062 if (current_time > sp->se_started && 1063 current_time - sp->se_started < GETTY_SPACING) { 1064 warning("getty repeating too quickly on port %s, sleeping", 1065 sp->se_device); 1066 sleep(GETTY_SLEEP); 1067 } 1068 1069 if (sp->se_window) { 1070 start_window_system(sp); 1071 sleep(WINDOW_WAIT); 1072 } 1073 1074 sigemptyset(&mask); 1075 sigprocmask(SIG_SETMASK, &mask, NULL); 1076 1077 setprocresources(RESOURCE_GETTY); 1078 1079 execv(sp->se_getty_argv[0], sp->se_getty_argv); 1080 stall("can't exec getty '%s' for port %s: %m", 1081 sp->se_getty_argv[0], sp->se_device); 1082 _exit(1); 1083} 1084 1085/* 1086 * Collect exit status for a child. 1087 * If an exiting login, start a new login running. 1088 */ 1089void 1090collect_child(pid_t pid) 1091{ 1092 session_t *sp, *sprev, *snext; 1093 1094 if (sessions == NULL) 1095 return; 1096 1097 if ((sp = find_session(pid)) == NULL) 1098 return; 1099 1100 clear_session_logs(sp); 1101 login_fbtab(sp->se_device + sizeof(_PATH_DEV) - 1, 0, 0); 1102 del_session(sp); 1103 sp->se_process = 0; 1104 1105 if (sp->se_flags & SE_SHUTDOWN) { 1106 if ((sprev = sp->se_prev)) 1107 sprev->se_next = sp->se_next; 1108 else 1109 sessions = sp->se_next; 1110 if ((snext = sp->se_next)) 1111 snext->se_prev = sp->se_prev; 1112 free_session(sp); 1113 return; 1114 } 1115 1116 if ((pid = start_getty(sp)) == -1) { 1117 /* serious trouble */ 1118 requested_transition = clean_ttys; 1119 return; 1120 } 1121 1122 sp->se_process = pid; 1123 sp->se_started = time(NULL); 1124 add_session(sp); 1125} 1126 1127/* 1128 * Catch a signal and request a state transition. 1129 */ 1130void 1131transition_handler(int sig) 1132{ 1133 1134 switch (sig) { 1135 case SIGHUP: 1136 requested_transition = clean_ttys; 1137 break; 1138 case SIGINT: 1139 requested_transition = do_reboot; 1140 break; 1141 case SIGTERM: 1142 requested_transition = death; 1143 break; 1144 case SIGUSR1: 1145 requested_transition = nice_death; 1146 break; 1147 case SIGUSR2: 1148 requested_transition = hard_death; 1149 break; 1150 case SIGTSTP: 1151 requested_transition = catatonia; 1152 break; 1153 default: 1154 requested_transition = 0; 1155 break; 1156 } 1157} 1158 1159/* 1160 * Take the system multiuser. 1161 */ 1162state_func_t 1163multi_user(void) 1164{ 1165 pid_t pid; 1166 session_t *sp; 1167 1168 requested_transition = 0; 1169 1170 /* 1171 * If the administrator has not set the security level to -1 1172 * to indicate that the kernel should not run multiuser in secure 1173 * mode, and the run script has not set a higher level of security 1174 * than level 1, then put the kernel into secure mode. 1175 */ 1176 if (getsecuritylevel() == 0) 1177 setsecuritylevel(1); 1178 1179 for (sp = sessions; sp; sp = sp->se_next) { 1180 if (sp->se_process) 1181 continue; 1182 if ((pid = start_getty(sp)) == -1) { 1183 /* serious trouble */ 1184 requested_transition = clean_ttys; 1185 break; 1186 } 1187 sp->se_process = pid; 1188 sp->se_started = time(NULL); 1189 add_session(sp); 1190 } 1191 1192 while (!requested_transition) 1193 if ((pid = waitpid(-1, NULL, 0)) != -1) 1194 collect_child(pid); 1195 1196 return (state_func_t) requested_transition; 1197} 1198 1199/* 1200 * This is an n-squared algorithm. We hope it isn't run often... 1201 */ 1202state_func_t 1203clean_ttys(void) 1204{ 1205 session_t *sp, *sprev; 1206 struct ttyent *typ; 1207 int session_index = 0; 1208 int devlen; 1209 1210 for (sp = sessions; sp; sp = sp->se_next) 1211 sp->se_flags &= ~SE_PRESENT; 1212 1213 devlen = sizeof(_PATH_DEV) - 1; 1214 while ((typ = getttyent())) { 1215 ++session_index; 1216 1217 for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) 1218 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1219 break; 1220 1221 if (sp) { 1222 sp->se_flags |= SE_PRESENT; 1223 if (sp->se_index != session_index) { 1224 warning("port %s changed utmp index from %d to %d", 1225 sp->se_device, sp->se_index, 1226 session_index); 1227 sp->se_index = session_index; 1228 } 1229 if ((typ->ty_status & TTY_ON) == 0 || 1230 typ->ty_getty == 0) { 1231 sp->se_flags |= SE_SHUTDOWN; 1232 kill(sp->se_process, SIGHUP); 1233 continue; 1234 } 1235 sp->se_flags &= ~SE_SHUTDOWN; 1236 if (setupargv(sp, typ) == 0) { 1237 warning("can't parse getty for port %s", 1238 sp->se_device); 1239 sp->se_flags |= SE_SHUTDOWN; 1240 kill(sp->se_process, SIGHUP); 1241 } 1242 continue; 1243 } 1244 1245 new_session(sprev, session_index, typ); 1246 } 1247 1248 endttyent(); 1249 1250 for (sp = sessions; sp; sp = sp->se_next) 1251 if ((sp->se_flags & SE_PRESENT) == 0) { 1252 sp->se_flags |= SE_SHUTDOWN; 1253 kill(sp->se_process, SIGHUP); 1254 } 1255 1256 return (state_func_t) multi_user; 1257} 1258 1259/* 1260 * Block further logins. 1261 */ 1262state_func_t 1263catatonia(void) 1264{ 1265 session_t *sp; 1266 1267 for (sp = sessions; sp; sp = sp->se_next) 1268 sp->se_flags |= SE_SHUTDOWN; 1269 1270 return (state_func_t) multi_user; 1271} 1272 1273/* 1274 * Note SIGALRM. 1275 */ 1276void 1277alrm_handler(int sig) 1278{ 1279 clang = 1; 1280} 1281 1282int death_howto = RB_HALT; 1283 1284/* 1285 * Reboot the system. 1286 */ 1287state_func_t 1288do_reboot(void) 1289{ 1290 death_howto = RB_AUTOBOOT; 1291 return nice_death(); 1292} 1293 1294/* 1295 * Bring the system down nicely, then we must powerdown because something 1296 * is very wrong. 1297 */ 1298state_func_t 1299hard_death(void) 1300{ 1301 death_howto |= RB_POWERDOWN; 1302 return nice_death(); 1303} 1304 1305/* 1306 * Bring the system down to single user nicely, after run the shutdown script. 1307 */ 1308state_func_t 1309nice_death(void) 1310{ 1311 session_t *sp; 1312 int i; 1313 pid_t pid; 1314 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1315 int status; 1316 1317#ifdef CPU_LIDSUSPEND 1318 int lidsuspend_mib[] = {CTL_MACHDEP, CPU_LIDSUSPEND}; 1319 int dontsuspend = 0; 1320 1321 if ((death_howto & RB_POWERDOWN) && 1322 (sysctl(lidsuspend_mib, 2, NULL, NULL, &dontsuspend, 1323 sizeof(dontsuspend)) < 0)) 1324 warning("cannot disable lid suspend"); 1325#endif 1326 1327 for (sp = sessions; sp; sp = sp->se_next) { 1328 sp->se_flags &= ~SE_PRESENT; 1329 sp->se_flags |= SE_SHUTDOWN; 1330 kill(sp->se_process, SIGHUP); 1331 } 1332 1333 /* terminate the accounting process */ 1334 acct(NULL); 1335 1336 /* NB: should send a message to the session logger to avoid blocking. */ 1337 logwtmp("~", "shutdown", ""); 1338 1339 if (access(_PATH_RUNCOM, R_OK) != -1) { 1340 pid_t pid; 1341 struct sigaction sa; 1342 1343 switch ((pid = fork())) { 1344 case -1: 1345 break; 1346 case 0: 1347 1348 memset(&sa, 0, sizeof sa); 1349 sigemptyset(&sa.sa_mask); 1350 sa.sa_flags = 0; 1351 sa.sa_handler = SIG_IGN; 1352 (void) sigaction(SIGTSTP, &sa, NULL); 1353 (void) sigaction(SIGHUP, &sa, NULL); 1354 1355 setctty(_PATH_CONSOLE); 1356 1357 sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); 1358 1359 execl(_PATH_BSHELL, "sh", _PATH_RUNCOM, "shutdown", 1360 (char *)NULL); 1361 stall("can't exec %s for %s %s: %m", _PATH_BSHELL, 1362 _PATH_RUNCOM, "shutdown"); 1363 _exit(1); 1364 default: 1365 waitpid(pid, &status, 0); 1366 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) 1367 death_howto |= RB_POWERDOWN; 1368 } 1369 } 1370 1371 for (i = 0; i < 3; ++i) { 1372 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1373 goto die; 1374 1375 clang = 0; 1376 alarm(DEATH_WATCH); 1377 do { 1378 if ((pid = waitpid(-1, NULL, 0)) != -1) 1379 collect_child(pid); 1380 } while (clang == 0 && errno != ECHILD); 1381 1382 if (errno == ECHILD) 1383 goto die; 1384 } 1385 1386 warning("some processes would not die; ps axl advised"); 1387 1388die: 1389 reboot(death_howto); 1390 1391 /* ... and if that fails.. oh well */ 1392 return (state_func_t) single_user; 1393} 1394 1395/* 1396 * Bring the system down to single user. 1397 */ 1398state_func_t 1399death(void) 1400{ 1401 session_t *sp; 1402 int i; 1403 pid_t pid; 1404 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1405 1406 /* terminate the accounting process */ 1407 acct(NULL); 1408 1409 for (sp = sessions; sp; sp = sp->se_next) 1410 sp->se_flags |= SE_SHUTDOWN; 1411 1412 /* NB: should send a message to the session logger to avoid blocking. */ 1413 logwtmp("~", "shutdown", ""); 1414 1415 for (i = 0; i < 3; ++i) { 1416 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1417 return (state_func_t) single_user; 1418 1419 clang = 0; 1420 alarm(DEATH_WATCH); 1421 do { 1422 if ((pid = waitpid(-1, NULL, 0)) != -1) 1423 collect_child(pid); 1424 } while (clang == 0 && errno != ECHILD); 1425 1426 if (errno == ECHILD) 1427 return (state_func_t) single_user; 1428 } 1429 1430 warning("some processes would not die; ps axl advised"); 1431 1432 return (state_func_t) single_user; 1433} 1434 1435#ifdef LOGIN_CAP 1436void 1437setprocresources(char *class) 1438{ 1439 login_cap_t *lc; 1440 1441 if ((lc = login_getclass(class)) != NULL) { 1442 setusercontext(lc, NULL, 0, 1443 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK); 1444 login_close(lc); 1445 } 1446} 1447#endif 1448