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