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