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