[BACK]Return to login.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / login

Diff for /src/usr.bin/login/login.c between version 1.35 and 1.36

version 1.35, 2000/10/14 20:33:13 version 1.36, 2001/05/29 21:39:26
Line 33 
Line 33 
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   /*-
    * Copyright (c) 1995 Berkeley Software Design, Inc. All rights reserved.
    *
    * 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 Berkeley Software Design,
    *      Inc.
    * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
    *    or promote products derived from this software without specific prior
    *    written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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.
    *
    *      BSDI $From: login.c,v 2.28 1999/09/08 22:35:36 prb Exp $
    */
   
 #ifndef lint  #ifndef lint
 static char copyright[] =  static char copyright[] =
Line 54 
Line 87 
  */   */
   
 #include <sys/param.h>  #include <sys/param.h>
   #include <sys/socket.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/time.h>  #include <sys/time.h>
 #include <sys/resource.h>  #include <sys/resource.h>
Line 64 
Line 98 
 #include <fcntl.h>  #include <fcntl.h>
 #include <grp.h>  #include <grp.h>
 #include <login_cap.h>  #include <login_cap.h>
   #include <netdb.h>
 #include <pwd.h>  #include <pwd.h>
 #include <setjmp.h>  #include <setjmp.h>
 #include <signal.h>  #include <signal.h>
   #include <stdarg.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
Line 76 
Line 112 
 #include <unistd.h>  #include <unistd.h>
 #include <utmp.h>  #include <utmp.h>
 #include <util.h>  #include <util.h>
 #include <skey.h>  #include <bsd_auth.h>
   
   #ifdef KERBEROS
   #include <kerberosIV/kafs.h>
   #endif
   
 #include "pathnames.h"  #include "pathnames.h"
   
 void     badlogin __P((char *));  void     badlogin __P((char *));
 void     checknologin __P((void));  
 void     dolastlog __P((int));  void     dolastlog __P((int));
 void     getloginname __P((void));  void     getloginname __P((void));
 void     motd __P((void));  void     motd __P((void));
   void     quickexit __P((int));
 int      rootterm __P((char *));  int      rootterm __P((char *));
 void     sigint __P((int));  void     sigint __P((int));
 void     sighup __P((int));  void     sighup __P((int));
 void     sleepexit __P((int));  void     sleepexit __P((int));
 char    *stypeof __P((char *));  char    *stypeof __P((char *));
 void     timedout __P((int));  void     timedout __P((int));
 int      pwcheck __P((char *, char *, char *, char *));  
 #if defined(KERBEROS) || defined(KERBEROS5)  
 int      klogin __P((struct passwd *, char *, char *, char *));  
 void     kdestroy __P((void));  
 void     dofork __P((void));  
 void     kgettokens __P((char *));  
 #endif  
   
 extern int check_failedlogin __P((uid_t));  extern int check_failedlogin __P((uid_t));
 extern void log_failedlogin __P((uid_t, char *, char *, char *));  extern void log_failedlogin __P((uid_t, char *, char *, char *));
Line 111 
Line 144 
  */   */
 u_int           timeout = 300;  u_int           timeout = 300;
   
 #if defined(KERBEROS) || defined(KERBEROS5)  struct passwd   *pwd;
 int             notickets = 1;  
 char            *instance;  
 char            *krbtkfile_env;  
 int             authok;  
 #endif  
   
 struct  passwd  *pwd;  
 login_cap_t     *lc = NULL;  login_cap_t     *lc = NULL;
   auth_session_t  *as = NULL;
 int             failures;  int             failures;
   int             needbanner = 1;
 char            term[64], *hostname, *tty;  char            term[64], *hostname, *tty;
   char            *style;
 char            *username = NULL, *rusername = NULL;  char            *username = NULL, *rusername = NULL;
   
 int  int
Line 130 
Line 159 
         char *argv[];          char *argv[];
 {  {
         extern char **environ;          extern char **environ;
           struct addrinfo *ai, hints;
         struct group *gr;          struct group *gr;
           struct rlimit cds, scds;
         struct stat st;          struct stat st;
         struct timeval tp;  
         struct utmp utmp;          struct utmp utmp;
         int ask, ch, cnt, fflag, hflag, pflag, uflag, quietlog, rootlogin, rval;          quad_t expire, warning;
         uid_t uid;          uid_t uid;
         char *domain, *p, *salt, *ttyn, *shell;          int ask, ch, cnt, fflag, pflag, quietlog, rootlogin, lastchance;
           int error, homeless, needto, authok;
           char *domain, *p, *ttyn, *shell, *fullname, *instance;
           char *lipaddr, *script, *ripaddr, *style, *type, *fqdn, *copyright;
         char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];          char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
         char localhost[MAXHOSTNAMELEN];          char localhost[MAXHOSTNAMELEN];
   
         (void)signal(SIGALRM, timedout);          (void)signal(SIGALRM, timedout);
         (void)alarm(timeout);          if (argc > 1) {
                   needto = 0;
                   (void)alarm(timeout);
           } else
                   needto = 1;
         (void)signal(SIGQUIT, SIG_IGN);          (void)signal(SIGQUIT, SIG_IGN);
         (void)signal(SIGINT, SIG_IGN);          (void)signal(SIGINT, SIG_IGN);
         (void)signal(SIGHUP, sighup);          (void)signal(SIGHUP, SIG_IGN);
         (void)setpriority(PRIO_PROCESS, 0, 0);          (void)setpriority(PRIO_PROCESS, 0, 0);
   
         openlog("login", LOG_ODELAY, LOG_AUTH);          openlog("login", LOG_ODELAY, LOG_AUTH);
   
           fqdn = lipaddr = ripaddr = fullname = NULL;
   
         /*          /*
            * Since login deals with sensitive information, turn off coredumps.
            */
           if (getrlimit(RLIMIT_CORE, &scds) < 0) {
                   syslog(LOG_ERR, "couldn't get core dump size: %m");
                   scds.rlim_cur = scds.rlim_max = QUAD_MIN;
           }
           cds.rlim_cur = cds.rlim_max = 0;
           if (setrlimit(RLIMIT_CORE, &cds) < 0) {
                   syslog(LOG_ERR, "couldn't set core dump size to 0: %m");
                   scds.rlim_cur = scds.rlim_max = QUAD_MIN;
           }
   
           /*
          * -p is used by getty to tell login not to destroy the environment           * -p is used by getty to tell login not to destroy the environment
          * -f is used to skip a second login authentication           * -f is used to skip a second login authentication
          * -h is used by other servers to pass the name of the remote           * -h is used by other servers to pass the name of the remote
Line 166 
Line 218 
                         domain = localhost;                          domain = localhost;
         }          }
   
         fflag = hflag = pflag = 0;          if ((as = auth_open()) == NULL) {
                   syslog(LOG_ERR, "%m");
                   err(1, NULL);
           }
   
           fflag = pflag = 0;
         uid = getuid();          uid = getuid();
         while ((ch = getopt(argc, argv, "fh:u:p")) != -1)          while ((ch = getopt(argc, argv, "fh:pu:L:R:")) != -1)
                 switch (ch) {                  switch (ch) {
                 case 'f':                  case 'f':
                         fflag = 1;                          fflag = 1;
                         break;                          break;
                 case 'h':                  case 'h':
                         if (uid)                          if (uid) {
                                 errx(1, "-h option: %s", strerror(EPERM));                                  warn("-h option: %s", strerror(EPERM));
                         hflag = 1;                                  quickexit(1);
                           }
                           if ((fqdn = strdup(optarg)) == NULL) {
                                   warn(NULL);
                                   quickexit(1);
                           }
                           auth_setoption(as, "fqdn", fqdn);
                         if (domain && (p = strchr(optarg, '.')) &&                          if (domain && (p = strchr(optarg, '.')) &&
                             strcasecmp(p+1, domain) == 0)                              strcasecmp(p+1, domain) == 0)
                                 *p = 0;                                  *p = 0;
                         hostname = optarg;                          hostname = optarg;
                           auth_setoption(as, "hostname", hostname);
                         break;                          break;
                   case 'L':
                           if (uid) {
                                   warnx("-L option: %s", strerror(EPERM));
                                   quickexit(1);
                           }
                           if (lipaddr) {
                                   warnx("duplicate -L option");
                                   quickexit(1);
                           }
                           lipaddr = optarg;
                           memset(&hints, 0, sizeof(hints));
                           hints.ai_family = PF_UNSPEC;
                           hints.ai_flags = AI_CANONNAME;
                           error = getaddrinfo(lipaddr, NULL, &hints, &ai);
                           if (!error) {
                                   strlcpy(localhost, ai->ai_canonname,
                                       sizeof(localhost));
                                   freeaddrinfo(ai);
                           } else
                                   strlcpy(localhost, lipaddr, sizeof(localhost));
                           auth_setoption(as, "local_addr", lipaddr);
                           break;
                 case 'p':                  case 'p':
                         pflag = 1;                          pflag = 1;
                         break;                          break;
                   case 'R':
                           if (uid) {
                                   warnx("-R option: %s", strerror(EPERM));
                                   quickexit(1);
                           }
                           if (ripaddr) {
                                   warnx("duplicate -R option");
                                   quickexit(1);
                           }
                           ripaddr = optarg;
                           auth_setoption(as, "remote_addr", ripaddr);
                           break;
                 case 'u':                  case 'u':
                         if (uid)                          if (uid) {
                                 errx(1, "-u option: %s", strerror(EPERM));                                  warnx("-u option: %s", strerror(EPERM));
                         uflag = 1;                                  quickexit(1);
                           }
                         rusername = optarg;                          rusername = optarg;
                         break;                          break;
                 case '?':  
                 default:                  default:
                         if (!uid)                          if (!uid)
                                 syslog(LOG_ERR, "invalid flag %c", ch);                                  syslog(LOG_ERR, "invalid flag %c", ch);
                         (void)fprintf(stderr,                          (void)fprintf(stderr,
                             "usage: login [-fp] [-h hostname] [username]\n");                              "usage: login [-fp] [-h hostname] [-L lipaddr] [-R ripaddr] [username]\n");
                         exit(1);                          quickexit(1);
                 }                  }
         argc -= optind;          argc -= optind;
         argv += optind;          argv += optind;
Line 221 
Line 319 
         else          else
                 tty = ttyn;                  tty = ttyn;
   
         for (cnt = 0;; ask = 1) {  #ifdef notyet
 #if defined(KERBEROS) || defined(KERBEROS5)          /* XXX - we don't (yet) support per-tty auth stuff */
                 kdestroy();          /* BSDi uses a ttys.conf file but we could just overload /etc/ttys */
                 authok = 0;          /*
            * Classify the attempt.
            * By default we use the value in the ttys file.
            * If there is a classify script we run that as
            *
            *      classify [-f] [username]
            */
           if (type = getttyauth(tty))
                   auth_setoption(as, "auth_type", type);
 #endif  #endif
   
           /* get the default login class */
           if ((lc = login_getclass(0)) == NULL) { /* get the default class */
                   warnx("Failure to retrieve default class");
                   quickexit(1);
           }
           if ((script = login_getcapstr(lc, "classify", NULL, NULL)) != NULL) {
                   unsetenv("AUTH_TYPE");
                   unsetenv("REMOTE_NAME");
                   if (script[0] != '/') {
                           syslog(LOG_ERR, "Invalid classify script: %s", script);
                           warnx("Classification failure");
                           quickexit(1);
                   }
                   shell = strrchr(script, '/') + 1;
                   auth_setstate(as, AUTH_OKAY);
                   auth_call(as, script, shell,
                       fflag ? "-f" : username, fflag ? username : 0, 0);
                   if (!(auth_getstate(as) & AUTH_ALLOW))
                           quickexit(1);
                   auth_setenv(as);
                   if ((p = getenv("AUTH_TYPE")) != NULL &&
                       strncmp(p, "auth-", 5) == 0)
                           type = p;
                   if ((p = getenv("REMOTE_NAME")) != NULL)
                           hostname = p;
                   /*
                    * we may have changed some values, reset them
                    */
                   auth_clroptions(as);
                   if (type)
                           auth_setoption(as, "auth_type", type);
                   if (fqdn)
                           auth_setoption(as, "fqdn", fqdn);
                   if (hostname)
                           auth_setoption(as, "hostname", hostname);
                   if (lipaddr)
                           auth_setoption(as, "local_addr", lipaddr);
                   if (ripaddr)
                           auth_setoption(as, "remote_addr", ripaddr);
           }
   
           /*
            * Request the things like the approval script print things
            * to stdout (in particular, the nologins files)
            */
           auth_setitem(as, AUTHV_INTERACTIVE, "True");
   
           for (cnt = 0;; ask = 1) {
                   /*
                    * Clean up our current authentication session.
                    * Options are not cleared so we need to clear any
                    * we might set below.
                    */
                   auth_clean(as);
                   auth_clroption(as, "style");
                   auth_clroption(as, "lastchance");
   
                   lastchance = 0;
   
                 if (ask) {                  if (ask) {
                         fflag = 0;                          fflag = 0;
                         getloginname();                          getloginname();
                 }                  }
                   if (needto) {
                           needto = 0;
                           alarm(timeout);
                   }
                   if ((style = strchr(username, ':')) != NULL)
                           *style++ = '\0';
                   if (fullname)
                           free(fullname);
                   if (auth_setitem(as, AUTHV_NAME, username) < 0 ||
                       (fullname = strdup(username)) == NULL) {
                           syslog(LOG_ERR, "%m");
                           warn(NULL);
                           quickexit(1);
                   }
                 rootlogin = 0;                  rootlogin = 0;
                   /* XXX - kerb5 uses a '/' not a '.' ??? */
 #if defined(KERBEROS) || defined(KERBEROS5)  
                 /*  
                  * Why should anyone with a root instance be able  
                  * to be root here?  
                  */  
                 instance = "";  
 #endif  
 #ifdef  KERBEROS  
                 if ((instance = strchr(username, '.')) != NULL) {                  if ((instance = strchr(username, '.')) != NULL) {
                         if (strncmp(instance, ".root", 5) == 0)                          if (strncmp(instance, ".root", 5) == 0)
                                 rootlogin = 1;                                  rootlogin = 1;
                         *instance++ = '\0';                          *instance++ = '\0';
                 } else                  } else
                         instance = "";                          instance = "";
 #endif  
 #ifdef KERBEROS5  
                 if ((instance = strchr(username, '/')) != NULL) {  
                         if (strncmp(instance, "/root", 5) == 0)  
                                 rootlogin = 1;  
                         *instance++ = '\0';  
                 } else  
                         instance = "";  
 #endif  
                 if (strlen(username) > UT_NAMESIZE)                  if (strlen(username) > UT_NAMESIZE)
                         username[UT_NAMESIZE] = '\0';                          username[UT_NAMESIZE] = '\0';
   
Line 268 
Line 432 
                                 badlogin(tbuf);                                  badlogin(tbuf);
                         failures = 0;                          failures = 0;
                 }                  }
                 (void)strlcpy(tbuf, username, sizeof tbuf);                  (void)strlcpy(tbuf, username, sizeof(tbuf));
   
                 if ((pwd = getpwnam(username)))                  if ((pwd = getpwnam(username)) != NULL &&
                         salt = pwd->pw_passwd;                      auth_setpwd(as, pwd) < 0) {
                 else                          syslog(LOG_ERR, "%m");
                         salt = "xx";                          warn(NULL);
                 lc = login_getclass(pwd ? pwd->pw_class : LOGIN_DEFCLASS);                          quickexit(1);
                 if (!lc)                  }
                     err(1, "unable to get login class");  
   
                 /*                  lc = login_getclass(pwd ? pwd->pw_class : NULL);
                  * If we have a valid account name, and it doesn't have a  
                  * password, or the -f option was specified and the caller  
                  * is root or the caller isn't changing their uid, don't  
                  * authenticate.  
                  */  
                 if (pwd) {  
                         if (pwd->pw_uid == 0)  
                                 rootlogin = 1;  
   
                         if (fflag && (uid == 0 || uid == pwd->pw_uid)) {                  if (!lc)
                                 /* already authenticated */                          goto failed;
                                 break;  
                         } else if (pwd->pw_passwd[0] == '\0') {  
                                 /* pretend password okay */  
                                 rval = 0;  
 #if defined(KERBEROS) || defined(KERBEROS5)  
                                 authok = 1;  
 #endif  
                                 goto ttycheck;  
                         }  
                 }  
   
                 fflag = 0;                  style = login_getstyle(lc, style, type);
   
                 (void)setpriority(PRIO_PROCESS, 0, -4);                  if (!style)
                           goto failed;
   
                 p = getpass("Password:");                  /*
                    * Turn off the fflag if we have an an invalid user
                    * or we are not root and we are trying to change uids.
                    */
                   if (!pwd || (uid && uid != pwd->pw_uid))
                           fflag = 0;
   
                 if (pwd) {                  if (pwd && pwd->pw_uid == 0)
 #if defined(KERBEROS) || defined(KERBEROS5)                          rootlogin = 1;
                         rval = klogin(pwd, instance, localhost, p);  
                         if (rval != 0 && rootlogin && pwd->pw_uid != 0)  
                                 rootlogin = 0;  
                         if (rval == 1) {  
                                 /* Fall back on password file. */  
                                 if (pwd->pw_uid != 0)  
                                         rootlogin = 0;  
                                 rval = pwcheck(username, p, salt, pwd->pw_passwd);  
                         }  
                         if (rval == 0)  
                                 authok = 1;  
 #else  
                         rval = pwcheck(username, p, salt, pwd->pw_passwd);  
 #endif  
                 } else {  
 #ifdef SKEY  
                         if (strcasecmp(p, "s/key") == 0)  
                                 (void)skey_authenticate(username);  
                         else  
 #endif  
                         {  
                                 useconds_t us;  
   
                                 /*                  /*
                                  * Sleep between 1 and 3 seconds                   * If we do not have the force flag authenticate the user
                                  * to emulate a crypt.                   */
                                  */                  if (fflag)
                                 us = arc4random() % 3000000;                          authok = AUTH_SECURE;
                                 usleep(us);                  else {
                           lastchance =
                               login_getcaptime(lc, "password-dead", 0, 0) != 0;
                           if (lastchance)
                                   auth_setoption(as, "lastchance", "yes");
                           /*
                            * Once we start asking for a password
                            *  we want to log a failure on a hup.
                            */
                           signal(SIGHUP, sighup);
                           auth_verify(as, style, NULL, lc->lc_class, NULL);
                           authok = auth_getstate(as);
                           /*
                            * If their password expired and it has not been
                            * too long since then, give the user one last
                            * chance to change their password
                            */
                           if ((authok & AUTH_PWEXPIRED) && lastchance) {
                                   authok = AUTH_OKAY;
                           } else
                                   lastchance = 0;
                           if ((authok & AUTH_ALLOW) == 0)
                                   goto failed;
                           if (auth_setoption(as, "style", style) < 0) {
                                   syslog(LOG_ERR, "%m");
                                   warn(NULL);
                                   quickexit(1);
                         }                          }
                         rval = 1;  
                 }                  }
                 memset(p, 0, strlen(p));  
   
                 (void)setpriority(PRIO_PROCESS, 0, 0);  
   
         ttycheck:  
                 /*                  /*
                  * If trying to log in as root without Kerberos,                   * explicitly reject users without password file entries
                  * but with insecure terminal, refuse the login attempt.  
                  */                   */
 #if defined(KERBEROS) || defined(KERBEROS5)                  if (pwd == 0)
                 if (authok == 1)                          goto failed;
 #endif  
                 /* if logging in as root, user must be on a secure tty */  
                 if (pwd && rval == 0 && (!rootlogin || rootterm(tty)))  
                         break;  
   
                   authok &= AUTH_SECURE;
   
                 /*                  /*
                  * We don't want to give out info to an attacker trying                   * If trying to log in as root on an insecure terminal,
                  * to guess root's password so we always say "login refused"                   * refuse the login attempt unless the authentication
                  * in that case, not "Login incorrect".                   * style explicitly says a root login is okay.
                  */                   */
                   if (authok == 0 && pwd && rootlogin && !rootterm(tty))
                           goto failed;
   
                   if (fflag) {
                           type = 0;
                           style = "forced";
                   }
                   break;
   
   failed:
                   if (authok & AUTH_SILENT)
                           quickexit(0);
                 if (rootlogin && !rootterm(tty)) {                  if (rootlogin && !rootterm(tty)) {
                         (void)fprintf(stderr,                          warnx("%s login refused on this terminal.",
                             "%s login refused on this terminal.\n",                              fullname);
                             pwd ? pwd->pw_name : "root");  
                         if (hostname)                          if (hostname)
                                 syslog(LOG_NOTICE,                                  syslog(LOG_NOTICE,
                                     "LOGIN %s REFUSED FROM %s%s%s ON TTY %s",                                      "LOGIN %s REFUSED FROM %s%s%s ON TTY %s",
                                     pwd ? pwd->pw_name : "root",                                      fullname, rusername ? rusername : "",
                                     rusername ? rusername : "",  
                                     rusername ? "@" : "", hostname, tty);                                      rusername ? "@" : "", hostname, tty);
                         else                          else
                                 syslog(LOG_NOTICE,                                  syslog(LOG_NOTICE,
                                     "LOGIN %s REFUSED ON TTY %s",                                      "LOGIN %s REFUSED ON TTY %s",
                                      pwd ? pwd->pw_name : "root", tty);                                       fullname, tty);
                 } else                  } else {
                         (void)printf("Login incorrect\n");                          if (!as || (p = auth_getvalue(as, "errormsg")) == NULL)
                                   p = "Login incorrect";
                           (void)printf("%s\n", p);
                   }
                 failures++;                  failures++;
                 if (pwd)                  if (pwd)
                         log_failedlogin(pwd->pw_uid, hostname, rusername, tty);                          log_failedlogin(pwd->pw_uid, hostname, rusername, tty);
                 /* we allow 10 tries, but after 3 we start backing off */                  /* we allow 10 tries, but after 3 we start backing off */
                   /* XXX - should be configurable */
                 if (++cnt > 3) {                  if (++cnt > 3) {
                         if (cnt >= 10) {                          if (cnt >= 10) {
                                 badlogin(username);                                  badlogin(username);
Line 392 
Line 552 
         }          }
   
         /* committed to login -- turn off timeout */          /* committed to login -- turn off timeout */
         (void)alarm((u_int)0);          (void)alarm(0);
   
         endpwent();          endpwent();
   
         /* if user not super-user, check for disabled logins */  
         if (!rootlogin)  
                 checknologin();  
   
         setegid(pwd->pw_gid);  
         seteuid(pwd->pw_uid);  
   
         if (chdir(pwd->pw_dir) < 0) {  
                 (void)printf("No home directory %s!\n", pwd->pw_dir);  
                 if (login_getcapbool(lc, "requirehome", 0))  
                         exit(1);  
                 if (chdir("/"))  
                         exit(0);  
                 pwd->pw_dir = "/";  
                 (void)printf("Logging in with home = \"/\".\n");  
         }  
   
         shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);          shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
         if (*shell == '\0')          if (*shell == '\0')
                 shell = _PATH_BSHELL;                  shell = _PATH_BSHELL;
         else if (strlen(shell) >= MAXPATHLEN) {          else if (strlen(shell) >= MAXPATHLEN) {
                 syslog(LOG_ERR, "shell path too long: %s", shell);                  syslog(LOG_ERR, "shell path too long: %s", shell);
                 warnx("invalid shell");                  warnx("invalid shell");
                 sleepexit(1);                  quickexit(1);
         }          }
   
         quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) ||  
             login_getcapbool(lc, "hushlogin", 0) ||  
             (access(_PATH_HUSHLOGIN, F_OK) == 0));  
   
         seteuid(0);  
         setegid(0);     /* XXX use a saved gid instead? */  
   
         if (pwd->pw_change || pwd->pw_expire)  
                 (void)gettimeofday(&tp, (struct timezone *)NULL);  
         if (pwd->pw_expire) {  
                 if (tp.tv_sec >= pwd->pw_expire) {  
                         (void)printf("Sorry -- your account has expired.\n");  
                         sleepexit(1);  
                 } else if (!quietlog &&pwd->pw_expire - tp.tv_sec <  
                     login_getcaptime(lc, "expire-warn",  
                     2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY))  
                         (void)printf("Warning: your account expires on %s",  
                             ctime(&pwd->pw_expire));  
         }  
         if (pwd->pw_change) {  
                 if (tp.tv_sec >= pwd->pw_change) {  
                         (void)printf("Sorry -- your password has expired.\n");  
                         sleepexit(1);  
                 } else if (!quietlog && pwd->pw_change - tp.tv_sec <  
                     login_getcaptime(lc, "password-warn",  
                     2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY))  
                         (void)printf("Warning: your password expires on %s",  
                             ctime(&pwd->pw_change));  
         }  
   
         /* Nothing else left to fail -- really log in. */  
         (void)signal(SIGHUP, SIG_DFL);  
         memset((void *)&utmp, 0, sizeof(utmp));  
         (void)time(&utmp.ut_time);  
         (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));  
         if (hostname)  
                 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));  
         (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));  
         login(&utmp);  
   
         if (!quietlog)  
                 (void)check_failedlogin(pwd->pw_uid);  
         dolastlog(quietlog);  
   
         login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);  
   
         (void)chown(ttyn, pwd->pw_uid,  
             (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);  
 #if defined(KERBEROS) || defined(KERBEROS5)  
         /* Fork so that we can call kdestroy */  
         if (krbtkfile_env)  
             dofork();  
 #endif  
   
         /* Destroy environment unless user has requested its preservation. */          /* Destroy environment unless user has requested its preservation. */
         if (!pflag) {          if (!pflag) {
                 if ((environ = calloc(1, sizeof (char *))) == NULL)                  if ((environ = calloc(1, sizeof (char *))) == NULL)
Line 496 
Line 585 
         if (setenv("HOME", pwd->pw_dir, 1) == -1 ||          if (setenv("HOME", pwd->pw_dir, 1) == -1 ||
             setenv("SHELL", shell, 1) == -1) {              setenv("SHELL", shell, 1) == -1) {
                 warn("unable to setenv()");                  warn("unable to setenv()");
                 exit(1);                  quickexit(1);
         }          }
         if (term[0] == '\0')          if (term[0] == '\0')
                 (void)strlcpy(term, stypeof(tty), sizeof(term));                  (void)strlcpy(term, stypeof(tty), sizeof(term));
Line 504 
Line 593 
             setenv("LOGNAME", pwd->pw_name, 1) == -1 ||              setenv("LOGNAME", pwd->pw_name, 1) == -1 ||
             setenv("USER", pwd->pw_name, 1) == -1) {              setenv("USER", pwd->pw_name, 1) == -1) {
                 warn("unable to setenv()");                  warn("unable to setenv()");
                 exit(1);                  quickexit(1);
         }          }
         if (hostname) {          if (hostname) {
                 if (setenv("REMOTEHOST", hostname, 1) == -1) {                  if (setenv("REMOTEHOST", hostname, 1) == -1) {
                         warn("unable to setenv()");                          warn("unable to setenv()");
                         exit(1);                          quickexit(1);
                 }                  }
         }          }
         if (rusername) {          if (rusername) {
                 if (setenv("REMOTEUSER", rusername, 1) == -1) {                  if (setenv("REMOTEUSER", rusername, 1) == -1) {
                         warn("unable to setenv()");                          warn("unable to setenv()");
                         exit(1);                          quickexit(1);
                 }                  }
         }          }
 #ifdef KERBEROS  
         if (krbtkfile_env) {          if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH)) {
                 if (setenv("KRBTKFILE", krbtkfile_env, 1) == -1) {                  warn("unable to set user context");
                         warn("unable to setenv()");                  quickexit(1);
                         exit(1);  
                 }  
         }          }
 #endif          auth_setenv(as);
 #ifdef KERBEROS5  
         if (krbtkfile_env) {          /* if user not super-user, check for disabled logins */
                 if (setenv("KRB5CCNAME", krbtkfile_env, 1) == -1) {          if (!rootlogin)
                         warn("unable to setenv()");                  auth_checknologin(lc);
                         exit(1);  
           setegid(pwd->pw_gid);
           seteuid(pwd->pw_uid);
   
           homeless = chdir(pwd->pw_dir);
           if (homeless) {
                   if (login_getcapbool(lc, "requirehome", 0)) {
                           (void)printf("No home directory %s!\n", pwd->pw_dir);
                           quickexit(1);
                 }                  }
                   if (chdir("/"))
                           quickexit(0);
         }          }
 #endif  
           quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) ||
               login_getcapbool(lc, "hushlogin", 0) ||
               (access(_PATH_HUSHLOGIN, F_OK) == 0));
   
           seteuid(0);
           setegid(0);     /* XXX use a saved gid instead? */
   
           if ((p = auth_getvalue(as, "warnmsg")) != NULL)
                   (void)printf("WARNING: %s\n\n", p);
   
           expire = auth_check_expire(as);
           if (expire < 0) {
                   (void)printf("Sorry -- your account has expired.\n");
                   quickexit(1);
           } else if (expire > 0 && !quietlog) {
                   warning = login_getcaptime(lc, "expire-warn",
                       2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY);
                   if (expire < warning)
                           (void)printf("Warning: your account expires on %s",
                               ctime(&pwd->pw_expire));
           }
   
           /* Nothing else left to fail -- really log in. */
           (void)signal(SIGHUP, SIG_DFL);
           memset(&utmp, 0, sizeof(utmp));
           (void)time(&utmp.ut_time);
           (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
           if (hostname)
                   (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
           (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
           login(&utmp);
   
           if (!quietlog)
                   (void)check_failedlogin(pwd->pw_uid);
           dolastlog(quietlog);
   
           login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
   
           (void)chown(ttyn, pwd->pw_uid,
               (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
   
         /* If fflag is on, assume caller/authenticator has logged root login. */          /* If fflag is on, assume caller/authenticator has logged root login. */
         if (rootlogin && fflag == 0) {          if (rootlogin && fflag == 0) {
                 if (hostname)                  if (hostname)
Line 544 
Line 682 
                         syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);                          syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
         }          }
   
 #if defined(KERBEROS) || defined(KERBEROS5)  
         if (!quietlog && notickets == 1)  
                 (void)printf("Warning: no Kerberos tickets issued.\n");  
 #endif  
   
         if (!quietlog) {          if (!quietlog) {
 #if 0  #if 0
                 (void)printf("%s\n\t%s  %s\n\n",                  (void)printf("%s\n\t%s  %s\n\n",
Line 556 
Line 689 
                     "The Regents of the University of California. ",                      "The Regents of the University of California. ",
                     "All rights reserved.");                      "All rights reserved.");
 #endif  #endif
                   if ((copyright =
                       login_getcapstr(lc, "copyright", NULL, NULL)) != NULL)
                           auth_cat(copyright);
                 motd();                  motd();
                 (void)snprintf(tbuf,                  (void)snprintf(tbuf,
                     sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);                      sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
Line 566 
Line 702 
   
         (void)signal(SIGALRM, SIG_DFL);          (void)signal(SIGALRM, SIG_DFL);
         (void)signal(SIGQUIT, SIG_DFL);          (void)signal(SIGQUIT, SIG_DFL);
           (void)signal(SIGHUP, SIG_DFL);
         (void)signal(SIGINT, SIG_DFL);          (void)signal(SIGINT, SIG_DFL);
         (void)signal(SIGTSTP, SIG_IGN);          (void)signal(SIGTSTP, SIG_IGN);
   
         tbuf[0] = '-';          tbuf[0] = '-';
         (void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ?          (void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ?
             p + 1 : shell, sizeof tbuf - 1);              p + 1 : shell, sizeof(tbuf) - 1);
   
         /* Discard permissions last so can't get killed and drop core. */          if ((scds.rlim_cur != QUAD_MIN || scds.rlim_max != QUAD_MIN) &&
         if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL)) {              setrlimit(RLIMIT_CORE, &scds) < 0)
                   syslog(LOG_ERR, "couldn't reset core dump size: %m");
   
           if (lastchance)
                   (void)printf("WARNING: Your password has expired.  You must change your password, now!\n");
   
           if (setusercontext(lc, pwd, pwd->pw_uid,
               LOGIN_SETALL & ~LOGIN_SETPATH) < 0) {
                 warn("unable to set user context");                  warn("unable to set user context");
                 exit(1);                  quickexit(1);
         }          }
   
           if (homeless) {
                   (void)printf("No home directory %s!\n", pwd->pw_dir);
                   (void)printf("Logging in with home = \"/\".\n");
                   (void)setenv("HOME", "/", 1);
           }
   
           if (auth_approval(as, lc, NULL, "login") == 0) {
                   if (auth_getstate(as) & AUTH_EXPIRED)
                           (void)printf("Sorry -- your account has expired.\n");
                   else
                           (void)printf("approval failure\n");
                   quickexit(1);
           }
   
           /*
            * The last thing we do is discard all of the open file descriptors.
            * Last because the C library may have some open.
            *
            * XXX
            * Assume that stdin, stdout and stderr are 0, 1 and 2, and that
            * STDERR_FILENO is 2.
            */
           for (cnt = getdtablesize(); cnt > STDERR_FILENO; cnt--)
                   (void)close(cnt);
   
           /*
            * Close the authentication session, make sure it is marked
            * as okay so no files are removed.
            */
           auth_setstate(as, AUTH_OKAY);
           auth_close(as);
   
 #ifdef KERBEROS  #ifdef KERBEROS
         kgettokens(pwd->pw_dir);          kgettokens(pwd->pw_dir);
 #endif  #endif
   
         execlp(shell, tbuf, 0);          execlp(shell, tbuf, 0);
         err(1, "%s", shell);          err(1, "%s", shell);
 }  }
   
 int  
 pwcheck(user, p, salt, passwd)  
         char *user, *p, *salt, *passwd;  
 {  
 #ifdef SKEY  
         if (strcasecmp(p, "s/key") == 0)  
                 return skey_authenticate(user);  
 #endif  
         return strcmp(crypt(p, salt), passwd);  
 }  
   
 #if defined(KERBEROS) || defined(KERBEROS5)  
 #define NBUFSIZ         (UT_NAMESIZE + 1 + 5)   /* .root suffix */  
 #else  
 #define NBUFSIZ         (UT_NAMESIZE + 1)  
 #endif  
   
 #if defined(KERBEROS) || defined(KERBEROS5)  
 /*  /*
  * This routine handles cleanup stuff, and the like.   * Allow for a '.' and 16 characters for any instance as well as
  * It exists only in the child process.   * space for a ':' and 16 charcters defining the authentication type.
  */   */
 #include <sys/wait.h>  #define NBUFSIZ         (UT_NAMESIZE + 1 + 16 + 1 + 16)
 void  
 dofork()  
 {  
     int child;  
   
     if (!(child = fork()))  
             return; /* Child process */  
   
     /* Setup stuff?  This would be things we could do in parallel with login */  
     (void) chdir("/");  /* Let's not keep the fs busy... */  
   
     /* If we're the parent, watch the child until it dies */  
     while (wait(0) != child)  
             ;  
   
     /* Cleanup stuff */  
     /* Run kdestroy to destroy tickets */  
     kdestroy();  
   
     /* Leave */  
     exit(0);  
 }  
 #endif  
   
 void  void
 getloginname()  getloginname()
 {  {
Line 646 
Line 781 
                 for (p = nbuf; (ch = getchar()) != '\n'; ) {                  for (p = nbuf; (ch = getchar()) != '\n'; ) {
                         if (ch == EOF) {                          if (ch == EOF) {
                                 badlogin(username);                                  badlogin(username);
                                 exit(0);                                  quickexit(0);
                         }                          }
                         if (p < nbuf + (NBUFSIZ - 1))                          if (p < nbuf + (NBUFSIZ - 1))
                                 *p++ = ch;                                  *p++ = ch;
Line 670 
Line 805 
 {  {
         struct ttyent *t;          struct ttyent *t;
   
           /* XXX - stash output of getttynam() elsewhere */
         return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);          return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
 }  }
   
Line 713 
Line 849 
 }  }
   
 void  void
 checknologin()  
 {  
         int fd, nchars;  
         char *nologin;  
         char tbuf[8192];  
   
         if (!login_getcapbool(lc, "ignorenologin", 0)) {  
                 nologin = login_getcapstr(lc, "nologin", _PATH_NOLOGIN,  
                     _PATH_NOLOGIN);  
                 if ((fd = open(nologin, O_RDONLY, 0)) >= 0) {  
                         while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)  
                                 (void)write(fileno(stdout), tbuf, nchars);  
                         sleepexit(0);  
                 }  
         }  
 }  
   
 void  
 dolastlog(quiet)  dolastlog(quiet)
         int quiet;          int quiet;
 {  {
Line 807 
Line 925 
 sleepexit(eval)  sleepexit(eval)
         int eval;          int eval;
 {  {
           auth_close(as);
         (void)sleep(5);          (void)sleep(5);
         exit(eval);          exit(eval);
 }  }
   
 void  void
   quickexit(eval)
           int eval;
   {
           if (as)
                   auth_close(as);
           exit(eval);
   }
   
   
   void
 sighup(signum)  sighup(signum)
         int signum;          int signum;
 {  {
Line 819 
Line 948 
                 badlogin(username);                  badlogin(username);
         exit(0);          exit(0);
 }  }
   
   #ifdef KERBEROS
   void
   kgettokens(homedir)
           char *homedir;
   {
   
           /* buy AFS-tokens for homedir */
           if (k_hasafs()) {
                   char cell[128];
                   k_setpag();
                   if (k_afs_cell_of_file(homedir,
                                          cell, sizeof(cell)) == 0)
                           krb_afslog(cell, 0);
                   krb_afslog(0, 0);
           }
   }
   #endif

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.36