85f77c059775234649bdc3ccfc9ad58cf8db88dd
* Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)login.c 5.48 (Berkeley) %G%";
* login -r hostname (for rlogind)
* login -h hostname (for telnetd, etc.)
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
#include <sys/resource.h>
#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], *hostname
, *username
, *tty
;
CINTR
, CQUIT
, CSTART
, CSTOP
, CEOT
, CBRK
CSUSP
, CDSUSP
, CRPRNT
, CFLUSH
, CWERASE
, CLNEXT
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec" };
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec" };
extern int errno
, optind
;
extern char *optarg
, **environ
;
int ask
, fflag
, hflag
, pflag
, rflag
, cnt
;
int quietlog
, passwd_req
, ioctlval
, timedout();
char *domain
, *salt
, *envinit
[1], *ttyn
, *pp
;
char tbuf
[MAXPATHLEN
+ 2], tname
[sizeof(_PATH_TTY
) + 10];
char localhost
[MAXHOSTNAMELEN
];
char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass();
(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);
(void)quota(Q_SETUID
, 0, 0, 0);
* -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
if (gethostname(localhost
, sizeof(localhost
)) < 0)
syslog(LOG_ERR
, "couldn't get local hostname: %m");
domain
= index(localhost
, '.');
openlog("login", LOG_ODELAY
, LOG_AUTH
);
fflag
= hflag
= pflag
= rflag
= 0;
while ((ch
= getopt(argc
, argv
, "fh:pr:")) != EOF
)
"login: only one of -r and -f allowed.\n");
"login: -h for super-user only.\n");
"login: only one of -r and -h allowed.\n");
if (domain
&& (p
= index(optarg
, '.')) &&
strcasecmp(p
, domain
) == 0)
"login: -f and -h not allowed with -r.\n");
"login: -r for super-user only.\n");
/* "-r hostname" must be last args */
fprintf(stderr
, "Syntax error.\n");
passwd_req
= (doremotelogin(optarg
) == -1);
if (domain
&& (p
= index(optarg
, '.')) &&
syslog(LOG_ERR
, "invalid flag %c", ch
);
"usage: login [-fp] [username]\n");
(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.
sgttyb
.sg_erase
= CERASE
;
(void)ioctl(0, TIOCSLTC
, <c
);
(void)ioctl(0, TIOCSETC
, &tc
);
(void)ioctl(0, TIOCSETP
, &sgttyb
);
for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
if (ttyn
== NULL
|| *ttyn
== '\0') {
(void)sprintf(tname
, "%s??", _PATH_TTY
);
if (tty
= rindex(ttyn
, '/'))
for (cnt
= 0;; ask
= 1) {
(void)ioctl(0, TIOCSETD
, &ioctlval
);
* 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 user not super-user, check for disabled logins */
if (pwd
== NULL
|| pwd
->pw_uid
)
* Disallow automatic login to root; if not invoked by
* root, disallow if the uid's differ.
(uid
&& uid
!= pwd
->pw_uid
);
* If no pre-authentication and a password exists
* for this user, prompt for one and verify it.
if (!passwd_req
|| (pwd
&& !*pwd
->pw_passwd
))
* If trying to log in as root, but with insecure terminal,
* refuse the login attempt.
if (pwd
->pw_uid
== 0 && !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",
setpriority(PRIO_PROCESS
, 0, -4);
pp
= getpass("Password:");
setpriority(PRIO_PROCESS
, 0, 0);
(void) bzero(pp
, strlen(pp
));
if (pwd
&& !strcmp(p
, pwd
->pw_passwd
))
(void)printf("Login incorrect\n");
/* we allow 10 tries, but after 3 we start backing off */
(void)ioctl(0, TIOCHPCL
, (struct sgttyb
*)NULL
);
sleep((u_int
)((cnt
- 3) * 5));
/* committed to login -- turn off timeout */
if (quota(Q_SETUID
, pwd
->pw_uid
, 0, 0) < 0 && errno
!= EINVAL
) {
"Too many users logged on already.\nTry again later.\n");
"You have too many processes running.\n");
perror("quota (Q_SETUID)");
if (chdir(pwd
->pw_dir
) < 0) {
(void)printf("No directory %s!\n", 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 (tp
.tv_sec
>= pwd
->pw_change
) {
printf("Sorry -- your password has expired.\n");
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 (tp
.tv_sec
>= pwd
->pw_expire
) {
printf("Sorry -- your account has expired.\n");
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
);
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
) {
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
);
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
) {
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
);
/* nothing else left to fail -- really log in */
bzero((char *)&utmp
, sizeof(utmp
));
(void)time(&utmp
.ut_time
);
strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
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)setgid(pwd
->pw_gid
);
initgroups(username
, pwd
->pw_gid
);
quota(Q_DOWARN
, pwd
->pw_uid
, (dev_t
)-1, 0);
if (*pwd
->pw_shell
== '\0')
pwd
->pw_shell
= _PATH_BSHELL
;
/* destroy environment unless user has requested preservation */
(void)setenv("HOME", pwd
->pw_dir
, 1);
(void)setenv("SHELL", pwd
->pw_shell
, 1);
strncpy(term
, stypeof(tty
), sizeof(term
));
(void)setenv("TERM", term
, 0);
(void)setenv("USER", pwd
->pw_name
, 1);
(void)setenv("PATH", _PATH_DEFPATH
, 0);
if (tty
[sizeof("tty")-1] == 'd')
syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
syslog(LOG_NOTICE
, "ROOT LOGIN ON %s FROM %s",
syslog(LOG_NOTICE
, "ROOT LOGIN ON %s", tty
);
(void)sprintf(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
);
strcpy(tbuf
+ 1, (p
= rindex(pwd
->pw_shell
, '/')) ?
if (setlogname(pwd
->pw_name
, strlen(pwd
->pw_name
)) < 0)
syslog(LOG_ERR
, "setlogname() 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
, "login: no shell: %s.\n", strerror(errno
));
static char nbuf
[UT_NAMESIZE
+ 1];
for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
if (p
< nbuf
+ UT_NAMESIZE
)
"login names may not start with '-'.\n");
(void)fprintf(stderr
, "Login timed out after %d seconds\n", timeout
);
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);
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",
sizeof(ll
.ll_host
), ll
.ll_host
);
(void)printf("on %.*s\n",
sizeof(ll
.ll_line
), ll
.ll_line
);
(void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
bzero((char *)&ll
, sizeof(ll
));
strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
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, %s",
failures
, failures
> 1 ? "S" : "", hostname
, name
);
syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s ON %s, %s",
failures
, failures
> 1 ? "S" : "", tty
, name
);
return(ttyid
&& (t
= getttynam(ttyid
)) ? t
->ty_type
: UNKNOWN
);
if (read(0, &ch
, sizeof(ch
)) != sizeof(ch
))
(void)fprintf(stderr
, "%s too long\r\n", err
);
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");
pwd
= getpwnam(username
);
return(ruserok(host
, (pwd
->pw_uid
== 0), rusername
, username
));
"0", "50", "75", "110", "134", "150", "200", "300", "600",
"1200", "1800", "2400", "4800", "9600", "19200", "38400",
#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
register char *cp
= index(term
, '/'), **cpp
;
for (cpp
= speeds
; cpp
< &speeds
[NSPEEDS
]; cpp
++)
if (strcmp(*cpp
, speed
) == 0) {
tp
->sg_ispeed
= tp
->sg_ospeed
= cpp
-speeds
;
tp
->sg_flags
= ECHO
|CRMOD
|ANYP
|XTABS
;