* Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University
* of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
"@(#) Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)login.c 5.78 (Berkeley) 6/29/92";
* login -h hostname (for telnetd, etc.)
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
#include <sys/resource.h>
void badlogin
__P((char *));
void checknologin
__P((void));
void dolastlog
__P((int));
void getloginname
__P((void));
int rootterm
__P((char *));
void sleepexit
__P((int));
char *stypeof
__P((char *));
void timedout
__P((int));
int klogin
__P((struct passwd
*, char *, char *, char *));
#define TTYGRPNAME "tty" /* name of group to own ttys */
* This bounds the time given to login. Not a define so it can
* be patched on machines where it's too small.
char term
[64], *envinit
[1], *hostname
, *username
, *tty
;
int ask
, cnt
, fflag
, hflag
, pflag
, quietlog
, rootlogin
, rval
, uid
;
char *domain
, *salt
, *ttyn
;
char tbuf
[MAXPATHLEN
+ 2], tname
[sizeof(_PATH_TTY
) + 10];
char localhost
[MAXHOSTNAMELEN
];
char *skey_getpass(), *skey_crypt();
(void)signal(SIGALRM
, timedout
);
(void)alarm((u_int
)timeout
);
(void)signal(SIGQUIT
, SIG_IGN
);
(void)signal(SIGINT
, SIG_IGN
);
(void)setpriority(PRIO_PROCESS
, 0, 0);
openlog("login", LOG_ODELAY
, LOG_AUTH
);
* -p is used by getty to tell login not to destroy the environment
* -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
if (gethostname(localhost
, sizeof(localhost
)) < 0)
syslog(LOG_ERR
, "couldn't get local hostname: %m");
domain
= index(localhost
, '.');
fflag
= hflag
= pflag
= 0;
while ((ch
= getopt(argc
, argv
, "fh:p")) != EOF
)
"login: -h option: %s\n", strerror(EPERM
));
if (domain
&& (p
= index(optarg
, '.')) &&
strcasecmp(p
, domain
) == 0)
syslog(LOG_ERR
, "invalid flag %c", ch
);
"usage: login [-fp] [-h hostname] [username]\n");
for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
ttyn
= ttyname(STDIN_FILENO
);
if (ttyn
== NULL
|| *ttyn
== '\0') {
(void)snprintf(tname
, sizeof(tname
), "%s??", _PATH_TTY
);
if (tty
= rindex(ttyn
, '/'))
permit_passwd
= (hostname
== 0 || authfile(hostname
) != 0);
for (cnt
= 0;; ask
= 1) {
if ((instance
= index(username
, '.')) != NULL
) {
if (strncmp(instance
, ".root", 5) == 0)
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
* for nonexistent name (mistyped username).
if (failures
&& strcmp(tbuf
, username
)) {
if (failures
> (pwd
? 0 : 1))
(void)strcpy(tbuf
, username
);
if (pwd
= getpwnam(username
))
* 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
if (fflag
&& (uid
== 0 || uid
== pwd
->pw_uid
)) {
/* already authenticated */
} else if (pwd
->pw_passwd
[0] == '\0') {
/* pretend password okay */
(void)setpriority(PRIO_PROCESS
, 0, -4);
p
= skey_getpass("Password:", pwd
, permit_passwd
);
p
= getpass("Password:");
rval
= klogin(pwd
, instance
, localhost
, p
);
rval
= strcmp(skey_crypt(p
, salt
, pwd
, permit_passwd
),
rval
= strcmp(crypt(p
, salt
), pwd
->pw_passwd
);
rval
= strcmp(skey_crypt(p
, salt
, pwd
, permit_passwd
),
rval
= strcmp(crypt(p
, salt
), pwd
->pw_passwd
);
(void)setpriority(PRIO_PROCESS
, 0, 0);
* If trying to log in as root without Kerberos,
* but with insecure terminal, refuse the login attempt.
if (pwd
&& !rval
&& rootlogin
&& !rootterm(tty
)) {
"%s login refused on this terminal.\n",
"LOGIN %s REFUSED FROM %s ON TTY %s",
pwd
->pw_name
, hostname
, tty
);
"LOGIN %s REFUSED ON TTY %s",
(void)printf("Login incorrect\n");
/* we allow 10 tries, but after 3 we start backing off */
sleep((u_int
)((cnt
- 3) * 5));
/* committed to login -- turn off timeout */
/* if user not super-user, check for disabled logins */
if (chdir(pwd
->pw_dir
) < 0) {
(void)printf("No home directory %s!\n", pwd
->pw_dir
);
(void)printf("Logging in with home = \"/\".\n");
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");
} else if (pwd
->pw_change
- tp
.tv_sec
<
2 * DAYSPERWEEK
* SECSPERDAY
&& !quietlog
)
(void)printf("Warning: your password expires on %s",
if (tp
.tv_sec
>= pwd
->pw_expire
) {
(void)printf("Sorry -- your account has expired.\n");
} else if (pwd
->pw_expire
- tp
.tv_sec
<
2 * DAYSPERWEEK
* SECSPERDAY
&& !quietlog
)
(void)printf("Warning: your account expires on %s",
/* Nothing else left to fail -- really log in. */
bzero((void *)&utmp
, sizeof(utmp
));
(void)time(&utmp
.ut_time
);
(void)strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
(void)strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
(void)strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
(void)chown(ttyn
, pwd
->pw_uid
,
(gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
);
(void)setgid(pwd
->pw_gid
);
initgroups(username
, pwd
->pw_gid
);
if (*pwd
->pw_shell
== '\0')
pwd
->pw_shell
= _PATH_BSHELL
;
/* Destroy environment unless user has requested its preservation. */
(void)setenv("HOME", pwd
->pw_dir
, 1);
(void)setenv("SHELL", pwd
->pw_shell
, 1);
(void)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);
(void)setenv("KRBTKFILE", krbtkfile_env
, 1);
if (tty
[sizeof("tty")-1] == 'd')
syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
/* If fflag is on, assume caller/authenticator has logged root login. */
if (rootlogin
&& fflag
== 0)
syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s FROM %s",
username
, tty
, hostname
);
syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s", username
, tty
);
if (!quietlog
&& notickets
== 1)
(void)printf("Warning: no Kerberos tickets issued.\n");
* Syslog each successful login, so we don't have to watch hundreds
* of wtmp or lastlogin files.
syslog(LOG_INFO
, "login from %s as %s", hostname
, pwd
->pw_name
);
syslog(LOG_INFO
, "login on %s as %s", tty
, pwd
->pw_name
);
"Copyright (c) 1980,1983,1986,1988,1990,1991 The Regents of the University\n%s",
"of California. All rights reserved.\n\n");
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 " : "");
if (login_access(pwd
->pw_name
, hostname
? hostname
: tty
) == 0) {
printf("Permission denied\n");
syslog(LOG_NOTICE
, "%s LOGIN REFUSED FROM %s",
syslog(LOG_NOTICE
, "%s LOGIN REFUSED ON %s",
(void)signal(SIGALRM
, SIG_DFL
);
(void)signal(SIGQUIT
, SIG_DFL
);
(void)signal(SIGINT
, SIG_DFL
);
(void)signal(SIGTSTP
, SIG_IGN
);
(void)strcpy(tbuf
+ 1, (p
= rindex(pwd
->pw_shell
, '/')) ?
if (setlogin(pwd
->pw_name
) < 0)
syslog(LOG_ERR
, "setlogin() failure: %m");
/* Discard permissions last so can't get killed and drop core. */
(void) setuid(pwd
->pw_uid
);
execlp(pwd
->pw_shell
, tbuf
, 0);
(void)fprintf(stderr
, "%s: %s\n", pwd
->pw_shell
, strerror(errno
));
#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */
#define NBUFSIZ (UT_NAMESIZE + 1)
static char nbuf
[NBUFSIZ
];
for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
if (p
< nbuf
+ (NBUFSIZ
- 1))
"login names may not start with '-'.\n");
return((t
= getttynam(ttyn
)) && t
->ty_status
& TTY_SECURE
);
if ((fd
= open(_PATH_MOTDFILE
, O_RDONLY
, 0)) < 0)
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
);
longjmp(motdinterrupt
, 1);
(void)fprintf(stderr
, "Login timed out after %d seconds\n", timeout
);
if ((fd
= open(_PATH_NOLOGIN
, O_RDONLY
, 0)) >= 0) {
while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
(void)write(fileno(stdout
), tbuf
, nchars
);
if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
(void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
(void)printf("Last login: %.*s ",
24-5, (char *)ctime(&ll
.ll_time
));
(void)printf("from %.*s\n",
(void)printf("on %.*s\n",
(void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
bzero((void *)&ll
, sizeof(ll
));
(void)strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
(void)strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
(void)write(fd
, (char *)&ll
, sizeof(ll
));
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
);
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
);
return(ttyid
&& (t
= getttynam(ttyid
)) ? t
->ty_type
: UNKNOWN
);