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