/*-
- * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University
+ * of California. All rights reserved.
*
- * %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
char copyright[] =
-"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
+"@(#) Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)login.c 5.56 (Berkeley) %G%";
+static char sccsid[] = "@(#)login.c 5.73 (Berkeley) 6/29/91";
#endif /* not lint */
/*
* login [ name ]
- * login -r hostname (for rlogind)
* login -h hostname (for telnetd, etc.)
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
*/
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
-#include <sgtty.h>
#include <utmp.h>
#include <signal.h>
* be patched on machines where it's too small.
*/
int timeout = 300;
+int rootlogin;
#ifdef KERBEROS
int notickets = 1;
+char *instance;
+char *krbtkfile_env;
+int authok;
#endif
struct passwd *pwd;
int failures;
char term[64], *envinit[1], *hostname, *username, *tty;
-struct sgttyb sgttyb;
-struct tchars tc = {
- CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
-};
-struct ltchars ltc = {
- CSUSP, CDSUSP, CRPRNT, CDISCARD, CWERASE, CLNEXT
-};
-
-char *months[] =
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec" };
-
-char *months[] =
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec" };
-
main(argc, argv)
int argc;
char **argv;
extern int optind;
extern char *optarg, **environ;
struct timeval tp;
- struct tm *ttp;
- struct timeval tp;
- struct tm *ttp;
struct group *gr;
register int ch;
register char *p;
- int ask, fflag, hflag, pflag, rflag, cnt;
- int quietlog, passwd_req, ioctlval, rval;
+ int ask, fflag, hflag, pflag, cnt, uid;
+ int quietlog, rval;
char *domain, *salt, *ttyn;
char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
char localhost[MAXHOSTNAMELEN];
/*
* -p is used by getty to tell login not to destroy the environment
- * -r is used by rlogind to cause the autologin protocol;
* -f is used to skip a second login authentication
* -h is used by other servers to pass the name of the remote
* host to login so that it may be placed in utmp and wtmp
else
domain = index(localhost, '.');
- fflag = hflag = pflag = rflag = 0;
- passwd_req = 1;
+ fflag = hflag = pflag = 0;
uid = getuid();
- while ((ch = getopt(argc, argv, "fh:pr:")) != EOF)
+ while ((ch = getopt(argc, argv, "fh:p")) != EOF)
switch (ch) {
case 'f':
- if (rflag) {
- fprintf(stderr,
- "login: only one of -r and -f allowed.\n");
- exit(1);
- }
fflag = 1;
break;
case 'h':
if (uid) {
(void)fprintf(stderr,
- "login: -h for super-user only.\n");
- exit(1);
- }
- if (rflag) {
- fprintf(stderr,
- "login: only one of -r and -h allowed.\n");
+ "login: -h option: %s\n", strerror(EPERM));
exit(1);
}
hflag = 1;
case 'p':
pflag = 1;
break;
- case 'r':
- if (hflag || fflag) {
- fprintf(stderr,
- "login: -f and -h not allowed with -r.\n");
- exit(1);
- }
- if (getuid()) {
- fprintf(stderr,
- "login: -r for super-user only.\n");
- exit(1);
- }
- /* "-r hostname" must be last args */
- if (optind != argc) {
- fprintf(stderr, "Syntax error.\n");
- exit(1);
- }
- rflag = 1;
- passwd_req = (doremotelogin(optarg) == -1);
- if (domain && (p = index(optarg, '.')) &&
- !strcmp(p, domain))
- *p = '\0';
- hostname = optarg;
- break;
case '?':
default:
if (!uid)
syslog(LOG_ERR, "invalid flag %c", ch);
(void)fprintf(stderr,
- "usage: login [-fp] [username]\n");
+ "usage: login [-fp] [-h hostname] [username]\n");
exit(1);
}
argc -= optind;
argv += optind;
if (*argv) {
username = *argv;
- if (strlen(username) > UT_NAMESIZE)
- username[UT_NAMESIZE] = '\0';
ask = 0;
} else
ask = 1;
- if (rflag)
- ask = 0;
-
- ioctlval = 0;
- (void)ioctl(0, TIOCLSET, &ioctlval);
- (void)ioctl(0, TIOCNXCL, 0);
- (void)fcntl(0, F_SETFL, ioctlval);
- (void)ioctl(0, TIOCGETP, &sgttyb);
-
- /*
- * If talking to an rlogin process, propagate the terminal type and
- * baud rate across the network.
- */
- if (rflag)
- doremoteterm(&sgttyb);
- sgttyb.sg_erase = CERASE;
- sgttyb.sg_kill = CKILL;
- (void)ioctl(0, TIOCSLTC, <c);
- (void)ioctl(0, TIOCSETC, &tc);
- (void)ioctl(0, TIOCSETP, &sgttyb);
for (cnt = getdtablesize(); cnt > 2; cnt--)
close(cnt);
tty = ttyn;
for (cnt = 0;; ask = 1) {
- ioctlval = TTYDISC;
- (void)ioctl(0, TIOCSETD, &ioctlval);
-
if (ask) {
fflag = 0;
getloginname();
}
+#ifdef KERBEROS
+ if ((instance = index(username, '.')) != NULL) {
+ if (strncmp(instance, ".root", 5) == 0)
+ rootlogin++;
+ *instance++ = '\0';
+ } else {
+ rootlogin = 0;
+ instance = "";
+ }
+#else
+ rootlogin = 0;
+#endif
+ if (strlen(username) > UT_NAMESIZE)
+ username[UT_NAMESIZE] = '\0';
+
/*
* Note if trying multiple user names; log failures for
* previous user name, but don't bother logging one failure
failures = 0;
}
(void)strcpy(tbuf, username);
+
if (pwd = getpwnam(username))
salt = pwd->pw_passwd;
- else {
- /* take up the right amount of time */
- (void)crypt(getpass("Password:"), "xx");
- goto faked;
- }
-
- /* if user not super-user, check for disabled logins */
- if (pwd->pw_uid)
- checknologin();
+ else
+ salt = "xx";
/*
- * Disallow automatic login to root; if not invoked by
- * root, disallow if the uid's differ.
+ * 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 (fflag) {
- passwd_req =
-#ifndef KERBEROS
- pwd->pw_uid == 0 ||
+ if (pwd && (*pwd->pw_passwd == '\0' ||
+ fflag && (uid == 0 || uid == pwd->pw_uid)))
+ break;
+ fflag = 0;
+ if (pwd && pwd->pw_uid == 0)
+ rootlogin = 1;
+
+ (void)setpriority(PRIO_PROCESS, 0, -4);
+
+ p = getpass("Password:");
+
+ if (pwd) {
+#ifdef KERBEROS
+ rval = klogin(pwd, instance, localhost, p);
+ if (rval == 0)
+ authok = 1;
+ else if (rval == 1) {
+ if (pwd->pw_uid != 0)
+ rootlogin = 0;
+ rval = strcmp(crypt(p, salt), pwd->pw_passwd);
+ }
+#else
+ if (pwd->pw_uid != 0)
+ rootlogin = 0;
+#ifdef DES
+ rval = strcmp(crypt(p, salt), pwd->pw_passwd);
+#else
+ rval = strcmp(p, pwd->pw_passwd);
+#endif
#endif
- (uid && uid != pwd->pw_uid);
}
+ bzero(p, strlen(p));
- /*
- * If no pre-authentication and a password exists
- * for this user, prompt for one and verify it.
- */
- if (!passwd_req || !*pwd->pw_passwd)
- break;
+ (void)setpriority(PRIO_PROCESS, 0, 0);
/*
- * If trying to log in as root, but with insecure terminal,
- * refuse the login attempt.
+ * If trying to log in as root without Kerberos,
+ * but with insecure terminal, refuse the login attempt.
*/
- if (pwd->pw_uid == 0 && !rootterm(tty)) {
+#ifdef KERBEROS
+ if (authok == 0)
+#endif
+ if (pwd && rootlogin && !rootterm(tty)) {
(void)fprintf(stderr,
"%s login refused on this terminal.\n",
pwd->pw_name);
continue;
}
- (void)setpriority(PRIO_PROCESS, 0, -4);
- p = getpass("Password:");
-
- bzero(p, strlen(p));
- if (!rval)
+ if (pwd && !rval)
break;
-faked: (void)printf("Login incorrect\n");
+ (void)printf("Login incorrect\n");
failures++;
/* we allow 10 tries, but after 3 we start backing off */
if (++cnt > 3) {
if (cnt >= 10) {
badlogin(username);
- (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL);
sleepexit(1);
}
sleep((u_int)((cnt - 3) * 5));
/* committed to login -- turn off timeout */
(void)alarm((u_int)0);
- /* reset priority */
- (void)setpriority(PRIO_PROCESS, 0, 0);
-
- /* paranoia... */
endpwent();
+ /* if user not super-user, check for disabled logins */
+ if (!rootlogin)
+ checknologin();
+
if (chdir(pwd->pw_dir) < 0) {
- (void)printf("No directory %s!\n", pwd->pw_dir);
+ (void)printf("No home directory %s!\n", pwd->pw_dir);
if (chdir("/"))
exit(0);
pwd->pw_dir = "/";
(void)printf("Logging in with home = \"/\".\n");
}
-#define TWOWEEKS (14*24*60*60)
- if (pwd->pw_change || pwd->pw_expire)
- (void)gettimeofday(&tp, (struct timezone *)NULL);
- if (pwd->pw_change)
- if (tp.tv_sec >= pwd->pw_change) {
- printf("Sorry -- your password has expired.\n");
- sleepexit(1);
- }
- else if (tp.tv_sec - pwd->pw_change < TWOWEEKS) {
- ttp = localtime(&pwd->pw_change);
- printf("Warning: your password expires on %s %d, 19%d\n",
- months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year);
- }
- if (pwd->pw_expire)
- if (tp.tv_sec >= pwd->pw_expire) {
- printf("Sorry -- your account has expired.\n");
- sleepexit(1);
- }
- else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS) {
- ttp = localtime(&pwd->pw_expire);
- printf("Warning: your account expires on %s %d, 19%d\n",
- months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year);
- }
+
+ quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
if (pwd->pw_change || pwd->pw_expire)
(void)gettimeofday(&tp, (struct timezone *)NULL);
if (tp.tv_sec >= pwd->pw_change) {
(void)printf("Sorry -- your password has expired.\n");
sleepexit(1);
- }
- else if (pwd->pw_change - tp.tv_sec <
- 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) {
- ttp = localtime(&pwd->pw_change);
- (void)printf("Warning: your password expires on %s %d, %d\n",
- months[ttp->tm_mon], ttp->tm_mday,
- TM_YEAR_BASE + ttp->tm_year);
- }
+ } else if (pwd->pw_change - tp.tv_sec <
+ 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
+ (void)printf("Warning: your password expires on %s",
+ ctime(&pwd->pw_expire));
if (pwd->pw_expire)
if (tp.tv_sec >= pwd->pw_expire) {
(void)printf("Sorry -- your account has expired.\n");
sleepexit(1);
- }
- else if (pwd->pw_expire - tp.tv_sec <
- 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) {
- ttp = localtime(&pwd->pw_expire);
- (void)printf("Warning: your account expires on %s %d, %d\n",
- months[ttp->tm_mon], ttp->tm_mday,
- TM_YEAR_BASE + ttp->tm_year);
- }
+ } else if (pwd->pw_expire - tp.tv_sec <
+ 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
+ (void)printf("Warning: your account expires on %s",
+ ctime(&pwd->pw_expire));
/* nothing else left to fail -- really log in */
{
dolastlog(quietlog);
- if (!hflag && !rflag) { /* XXX */
- static struct winsize win = { 0, 0, 0, 0 };
-
- (void)ioctl(0, TIOCSWINSZ, &win);
- }
-
(void)chown(ttyn, pwd->pw_uid,
(gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
- (void)chmod(ttyn, 0620);
(void)setgid(pwd->pw_gid);
initgroups(username, pwd->pw_gid);
if (term[0] == '\0')
strncpy(term, stypeof(tty), sizeof(term));
(void)setenv("TERM", term, 0);
+ (void)setenv("LOGNAME", pwd->pw_name, 1);
(void)setenv("USER", pwd->pw_name, 1);
(void)setenv("PATH", _PATH_DEFPATH, 0);
+#ifdef KERBEROS
+ if (krbtkfile_env)
+ (void)setenv("KRBTKFILE", krbtkfile_env, 1);
+#endif
if (tty[sizeof("tty")-1] == 'd')
syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
- if (pwd->pw_uid == 0)
+ /* if fflag is on, assume caller/authenticator has logged root login */
+ if (rootlogin && fflag == 0)
if (hostname)
- syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s",
- tty, hostname);
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
+ username, tty, hostname);
else
- syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty);
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
#ifdef KERBEROS
if (!quietlog && notickets == 1)
if (!quietlog) {
struct stat st;
+ printf("%s%s",
+ "386BSD Release 0.1 by William and Lynne Jolitz.\n",
+"Copyright (c) 1989,1990,1991,1992 William F. Jolitz. All rights reserved.\n\
+Based in part on work by the 386BSD User Community and the\n\
+BSD Networking Software, Release 2 by UCB EECS Department.\n");
+
motd();
(void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
if (stat(tbuf, &st) == 0 && st.st_size != 0)
syslog(LOG_ERR, "setlogin() failure: %m");
/* discard permissions last so can't get killed and drop core */
- (void)setuid(pwd->pw_uid);
+ if (rootlogin)
+ (void) setuid(0);
+ else
+ (void) setuid(pwd->pw_uid);
execlp(pwd->pw_shell, tbuf, 0);
- (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno));
- exit(0);
+ (void)fprintf(stderr, "%s: %s\n", pwd->pw_shell, strerror(errno));
+ exit(1);
}
+#ifdef KERBEROS
+#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */
+#else
+#define NBUFSIZ (UT_NAMESIZE + 1)
+#endif
+
getloginname()
{
register int ch;
register char *p;
- static char nbuf[UT_NAMESIZE + 1];
+ static char nbuf[NBUFSIZ];
for (;;) {
(void)printf("login: ");
badlogin(username);
exit(0);
}
- if (p < nbuf + UT_NAMESIZE)
+ if (p < nbuf + (NBUFSIZ - 1))
*p++ = ch;
}
if (p > nbuf)
{
register int fd, nchars;
sig_t oldint;
- int sigint();
+ void sigint();
char tbuf[8192];
if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
(void)close(fd);
}
+void
sigint()
{
longjmp(motdinterrupt, 1);
struct lastlog ll;
int fd;
char *ctime();
- char *ctime();
if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
{
if (failures == 0)
return;
- if (hostname)
- syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s",
+ if (hostname) {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
+ failures, failures > 1 ? "S" : "", hostname);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s FROM %s, %s",
failures, failures > 1 ? "S" : "", hostname, name);
- else
- syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s",
+ } 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
sleep((u_int)5);
exit(eval);
}
-
-doremotelogin(host)
- char *host;
-{
- static char lusername[UT_NAMESIZE+1];
- char rusername[UT_NAMESIZE+1];
-
- getstr(rusername, sizeof(rusername), "remuser");
- getstr(lusername, sizeof(lusername), "locuser");
- getstr(term, sizeof(term), "Terminal type");
- username = lusername;
- pwd = getpwnam(username);
- if (pwd == NULL)
- return(-1);
- return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
-}
-
-char *speeds[] = {
- "0", "50", "75", "110", "134", "150", "200", "300", "600",
- "1200", "1800", "2400", "4800", "9600", "19200", "38400",
-};
-#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
-
-doremoteterm(tp)
- struct sgttyb *tp;
-{
- register char *cp = index(term, '/'), **cpp;
- char *speed;
-
- if (cp) {
- *cp++ = '\0';
- speed = cp;
- cp = index(speed, '/');
- if (cp)
- *cp++ = '\0';
- for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
- if (strcmp(*cpp, speed) == 0) {
- tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
- break;
- }
- }
- tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
-}