BSD 4_4_Lite2 release
[unix-history] / usr / src / sbin / init / init.c
index 32bc0e8..316aa93 100644 (file)
@@ -1,36 +1,64 @@
 /*-
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  *
  * This code is derived from software contributed to Berkeley by
- * Donn Seeley at UUNET Technologies, Inc.
+ * Donn Seeley at Berkeley Software Design, Inc.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)init.c     6.10 (Berkeley) %G%";
+static char sccsid[] = "@(#)init.c     8.2 (Berkeley) 4/28/95";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
+
 #include <db.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <db.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <syslog.h>
 #include <time.h>
 #include <ttyent.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <time.h>
 #include <ttyent.h>
 #include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
 #ifdef __STDC__
 #include <stdarg.h>
 
 #ifdef __STDC__
 #include <stdarg.h>
@@ -54,7 +82,8 @@ extern void logwtmp __P((const char *, const char *, const char *));
 /*
  * Sleep times; used to prevent thrashing.
  */
 /*
  * Sleep times; used to prevent thrashing.
  */
-#define        GETTY_SPACING           10      /* fork getty on a port every N secs */
+#define        GETTY_SPACING            5      /* N secs minimum getty spacing */
+#define        GETTY_SLEEP             30      /* sleep N secs after spacing problem */
 #define        WINDOW_WAIT              3      /* wait N secs after starting window */
 #define        STALL_TIMEOUT           30      /* wait N secs after warning */
 #define        DEATH_WATCH             10      /* wait N secs for procs to die */
 #define        WINDOW_WAIT              3      /* wait N secs after starting window */
 #define        STALL_TIMEOUT           30      /* wait N secs after warning */
 #define        DEATH_WATCH             10      /* wait N secs for procs to die */
@@ -66,6 +95,7 @@ void stall __P((char *, ...));
 void warning __P((char *, ...));
 void emergency __P((char *, ...));
 void disaster __P((int));
 void warning __P((char *, ...));
 void emergency __P((char *, ...));
 void disaster __P((int));
+void badsys __P((int));
 
 /*
  * We really need a recursive typedef...
 
 /*
  * We really need a recursive typedef...
@@ -90,7 +120,7 @@ state_t requested_transition = runcom;
 
 void setctty __P((char *));
 
 
 void setctty __P((char *));
 
-typedef struct session {
+typedef struct init_session {
        int     se_index;               /* index of entry in ttys file */
        pid_t   se_process;             /* controlling process */
        time_t  se_started;             /* used to avoid thrashing */
        int     se_index;               /* index of entry in ttys file */
        pid_t   se_process;             /* controlling process */
        time_t  se_started;             /* used to avoid thrashing */
@@ -101,8 +131,8 @@ typedef struct session {
        char    **se_getty_argv;        /* pre-parsed argument array */
        char    *se_window;             /* window system (started only once) */
        char    **se_window_argv;       /* pre-parsed argument array */
        char    **se_getty_argv;        /* pre-parsed argument array */
        char    *se_window;             /* window system (started only once) */
        char    **se_window_argv;       /* pre-parsed argument array */
-       struct  session *se_prev;
-       struct  session *se_next;
+       struct  init_session *se_prev;
+       struct  init_session *se_next;
 } session_t;
 
 void free_session __P((session_t *));
 } session_t;
 
 void free_session __P((session_t *));
@@ -111,15 +141,16 @@ session_t *sessions;
 
 char **construct_argv __P((char *));
 void start_window_system __P((session_t *));
 
 char **construct_argv __P((char *));
 void start_window_system __P((session_t *));
-void collect_child __P((int));
+void collect_child __P((pid_t));
 pid_t start_getty __P((session_t *));
 void transition_handler __P((int));
 void alrm_handler __P((int));
 pid_t start_getty __P((session_t *));
 void transition_handler __P((int));
 void alrm_handler __P((int));
+void setsecuritylevel __P((int));
+int getsecuritylevel __P((void));
+int setupargv __P((session_t *, struct ttyent *));
 int clang;
 
 int clang;
 
-int start_logger __P((void));
 void clear_session_logs __P((session_t *));
 void clear_session_logs __P((session_t *));
-int logger_enable;
 
 int start_session_db __P((void));
 void add_session __P((session_t *));
 
 int start_session_db __P((void));
 void add_session __P((session_t *));
@@ -162,7 +193,14 @@ main(argc, argv)
         * Create an initial session.
         */
        if (setsid() < 0)
         * Create an initial session.
         */
        if (setsid() < 0)
-               syslog(LOG_ERR, "setsid failed (initial) %m");
+               warning("initial setsid() failed: %m");
+
+       /*
+        * Establish an initial user so that programs running
+        * single user do not freak out and die (like passwd).
+        */
+       if (setlogin("root") < 0)
+               warning("setlogin() failed: %m");
 
        /*
         * This code assumes that we always get arguments through flags,
 
        /*
         * This code assumes that we always get arguments through flags,
@@ -188,8 +226,9 @@ main(argc, argv)
         * We catch or block signals rather than ignore them,
         * so that they get reset on exec.
         */
         * We catch or block signals rather than ignore them,
         * so that they get reset on exec.
         */
+       handle(badsys, SIGSYS, 0);
        handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
        handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
-              SIGBUS, SIGSYS, SIGXCPU, SIGXFSZ, 0);
+              SIGBUS, SIGXCPU, SIGXFSZ, 0);
        handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
        handle(alrm_handler, SIGALRM, 0);
        sigfillset(&mask);
        handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
        handle(alrm_handler, SIGALRM, 0);
        sigfillset(&mask);
@@ -253,6 +292,7 @@ handle(va_alist)
                sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
                sigaction(sig, &sa, (struct sigaction *) 0);
        }
                sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
                sigaction(sig, &sa, (struct sigaction *) 0);
        }
+       va_end(ap);
 }
 
 /*
 }
 
 /*
@@ -279,6 +319,7 @@ delset(va_alist)
 
        while (sig = va_arg(ap, int))
                sigdelset(maskp, sig);
 
        while (sig = va_arg(ap, int))
                sigdelset(maskp, sig);
+       va_end(ap);
 }
 
 /*
 }
 
 /*
@@ -294,7 +335,6 @@ stall(va_alist)
        va_dcl
 #endif
 {
        va_dcl
 #endif
 {
-       pid_t pid;
        va_list ap;
 #ifndef __STDC__
        char *message;
        va_list ap;
 #ifndef __STDC__
        char *message;
@@ -363,6 +403,23 @@ emergency(va_alist)
        va_end(ap);
 }
 
        va_end(ap);
 }
 
+/*
+ * Catch a SIGSYS signal.
+ *
+ * These may arise if a system does not support sysctl.
+ * We tolerate up to 25 of these, then throw in the towel.
+ */
+void
+badsys(sig)
+       int sig;
+{
+       static int badcount = 0;
+
+       if (badcount++ < 25)
+               return;
+       disaster(sig);
+}
+
 /*
  * Catch an unexpected signal.
  */
 /*
  * Catch an unexpected signal.
  */
@@ -378,74 +435,69 @@ disaster(sig)
 }
 
 /*
 }
 
 /*
- * Change states in the finite state machine.
- * The initial state is passed as an argument.
+ * Get the security level of the kernel.
  */
  */
-void
-transition(s)
-       state_t s;
+int
+getsecuritylevel()
 {
 {
-       for (;;)
-               s = (state_t) (*s)();
+#ifdef KERN_SECURELVL
+       int name[2], curlevel;
+       size_t len;
+       extern int errno;
+
+       name[0] = CTL_KERN;
+       name[1] = KERN_SECURELVL;
+       len = sizeof curlevel;
+       if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
+               emergency("cannot get kernel security level: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       return (curlevel);
+#else
+       return (-1);
+#endif
 }
 
 /*
 }
 
 /*
- * We send requests for session logging to another process for two reasons.
- * First, we don't want to block if the log files go away (e.g. because
- * one or more are on hard-mounted NFS systems whose server crashes).
- * Second, despite all the crud already contained in init, it still isn't
- * right that init should care about session logging record formats and files.
- * We could use explicit 'Unix' IPC for this, but let's try to be POSIX...
+ * Set the security level of the kernel.
  */
  */
-int
-start_logger()
+void
+setsecuritylevel(newlevel)
+       int newlevel;
 {
 {
-       static char *argv[] = { _PATH_SLOGGER, 0 };
-       int fd, pfd[2];
-       pid_t pid;
-       sigset_t mask;
+#ifdef KERN_SECURELVL
+       int name[2], curlevel;
+       extern int errno;
 
 
-       if (pipe(pfd) == -1) {
-               warning("session logging disabled: can't make pipe to %s: %m",
-                         argv[0]);
-               return -1;
-       }
-       if ((pid = fork()) == -1) {
-               emergency("session logging disabled: can't fork for %s: %m",
-                         argv[0]);
-               return -1;
-       }
-
-       if (pid == 0) {
-               close(pfd[1]);
-               if (pfd[0] != 0) {
-                       dup2(pfd[0], 0);
-                       close(pfd[0]);
-               }
-               if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != -1) {
-                       if (fd != 1)
-                               dup2(fd, 1);
-                       if (fd != 2)
-                               dup2(fd, 2);
-                       if (fd != 1 && fd != 2)
-                               close(fd);
-               } else {
-                       /* paranoid */
-                       close(1);
-                       close(2);
-               }
-               sigemptyset(&mask);
-               sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
-               execv(argv[0], argv);
-               stall("can't exec %s: %m", argv[0]);
-               _exit(1);
+       curlevel = getsecuritylevel();
+       if (newlevel == curlevel)
+               return;
+       name[0] = CTL_KERN;
+       name[1] = KERN_SECURELVL;
+       if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
+               emergency(
+                   "cannot change kernel security level from %d to %d: %s",
+                   curlevel, newlevel, strerror(errno));
+               return;
        }
        }
+#ifdef SECURE
+       warning("kernel security level changed from %d to %d",
+           curlevel, newlevel);
+#endif
+#endif
+}
 
 
-       close(pfd[0]);
-       fcntl(pfd[1], F_SETFD, FD_CLOEXEC);
-       fcntl(pfd[1], F_SETFL, O_NONBLOCK);
-
-       return pfd[1];
+/*
+ * Change states in the finite state machine.
+ * The initial state is passed as an argument.
+ */
+void
+transition(s)
+       state_t s;
+{
+       for (;;)
+               s = (state_t) (*s)();
 }
 
 /*
 }
 
 /*
@@ -473,6 +525,7 @@ setctty(name)
        int fd;
 
        (void) revoke(name);
        int fd;
 
        (void) revoke(name);
+       sleep (2);                      /* leave DTR low */
        if ((fd = open(name, O_RDWR)) == -1) {
                stall("can't open %s: %m", name);
                _exit(1);
        if ((fd = open(name, O_RDWR)) == -1) {
                stall("can't open %s: %m", name);
                _exit(1);
@@ -499,9 +552,15 @@ single_user()
        struct passwd *pp;
        static const char banner[] =
                "Enter root password, or ^D to go multi-user\n";
        struct passwd *pp;
        static const char banner[] =
                "Enter root password, or ^D to go multi-user\n";
-       char *password;
+       char *clear, *password;
 #endif
 
 #endif
 
+       /*
+        * If the kernel is in secure mode, downgrade it to insecure mode.
+        */
+       if (getsecuritylevel() > 0)
+               setsecuritylevel(0);
+
        if ((pid = fork()) == 0) {
                /*
                 * Start the single user session.
        if ((pid = fork()) == 0) {
                /*
                 * Start the single user session.
@@ -519,24 +578,37 @@ single_user()
                if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) {
                        write(2, banner, sizeof banner - 1);
                        for (;;) {
                if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) {
                        write(2, banner, sizeof banner - 1);
                        for (;;) {
-                               password = getpass("Password:");
-                               if (password == 0 || *password == '\0')
+                               clear = getpass("Password:");
+                               if (clear == 0 || *clear == '\0')
                                        _exit(0);
                                        _exit(0);
-                               password = crypt(password, pp->pw_passwd);
+                               password = crypt(clear, pp->pw_passwd);
+                               memset(clear, 0, _PASSWORD_LEN);
                                if (strcmp(password, pp->pw_passwd) == 0)
                                        break;
                                if (strcmp(password, pp->pw_passwd) == 0)
                                        break;
+                               warning("single-user login failed\n");
                        }
                }
                        }
                }
-#if 0
-               /*
-                * Make the single-user shell be root's standard shell?
-                */
-               if (pp && pp->pw_shell)
-                       shell = pp->pw_shell;
-#endif
                endttyent();
                endpwent();
                endttyent();
                endpwent();
-#endif
+#endif /* SECURE */
+
+#ifdef DEBUGSHELL
+               {
+                       char altshell[128], *cp = altshell;
+                       int num;
+
+#define        SHREQUEST \
+       "Enter pathname of shell or RETURN for sh: "
+                       (void)write(STDERR_FILENO,
+                           SHREQUEST, sizeof(SHREQUEST) - 1);
+                       while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
+                           num != 0 && *cp != '\n' && cp < &altshell[127])
+                                       cp++;
+                       *cp = '\0';
+                       if (altshell[0] != '\0')
+                               shell = altshell;
+               }
+#endif /* DEBUGSHELL */
 
                /*
                 * Unblock signals.
 
                /*
                 * Unblock signals.
@@ -670,6 +742,16 @@ runcom()
                }
        } while (wpid != pid);
 
                }
        } while (wpid != pid);
 
+       if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
+           requested_transition == catatonia) {
+               /* /etc/rc executed /sbin/reboot; wait for the end quietly */
+               sigset_t s;
+
+               sigfillset(&s);
+               for (;;)
+                       sigsuspend(&s);
+       }
+
        if (!WIFEXITED(status)) {
                warning("%s on %s terminated abnormally, going to single user mode",
                        _PATH_BSHELL, _PATH_RUNCOM);
        if (!WIFEXITED(status)) {
                warning("%s on %s terminated abnormally, going to single user mode",
                        _PATH_BSHELL, _PATH_RUNCOM);
@@ -757,7 +839,7 @@ find_session(pid)
        key.size = sizeof pid;
        if ((*session_db->get)(session_db, &key, &data, 0) != 0)
                return 0;
        key.size = sizeof pid;
        if ((*session_db->get)(session_db, &key, &data, 0) != 0)
                return 0;
-       bcopy(data.data, (char *)&ret, sizeof(ret));
+       memmove(&ret, data.data, sizeof(ret));
        return ret;
 }
 
        return ret;
 }
 
@@ -788,8 +870,10 @@ free_session(sp)
        register session_t *sp;
 {
        free(sp->se_device);
        register session_t *sp;
 {
        free(sp->se_device);
-       free(sp->se_getty);
-       free(sp->se_getty_argv);
+       if (sp->se_getty) {
+               free(sp->se_getty);
+               free(sp->se_getty_argv);
+       }
        if (sp->se_window) {
                free(sp->se_window);
                free(sp->se_window_argv);
        if (sp->se_window) {
                free(sp->se_window);
                free(sp->se_window_argv);
@@ -814,33 +898,16 @@ new_session(sprev, session_index, typ)
                return 0;
 
        sp = (session_t *) malloc(sizeof (session_t));
                return 0;
 
        sp = (session_t *) malloc(sizeof (session_t));
+       memset(sp, 0, sizeof *sp);
 
        sp->se_index = session_index;
 
        sp->se_index = session_index;
-       sp->se_process = 0;
-       sp->se_started = 0;
-       sp->se_flags = 0;
-       sp->se_window = 0;
 
        sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
        (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
 
 
        sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
        (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
 
-       sp->se_getty = strdup(typ->ty_getty);
-       sp->se_getty_argv = construct_argv(sp->se_getty);
-       if (sp->se_getty_argv == 0) {
-               warning("can't parse getty for port %s",
-                       sp->se_device);
+       if (setupargv(sp, typ) == 0) {
                free_session(sp);
                free_session(sp);
-               return 0;
-       }
-       if (typ->ty_window) {
-               sp->se_window = strdup(typ->ty_window);
-               sp->se_window_argv = construct_argv(sp->se_window);
-               if (sp->se_window_argv == 0) {
-                       warning("can't parse window for port %s",
-                               sp->se_device);
-                       free_session(sp);
-                       return 0;
-               }
+               return (0);
        }
 
        sp->se_next = 0;
        }
 
        sp->se_next = 0;
@@ -855,6 +922,44 @@ new_session(sprev, session_index, typ)
        return sp;
 }
 
        return sp;
 }
 
+/*
+ * Calculate getty and if useful window argv vectors.
+ */
+int
+setupargv(sp, typ)
+       session_t *sp;
+       struct ttyent *typ;
+{
+
+       if (sp->se_getty) {
+               free(sp->se_getty);
+               free(sp->se_getty_argv);
+       }
+       sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2);
+       (void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
+       sp->se_getty_argv = construct_argv(sp->se_getty);
+       if (sp->se_getty_argv == 0) {
+               warning("can't parse getty for port %s", sp->se_device);
+               free(sp->se_getty);
+               sp->se_getty = 0;
+               return (0);
+       }
+       if (typ->ty_window) {
+               if (sp->se_window)
+                       free(sp->se_window);
+               sp->se_window = strdup(typ->ty_window);
+               sp->se_window_argv = construct_argv(sp->se_window);
+               if (sp->se_window_argv == 0) {
+                       warning("can't parse window for port %s",
+                               sp->se_device);
+                       free(sp->se_window);
+                       sp->se_window = 0;
+                       return (0);
+               }
+       }
+       return (1);
+}
+
 /*
  * Walk the list of ttys and create sessions for each active line.
  */
 /*
  * Walk the list of ttys and create sessions for each active line.
  */
@@ -889,7 +994,6 @@ read_ttys()
 
        endttyent();
 
 
        endttyent();
 
-       logger_enable = 1;
        return (state_func_t) multi_user;
 }
 
        return (state_func_t) multi_user;
 }
 
@@ -951,8 +1055,7 @@ start_getty(sp)
            current_time - sp->se_started < GETTY_SPACING) {
                warning("getty repeating too quickly on port %s, sleeping",
                        sp->se_device);
            current_time - sp->se_started < GETTY_SPACING) {
                warning("getty repeating too quickly on port %s, sleeping",
                        sp->se_device);
-               sleep((unsigned) GETTY_SPACING -
-                     (current_time - sp->se_started));
+               sleep((unsigned) GETTY_SLEEP);
        }
 
        if (sp->se_window) {
        }
 
        if (sp->se_window) {
@@ -960,8 +1063,6 @@ start_getty(sp)
                sleep(WINDOW_WAIT);
        }
 
                sleep(WINDOW_WAIT);
        }
 
-       setctty(sp->se_device);
-
        sigemptyset(&mask);
        sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
 
        sigemptyset(&mask);
        sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
 
@@ -976,8 +1077,12 @@ start_getty(sp)
  * If an exiting login, start a new login running.
  */
 void
  * If an exiting login, start a new login running.
  */
 void
+#ifdef __STDC__
+collect_child(pid_t pid)
+#else
 collect_child(pid)
        pid_t pid;
 collect_child(pid)
        pid_t pid;
+#endif
 {
        register session_t *sp, *sprev, *snext;
 
 {
        register session_t *sp, *sprev, *snext;
 
@@ -1047,7 +1152,15 @@ multi_user()
        register session_t *sp;
 
        requested_transition = 0;
        register session_t *sp;
 
        requested_transition = 0;
-       logger_enable = 1;
+
+       /*
+        * If the administrator has not set the security level to -1
+        * to indicate that the kernel should not run multiuser in secure
+        * mode, and the run script has not set a higher level of security 
+        * than level 1, then put the kernel into secure mode.
+        */
+       if (getsecuritylevel() == 0)
+               setsecuritylevel(1);
 
        for (sp = sessions; sp; sp = sp->se_next) {
                if (sp->se_process)
 
        for (sp = sessions; sp; sp = sp->se_next) {
                if (sp->se_process)
@@ -1087,7 +1200,7 @@ clean_ttys()
        while (typ = getttyent()) {
                ++session_index;
 
        while (typ = getttyent()) {
                ++session_index;
 
-               for (sp = sessions; sp; sprev = sp, sp = sp->se_next)
+               for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
                        if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
                                break;
 
                        if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
                                break;
 
@@ -1098,9 +1211,16 @@ clean_ttys()
                                       session_index);
                                sp->se_index = session_index;
                        }
                                       session_index);
                                sp->se_index = session_index;
                        }
-                       if (typ->ty_status & TTY_ON)
-                               sp->se_flags &= ~SE_SHUTDOWN;
-                       else {
+                       if ((typ->ty_status & TTY_ON) == 0 ||
+                           typ->ty_getty == 0) {
+                               sp->se_flags |= SE_SHUTDOWN;
+                               kill(sp->se_process, SIGHUP);
+                               continue;
+                       }
+                       sp->se_flags &= ~SE_SHUTDOWN;
+                       if (setupargv(sp, typ) == 0) {
+                               warning("can't parse getty for port %s",
+                                       sp->se_device);
                                sp->se_flags |= SE_SHUTDOWN;
                                kill(sp->se_process, SIGHUP);
                        }
                                sp->se_flags |= SE_SHUTDOWN;
                                kill(sp->se_process, SIGHUP);
                        }
@@ -1155,7 +1275,6 @@ death()
 
        /* NB: should send a message to the session logger to avoid blocking. */
        logwtmp("~", "shutdown", "");
 
        /* NB: should send a message to the session logger to avoid blocking. */
        logwtmp("~", "shutdown", "");
-       logger_enable = 0;
 
        for (i = 0; i < 3; ++i) {
                if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
 
        for (i = 0; i < 3; ++i) {
                if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
@@ -1172,7 +1291,7 @@ death()
                        return (state_func_t) single_user;
        }
 
                        return (state_func_t) single_user;
        }
 
-       warning("some processes wouldn't die");
+       warning("some processes would not die; ps axl advised");
 
        return (state_func_t) single_user;
 }
 
        return (state_func_t) single_user;
 }