char	*stypeof __P((char *)); 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 void log_failedlogin __P((uid_t, char *, char *, char *));  #define	TTYGRPNAME	"tty"		   u_int		timeout = 300;  #if defined(KERBEROS) || defined(KERBEROS5) int		notickets = 1; char		*instance; char		*krbtkfile_env; int		authok; #endif  struct	passwd	*pwd; login_cap_t	*lc = NULL; int		failures; char		term[64], *hostname, *tty; char		*username = NULL, *rusername = NULL;  int main(argc, argv) int argc; char *argv[]; { extern char **environ; struct group *gr; struct stat st; struct timeval tp; struct utmp utmp; int ask, ch, cnt, fflag, hflag, pflag, uflag, quietlog, rootlogin, rval; uid_t uid; char *domain, *p, *salt, *ttyn, *shell; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char localhost[MAXHOSTNAMELEN];  (void)signal(SIGALRM, timedout); (void)alarm(timeout); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGHUP, sighup); (void)setpriority(PRIO_PROCESS, 0, 0);  openlog("login", LOG_ODELAY, LOG_AUTH);   domain = NULL; if (gethostname(localhost, sizeof(localhost)) < 0) syslog(LOG_ERR, "couldn't get local hostname: %m"); else domain = strchr(localhost, '.'); if (domain) { domain++; if (*domain && strchr(domain, '.') == NULL) domain = localhost; }  fflag = hflag = pflag = 0; uid = getuid(); while ((ch = getopt(argc, argv, "fh:u:p")) != -1) switch (ch) { case 'f': fflag = 1; break; case 'h': if (uid) errx(1, "-h option: %s", strerror(EPERM)); hflag = 1; if (domain && (p = strchr(optarg, '.')) && strcasecmp(p+1, domain) == 0) *p = 0; hostname = optarg; break; case 'p': pflag = 1; break; case 'u': if (uid) errx(1, "-u option: %s", strerror(EPERM)); uflag = 1; rusername = optarg; break; case '?': default: if (!uid) syslog(LOG_ERR, "invalid flag %c", ch); (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); exit(1); } argc -= optind; argv += optind;  if (*argv) { username = *argv; ask = 0; } else ask = 1;  for (cnt = getdtablesize(); cnt > 2; cnt--) (void)close(cnt);  ttyn = ttyname(STDIN_FILENO); if (ttyn == NULL || *ttyn == '\0') { (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); ttyn = tname; } if ((tty = strrchr(ttyn, '/'))) ++tty; else tty = ttyn;  for (cnt = 0;; ask = 1) { #if defined(KERBEROS) || defined(KERBEROS5) kdestroy(); #endif if (ask) { fflag = 0; getloginname(); } rootlogin = 0;  #if defined(KERBEROS) || defined(KERBEROS5)  instance = ""; #endif #ifdef	KERBEROS if ((instance = strchr(username, '.')) != NULL) { if (strncmp(instance, ".root", 5) == 0) rootlogin = 1; *instance++ = '\0'; } else 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) username[UT_NAMESIZE] = '\0';   if (failures && strcmp(tbuf, username)) { if (failures > (pwd ? 0 : 1)) badlogin(tbuf); failures = 0; } (void)strlcpy(tbuf, username, sizeof tbuf);  if ((pwd = getpwnam(username))) salt = pwd->pw_passwd; else salt = "xx"; lc = login_getclass(pwd ? pwd->pw_class : LOGIN_DEFCLASS); if (!lc) err(1, "unable to get login class");   if (pwd) { if (pwd->pw_uid == 0) rootlogin = 1;  if (fflag && (uid == 0 || uid == pwd->pw_uid)) {  break; } else if (pwd->pw_passwd[0] == '\0') {  rval = 0; goto ttycheck; } }  fflag = 0;  (void)setpriority(PRIO_PROCESS, 0, -4);  p = getpass("Password:");  if (pwd) { #if defined(KERBEROS) || defined(KERBEROS5) rval = klogin(pwd, instance, localhost, p); if (rval != 0 && rootlogin && pwd->pw_uid != 0) rootlogin = 0; if (rval == 0) authok = 1; else if (rval == 1) { if (pwd->pw_uid != 0) rootlogin = 0; rval = pwcheck(username, p, salt, pwd->pw_passwd); } #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;   us = arc4random() % 3000000; usleep(us); } rval = 1; } memset(p, 0, strlen(p));  (void)setpriority(PRIO_PROCESS, 0, 0);  ttycheck:  #if defined(KERBEROS) || defined(KERBEROS5) if (authok == 1) #endif  if (pwd && rval == 0 && (!rootlogin || rootterm(tty))) break;   if (rootlogin && !rootterm(tty)) { (void)fprintf(stderr, "%s login refused on this terminal.\n", pwd ? pwd->pw_name : "root"); if (hostname) syslog(LOG_NOTICE, "LOGIN %s REFUSED FROM %s%s%s ON TTY %s", pwd ? pwd->pw_name : "root", rusername ? rusername : "", rusername ? "@" : "", hostname, tty); else syslog(LOG_NOTICE, "LOGIN %s REFUSED ON TTY %s", pwd ? pwd->pw_name : "root", tty); } else (void)printf("Login incorrect\n"); failures++; if (pwd) log_failedlogin(pwd->pw_uid, hostname, rusername, tty);  if (++cnt > 3) { if (cnt >= 10) { badlogin(username); sleepexit(1); } sleep((u_int)((cnt - 3) * 5)); } }   (void)alarm((u_int)0);  endpwent();   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); if (*shell == '\0') shell = _PATH_BSHELL; else if (strlen(shell) >= MAXPATHLEN) { syslog(LOG_ERR, "shell path too long: %s", shell); warnx("invalid shell"); sleepexit(1); }  quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) || login_getcapbool(lc, "hushlogin", 0) || (access(_PATH_HUSHLOGIN, F_OK) == 0));  seteuid(0); setegid(0);	  if (pwd->pw_change || pwd->pw_expire) (void)gettimeofday(&tp, (struct timezone *)NULL); 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)); } 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)); }   (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)  if (krbtkfile_env) dofork(); #endif   if (!pflag) { if ((environ = calloc(1, sizeof (char *))) == NULL) err(1, "calloc"); } else { char **cpp, **cpp2;  for (cpp2 = cpp = environ; *cpp; cpp++) { if (strncmp(*cpp, "LD_", 3) && strncmp(*cpp, "ENV=", 4) && strncmp(*cpp, "BASH_ENV=", 9) && strncmp(*cpp, "IFS=", 4)) *cpp2++ = *cpp; } *cpp2 = 0; }  (void)setenv("HOME", pwd->pw_dir, 1); (void)setenv("SHELL", shell, 1); if (term[0] == '\0') (void)strlcpy(term, stypeof(tty), sizeof(term)); (void)setenv("TERM", term, 0); (void)setenv("LOGNAME", pwd->pw_name, 1); (void)setenv("USER", pwd->pw_name, 1); if (hostname) (void)setenv("REMOTEHOST", hostname, 1); if (rusername) (void)setenv("REMOTEUSER", rusername, 1); #ifdef KERBEROS if (krbtkfile_env) (void)setenv("KRBTKFILE", krbtkfile_env, 1); #endif #ifdef KERBEROS5 if (krbtkfile_env) (void)setenv("KRB5CCNAME", krbtkfile_env, 1); #endif  if (rootlogin && fflag == 0) { if (hostname) syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s%s%s", username, tty, rusername ? rusername : "", rusername ? "@" : "", hostname); else 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 0 (void)printf("%s\n\t%s  %s\n\n", "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", "The Regents of the University of California. ", "All rights reserved."); #endif motd(); (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); if (stat(tbuf, &st) == 0 && st.st_size != 0) (void)printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : ""); }  (void)signal(SIGALRM, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN);  tbuf[0] = '-'; (void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ? p + 1 : shell, sizeof tbuf - 1);   if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL)) { warn("unable to set user context"); exit(1); }  #ifdef KERBEROS kgettokens(pwd->pw_dir); #endif  execlp(shell, tbuf, 0); 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)	 #else #define	NBUFSIZ		(UT_NAMESIZE + 1) #endif  #if defined(KERBEROS) || defined(KERBEROS5)  #include <sys/wait.h> void dofork() { int child;  if (!(child = fork())) return;    (void) chdir("/");	   while (wait(0) != child) ;    kdestroy();   exit(0); } #endif  void getloginname() { int ch; char *p; static char nbuf[NBUFSIZ];  for (;;) { (void)printf("login: "); for (p = nbuf; (ch = getchar()) != '\n'; ) { if (ch == EOF) { badlogin(username); exit(0); } if (p < nbuf + (NBUFSIZ - 1)) *p++ = ch; } if (p > nbuf) { if (nbuf[0] == '-') (void)fprintf(stderr, "login names may not start with '-'.\n"); else { *p = '\0'; username = nbuf; break; } } } }  int rootterm(ttyn) char *ttyn; { struct ttyent *t;  return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); }  jmp_buf motdinterrupt;  void motd() { int fd, nchars; sig_t oldint; char tbuf[8192]; char *motd;  motd = login_getcapstr(lc, "welcome", _PATH_MOTDFILE, _PATH_MOTDFILE);  if ((fd = open(motd, O_RDONLY, 0)) < 0) return; oldint = signal(SIGINT, sigint); if (setjmp(motdinterrupt) == 0) while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); (void)signal(SIGINT, oldint); (void)close(fd); }   void sigint(signo) int signo; { longjmp(motdinterrupt, 1); }   void timedout(signo) int signo; { (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); exit(0); }  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) int quiet; { struct lastlog ll; int fd;  if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); if (!quiet) { if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) { (void)printf("Last login: %.*s ", 24-5, (char *)ctime(&ll.ll_time)); (void)printf("on %.*s", (int)sizeof(ll.ll_line), ll.ll_line); if (*ll.ll_host != '\0') (void)printf(" from %.*s", (int)sizeof(ll.ll_host), ll.ll_host); (void)putchar('\n'); } (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); } memset((void *)&ll, 0, sizeof(ll)); (void)time(&ll.ll_time); (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); if (hostname) (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); (void)write(fd, (char *)&ll, sizeof(ll)); (void)close(fd); } }  void badlogin(name) char *name; { if (failures == 0) return; if (hostname) { syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s%s%s", failures, failures > 1 ? "S" : "", rusername ? rusername : "", rusername ? "@" : "", hostname); syslog(LOG_AUTHPRIV|LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s%s%s, %s", failures, failures > 1 ? "S" : "", rusername ? rusername : "", rusername ? "@" : "", hostname, name); } else { syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", failures, failures > 1 ? "S" : "", tty); syslog(LOG_AUTHPRIV|LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", failures, failures > 1 ? "S" : "", tty, name); } }  #undef	UNKNOWN #define	UNKNOWN	"su"  char *
stypeof(ttyid)	char *ttyid;{	struct ttyent *t;	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type :	    login_getcapstr(lc, "term", UNKNOWN, UNKNOWN));}