5328c7eb7e
on rshd and rlogind. However, note that: 1: rshd used to drop a connection with -a if the hostname != ip address. This is unneeded, because iruserok() does it's own checking. It was also wrong if .rhosts had an explicit IP address in it, connections would be dropped from that host solely because the DNS was mismatched even though it was explicitly intended to work by IP address. 2: rlogind and rshd check the hostname mappings by default now because that is what goes into the utmp/wtmp and logs. If the hostname != ip address, then it uses the IP address for logging/utmp/wtmp purposes. There isn't much point logging ficticious hostnames. 3: rshd -a is now accepted (but ignored) for compatability. If you really want to make life miserable for people with bad reverse DNS, use tcpd in paranoid mode (which is questionable anyway, given DNS ttl tweaking).
761 lines
17 KiB
C
761 lines
17 KiB
C
/*-
|
|
* Copyright (c) 1983, 1988, 1989, 1993
|
|
* 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
|
|
* 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
|
|
static const char copyright[] =
|
|
"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
|
|
The Regents of the University of California. All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
#if 0
|
|
static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
|
|
#endif
|
|
static const char rcsid[] =
|
|
"$Id: rlogind.c,v 1.19 1997/11/25 07:17:15 charnier Exp $";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* remote login server:
|
|
* \0
|
|
* remuser\0
|
|
* locuser\0
|
|
* terminal_type/speed\0
|
|
* data
|
|
*/
|
|
|
|
#define FD_SETSIZE 16 /* don't need many bits for select */
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <signal.h>
|
|
#include <termios.h>
|
|
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/tcp.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
#include <errno.h>
|
|
#include <libutil.h>
|
|
#include <pwd.h>
|
|
#include <syslog.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "pathnames.h"
|
|
|
|
#ifndef TIOCPKT_WINDOW
|
|
#define TIOCPKT_WINDOW 0x80
|
|
#endif
|
|
|
|
#ifdef KERBEROS
|
|
#include <des.h>
|
|
#include <krb.h>
|
|
#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
|
|
|
|
AUTH_DAT *kdata;
|
|
KTEXT ticket;
|
|
u_char auth_buf[sizeof(AUTH_DAT)];
|
|
u_char tick_buf[sizeof(KTEXT_ST)];
|
|
Key_schedule schedule;
|
|
int doencrypt, retval, use_kerberos, vacuous;
|
|
|
|
#define ARGSTR "Dalnkvx"
|
|
#else
|
|
#define ARGSTR "Daln"
|
|
#endif /* KERBEROS */
|
|
|
|
char *env[2];
|
|
#define NMAX 30
|
|
char lusername[NMAX+1], rusername[NMAX+1];
|
|
static char term[64] = "TERM=";
|
|
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
|
|
int keepalive = 1;
|
|
int check_all = 0;
|
|
int no_delay;
|
|
|
|
struct passwd *pwd;
|
|
|
|
void doit __P((int, struct sockaddr_in *));
|
|
int control __P((int, char *, int));
|
|
void protocol __P((int, int));
|
|
void cleanup __P((int));
|
|
void fatal __P((int, char *, int));
|
|
int do_rlogin __P((struct sockaddr_in *));
|
|
void getstr __P((char *, int, char *));
|
|
void setup_term __P((int));
|
|
int do_krb_login __P((struct sockaddr_in *));
|
|
void usage __P((void));
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
extern int __check_rhosts_file;
|
|
struct sockaddr_in from;
|
|
int ch, fromlen, on;
|
|
|
|
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
|
|
|
|
opterr = 0;
|
|
while ((ch = getopt(argc, argv, ARGSTR)) != -1)
|
|
switch (ch) {
|
|
case 'D':
|
|
no_delay = 1;
|
|
break;
|
|
case 'a':
|
|
check_all = 1;
|
|
break;
|
|
case 'l':
|
|
__check_rhosts_file = 0;
|
|
break;
|
|
case 'n':
|
|
keepalive = 0;
|
|
break;
|
|
#ifdef KERBEROS
|
|
case 'k':
|
|
use_kerberos = 1;
|
|
break;
|
|
case 'v':
|
|
vacuous = 1;
|
|
break;
|
|
#ifdef CRYPT
|
|
case 'x':
|
|
doencrypt = 1;
|
|
break;
|
|
#endif
|
|
#endif
|
|
case '?':
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
#ifdef KERBEROS
|
|
if (use_kerberos && vacuous) {
|
|
usage();
|
|
fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
|
|
}
|
|
#endif
|
|
fromlen = sizeof (from);
|
|
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
|
|
syslog(LOG_ERR,"Can't get peer name of remote host: %m");
|
|
fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
|
|
}
|
|
on = 1;
|
|
if (keepalive &&
|
|
setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
|
|
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
|
|
if (no_delay &&
|
|
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
|
|
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
|
|
on = IPTOS_LOWDELAY;
|
|
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
|
|
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
|
|
|
doit(0, &from);
|
|
return 0;
|
|
}
|
|
|
|
int child;
|
|
int netf;
|
|
char line[MAXPATHLEN];
|
|
int confirmed;
|
|
|
|
struct winsize win = { 0, 0, 0, 0 };
|
|
|
|
|
|
void
|
|
doit(f, fromp)
|
|
int f;
|
|
struct sockaddr_in *fromp;
|
|
{
|
|
int master, pid, on = 1;
|
|
int authenticated = 0;
|
|
register struct hostent *hp;
|
|
char hostname[2 * MAXHOSTNAMELEN + 1];
|
|
char c;
|
|
|
|
alarm(60);
|
|
read(f, &c, 1);
|
|
|
|
if (c != 0)
|
|
exit(1);
|
|
#ifdef KERBEROS
|
|
if (vacuous)
|
|
fatal(f, "Remote host requires Kerberos authentication", 0);
|
|
#endif
|
|
|
|
alarm(0);
|
|
fromp->sin_port = ntohs((u_short)fromp->sin_port);
|
|
hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
|
|
fromp->sin_family);
|
|
if (hp) {
|
|
strncpy(hostname, hp->h_name, sizeof(hostname) - 1);
|
|
hostname[sizeof(hostname) - 1] = '\0';
|
|
hp = gethostbyname(hostname);
|
|
if (hp == NULL) {
|
|
strncpy(hostname, inet_ntoa(fromp->sin_addr),
|
|
sizeof(hostname) - 1);
|
|
} else for (; ; hp->h_addr_list++) {
|
|
if (hp->h_addr_list[0] == NULL) {
|
|
/* End of list - ditch it */
|
|
strncpy(hostname, inet_ntoa(fromp->sin_addr),
|
|
sizeof(hostname) - 1);
|
|
break;
|
|
}
|
|
if (!bcmp(hp->h_addr_list[0],
|
|
(caddr_t)&fromp->sin_addr,
|
|
sizeof(fromp->sin_addr)))
|
|
break; /* OK! */
|
|
}
|
|
} else {
|
|
strncpy(hostname, inet_ntoa(fromp->sin_addr),
|
|
sizeof(hostname) - 1);
|
|
}
|
|
hostname[sizeof(hostname) - 1] = '\0';
|
|
|
|
#ifdef KERBEROS
|
|
if (use_kerberos) {
|
|
retval = do_krb_login(fromp);
|
|
if (retval == 0)
|
|
authenticated++;
|
|
else if (retval > 0)
|
|
fatal(f, krb_err_txt[retval], 0);
|
|
write(f, &c, 1);
|
|
confirmed = 1; /* we sent the null! */
|
|
} else
|
|
#endif
|
|
{
|
|
if (fromp->sin_family != AF_INET ||
|
|
fromp->sin_port >= IPPORT_RESERVED ||
|
|
fromp->sin_port < IPPORT_RESERVED/2) {
|
|
syslog(LOG_NOTICE, "Connection from %s on illegal port",
|
|
inet_ntoa(fromp->sin_addr));
|
|
fatal(f, "Permission denied", 0);
|
|
}
|
|
#ifdef IP_OPTIONS
|
|
{
|
|
u_char optbuf[BUFSIZ/3];
|
|
int optsize = sizeof(optbuf), ipproto, i;
|
|
struct protoent *ip;
|
|
|
|
if ((ip = getprotobyname("ip")) != NULL)
|
|
ipproto = ip->p_proto;
|
|
else
|
|
ipproto = IPPROTO_IP;
|
|
if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
|
|
&optsize) == 0 && optsize != 0) {
|
|
for (i = 0; i < optsize; ) {
|
|
u_char c = optbuf[i];
|
|
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
|
|
syslog(LOG_NOTICE,
|
|
"Connection refused from %s with IP option %s",
|
|
inet_ntoa(fromp->sin_addr),
|
|
c == IPOPT_LSRR ? "LSRR" : "SSRR");
|
|
exit(1);
|
|
}
|
|
if (c == IPOPT_EOL)
|
|
break;
|
|
i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (do_rlogin(fromp) == 0)
|
|
authenticated++;
|
|
}
|
|
if (confirmed == 0) {
|
|
write(f, "", 1);
|
|
confirmed = 1; /* we sent the null! */
|
|
}
|
|
#ifdef KERBEROS
|
|
#ifdef CRYPT
|
|
if (doencrypt)
|
|
(void) des_enc_write(f,
|
|
SECURE_MESSAGE,
|
|
strlen(SECURE_MESSAGE),
|
|
schedule, &kdata->session);
|
|
#endif
|
|
#endif
|
|
netf = f;
|
|
|
|
pid = forkpty(&master, line, NULL, &win);
|
|
if (pid < 0) {
|
|
if (errno == ENOENT)
|
|
fatal(f, "Out of ptys", 0);
|
|
else
|
|
fatal(f, "Forkpty", 1);
|
|
}
|
|
if (pid == 0) {
|
|
if (f > 2) /* f should always be 0, but... */
|
|
(void) close(f);
|
|
setup_term(0);
|
|
if (*lusername=='-') {
|
|
syslog(LOG_ERR, "tried to pass user \"%s\" to login",
|
|
lusername);
|
|
fatal(STDERR_FILENO, "invalid user", 0);
|
|
}
|
|
if (authenticated) {
|
|
#ifdef KERBEROS
|
|
if (use_kerberos && (pwd->pw_uid == 0))
|
|
syslog(LOG_INFO|LOG_AUTH,
|
|
"ROOT Kerberos login from %s.%s@%s on %s\n",
|
|
kdata->pname, kdata->pinst, kdata->prealm,
|
|
hostname);
|
|
#endif
|
|
|
|
execl(_PATH_LOGIN, "login", "-p",
|
|
"-h", hostname, "-f", lusername, (char *)NULL);
|
|
} else
|
|
execl(_PATH_LOGIN, "login", "-p",
|
|
"-h", hostname, lusername, (char *)NULL);
|
|
fatal(STDERR_FILENO, _PATH_LOGIN, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
#ifdef CRYPT
|
|
#ifdef KERBEROS
|
|
/*
|
|
* If encrypted, don't turn on NBIO or the des read/write
|
|
* routines will croak.
|
|
*/
|
|
|
|
if (!doencrypt)
|
|
#endif
|
|
#endif
|
|
ioctl(f, FIONBIO, &on);
|
|
ioctl(master, FIONBIO, &on);
|
|
ioctl(master, TIOCPKT, &on);
|
|
signal(SIGCHLD, cleanup);
|
|
protocol(f, master);
|
|
signal(SIGCHLD, SIG_IGN);
|
|
cleanup(0);
|
|
}
|
|
|
|
char magic[2] = { 0377, 0377 };
|
|
char oobdata[] = {TIOCPKT_WINDOW};
|
|
|
|
/*
|
|
* Handle a "control" request (signaled by magic being present)
|
|
* in the data stream. For now, we are only willing to handle
|
|
* window size changes.
|
|
*/
|
|
int
|
|
control(pty, cp, n)
|
|
int pty;
|
|
char *cp;
|
|
int n;
|
|
{
|
|
struct winsize w;
|
|
|
|
if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
|
|
return (0);
|
|
oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
|
|
bcopy(cp+4, (char *)&w, sizeof(w));
|
|
w.ws_row = ntohs(w.ws_row);
|
|
w.ws_col = ntohs(w.ws_col);
|
|
w.ws_xpixel = ntohs(w.ws_xpixel);
|
|
w.ws_ypixel = ntohs(w.ws_ypixel);
|
|
(void)ioctl(pty, TIOCSWINSZ, &w);
|
|
return (4+sizeof (w));
|
|
}
|
|
|
|
/*
|
|
* rlogin "protocol" machine.
|
|
*/
|
|
void
|
|
protocol(f, p)
|
|
register int f, p;
|
|
{
|
|
char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
|
|
register pcc = 0, fcc = 0;
|
|
int cc, nfd, n;
|
|
char cntl;
|
|
|
|
/*
|
|
* Must ignore SIGTTOU, otherwise we'll stop
|
|
* when we try and set slave pty's window shape
|
|
* (our controlling tty is the master pty).
|
|
*/
|
|
(void) signal(SIGTTOU, SIG_IGN);
|
|
send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
|
|
if (f > p)
|
|
nfd = f + 1;
|
|
else
|
|
nfd = p + 1;
|
|
if (nfd > FD_SETSIZE) {
|
|
syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
|
|
fatal(f, "internal error (select mask too small)", 0);
|
|
}
|
|
for (;;) {
|
|
fd_set ibits, obits, ebits, *omask;
|
|
|
|
FD_ZERO(&ebits);
|
|
FD_ZERO(&ibits);
|
|
FD_ZERO(&obits);
|
|
omask = (fd_set *)NULL;
|
|
if (fcc) {
|
|
FD_SET(p, &obits);
|
|
omask = &obits;
|
|
} else
|
|
FD_SET(f, &ibits);
|
|
if (pcc >= 0)
|
|
if (pcc) {
|
|
FD_SET(f, &obits);
|
|
omask = &obits;
|
|
} else
|
|
FD_SET(p, &ibits);
|
|
FD_SET(p, &ebits);
|
|
if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
fatal(f, "select", 1);
|
|
}
|
|
if (n == 0) {
|
|
/* shouldn't happen... */
|
|
sleep(5);
|
|
continue;
|
|
}
|
|
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
|
|
if (FD_ISSET(p, &ebits)) {
|
|
cc = read(p, &cntl, 1);
|
|
if (cc == 1 && pkcontrol(cntl)) {
|
|
cntl |= oobdata[0];
|
|
send(f, &cntl, 1, MSG_OOB);
|
|
if (cntl & TIOCPKT_FLUSHWRITE) {
|
|
pcc = 0;
|
|
FD_CLR(p, &ibits);
|
|
}
|
|
}
|
|
}
|
|
if (FD_ISSET(f, &ibits)) {
|
|
#ifdef CRYPT
|
|
#ifdef KERBEROS
|
|
if (doencrypt)
|
|
fcc = des_enc_read(f, fibuf, sizeof(fibuf),
|
|
schedule, &kdata->session);
|
|
else
|
|
#endif
|
|
#endif
|
|
fcc = read(f, fibuf, sizeof(fibuf));
|
|
if (fcc < 0 && errno == EWOULDBLOCK)
|
|
fcc = 0;
|
|
else {
|
|
register char *cp;
|
|
int left, n;
|
|
|
|
if (fcc <= 0)
|
|
break;
|
|
fbp = fibuf;
|
|
|
|
top:
|
|
for (cp = fibuf; cp < fibuf+fcc-1; cp++)
|
|
if (cp[0] == magic[0] &&
|
|
cp[1] == magic[1]) {
|
|
left = fcc - (cp-fibuf);
|
|
n = control(p, cp, left);
|
|
if (n) {
|
|
left -= n;
|
|
if (left > 0)
|
|
bcopy(cp+n, cp, left);
|
|
fcc -= n;
|
|
goto top; /* n^2 */
|
|
}
|
|
}
|
|
FD_SET(p, &obits); /* try write */
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(p, &obits) && fcc > 0) {
|
|
cc = write(p, fbp, fcc);
|
|
if (cc > 0) {
|
|
fcc -= cc;
|
|
fbp += cc;
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(p, &ibits)) {
|
|
pcc = read(p, pibuf, sizeof (pibuf));
|
|
pbp = pibuf;
|
|
if (pcc < 0 && errno == EWOULDBLOCK)
|
|
pcc = 0;
|
|
else if (pcc <= 0)
|
|
break;
|
|
else if (pibuf[0] == 0) {
|
|
pbp++, pcc--;
|
|
#ifdef CRYPT
|
|
#ifdef KERBEROS
|
|
if (!doencrypt)
|
|
#endif
|
|
#endif
|
|
FD_SET(f, &obits); /* try write */
|
|
} else {
|
|
if (pkcontrol(pibuf[0])) {
|
|
pibuf[0] |= oobdata[0];
|
|
send(f, &pibuf[0], 1, MSG_OOB);
|
|
}
|
|
pcc = 0;
|
|
}
|
|
}
|
|
if ((FD_ISSET(f, &obits)) && pcc > 0) {
|
|
#ifdef CRYPT
|
|
#ifdef KERBEROS
|
|
if (doencrypt)
|
|
cc = des_enc_write(f, pbp, pcc,
|
|
schedule, &kdata->session);
|
|
else
|
|
#endif
|
|
#endif
|
|
cc = write(f, pbp, pcc);
|
|
if (cc < 0 && errno == EWOULDBLOCK) {
|
|
/*
|
|
* This happens when we try write after read
|
|
* from p, but some old kernels balk at large
|
|
* writes even when select returns true.
|
|
*/
|
|
if (!FD_ISSET(p, &ibits))
|
|
sleep(5);
|
|
continue;
|
|
}
|
|
if (cc > 0) {
|
|
pcc -= cc;
|
|
pbp += cc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cleanup(signo)
|
|
int signo;
|
|
{
|
|
char *p;
|
|
|
|
p = line + sizeof(_PATH_DEV) - 1;
|
|
if (logout(p))
|
|
logwtmp(p, "", "");
|
|
(void)chmod(line, 0666);
|
|
(void)chown(line, 0, 0);
|
|
*p = 'p';
|
|
(void)chmod(line, 0666);
|
|
(void)chown(line, 0, 0);
|
|
shutdown(netf, 2);
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
fatal(f, msg, syserr)
|
|
int f;
|
|
char *msg;
|
|
int syserr;
|
|
{
|
|
int len;
|
|
char buf[BUFSIZ], *bp = buf;
|
|
|
|
/*
|
|
* Prepend binary one to message if we haven't sent
|
|
* the magic null as confirmation.
|
|
*/
|
|
if (!confirmed)
|
|
*bp++ = '\01'; /* error indicator */
|
|
if (syserr)
|
|
len = sprintf(bp, "rlogind: %s: %s.\r\n",
|
|
msg, strerror(errno));
|
|
else
|
|
len = sprintf(bp, "rlogind: %s.\r\n", msg);
|
|
(void) write(f, buf, bp + len - buf);
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
do_rlogin(dest)
|
|
struct sockaddr_in *dest;
|
|
{
|
|
getstr(rusername, sizeof(rusername), "remuser too long");
|
|
getstr(lusername, sizeof(lusername), "locuser too long");
|
|
getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
|
|
|
|
pwd = getpwnam(lusername);
|
|
if (pwd == NULL)
|
|
return (-1);
|
|
/* XXX why don't we syslog() failure? */
|
|
return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
|
|
rusername, lusername));
|
|
}
|
|
|
|
void
|
|
getstr(buf, cnt, errmsg)
|
|
char *buf;
|
|
int cnt;
|
|
char *errmsg;
|
|
{
|
|
char c;
|
|
|
|
do {
|
|
if (read(0, &c, 1) != 1)
|
|
exit(1);
|
|
if (--cnt < 0)
|
|
fatal(STDOUT_FILENO, errmsg, 0);
|
|
*buf++ = c;
|
|
} while (c != 0);
|
|
}
|
|
|
|
extern char **environ;
|
|
|
|
void
|
|
setup_term(fd)
|
|
int fd;
|
|
{
|
|
register char *cp = index(term+ENVSIZE, '/');
|
|
char *speed;
|
|
struct termios tt;
|
|
|
|
#ifndef notyet
|
|
tcgetattr(fd, &tt);
|
|
if (cp) {
|
|
*cp++ = '\0';
|
|
speed = cp;
|
|
cp = index(speed, '/');
|
|
if (cp)
|
|
*cp++ = '\0';
|
|
cfsetspeed(&tt, atoi(speed));
|
|
}
|
|
|
|
tt.c_iflag = TTYDEF_IFLAG;
|
|
tt.c_oflag = TTYDEF_OFLAG;
|
|
tt.c_lflag = TTYDEF_LFLAG;
|
|
tcsetattr(fd, TCSAFLUSH, &tt);
|
|
#else
|
|
if (cp) {
|
|
*cp++ = '\0';
|
|
speed = cp;
|
|
cp = index(speed, '/');
|
|
if (cp)
|
|
*cp++ = '\0';
|
|
tcgetattr(fd, &tt);
|
|
cfsetspeed(&tt, atoi(speed));
|
|
tcsetattr(fd, TCSAFLUSH, &tt);
|
|
}
|
|
#endif
|
|
|
|
env[0] = term;
|
|
env[1] = 0;
|
|
environ = env;
|
|
}
|
|
|
|
#ifdef KERBEROS
|
|
#define VERSION_SIZE 9
|
|
|
|
/*
|
|
* Do the remote kerberos login to the named host with the
|
|
* given inet address
|
|
*
|
|
* Return 0 on valid authorization
|
|
* Return -1 on valid authentication, no authorization
|
|
* Return >0 for error conditions
|
|
*/
|
|
int
|
|
do_krb_login(dest)
|
|
struct sockaddr_in *dest;
|
|
{
|
|
int rc;
|
|
char instance[INST_SZ], version[VERSION_SIZE];
|
|
long authopts = 0L; /* !mutual */
|
|
struct sockaddr_in faddr;
|
|
|
|
kdata = (AUTH_DAT *) auth_buf;
|
|
ticket = (KTEXT) tick_buf;
|
|
|
|
instance[0] = '*';
|
|
instance[1] = '\0';
|
|
|
|
#ifdef CRYPT
|
|
if (doencrypt) {
|
|
rc = sizeof(faddr);
|
|
if (getsockname(0, (struct sockaddr *)&faddr, &rc))
|
|
return (-1);
|
|
authopts = KOPT_DO_MUTUAL;
|
|
rc = krb_recvauth(
|
|
authopts, 0,
|
|
ticket, "rcmd",
|
|
instance, dest, &faddr,
|
|
kdata, "", schedule, version);
|
|
des_set_key(&kdata->session, schedule);
|
|
|
|
} else
|
|
#endif
|
|
rc = krb_recvauth(
|
|
authopts, 0,
|
|
ticket, "rcmd",
|
|
instance, dest, (struct sockaddr_in *) 0,
|
|
kdata, "", NULL, version);
|
|
|
|
if (rc != KSUCCESS)
|
|
return (rc);
|
|
|
|
getstr(lusername, sizeof(lusername), "locuser");
|
|
/* get the "cmd" in the rcmd protocol */
|
|
getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
|
|
|
|
pwd = getpwnam(lusername);
|
|
if (pwd == NULL)
|
|
return (-1);
|
|
|
|
/* returns nonzero for no access */
|
|
if (kuserok(kdata, lusername) != 0)
|
|
return (-1);
|
|
|
|
return (0);
|
|
|
|
}
|
|
#endif /* KERBEROS */
|
|
|
|
void
|
|
usage()
|
|
{
|
|
#ifdef KERBEROS
|
|
syslog(LOG_ERR, "usage: rlogind [-Daln] [-k | -v]");
|
|
#else
|
|
syslog(LOG_ERR, "usage: rlogind [-Daln]");
|
|
#endif
|
|
}
|