[551] in Kerberos-V5-bugs
login.c
daemon@ATHENA.MIT.EDU (Brian Kantor)
Thu Jun 30 16:04:01 1994
Date: Thu, 30 Jun 1994 13:03:35 -0700
From: brian@nothing.ucsd.edu (Brian Kantor)
To: krb5-bugs@MIT.EDU
I enclose 'login.c' which I have heavily patched by ripping out all of
the KRB4 code and sticking in krb5 code. We're successfully using this
on a small cluster of Sun SPARCS running Sunix 4.1.3U2 without any
problems. Kerberos V5B3.
Note that this login is set up to automatically issue a ticket when you
log in and authenticate locally, so for most users, the 'kinit' program
doesn't have to be separately invoked.
The diffs would have been larger than the source, so here's the whole
thing.
- Brian
/*
* $Source: /mit/krb5/.cvsroot/src/appl/bsd/login.c,v $
* $Author: tytso $
* $Id: Exp $
*
* look for 'SITE' for configuration options
*
*/
#ifndef lint
static char rcsid_login_c[] = "$Id: $";
#endif lint
/*
* Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
* All rights reserved.
*
* 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.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89";
#endif /* not lint */
#define DEFPATH "/usr/local/bin:/usr/bin/X11:/usr/ucb:/bin:/usr/bin:/usr/kerberos/bin:."
/*
* login [ name ]
* login -r hostname (for rlogind)
* login -h hostname (for telnetd, etc.)
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
* login -e name (for pre-authenticated encrypted, must do term
* negotiation)
* ifdef KERBEROS
* login -k hostname (for Kerberos V5 rlogind with password access)
* login -K hostname (for Kerberos V5 rlogind with restricted access)
* endif KERBEROS
*
* only one of: -r -f -e -k -K
* only one of: -r -h -k -K
*/
#include <sys/types.h>
#include <sys/param.h>
#ifdef OQUOTA
#include <sys/quota.h>
#endif
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <utmp.h>
#include <signal.h>
#include <lastlog.h>
#include <errno.h>
#ifndef NOTTYENT
#include <ttyent.h>
#endif /* NOTTYENT */
#include <syslog.h>
#include <grp.h>
#include <pwd.h>
#include <setjmp.h>
#include <stdio.h>
#include <strings.h>
#include <string.h>
#ifdef POSIX
#include <stdlib.h>
#include <termios.h>
#endif
#ifdef UIDGID_T
uid_t getuid();
#define uid_type uid_t
#define gid_type gid_t
#else
int getuid();
#define uid_type int
#define gid_type int
#endif /* UIDGID_T */
#define TTYGRPNAME "tty" /* name of group to own ttys */
#define MOTDFILE "/etc/motd"
#define MAILDIR "/var/spool/mail"
#define NOLOGIN "/etc/nologin"
#define HUSHLOGIN ".hushlogin"
#define LASTLOG "/var/adm/lastlog"
#define BSHELL "/bin/sh"
#if !defined(OQUOTA) && !defined(QUOTAWARN)
#define QUOTAWARN "/usr/ucb/quota" /* warn user about quotas */
#endif
#define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
#define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
#define MAXENVIRON 32
#ifdef KERBEROS
#define KRB5_DEFAULT_OPTIONS 0
#define KRB5_DEFAULT_LIFE 60*60*8 /* 8 hours */
/*
* WARNING: Danger Will Robinson: the following filenames are stupidly
* hard-coded elsewhere in Kerberos and MUST match that in
* lib/ccache/cc_defname or you are in deep shit.
*
* you have to do it this way or else someone failing to log in to your
* username on your machine will destroy your perfectly-valid
* credentials cache, which is a denial of service you betcha!
*/
#define TKT_ROOT "FILE:/tmp/krb5cc_"
#define TKT_RTMP "FILE:/tmp/#krb5cc_"
#include <krb5/krb5.h>
#include <krb5/ext-proto.h>
#include <krb5/los-proto.h>
#include <com_err.h>
krb5_ccache ccache;
krb5_address **my_addresses;
krb5_error_code krb5_err;
krb5_principal me;
krb5_principal server;
krb5_creds my_creds;
krb5_timestamp now;
int preauth_type = -1;
krb5_keytab keytab = NULL;
krb5_keytab_entry kt_ent;
char password[255], *client_name, tmpcf[128], tmpcn[128];
int pwsize;
krb5_data tgtname = { KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
#endif /* KERBEROS */
/*
* This bounds the time given to login. Not a define so it can
* be patched on machines where it's too small.
*/
int timeout = 300;
struct passwd *pwd;
char term[64], *hostname, *username;
#ifndef POSIX
struct sgttyb sgttyb;
struct tchars tc = {
CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
};
struct ltchars ltc = {
CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
};
#endif
extern int errno;
char *getenv();
char *strsave();
#ifdef POSIX
typedef void sigtype;
#else
typedef int sigtype;
#endif /* POSIX */
#define EXCL_AUTH_TEST if (rflag || kflag || Kflag || eflag) { \
fprintf(stderr, \
"login: only one of -r, -k, -K, -e, and -f allowed.\n"); \
exit(1);\
}
#define EXCL_HOST_TEST if (rflag || kflag || Kflag || hflag) { \
fprintf(stderr, \
"login: only one of -r, -k, -K, and -h allowed.\n"); \
exit(1);\
}
main(argc, argv)
int argc;
char **argv;
{
extern int optind;
extern char *optarg, **environ;
struct group *gr;
register int ch, i;
register char *p;
int fflag, hflag, pflag, rflag, cnt;
int kflag, Kflag, eflag;
int quietlog, passwd_req, ioctlval;
sigtype timedout();
int lpass_ok = 0;
int kpass_ok = 0;
char *domain, *salt, **envinit, *ttyn, *tty, *ktty;
char tbuf[MAXPATHLEN + 2];
char *ttyname(), *stypeof(), *crypt(), *getpass();
time_t time(), login_time;
off_t lseek();
#ifdef POSIX
struct termios tc;
#endif
(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);
#ifdef OQUOTA
(void)quota(Q_SETUID, 0, 0, 0);
#endif
/*
* -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
* -e is used to skip a second login authentication, but allows
* login as root.
* -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
* -k is used by klogind to cause the Kerberos V4 autologin protocol;
* -K is used by klogind to cause the Kerberos V4 autologin
* protocol with restricted access.
*/
(void)gethostname(tbuf, sizeof(tbuf));
domain = strchr(tbuf, '.');
fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
passwd_req = 1;
while ((ch = getopt(argc, argv, "feh:pr:k:K:")) != EOF)
switch (ch) {
case 'f':
EXCL_AUTH_TEST;
fflag = 1;
break;
case 'h':
EXCL_HOST_TEST;
if (getuid()) {
fprintf(stderr,
"login: -h for super-user only.\n");
exit(1);
}
hflag = 1;
if (domain && (p = strchr(optarg, '.')) &&
strcmp(p, domain) == 0)
*p = 0;
hostname = optarg;
break;
case 'p':
pflag = 1;
break;
case 'r':
EXCL_AUTH_TEST;
EXCL_HOST_TEST;
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 = strchr(optarg, '.')) &&
!strcmp(p, domain))
*p = '\0';
hostname = optarg;
break;
#ifdef KERBEROS
case 'k':
case 'K':
EXCL_AUTH_TEST;
EXCL_HOST_TEST;
if (getuid()) {
fprintf(stderr,
"login: -%c for super-user only.\n", ch);
exit(1);
}
/* "-k hostname" must be last args */
if (optind != argc) {
fprintf(stderr, "Syntax error.\n");
exit(1);
}
if (ch == 'K')
Kflag = 1;
else
kflag = 1;
passwd_req = 1;
if (domain && (p = strchr(optarg, '.')) &&
!strcmp(p, domain))
*p = '\0';
hostname = optarg;
break;
#endif /* KERBEROS */
case 'e':
EXCL_AUTH_TEST;
if (getuid()) {
fprintf(stderr,
"login: -e for super-user only.\n");
exit(1);
}
eflag = 1;
passwd_req = 0;
break;
case '?':
default:
fprintf(stderr, "usage: login [-fp] [username]\n");
exit(1);
}
argc -= optind;
argv += optind;
if (*argv)
username = *argv;
ioctlval = 0;
(void)ioctl(0, TIOCLSET, (char *)&ioctlval);
(void)ioctl(0, TIOCNXCL, (char *)0);
(void)fcntl(0, F_SETFL, ioctlval);
#ifdef POSIX
(void)tcgetattr(0, &tc);
#else
(void)ioctl(0, TIOCGETP, (char *)&sgttyb);
#endif
/*
* If talking to an rlogin process, propagate the terminal type and
* baud rate across the network.
*/
if (eflag)
lgetstr(term, sizeof(term), "Terminal type");
#ifdef POSIX
if (rflag || kflag || Kflag || eflag)
doremoteterm(&tc);
tc.c_cc[VMIN] = 1;
tc.c_cc[VTIME] = 0;
tc.c_cc[VERASE] = CERASE;
tc.c_cc[VKILL] = CKILL;
tc.c_cc[VEOF] = CEOF;
tc.c_cc[VINTR] = CINTR;
tc.c_cc[VQUIT] = CQUIT;
tc.c_cc[VSTART] = CSTART;
tc.c_cc[VSTOP] = CSTOP;
tc.c_cc[VEOL] = CNUL;
/* The following are common extensions to POSIX */
#ifdef VEOL2
tc.c_cc[VEOL2] = CNUL;
#endif
#ifdef VSUSP
tc.c_cc[VSUSP] = CSUSP;
#endif
#ifdef VDSUSP
tc.c_cc[VDSUSP] = CDSUSP;
#endif
#ifdef VLNEXT
tc.c_cc[VLNEXT] = CLNEXT;
#endif
#ifdef VREPRINT
tc.c_cc[VREPRINT] = CRPRNT;
#endif
#ifdef VDISCRD
tc.c_cc[VDISCRD] = CFLUSH;
#endif
#ifdef VWERSE
tc.c_cc[VWERSE] = CWERASE;
#endif
tcsetattr(0, TCSANOW, &tc);
#else
if (rflag || kflag || Kflag || eflag)
doremoteterm(&sgttyb);
sgttyb.sg_erase = CERASE;
sgttyb.sg_kill = CKILL;
(void)ioctl(0, TIOCSLTC, (char *)<c);
(void)ioctl(0, TIOCSETC, (char *)&tc);
(void)ioctl(0, TIOCSETP, (char *)&sgttyb);
#endif
for (cnt = getdtablesize(); cnt > 2; cnt--)
(void) close(cnt);
ttyn = ttyname(0);
if (ttyn == NULL || *ttyn == '\0')
ttyn = "/dev/tty??";
/* This allows for tty names of the form /dev/pts/4 as well */
if ((tty = strchr(ttyn, '/')) && (tty = strchr(tty+1, '/')))
++tty;
else
tty = ttyn;
/* For kerberos tickets, extract only the last part of the ttyname */
if (ktty = strrchr(tty, '/'))
++ktty;
else
ktty = tty;
openlog("login", LOG_ODELAY, LOG_AUTH);
#ifdef KERBEROS
/* initialize kerberos stuff */
krb5_init_ets();
#endif
for (cnt = 0;; username = NULL) {
if (username == NULL) {
fflag = 0;
getloginname();
}
if (pwd = getpwnam(username))
salt = pwd->pw_passwd;
else
salt = "xx"; /* dummy */
/* =====================================================
* LOCAL SITE POLICY DECISION
* you have to change the following tests to suit your
* site's login policy regarding local (system password)
* vs Kerberos passwords vs root
* ===================================================== */
/*
* if user is not the super-user,
* check for disabled logins
*/
if (pwd == NULL || pwd->pw_uid)
checknologin();
/*
* if 'fflag' is set to purport that the user
* has already been authenticated, be sure that
* 1) it's not root he's trying to log in as AND
* 2a) root is doing it, OR
* 2b) he's logging in as himself
* otherwise require a password be entered
*/
if (fflag && pwd) {
int uid = (int)getuid();
passwd_req = (pwd->pw_uid == 0)
|| (uid && uid != pwd->pw_uid);
}
/*
* if a password isn't required (because of some other
* kind of authentication has reset 'passwd_req', or
* there's no password in the local passwd file, don't
* bother to prompt for a password, just procede
*/
if (passwd_req == 0 || (pwd && *pwd->pw_passwd == NULL))
break;
#ifdef KERBEROS
pwsize = sizeof(password);
memset(password, 0, sizeof(password));
krb5_err = krb5_read_password("Password: ",
0, password, &pwsize);
if (krb5_err) {
memset(password, 0, sizeof(password));
krb5_free_addresses(my_addresses);
printf("Error reading password\r\n");
exit(1);
}
/*
* check the password against the kerberos server
*
* note that most errors are silently ignored to avoid
* probes of the kerberos server
*
* most of this code stolen from the KINIT program
*/
kpass_ok = 0;
ccache = NULL;
if (pwd == NULL)
goto krberr;
sprintf(tmpcf, "%s%d", TKT_RTMP, pwd->pw_uid);
sprintf(tmpcn, "%s%d", TKT_ROOT, pwd->pw_uid);
if (krb5_cc_resolve(tmpcf, &ccache))
goto krberr;
if (krb5_parse_name(username, &me))
goto krberr;
if (krb5_unparse_name(me, &client_name))
goto krberr;
if (krb5_cc_initialize(ccache, me))
goto krberr;
memset((char *)&my_creds, 0, sizeof(my_creds));
my_creds.client = me;
if ( krb5_build_principal_ext( &server,
krb5_princ_realm(me)->length,
krb5_princ_realm(me)->data,
tgtname.length,
tgtname.data,
krb5_princ_realm(me)->length,
krb5_princ_realm(me)->data,
0 ) )
goto krberr;
my_creds.server = server;
if (krb5_os_localaddr(&my_addresses))
goto krberr;
if (krb5_timeofday(&now))
goto krberr;
my_creds.times.starttime = 0;
my_creds.times.endtime = now + KRB5_DEFAULT_LIFE;
my_creds.times.renew_till = 0;
if ( krb5_get_in_tkt_with_password(
KRB5_DEFAULT_OPTIONS,
my_addresses,
KRB5_PADATA_NONE,
ETYPE_DES_CBC_CRC,
KEYTYPE_DES,
password,
ccache,
&my_creds, 0 ) == 0)
{
kpass_ok = 1;
krb5_free_principal(server);
krb5_free_addresses(my_addresses);
}
else
{
krberr:
kpass_ok = 0;
if (ccache)
(void)krb5_cc_destroy(ccache);
}
#else /* !KERBEROS */
strcpy(password, getpass("Password:"));
#endif /* !KERBEROS */
/* check the password against the password file */
lpass_ok = 0;
password[8] = 0; /* truncate to 8 chars */
p = crypt(password,salt);
if (pwd && strcmp(p, pwd->pw_passwd) == 0)
lpass_ok = 1; /* his passwd is ok in passwd file */
memset(password, 0, sizeof(password)); /* zap */
/* SITE local vs kerberos password */
if (pwd && (lpass_ok || kpass_ok))
break;
printf("Login incorrect\n");
if (++cnt >= 2) {
if (hostname)
syslog(LOG_ERR,
"REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
username);
else
syslog(LOG_ERR,
"REPEATED LOGIN FAILURES ON %s, %.*s",
tty, UT_NAMESIZE, username);
(void)ioctl(0, TIOCHPCL, (char *)0);
sleepexit(1);
}
}
/* committed to login -- turn off timeout */
(void)alarm((u_int)0);
/*
* If valid so far and root is logging in, see if root logins on
* this terminal are permitted.
*
* We allow authenticated remote root logins (except -r style)
*/
if (pwd->pw_uid == 0 && !rootterm(tty) && (passwd_req || rflag)) {
if (hostname)
syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
tty, UT_HOSTSIZE, hostname);
else
syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
printf("Login incorrect\n");
sleepexit(1);
}
#ifdef OQUOTA
if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
switch(errno) {
case EUSERS:
fprintf(stderr,
"Too many users logged on already.\nTry again later.\n");
break;
case EPROCLIM:
fprintf(stderr,
"You have too many processes running.\n");
break;
default:
perror("quota (Q_SETUID)");
}
sleepexit(0);
}
#endif
if (hostname)
syslog(LOG_INFO, "%s on %s from %.*s",
pwd->pw_name, tty, UT_HOSTSIZE, hostname);
else
syslog(LOG_INFO, "%s on %s", pwd->pw_name, tty);
#ifdef KERBEROS
/* change the scratch credentials cache to a real one */
rename(tmpcf+5, tmpcn+5);
(void)chown(tmpcn+5, pwd->pw_uid, pwd->pw_gid);
unlink(tmpcf+5);
#endif
if (chdir(pwd->pw_dir) < 0) {
syslog(LOG_ERR, "%s no home directory %s",
pwd->pw_name, pwd->pw_dir);
printf("No directory %s!\n", pwd->pw_dir);
if (chdir("/"))
exit(0);
pwd->pw_dir = "/";
printf("Logging in with home = \"/\".\n");
}
/* nothing else left to fail -- really log in */
{
struct utmp utmp;
bzero((char *)&utmp, sizeof(utmp));
login_time = 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));
else
bzero(utmp.ut_host, sizeof(utmp.ut_host));
(void) strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
login(&utmp);
}
quietlog = access(HUSHLOGIN, F_OK) == 0;
dolastlog(quietlog, tty);
if (!hflag && !rflag && !kflag && !Kflag && !eflag) { /* XXX */
static struct winsize win = { 0, 0, 0, 0 };
(void)ioctl(0, TIOCSWINSZ, (char *)&win);
}
(void)chown(ttyn, pwd->pw_uid,
(gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
(void)chmod(ttyn, 0620);
(void)setgid((gid_type) pwd->pw_gid);
(void) initgroups(username, pwd->pw_gid);
#ifdef OQUOTA
quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
#endif
/* This call MUST succeed */
if(setuid((uid_type) pwd->pw_uid) < 0) {
perror("setuid");
sleepexit(1);
}
if (*pwd->pw_shell == '\0')
pwd->pw_shell = BSHELL;
/* turn on new line discipline for the csh */
else if (!strcmp(pwd->pw_shell, "/bin/csh")) {
ioctlval = NTTYDISC;
(void)ioctl(0, TIOCSETD, (char *)&ioctlval);
}
/* destroy environment unless user has requested preservation */
envinit = (char **)malloc(MAXENVIRON * sizeof(char *));
if (envinit == 0) {
fprintf(stderr, "Can't malloc empty environment.\n");
sleepexit(1);
}
if (!pflag)
environ = envinit;
i = 0;
sprintf(tbuf,"LOGNAME=%s",pwd->pw_name);
envinit[i++] = strsave(tbuf);
sprintf(tbuf,"LOGIN=%s",pwd->pw_name);
envinit[i++] = strsave(tbuf);
envinit[i++] = NULL;
setenv("HOME", pwd->pw_dir, 0);
setenv("PATH", DEFPATH, 0);
setenv("USER", pwd->pw_name, 0);
setenv("SHELL", pwd->pw_shell, 0);
if (hostname)
setenv("RHOST", hostname, 0);
if (term[0] == '\0')
(void) strncpy(term, stypeof(tty), sizeof(term));
(void)setenv("TERM", term, 0);
/* root logins */
if (pwd->pw_uid == 0)
if (hostname)
#ifdef KERBEROS
if (kpass_ok) {
char buf[BUFSIZ];
syslog("ROOT LOGIN (krb) %s from %.*s, %s",
tty, UT_HOSTSIZE, hostname, client_name);
} else {
#endif /* KERBEROS */
syslog(LOG_NOTICE, "ROOT LOGIN on %s FROM %.*s",
tty, UT_HOSTSIZE, hostname);
#ifdef KERBEROS
}
else
if (kpass_ok) {
syslog(LOG_NOTICE, "ROOT LOGIN (krb) %s, %s",
tty, client_name);
}
#endif /* KERBEROS */
else
syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
if (!quietlog) {
struct stat st;
motd();
#ifdef KERBEROS
if (kpass_ok)
printf("\nKERBEROS ticket obtained.\n\n");
else
printf("\nWarning: NO Kerberos tickets obtained.\n\n");
#endif /* KERBEROS */
(void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name);
if (stat(tbuf, &st) == 0 && st.st_size != 0)
printf("You have %smail.\n",
(st.st_mtime > st.st_atime) ? "new " : "");
}
#ifndef OQUOTA
if (!access(QUOTAWARN, X_OK))
(void) system(QUOTAWARN);
#endif
(void)signal(SIGALRM, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGTSTP, SIG_IGN);
tbuf[0] = '-';
(void) strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
p + 1 : pwd->pw_shell);
execlp(pwd->pw_shell, tbuf, 0);
syslog(LOG_ERR, "%s no shell %s", pwd->pw_name, pwd->pw_shell);
fprintf(stderr, "login: no shell: ");
perror(pwd->pw_shell);
exit(0);
}
getloginname()
{
register int ch;
register char *p;
static char nbuf[UT_NAMESIZE + 1];
for (;;) {
printf("login: ");
for (p = nbuf; (ch = getchar()) != '\n'; ) {
if (ch == EOF)
exit(0);
if (p < nbuf + UT_NAMESIZE)
*p++ = ch;
}
if (p > nbuf)
if (nbuf[0] == '-')
fprintf(stderr,
"login names may not start with '-'.\n");
else {
*p = '\0';
username = nbuf;
break;
}
}
}
char *strsave(s)
char *s;
{
char *ret = (char *)malloc(strlen(s) + 1);
strcpy(ret, s);
return(ret);
}
sigtype
timedout()
{
fprintf(stderr, "Login timed out after %d seconds\n", timeout);
exit(0);
}
#ifdef NOTTYENT
int root_tty_security = 1;
#endif
rootterm(tty)
char *tty;
{
#ifdef NOTTYENT
return(root_tty_security);
#else
struct ttyent *t;
return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
#endif /* NOTTYENT */
}
jmp_buf motdinterrupt;
motd()
{
register int fd, nchars;
sigtype (*oldint)(), sigint();
char tbuf[8192];
if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
return;
oldint = (void *)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);
}
sigtype
sigint()
{
longjmp(motdinterrupt, 1);
}
checknologin()
{
register int fd, nchars;
char tbuf[8192];
if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
(void)write(fileno(stdout), tbuf, nchars);
sleepexit(0);
}
}
dolastlog(quiet, tty)
int quiet;
char *tty;
{
struct lastlog ll;
int fd;
if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
if (!quiet) {
if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
ll.ll_time != 0) {
printf("Last login: %.*s ",
24-5, (char *)ctime(&ll.ll_time));
if (*ll.ll_host != '\0')
printf("from %.*s\n",
sizeof(ll.ll_host), ll.ll_host);
else
printf("on %.*s\n",
sizeof(ll.ll_line), ll.ll_line);
}
(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
}
(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));
else
(void) bzero(ll.ll_host, sizeof(ll.ll_host));
(void)write(fd, (char *)&ll, sizeof(ll));
(void)close(fd);
}
}
#undef UNKNOWN
#define UNKNOWN "su"
char *
stypeof(ttyid)
char *ttyid;
{
#ifdef NOTTYENT
return(UNKNOWN);
#else
struct ttyent *t;
return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
#endif
}
doremotelogin(host)
char *host;
{
static char lusername[UT_NAMESIZE+1];
char rusername[UT_NAMESIZE+1];
lgetstr(rusername, sizeof(rusername), "Remote user");
lgetstr(lusername, sizeof(lusername), "Local user");
lgetstr(term, sizeof(term), "Terminal type");
username = lusername;
pwd = getpwnam(username);
if (pwd == NULL)
return(-1);
return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
}
lgetstr(buf, cnt, err)
char *buf, *err;
int cnt;
{
int ocnt = cnt;
char *obuf = buf;
char ch;
do {
if (read(0, &ch, sizeof(ch)) != sizeof(ch))
exit(1);
if (--cnt < 0) {
fprintf(stderr,"%s '%.*s' too long, %d characters maximum.\r\n",
err, ocnt, obuf, ocnt-1);
sleepexit(1);
}
*buf++ = ch;
} while (ch);
}
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)
#ifdef POSIX
struct termios *tp;
#else
struct sgttyb *tp;
#endif
{
register char *cp = strchr(term, '/'), **cpp;
char *speed;
if (cp) {
*cp++ = '\0';
speed = cp;
cp = strchr(speed, '/');
if (cp)
*cp++ = '\0';
for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
if (strcmp(*cpp, speed) == 0) {
#ifdef POSIX
tp->c_cflag =
(tp->c_cflag & ~CBAUD) | (cpp-speeds);
#else
tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
#endif
break;
}
}
#ifdef POSIX
/* set all standard echo, edit, and job control options */
tp->c_lflag = ECHO|ECHOE|ECHOK|ICANON|ISIG;
tp->c_iflag |= ICRNL|BRKINT;
tp->c_oflag |= ONLCR|OPOST|TAB3;
#else /* !POSIX */
tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
#endif
}
sleepexit(eval)
int eval;
{
(void)krb5_cc_destroy(ccache);
sleep((u_int)5);
exit(eval);
}