* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
static char sccsid
[] = "@(#)login.c 5.2 (Berkeley) %G%";
* login -r hostname (for rlogind)
* login -h hostname (for telnetd, etc.)
#include <sys/resource.h>
#define SCMPN(a, b) strncmp(a, b, sizeof(a))
#define SCPYN(a, b) strncpy(a, b, sizeof(a))
#define NMAX sizeof(utmp.ut_name)
char nolog
[] = "/etc/nologin";
char qlog
[] = ".hushlogin";
char maildir
[30] = "/usr/spool/mail/";
char lastlog
[] = "/usr/adm/lastlog";
struct passwd nouser
= {"", "nope", -1, -1, -1, "", "", "", "" };
char *envinit
[] = { 0 }; /* now set by setenv calls */
* This bounds the time given to login. We initialize it here
* so it can be patched on machines where it's too small.
char *strcat(), *rindex(), *index(), *malloc(), *realloc();
CINTR
, CQUIT
, CSTART
, CSTOP
, CEOT
, CBRK
CSUSP
, CDSUSP
, CRPRNT
, CFLUSH
, CWERASE
, CLNEXT
struct winsize win
= { 0, 0, 0, 0 };
char rusername
[NMAX
+1], lusername
[NMAX
+1];
int pflag
= 0, hflag
= 0, t
, f
, c
;
int ldisc
= 0, zero
= 0, i
;
signal(SIGALRM
, timedout
);
signal(SIGQUIT
, SIG_IGN
);
setpriority(PRIO_PROCESS
, 0, 0);
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;
* -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 (strcmp(argv
[1], "-r") == 0) {
rflag
= doremotelogin(argv
[2]);
SCPYN(utmp
.ut_host
, argv
[2]);
if (strcmp(argv
[1], "-h") == 0 && getuid() == 0) {
SCPYN(utmp
.ut_host
, argv
[2]);
if (strcmp(argv
[1], "-p") == 0) {
ioctl(0, TIOCLSET
, &zero
);
ioctl(0, FIONBIO
, &zero
);
ioctl(0, FIOASYNC
, &zero
);
ioctl(0, TIOCGETP
, &ttyb
);
* If talking to an rlogin process,
* propagate the terminal type and
* baud rate across the network.
doremoteterm(term
, &ttyb
);
ioctl(0, TIOCSLTC
, <c
);
ioctl(0, TIOCSETP
, &ttyb
);
for (t
= getdtablesize(); t
> 3; t
--)
openlog("login", LOG_ODELAY
, 0);
ioctl(0, TIOCSETD
, &ldisc
);
* Name specified, take it.
SCPYN(utmp
.ut_name
, argv
[1]);
* If remote login take given name,
* otherwise prompt user for something.
SCPYN(utmp
.ut_name
, lusername
);
/* autologin failed, prompt for passwd */
if (!strcmp(pwd
->pw_shell
, "/bin/csh")) {
ioctl(0, TIOCSETD
, &ldisc
);
* If no remote login authentication and
* a password exists for this user, prompt
if (!rflag
&& *pwd
->pw_passwd
!= '\0') {
setpriority(PRIO_PROCESS
, 0, -4);
pp
= getpass("Password:");
namep
= crypt(pp
, pwd
->pw_passwd
);
setpriority(PRIO_PROCESS
, 0, 0);
if (strcmp(namep
, pwd
->pw_passwd
))
* If user not super-user, check for logins disabled.
if (pwd
->pw_uid
!= 0 && (nlfd
= fopen(nolog
, "r")) > 0) {
while ((c
= getc(nlfd
)) != EOF
)
* If valid so far and root is logging in,
* see if root logins on this terminal are permitted.
if (!invalid
&& pwd
->pw_uid
== 0 && !rootterm(tty
)) {
syslog(LOG_SECURITY
, "ROOT LOGIN REFUSED %s", tty
);
printf("Login incorrect\n");
"REPEATED LOGIN FAILURES %s, %s",
ioctl(0, TIOCHPCL
, (struct sgttyb
*) 0);
close(0), close(1), close(2);
if (*pwd
->pw_shell
== '\0')
pwd
->pw_shell
= "/bin/sh";
if (chdir(pwd
->pw_dir
) < 0 && !invalid
) {
printf("No directory!\n");
printf("No directory! %s\n",
"Logging in with home=/");
* Remote login invalid must have been because
* of a restriction of some sort, no extra chances.
/* committed to login turn off timeout */
if (quota(Q_SETUID
, pwd
->pw_uid
, 0, 0) < 0 && errno
!= EINVAL
) {
"Too many users logged on already",
else if (errno
== EPROCLIM
)
printf("You have too many processes running.\n");
perror("quota (Q_SETUID)");
if (t
> 0 && (f
= open("/etc/utmp", O_WRONLY
)) >= 0) {
lseek(f
, (long)(t
*sizeof(utmp
)), 0);
SCPYN(utmp
.ut_line
, tty
);
write(f
, (char *)&utmp
, sizeof(utmp
));
if ((f
= open("/usr/adm/wtmp", O_WRONLY
|O_APPEND
)) >= 0) {
write(f
, (char *)&utmp
, sizeof(utmp
));
quietlog
= access(qlog
, F_OK
) == 0;
if ((f
= open(lastlog
, O_RDWR
)) >= 0) {
lseek(f
, (long)pwd
->pw_uid
* sizeof (struct lastlog
), 0);
if (read(f
, (char *) &ll
, sizeof ll
) == sizeof ll
&&
ll
.ll_time
!= 0 && !quietlog
) {
printf("Last login: %.*s ",
24-5, (char *)ctime(&ll
.ll_time
));
sizeof (ll
.ll_host
), ll
.ll_host
);
sizeof (ll
.ll_line
), ll
.ll_line
);
lseek(f
, (long)pwd
->pw_uid
* sizeof (struct lastlog
), 0);
SCPYN(ll
.ll_host
, utmp
.ut_host
);
write(f
, (char *) &ll
, sizeof ll
);
chown(ttyn
, pwd
->pw_uid
, pwd
->pw_gid
);
ioctl(0, TIOCSWINSZ
, &win
);
strncpy(name
, utmp
.ut_name
, NMAX
);
initgroups(name
, pwd
->pw_gid
);
quota(Q_DOWARN
, pwd
->pw_uid
, (dev_t
)-1, 0);
/* destroy environment unless user has asked to preserve it */
/* set up environment, this time without destruction */
/* copy the environment before setenving */
while (environ
[i
] != NULL
)
envnew
= (char **) malloc(sizeof (char *) * (i
+ 1));
setenv("HOME=", pwd
->pw_dir
);
setenv("SHELL=", pwd
->pw_shell
);
strncpy(term
, stypeof(tty
), sizeof(term
));
setenv("USER=", pwd
->pw_name
);
setenv("PATH=", ":/usr/ucb:/bin:/usr/bin");
if ((namep
= rindex(pwd
->pw_shell
, '/')) == NULL
)
if (tty
[sizeof("tty")-1] == 'd')
syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
syslog(LOG_SECURITY
, "ROOT LOGIN %s", tty
);
strcat(maildir
, pwd
->pw_name
);
if (stat(maildir
, &st
) == 0 && st
.st_size
!= 0)
printf("You have %smail.\n",
(st
.st_mtime
> st
.st_atime
) ? "new " : "");
signal(SIGALRM
, SIG_DFL
);
signal(SIGQUIT
, SIG_DFL
);
signal(SIGTSTP
, SIG_IGN
);
execlp(pwd
->pw_shell
, minusnam
, 0);
register struct utmp
*up
;
while (up
->ut_name
[0] == '\0') {
while ((c
= getchar()) != '\n') {
if (namep
< up
->ut_name
+NMAX
)
strncpy(lusername
, up
->ut_name
, NMAX
);
if ((pwd
= getpwnam(lusername
)) == NULL
)
printf("Login timed out after %d seconds\n", timeout
);
register struct ttyent
*t
;
if ((t
= getttynam(tty
)) != NULL
) {
if (t
->ty_status
& TTY_SECURE
)
if ((mf
= fopen("/etc/motd", "r")) != NULL
) {
while ((c
= getc(mf
)) != EOF
&& stopmotd
== 0)
register struct ttyent
*t
;
if (ttyid
== NULL
|| (t
= getttynam(ttyid
)) == NULL
)
getstr(rusername
, sizeof (rusername
), "remuser");
getstr(lusername
, sizeof (lusername
), "locuser");
getstr(term
, sizeof(term
), "Terminal type");
pwd
= getpwnam(lusername
);
hostf
= pwd
->pw_uid
? fopen("/etc/hosts.equiv", "r") : 0;
while (fgets(ahost
, sizeof (ahost
), hostf
)) {
while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' && *p
!= '\0')
if (*p
== ' ' || *p
== '\t') {
while (*p
== ' ' || *p
== '\t')
while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' && *p
!= '\0')
if (!strcmp(host
, ahost
) &&
!strcmp(rusername
, *user
? user
: lusername
)) {
char *rhosts
= ".rhosts";
if (chdir(pwd
->pw_dir
) < 0)
if (lstat(rhosts
, &sbuf
) < 0)
if ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
) {
printf("login: .rhosts is a soft link.\r\n");
hostf
= fopen(rhosts
, "r");
fstat(fileno(hostf
), &sbuf
);
if (sbuf
.st_uid
&& sbuf
.st_uid
!= pwd
->pw_uid
) {
printf("login: Bad .rhosts ownership.\r\n");
printf("%s too long\r\n", err
);
{ "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
;
ws
.ws_row
= ws
.ws_col
= -1;
ws
.ws_xpixel
= ws
.ws_ypixel
= -1;
ws
.ws_xpixel
= atoi(++cp
);
ws
.ws_ypixel
= atoi(++cp
);
if (ws
.ws_row
!= -1 && ws
.ws_col
!= -1 &&
ws
.ws_xpixel
!= -1 && ws
.ws_ypixel
!= -1)
tp
->sg_flags
= ECHO
|CRMOD
|ANYP
|XTABS
;
* Set the value of var to be arg in the Unix 4.2 BSD environment env.
* Var should end with '='.
* (bindings are of the form "var=value")
* This procedure assumes the memory for the first level of environ
* was allocated using malloc.
int varlen
= strlen(var
);
int vallen
= strlen(value
);
for (index
= 0; environ
[index
] != NULL
; index
++) {
if (strncmp(environ
[index
], var
, varlen
) == 0) {
environ
[index
] = malloc(varlen
+ vallen
+ 1);
strcpy(environ
[index
], var
);
strcat(environ
[index
], value
);
environ
= (char **) realloc(environ
, sizeof (char *) * (index
+ 2));
fprintf(stderr
, "login: malloc out of memory\n");
environ
[index
] = malloc(varlen
+ vallen
+ 1);
strcpy(environ
[index
], var
);
strcat(environ
[index
], value
);