This patch revive almost all login.conf and password/account expiration
features, makes OpenSSH more FreeBSD login compatible and fix non-critical
memory leak.

Please review and commit.

--- sshd.c.old  Fri Feb 25 08:23:45 2000
+++ sshd.c      Sun Feb 27 02:53:33 2000
@@ -37,9 +37,8 @@
 #endif /* LIBWRAP */
 
 #ifdef __FreeBSD__
-#include <libutil.h>
-#include <syslog.h>
 #define        LOGIN_CAP
+#define _PATH_CHPASS "/usr/bin/passwd"
 #endif /* __FreeBSD__ */
 
 #ifdef LOGIN_CAP
@@ -1246,6 +1245,7 @@
                                return 0;
                }
        }
+#ifndef __FreeBSD__     /* FreeBSD handle it later */
        /* Fail if the account's expiration time has passed. */
        if (pw->pw_expire != 0) {
                struct timeval tv;
@@ -1254,6 +1254,7 @@
                if (tv.tv_sec >= pw->pw_expire)
                        return 0;
        }
+#endif /* !__FreeBSD__ */
        /* We found no reason not to let this user try to log on... */
        return 1;
 }
@@ -1268,6 +1269,12 @@
        struct passwd *pw, pwcopy;
        int plen, ulen;
        char *user;
+#ifdef LOGIN_CAP
+       login_cap_t *lc;
+       char *hosts;
+       const char *from_host, *from_ip;
+       int denied;
+#endif /* LOGIN_CAP */
 
        /* Get the name of the user that we wish to log in as. */
        packet_read_expect(&plen, SSH_CMSG_USER);
@@ -1338,6 +1345,38 @@
                        packet_disconnect("ROOT LOGIN REFUSED FROM %.200s",
                                          get_canonical_hostname());
        }
+
+#ifdef LOGIN_CAP
+       lc = login_getpwclass(pw);
+       if (lc == NULL)
+               lc = login_getclassbyname(NULL, pw);
+       from_host = get_canonical_hostname();
+       from_ip = get_remote_ipaddr();
+
+       denied = 0;
+       if ((hosts = login_getcapstr(lc, "host.deny", NULL, NULL)) != NULL) {
+               denied = match_hostname(from_host, hosts, strlen(hosts));
+               if (!denied)
+                       denied = match_hostname(from_ip, hosts, strlen(hosts));
+       }
+       if (!denied &&
+           (hosts = login_getcapstr(lc, "host.allow", NULL, NULL)) != NULL) {
+               denied = !match_hostname(from_host, hosts, strlen(hosts));
+               if (denied)
+                       denied = !match_hostname(from_ip, hosts, strlen(hosts));
+       }
+       login_close(lc);
+       if (denied) {
+               log("Denied connection for %.200s from %.200s [%.200s].",
+                   pw->pw_name, from_host, from_ip);
+               packet_disconnect("Sorry, you are not allowed to connect.");
+       }
+#endif  /* LOGIN_CAP */
+
+       if (pw->pw_uid == 0)
+               log("ROOT LOGIN as '%.100s' from %.100s",
+                   pw->pw_name, get_canonical_hostname());
+
        /* The user has been authenticated and accepted. */
        packet_start(SSH_SMSG_SUCCESS);
        packet_send();
@@ -2086,6 +2125,11 @@
        login_cap_t *lc;
        char *fname;
 #endif /* LOGIN_CAP */
+#ifdef __FreeBSD__
+#define DEFAULT_WARN  (2L * 7L * 86400L)  /* Two weeks */
+       struct timeval tv;
+       time_t warntime = DEFAULT_WARN;
+#endif /* __FreeBSD__ */
 
        /* Get remote host name. */
        hostname = get_canonical_hostname();
@@ -2157,6 +2201,50 @@
                quiet_login = login_getcapbool(lc, "hushlogin", quiet_login);
 #endif /* LOGIN_CAP */
 
+#ifdef __FreeBSD__
+               if (pw->pw_change || pw->pw_expire)
+                       (void)gettimeofday(&tv, NULL);
+#ifdef LOGIN_CAP
+               warntime = login_getcaptime(lc, "warnpassword",
+                                           DEFAULT_WARN, DEFAULT_WARN);
+#endif /* LOGIN_CAP */
+               /*
+                * If the password change time is set and has passed, give the
+                * user a password expiry notice and chance to change it.
+                */
+               if (pw->pw_change != 0) {
+                       if (tv.tv_sec >= pw->pw_change) {
+                               (void)printf(
+                                   "Sorry -- your password has expired.\n");
+                               log("%s Password expired - forcing change",
+                                   pw->pw_name);
+                               command = _PATH_CHPASS;
+                       } else if (pw->pw_change - tv.tv_sec < warntime &&
+                                  !quiet_login)
+                               (void)printf(
+                                   "Warning: your password expires on %s",
+                                    ctime(&pw->pw_change));
+               }
+#ifdef LOGIN_CAP
+               warntime = login_getcaptime(lc, "warnexpire",
+                                           DEFAULT_WARN, DEFAULT_WARN);
+#endif /* LOGIN_CAP */
+               if (pw->pw_expire) {
+                       if (tv.tv_sec >= pw->pw_expire) {
+                               (void)printf(
+                                   "Sorry -- your account has expired.\n");
+                               log(
+                  "LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s",
+                                       pw->pw_name, hostname, ttyname);
+                               exit(254);
+                       } else if (pw->pw_expire - tv.tv_sec < warntime &&
+                                  !quiet_login)
+                               (void)printf(
+                                   "Warning: your account expires on %s",
+                                    ctime(&pw->pw_expire));
+               }
+#endif /* __FreeBSD__ */
+
                /*
                 * If the user has logged in before, display the time of last
                 * login. However, don't display anything extra if a command
@@ -2203,10 +2291,9 @@
                    !options.use_login) {
 #ifdef LOGIN_CAP
                        fname = login_getcapstr(lc, "welcome", NULL, NULL);
-                       login_close(lc);
                        if (fname == NULL || (f = fopen(fname, "r")) == NULL)
                                f = fopen("/etc/motd", "r");
-#else /* LOGIN_CAP */
+#else /* !LOGIN_CAP */
                        f = fopen("/etc/motd", "r");
 #endif /* LOGIN_CAP */
                        /* Print /etc/motd if it exists. */
@@ -2216,6 +2303,9 @@
                                fclose(f);
                        }
                }
+#ifdef LOGIN_CAP
+               login_close(lc);
+#endif /* LOGIN_CAP */
 
                /* Do common processing for the child, such as execing the command. */
                do_child(command, pw, term, display, auth_proto, auth_data, ttyname);
@@ -2363,7 +2453,7 @@
        char buf[256];
        FILE *f;
        unsigned int envsize, i;
-       char **env;
+       char **env = NULL;
        extern char **environ;
        struct stat st;
        char *argv[10];
@@ -2373,29 +2463,24 @@
        lc = login_getpwclass(pw);
        if (lc == NULL)
                lc = login_getclassbyname(NULL, pw);
-#endif /* LOGIN_CAP */
-
+       if (pw->pw_uid != 0)
+               auth_checknologin(lc);
+#else /* !LOGIN_CAP */
        f = fopen("/etc/nologin", "r");
-#ifdef __FreeBSD__
-       if (f == NULL)
-               f = fopen("/var/run/nologin", "r");
-#endif /* __FreeBSD__ */
        if (f) {
                /* /etc/nologin exists.  Print its contents and exit. */
-#ifdef LOGIN_CAP
-               /* On FreeBSD, etc., allow overriding nologin via login.conf. */
-               if (!login_getcapbool(lc, "ignorenologin", 0)) {
-#else /* LOGIN_CAP */
-               if (1) {
-#endif /* LOGIN_CAP */
-                       while (fgets(buf, sizeof(buf), f))
-                               fputs(buf, stderr);
-                       fclose(f);
-                       if (pw->pw_uid != 0)
-                               exit(254);
-               }
+               while (fgets(buf, sizeof(buf), f))
+                       fputs(buf, stderr);
+               fclose(f);
+               if (pw->pw_uid != 0)
+                       exit(254);
 
        }
+#endif /* LOGIN_CAP */
+
+#ifdef LOGIN_CAP
+       if (options.use_login)
+#endif /* LOGIN_CAP */
        /* Set login name in the kernel. */
        if (setlogin(pw->pw_name) < 0)
                error("setlogin failed: %s", strerror(errno));
@@ -2405,12 +2490,42 @@
           switch, so we let login(1) to this for us. */
        if (!options.use_login) {
 #ifdef LOGIN_CAP
-               if (setclasscontext(pw->pw_class, LOGIN_SETPRIORITY |
-                   LOGIN_SETRESOURCES | LOGIN_SETUMASK) == -1) {
-                       perror("setclasscontext");
-                       exit(1);
-               }
-#endif /* LOGIN_CAP */
+               char **tmpenv;
+
+               /* Initialize temp environment */
+               envsize = 64;
+               env = xmalloc(envsize * sizeof(char *));
+               env[0] = NULL;
+
+               child_set_env(&env, &envsize, "PATH",
+                             (pw->pw_uid == 0) ?
+                             _PATH_STDPATH : _PATH_DEFPATH);
+
+               snprintf(buf, sizeof buf, "%.200s/%.50s",
+                        _PATH_MAILDIR, pw->pw_name);
+               child_set_env(&env, &envsize, "MAIL", buf);
+
+               if (getenv("TZ"))
+                       child_set_env(&env, &envsize, "TZ", getenv("TZ"));
+
+               /* Save parent environment */
+               tmpenv = environ;
+               environ = env;
+
+               if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETALL) < 0)
+                       fatal("setusercontext failed: %s", strerror(errno));
+
+               /* Restore parent environment */
+               env = environ;
+               environ = tmpenv;
+
+               for (envsize = 0; env[envsize] != NULL; ++envsize)
+                       ;
+               envsize = (envsize < 100) ? 100 : envsize + 16;
+               env = xrealloc(env, envsize * sizeof(char *));
+
+#else /* !LOGIN_CAP */
+
                if (getuid() == 0 || geteuid() == 0) {
                        if (setgid(pw->pw_gid) < 0) {
                                perror("setgid");
@@ -2428,18 +2543,15 @@
                }
                if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
                        fatal("Failed to set uids to %d.", (int) pw->pw_uid);
+#endif /* LOGIN_CAP */
        }
        /*
         * Get the shell from the password data.  An empty shell field is
         * legal, and means /bin/sh.
         */
+       shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
 #ifdef LOGIN_CAP
-       shell = pw->pw_shell;
        shell = login_getcapstr(lc, "shell", shell, shell);
-       if (shell[0] == '\0')
-               shell = _PATH_BSHELL;
-#else /* LOGIN_CAP */
-       shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
 #endif /* LOGIN_CAP */
 
 #ifdef AFS
@@ -2455,29 +2567,31 @@
 #endif /* AFS */
 
        /* Initialize the environment. */
-       envsize = 100;
-       env = xmalloc(envsize * sizeof(char *));
-       env[0] = NULL;
+       if (env == NULL) {
+               envsize = 100;
+               env = xmalloc(envsize * sizeof(char *));
+               env[0] = NULL;
+       }
 
        if (!options.use_login) {
                /* Set basic environment. */
                child_set_env(&env, &envsize, "USER", pw->pw_name);
                child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
                child_set_env(&env, &envsize, "HOME", pw->pw_dir);
-#ifdef LOGIN_CAP
-               child_set_env(&env, &envsize, "PATH",
-                   login_getpath(lc, "path", _PATH_STDPATH));
-#else /* LOGIN_CAP */
+#ifndef LOGIN_CAP
                child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
-#endif /* LOGIN_CAP */
 
                snprintf(buf, sizeof buf, "%.200s/%.50s",
                         _PATH_MAILDIR, pw->pw_name);
                child_set_env(&env, &envsize, "MAIL", buf);
+#endif /* !LOGIN_CAP */
 
                /* Normal systems set SHELL by default. */
                child_set_env(&env, &envsize, "SHELL", shell);
        }
+#ifdef LOGIN_CAP
+       if (options.use_login)
+#endif /* LOGIN_CAP */
        if (getenv("TZ"))
                child_set_env(&env, &envsize, "TZ", getenv("TZ"));
 
@@ -2559,10 +2673,6 @@
         */
        endpwent();
 
-#ifdef LOGIN_CAP
-       login_close(lc);
-#endif /* LOGIN_CAP */
-
        /*
         * Close any extra open file descriptors so that we don\'t have them
         * hanging around in clients.  Note that we want to do this after
@@ -2573,9 +2683,46 @@
                close(i);
 
        /* Change current directory to the user\'s home directory. */
-       if (chdir(pw->pw_dir) < 0)
+       if (
+#ifdef __FreeBSD__
+               !*pw->pw_dir ||
+#endif /* __FreeBSD__ */
+               chdir(pw->pw_dir) < 0
+          ) {
+#ifdef __FreeBSD__
+               int quiet_login = 0;
+#endif /* __FreeBSD__ */
+#ifdef LOGIN_CAP
+               if (login_getcapbool(lc, "requirehome", 0)) {
+                       (void)printf("Home directory not available\n");
+                       log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s",
+                               pw->pw_name, ttyname);
+                       exit(254);
+               }
+#endif /* LOGIN_CAP */
+#ifdef __FreeBSD__
+               if (chdir("/") < 0) {
+                       (void)printf("Cannot find root directory\n");
+                       log("LOGIN %.200s REFUSED (ROOTDIR) ON TTY %.200s",
+                               pw->pw_name, ttyname);
+                       exit(254);
+               }
+#ifdef LOGIN_CAP
+               quiet_login = login_getcapbool(lc, "hushlogin", 0);
+#endif /* LOGIN_CAP */
+               if (!quiet_login || *pw->pw_dir)
+                       (void)printf(
+                      "No home directory.\nLogging in with home = \"/\".\n");
+
+#else /* !__FreeBSD__ */
+
                fprintf(stderr, "Could not chdir to home directory %s: %s\n",
                        pw->pw_dir, strerror(errno));
+#endif /* __FreeBSD__ */
+       }
+#ifdef LOGIN_CAP
+       login_close(lc);
+#endif /* LOGIN_CAP */
 
        /*
         * Must take new environment into use so that .ssh/rc, /etc/sshrc and
@@ -2588,26 +2735,6 @@
         * in this order).
         */
        if (!options.use_login) {
-#ifdef __FreeBSD__
-               /*
-                * If the password change time is set and has passed, give the
-                * user a password expiry notice and chance to change it.
-                */
-               if (pw->pw_change != 0) {
-                       struct timeval tv;
-
-                       (void)gettimeofday(&tv, NULL);
-                       if (tv.tv_sec >= pw->pw_change) {
-                               (void)printf(
-                                   "Sorry -- your password has expired.\n");
-                               syslog(LOG_INFO,
-                                   "%s Password expired - forcing change",
-                                   pw->pw_name);
-                               if (system("/usr/bin/passwd") != 0)
-                                       perror("/usr/bin/passwd");
-                       }
-               }
-#endif /* __FreeBSD__ */
                if (stat(SSH_USER_RC, &st) >= 0) {
                        if (debug_flag)
                                fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
@@ -2675,7 +2802,11 @@
                                mailbox = getenv("MAIL");
                                if (mailbox != NULL) {
                                        if (stat(mailbox, &mailstat) != 0 || 
mailstat.st_size == 0)
+#ifdef __FreeBSD__
+                                               ;
+#else /* !__FreeBSD__ */
                                                printf("No mail.\n");
+#endif /* __FreeBSD__ */
                                        else if (mailstat.st_mtime < mailstat.st_atime)
                                                printf("You have mail.\n");
                                        else

-- 
Andrey A. Chernov
<[EMAIL PROTECTED]>
http://nagual.pp.ru/~ache/


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to