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