summaryrefslogtreecommitdiff
path: root/usr.bin/rlogin
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/rlogin
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/rlogin')
-rw-r--r--usr.bin/rlogin/Makefile14
-rw-r--r--usr.bin/rlogin/des_rw.c209
-rw-r--r--usr.bin/rlogin/kcmd.c313
-rw-r--r--usr.bin/rlogin/krb.h53
-rw-r--r--usr.bin/rlogin/krcmd.c164
-rw-r--r--usr.bin/rlogin/rlogin.1185
-rw-r--r--usr.bin/rlogin/rlogin.c910
7 files changed, 1848 insertions, 0 deletions
diff --git a/usr.bin/rlogin/Makefile b/usr.bin/rlogin/Makefile
new file mode 100644
index 00000000000..b53f6bd52bc
--- /dev/null
+++ b/usr.bin/rlogin/Makefile
@@ -0,0 +1,14 @@
+# $NetBSD: Makefile,v 1.5 1995/03/21 07:58:28 cgd Exp $
+# @(#)Makefile 8.1 (Berkeley) 7/19/93
+
+PROG= rlogin
+SRCS= rlogin.c
+#SRCS+= krcmd.c kcmd.c des_rw.c
+#DPADD= ${LIBKRB} ${LIBDES}
+#CFLAGS+=-DKERBEROS -DCRYPT
+#LDADD= -lkrb -ldes
+BINOWN= root
+BINMODE=4555
+#INSTALLFLAGS=-fschg
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rlogin/des_rw.c b/usr.bin/rlogin/des_rw.c
new file mode 100644
index 00000000000..592e5ba7cd7
--- /dev/null
+++ b/usr.bin/rlogin/des_rw.c
@@ -0,0 +1,209 @@
+/* $NetBSD: des_rw.c,v 1.2 1995/03/21 07:58:30 cgd Exp $ */
+
+/*-
+ * Copyright (c) 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
+#if 0
+static char sccsid[] = "@(#)des_rw.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: des_rw.c,v 1.2 1995/03/21 07:58:30 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#ifdef CRYPT
+#ifdef KERBEROS
+#include <sys/param.h>
+
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+static unsigned char des_inbuf[10240], storage[10240], *store_ptr;
+static bit_64 *key;
+static u_char *key_schedule;
+
+/* XXX these should be in a kerberos include file */
+int krb_net_read __P((int, char *, int));
+#ifdef notdef
+/* XXX too hard to make this work */
+int des_pcbc_encrypt __P((des_cblock *, des_cblock *, long,
+ des_key_schedule, des_cblock *, int));
+#endif
+
+/*
+ * NB: These routines will not function properly if NBIO
+ * is set
+ */
+
+/*
+ * des_set_key
+ *
+ * Set des encryption/decryption key for use by the des_read and
+ * des_write routines
+ *
+ * The inkey parameter is actually the DES initial vector,
+ * and the insched is the DES Key unwrapped for faster decryption
+ */
+
+void
+des_set_key(inkey, insched)
+ bit_64 *inkey;
+ u_char *insched;
+{
+ key = inkey;
+ key_schedule = insched;
+}
+
+void
+des_clear_key()
+{
+ bzero((char *) key, sizeof(C_Block));
+ bzero((char *) key_schedule, sizeof(Key_schedule));
+}
+
+
+int
+des_read(fd, buf, len)
+ int fd;
+ register char *buf;
+ int len;
+{
+ int nreturned = 0;
+ long net_len, rd_len;
+ int nstored = 0;
+
+ if (nstored >= len) {
+ (void) bcopy(store_ptr, buf, len);
+ store_ptr += len;
+ nstored -= len;
+ return(len);
+ } else if (nstored) {
+ (void) bcopy(store_ptr, buf, nstored);
+ nreturned += nstored;
+ buf += nstored;
+ len -= nstored;
+ nstored = 0;
+ }
+
+ if (krb_net_read(fd, (char *)&net_len, sizeof(net_len)) !=
+ sizeof(net_len)) {
+ /* XXX can't read enough, pipe
+ must have closed */
+ return(0);
+ }
+ net_len = ntohl(net_len);
+ if (net_len <= 0 || net_len > sizeof(des_inbuf)) {
+ /* preposterous length; assume out-of-sync; only
+ recourse is to close connection, so return 0 */
+ return(0);
+ }
+ /* the writer tells us how much real data we are getting, but
+ we need to read the pad bytes (8-byte boundary) */
+ rd_len = roundup(net_len, 8);
+ if (krb_net_read(fd, (char *)des_inbuf, rd_len) != rd_len) {
+ /* pipe must have closed, return 0 */
+ return(0);
+ }
+ (void) des_pcbc_encrypt(des_inbuf, /* inbuf */
+ storage, /* outbuf */
+ net_len, /* length */
+ key_schedule, /* DES key */
+ key, /* IV */
+ DECRYPT); /* direction */
+
+ if(net_len < 8)
+ store_ptr = storage + 8 - net_len;
+ else
+ store_ptr = storage;
+
+ nstored = net_len;
+ if (nstored > len) {
+ (void) bcopy(store_ptr, buf, len);
+ nreturned += len;
+ store_ptr += len;
+ nstored -= len;
+ } else {
+ (void) bcopy(store_ptr, buf, nstored);
+ nreturned += nstored;
+ nstored = 0;
+ }
+
+ return(nreturned);
+}
+
+static unsigned char des_outbuf[10240]; /* > longest write */
+
+int
+des_write(fd, buf, len)
+ int fd;
+ char *buf;
+ int len;
+{
+ static int seeded = 0;
+ static char garbage_buf[8];
+ long net_len, garbage;
+
+ if(len < 8) {
+ if(!seeded) {
+ seeded = 1;
+ srandom((int) time((long *)0));
+ }
+ garbage = random();
+ /* insert random garbage */
+ (void) bcopy(&garbage, garbage_buf, MIN(sizeof(long),8));
+ /* this "right-justifies" the data in the buffer */
+ (void) bcopy(buf, garbage_buf + 8 - len, len);
+ }
+ /* pcbc_encrypt outputs in 8-byte (64 bit) increments */
+
+ (void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf,
+ des_outbuf,
+ (len < 8) ? 8 : len,
+ key_schedule, /* DES key */
+ key, /* IV */
+ ENCRYPT);
+
+ /* tell the other end the real amount, but send an 8-byte padded
+ packet */
+ net_len = htonl(len);
+ (void) write(fd, &net_len, sizeof(net_len));
+ (void) write(fd, des_outbuf, roundup(len,8));
+ return(len);
+}
+#endif /* KERBEROS */
+#endif /* CRYPT */
diff --git a/usr.bin/rlogin/kcmd.c b/usr.bin/rlogin/kcmd.c
new file mode 100644
index 00000000000..16772d4e251
--- /dev/null
+++ b/usr.bin/rlogin/kcmd.c
@@ -0,0 +1,313 @@
+/* $NetBSD: kcmd.c,v 1.2 1995/03/21 07:58:32 cgd Exp $ */
+
+/*
+ * Copyright (c) 1983, 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
+#if 0
+static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88";
+static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93";
+#else
+static char rcsid[] = "$NetBSD: kcmd.c,v 1.2 1995/03/21 07:58:32 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+#include <kerberosIV/kparse.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "krb.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define START_PORT 5120 /* arbitrary */
+
+int getport __P((int *));
+
+int
+kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
+ cred, schedule, msg_data, laddr, faddr, authopts)
+ int *sock;
+ char **ahost;
+ u_short rport;
+ char *locuser, *remuser, *cmd;
+ int *fd2p;
+ KTEXT ticket;
+ char *service;
+ char *realm;
+ CREDENTIALS *cred;
+ Key_schedule schedule;
+ MSG_DAT *msg_data;
+ struct sockaddr_in *laddr, *faddr;
+ long authopts;
+{
+ int s, timo = 1, pid;
+ long oldmask;
+ struct sockaddr_in sin, from;
+ char c;
+#ifdef ATHENA_COMPAT
+ int lport = IPPORT_RESERVED - 1;
+#else
+ int lport = START_PORT;
+#endif
+ struct hostent *hp;
+ int rc;
+ char *host_save;
+ int status;
+
+ pid = getpid();
+ hp = gethostbyname(*ahost);
+ if (hp == NULL) {
+ /* fprintf(stderr, "%s: unknown host\n", *ahost); */
+ return (-1);
+ }
+
+ host_save = malloc(strlen(hp->h_name) + 1);
+ strcpy(host_save, hp->h_name);
+ *ahost = host_save;
+
+#ifdef KERBEROS
+ /* If realm is null, look up from table */
+ if (realm == NULL || realm[0] == '\0')
+ realm = krb_realmofhost(host_save);
+#endif /* KERBEROS */
+
+ oldmask = sigblock(sigmask(SIGURG));
+ for (;;) {
+ s = getport(&lport);
+ if (s < 0) {
+ if (errno == EAGAIN)
+ fprintf(stderr,
+ "kcmd(socket): All ports in use\n");
+ else
+ perror("kcmd: socket");
+ sigsetmask(oldmask);
+ return (-1);
+ }
+ fcntl(s, F_SETOWN, pid);
+ sin.sin_family = hp->h_addrtype;
+#if defined(ultrix) || defined(sun)
+ bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+#else
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
+#endif
+ sin.sin_port = rport;
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ break;
+ (void) close(s);
+ if (errno == EADDRINUSE) {
+ lport--;
+ continue;
+ }
+ /*
+ * don't wait very long for Kerberos rcmd.
+ */
+ if (errno == ECONNREFUSED && timo <= 4) {
+ /* sleep(timo); don't wait at all here */
+ timo *= 2;
+ continue;
+ }
+#if !(defined(ultrix) || defined(sun))
+ if (hp->h_addr_list[1] != NULL) {
+ int oerrno = errno;
+
+ fprintf(stderr,
+ "kcmd: connect to address %s: ",
+ inet_ntoa(sin.sin_addr));
+ errno = oerrno;
+ perror(NULL);
+ hp->h_addr_list++;
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
+ hp->h_length);
+ fprintf(stderr, "Trying %s...\n",
+ inet_ntoa(sin.sin_addr));
+ continue;
+ }
+#endif /* !(defined(ultrix) || defined(sun)) */
+ if (errno != ECONNREFUSED)
+ perror(hp->h_name);
+ sigsetmask(oldmask);
+ return (-1);
+ }
+ lport--;
+ if (fd2p == 0) {
+ write(s, "", 1);
+ lport = 0;
+ } else {
+ char num[8];
+ int s2 = getport(&lport), s3;
+ int len = sizeof(from);
+
+ if (s2 < 0) {
+ status = -1;
+ goto bad;
+ }
+ listen(s2, 1);
+ (void) sprintf(num, "%d", lport);
+ if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
+ perror("kcmd(write): setting up stderr");
+ (void) close(s2);
+ status = -1;
+ goto bad;
+ }
+ s3 = accept(s2, (struct sockaddr *)&from, &len);
+ (void) close(s2);
+ if (s3 < 0) {
+ perror("kcmd:accept");
+ lport = 0;
+ status = -1;
+ goto bad;
+ }
+ *fd2p = s3;
+ from.sin_port = ntohs((u_short)from.sin_port);
+ if (from.sin_family != AF_INET ||
+ from.sin_port >= IPPORT_RESERVED) {
+ fprintf(stderr,
+ "kcmd(socket): protocol failure in circuit setup.\n");
+ status = -1;
+ goto bad2;
+ }
+ }
+ /*
+ * Kerberos-authenticated service. Don't have to send locuser,
+ * since its already in the ticket, and we'll extract it on
+ * the other side.
+ */
+ /* (void) write(s, locuser, strlen(locuser)+1); */
+
+ /* set up the needed stuff for mutual auth, but only if necessary */
+ if (authopts & KOPT_DO_MUTUAL) {
+ int sin_len;
+ *faddr = sin;
+
+ sin_len = sizeof(struct sockaddr_in);
+ if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) {
+ perror("kcmd(getsockname)");
+ status = -1;
+ goto bad2;
+ }
+ }
+#ifdef KERBEROS
+ if ((status = krb_sendauth(authopts, s, ticket, service, *ahost,
+ realm, (unsigned long) getpid(), msg_data,
+ cred, schedule,
+ laddr,
+ faddr,
+ "KCMDV0.1")) != KSUCCESS)
+ goto bad2;
+#endif /* KERBEROS */
+
+ (void) write(s, remuser, strlen(remuser)+1);
+ (void) write(s, cmd, strlen(cmd)+1);
+
+ if ((rc = read(s, &c, 1)) != 1) {
+ if (rc == -1)
+ perror(*ahost);
+ else
+ fprintf(stderr,"kcmd: bad connection with remote host\n");
+ status = -1;
+ goto bad2;
+ }
+ if (c != '\0') {
+ while (read(s, &c, 1) == 1) {
+ (void) write(2, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ status = -1;
+ goto bad2;
+ }
+ sigsetmask(oldmask);
+ *sock = s;
+ return (KSUCCESS);
+bad2:
+ if (lport)
+ (void) close(*fd2p);
+bad:
+ (void) close(s);
+ sigsetmask(oldmask);
+ return (status);
+}
+
+int
+getport(alport)
+ int *alport;
+{
+ struct sockaddr_in sin;
+ int s;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return (-1);
+ for (;;) {
+ sin.sin_port = htons((u_short)*alport);
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ return (s);
+ if (errno != EADDRINUSE) {
+ (void) close(s);
+ return (-1);
+ }
+ (*alport)--;
+#ifdef ATHENA_COMPAT
+ if (*alport == IPPORT_RESERVED/2) {
+#else
+ if (*alport == IPPORT_RESERVED) {
+#endif
+ (void) close(s);
+ errno = EAGAIN; /* close */
+ return (-1);
+ }
+ }
+}
diff --git a/usr.bin/rlogin/krb.h b/usr.bin/rlogin/krb.h
new file mode 100644
index 00000000000..f40cdb6dd93
--- /dev/null
+++ b/usr.bin/rlogin/krb.h
@@ -0,0 +1,53 @@
+/* $NetBSD: krb.h,v 1.2 1995/03/21 07:58:34 cgd Exp $ */
+
+/*-
+ * Copyright (c) 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.
+ *
+ * @(#)krb.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * XXX
+ * These should be in a kerberos include file.
+ */
+void des_clear_key __P(());
+int des_read __P((int, char *, int));
+void des_set_key __P((C_Block, Key_schedule));
+int des_write __P((int, char *, int));
+int krb_net_read __P((int, char *, int));
+char *krb_realmofhost __P((char *));
+int krb_sendauth __P((long, int, KTEXT, char *, char *, char *,
+ u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
+ struct sockaddr_in *, struct sockaddr_in *, char *));
+int krcmd __P((char **, u_short, char *, char *, int *, char *));
+int krcmd_mutual __P((char **, u_short, char *, char *, int *,
+ char *, CREDENTIALS *, Key_schedule));
diff --git a/usr.bin/rlogin/krcmd.c b/usr.bin/rlogin/krcmd.c
new file mode 100644
index 00000000000..5bcbb4c3312
--- /dev/null
+++ b/usr.bin/rlogin/krcmd.c
@@ -0,0 +1,164 @@
+/* $NetBSD: krcmd.c,v 1.2 1995/03/21 07:58:36 cgd Exp $ */
+
+/*
+ * Copyright (c) 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
+#if 0
+static char sccsid[] = "@(#)krcmd.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: krcmd.c,v 1.2 1995/03/21 07:58:36 cgd Exp $";
+#endif
+#endif /* not lint */
+
+/*
+ * $Source: /a/cvsroot/src/usr.bin/rlogin/krcmd.c,v
+ * $Header: /mit/kerberos/ucb/mit/kcmd/RCS/krcmd.c,v 5.1
+ * 89/07/25 15:38:44 kfall Exp Locker: kfall
+ * static char *rcsid_kcmd_c =
+ * "$Header: /mit/kerberos/ucb/mit/kcmd/RCS/krcmd.c,v 5.1 89/07/25 15:38:44
+ * kfall Exp Locker: kfall ";
+ */
+
+#ifdef KERBEROS
+#include <sys/types.h>
+#ifdef CRYPT
+#include <sys/socket.h>
+#endif
+
+#include <netinet/in.h>
+
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+#include <stdio.h>
+
+#define SERVICE_NAME "rcmd"
+
+int kcmd __P((int *, char **, u_short, char *, char *, char *, int *,
+ KTEXT, char *, char *, CREDENTIALS *, Key_schedule, MSG_DAT *,
+ struct sockaddr_in *, struct sockaddr_in *, long));
+
+/*
+ * krcmd: simplified version of Athena's "kcmd"
+ * returns a socket attached to the destination, -1 or krb error on error
+ * if fd2p is non-NULL, another socket is filled in for it
+ */
+
+int
+krcmd(ahost, rport, remuser, cmd, fd2p, realm)
+ char **ahost;
+ u_short rport;
+ char *remuser, *cmd;
+ int *fd2p;
+ char *realm;
+{
+ int sock = -1, err = 0;
+ KTEXT_ST ticket;
+ long authopts = 0L;
+
+ err = kcmd(
+ &sock,
+ ahost,
+ rport,
+ NULL, /* locuser not used */
+ remuser,
+ cmd,
+ fd2p,
+ &ticket,
+ SERVICE_NAME,
+ realm,
+ (CREDENTIALS *) NULL, /* credentials not used */
+ (bit_64 *) NULL, /* key schedule not used */
+ (MSG_DAT *) NULL, /* MSG_DAT not used */
+ (struct sockaddr_in *) NULL, /* local addr not used */
+ (struct sockaddr_in *) NULL, /* foreign addr not used */
+ authopts
+ );
+
+ if (err > KSUCCESS && err < MAX_KRB_ERRORS) {
+ fprintf(stderr, "krcmd: %s\n", krb_err_txt[err]);
+ return(-1);
+ }
+ if (err < 0)
+ return(-1);
+ return(sock);
+}
+
+#ifdef CRYPT
+int
+krcmd_mutual(ahost, rport, remuser, cmd, fd2p, realm, cred, sched)
+ char **ahost;
+ u_short rport;
+ char *remuser, *cmd;
+ int *fd2p;
+ char *realm;
+ CREDENTIALS *cred;
+ Key_schedule sched;
+{
+ int sock, err;
+ KTEXT_ST ticket;
+ MSG_DAT msg_dat;
+ struct sockaddr_in laddr, faddr;
+ long authopts = KOPT_DO_MUTUAL;
+
+ err = kcmd(
+ &sock,
+ ahost,
+ rport,
+ NULL, /* locuser not used */
+ remuser,
+ cmd,
+ fd2p,
+ &ticket,
+ SERVICE_NAME,
+ realm,
+ cred, /* filled in */
+ sched, /* filled in */
+ &msg_dat, /* filled in */
+ &laddr, /* filled in */
+ &faddr, /* filled in */
+ authopts
+ );
+
+ if (err > KSUCCESS && err < MAX_KRB_ERRORS) {
+ fprintf(stderr, "krcmd_mutual: %s\n", krb_err_txt[err]);
+ return(-1);
+ }
+
+ if (err < 0)
+ return (-1);
+ return(sock);
+}
+#endif /* CRYPT */
+#endif /* KERBEROS */
diff --git a/usr.bin/rlogin/rlogin.1 b/usr.bin/rlogin/rlogin.1
new file mode 100644
index 00000000000..5a73e933f5d
--- /dev/null
+++ b/usr.bin/rlogin/rlogin.1
@@ -0,0 +1,185 @@
+.\" $NetBSD: rlogin.1,v 1.4 1995/08/18 15:07:35 pk Exp $
+.\"
+.\" Copyright (c) 1983, 1990, 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.
+.\"
+.\" @(#)rlogin.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt RLOGIN 1
+.Os BSD 4.2
+.Sh NAME
+.Nm rlogin
+.Nd remote login
+.Sh SYNOPSIS
+.Ar rlogin
+.Op Fl 8EKLdx
+.Op Fl e Ar char
+.Op Fl k Ar realm
+.Op Fl l Ar username
+.Ar host
+.Sh DESCRIPTION
+.Nm Rlogin
+starts a terminal session on a remote host
+.Ar host .
+.Pp
+.Nm Rlogin
+first attempts to use the Kerberos authorization mechanism, described below.
+If the remote host does not supporting Kerberos the standard Berkeley
+.Pa rhosts
+authorization mechanism is used.
+The options are as follows:
+.Bl -tag -width flag
+.It Fl 8
+The
+.Fl 8
+option allows an eight-bit input data path at all times; otherwise
+parity bits are stripped except when the remote side's stop and start
+characters are other than
+^S/^Q .
+.It Fl E
+The
+.Fl E
+option stops any character from being recognized as an escape character.
+When used with the
+.Fl 8
+option, this provides a completely transparent connection.
+.It Fl K
+The
+.Fl K
+option turns off all Kerberos authentication.
+.It Fl L
+The
+.Fl L
+option allows the rlogin session to be run in ``litout'' (see
+.Xr tty 4 )
+mode.
+.It Fl d
+The
+.Fl d
+option turns on socket debugging (see
+.Xr setsockopt 2 )
+on the TCP sockets used for communication with the remote host.
+.It Fl e
+The
+.Fl e
+option allows user specification of the escape character, which is
+``~'' by default.
+This specification may be as a literal character, or as an octal
+value in the form \ennn.
+.It Fl k
+The
+.Fl k
+option requests rlogin to obtain tickets for the remote host
+in realm
+.Ar realm
+instead of the remote host's realm as determined by
+.Xr krb_realmofhost 3 .
+.It Fl x
+The
+.Fl x
+option turns on
+.Tn DES
+encryption for all data passed via the
+rlogin session.
+This may impact response time and
+.Tn CPU
+utilization, but provides
+increased security.
+.El
+.Pp
+A line of the form ``<escape char>.'' disconnects from the remote host.
+Similarly, the line ``<escape char>^Z'' will suspend the
+.Nm rlogin
+session, and ``<escape char><delayed-suspend char>'' suspends the
+send portion of the rlogin, but allows output from the remote system.
+By default, the tilde (``~'') character is the escape character, and
+normally control-Y (``^Y'') is the delayed-suspend character.
+.Pp
+All echoing takes place at the remote site, so that (except for delays)
+the
+.Nm rlogin
+is transparent.
+Flow control via ^S/^Q and flushing of input and output on interrupts
+are handled properly.
+.Sh KERBEROS AUTHENTICATION
+Each user may have a private authorization list in the file
+.Pa .klogin
+in their home directory.
+Each line in this file should contain a Kerberos principal name of the
+form
+.Ar principal.instance@realm .
+If the originating user is authenticated to one of the principals named
+in
+.Pa .klogin ,
+access is granted to the account.
+The principal
+.Ar accountname.@localrealm
+is granted access if
+there is no
+.Pa .klogin
+file.
+Otherwise a login and password will be prompted for on the remote machine
+as in
+.Xr login 1 .
+To avoid certain security problems, the
+.Pa .klogin
+file must be owned by
+the remote user.
+.Pp
+If Kerberos authentication fails, a warning message is printed and the
+standard Berkeley
+.Nm rlogin
+is used instead.
+.Sh ENVIRONMENT
+The following environment variable is utilized by
+.Nm rlogin :
+.Bl -tag -width TERM
+.It Ev TERM
+Determines the user's terminal type.
+.El
+.Sh SEE ALSO
+.Xr rsh 1 ,
+.Xr kerberos 3 ,
+.Xr krb_sendauth 3 ,
+.Xr krb_realmofhost 3
+.Sh HISTORY
+The
+.Nm rlogin
+command appeared in
+.Bx 4.2 .
+.Sh BUGS
+.Nm Rlogin
+will be replaced by
+.Xr telnet 1
+in the near future.
+.Pp
+More of the environment should be propagated.
diff --git a/usr.bin/rlogin/rlogin.c b/usr.bin/rlogin/rlogin.c
new file mode 100644
index 00000000000..8c93cd8f5c1
--- /dev/null
+++ b/usr.bin/rlogin/rlogin.c
@@ -0,0 +1,910 @@
+/* $NetBSD: rlogin.c,v 1.8 1995/10/05 09:07:22 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1983, 1990, 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 char copyright[] =
+"@(#) Copyright (c) 1983, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: rlogin.c,v 1.8 1995/10/05 09:07:22 mycroft Exp $";
+#endif
+#endif /* not lint */
+
+/*
+ * rlogin - remote login
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <termios.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef KERBEROS
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+#include "krb.h"
+
+CREDENTIALS cred;
+Key_schedule schedule;
+int use_kerberos = 1, doencrypt;
+char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
+#endif
+
+#ifndef TIOCPKT_WINDOW
+#define TIOCPKT_WINDOW 0x80
+#endif
+
+/* concession to Sun */
+#ifndef SIGUSR1
+#define SIGUSR1 30
+#endif
+
+#ifndef CCEQ
+#define CCEQ(val, c) (c == val ? val != _POSIX_VDISABLE : 0)
+#endif
+
+int eight, rem;
+struct termios deftty;
+
+int noescape;
+u_char escapechar = '~';
+
+#ifdef OLDSUN
+struct winsize {
+ unsigned short ws_row, ws_col;
+ unsigned short ws_xpixel, ws_ypixel;
+};
+#else
+#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
+#endif
+struct winsize winsize;
+
+void catch_child __P((int));
+void copytochild __P((int));
+__dead void doit __P((long));
+__dead void done __P((int));
+void echo __P((char));
+u_int getescape __P((char *));
+void lostpeer __P((int));
+void mode __P((int));
+void msg __P((char *));
+void oob __P((int));
+int reader __P((int));
+void sendwindow __P((void));
+void setsignal __P((int));
+void sigwinch __P((int));
+void stop __P((int));
+__dead void usage __P((void));
+void writer __P((void));
+void writeroob __P((int));
+
+#ifdef KERBEROS
+void warning __P((const char *, ...));
+#endif
+#ifdef OLDSUN
+int get_window_size __P((int, struct winsize *));
+#endif
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ struct passwd *pw;
+ struct servent *sp;
+ struct termios tty;
+ long omask;
+ int argoff, ch, dflag, one, uid;
+ char *host, *p, *user, term[1024];
+
+ argoff = dflag = 0;
+ one = 1;
+ host = user = NULL;
+
+ if (p = rindex(argv[0], '/'))
+ ++p;
+ else
+ p = argv[0];
+
+ if (strcmp(p, "rlogin"))
+ host = p;
+
+ /* handle "rlogin host flags" */
+ if (!host && argc > 2 && argv[1][0] != '-') {
+ host = argv[1];
+ argoff = 1;
+ }
+
+#ifdef KERBEROS
+#define OPTIONS "8EKLde:k:l:x"
+#else
+#define OPTIONS "8EKLde:l:"
+#endif
+ while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
+ switch(ch) {
+ case '8':
+ eight = 1;
+ break;
+ case 'E':
+ noescape = 1;
+ break;
+ case 'K':
+#ifdef KERBEROS
+ use_kerberos = 0;
+#endif
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ noescape = 0;
+ escapechar = getescape(optarg);
+ break;
+#ifdef KERBEROS
+ case 'k':
+ dest_realm = dst_realm_buf;
+ (void)strncpy(dest_realm, optarg, REALM_SZ);
+ break;
+#endif
+ case 'l':
+ user = optarg;
+ break;
+#ifdef CRYPT
+#ifdef KERBEROS
+ case 'x':
+ doencrypt = 1;
+ des_set_key(cred.session, schedule);
+ break;
+#endif
+#endif
+ case '?':
+ default:
+ usage();
+ }
+ optind += argoff;
+ argc -= optind;
+ argv += optind;
+
+ /* if haven't gotten a host yet, do so */
+ if (!host && !(host = *argv++))
+ usage();
+
+ if (*argv)
+ usage();
+
+ if (!(pw = getpwuid(uid = getuid()))) {
+ (void)fprintf(stderr, "rlogin: unknown user id.\n");
+ exit(1);
+ }
+ if (!user)
+ user = pw->pw_name;
+
+ sp = NULL;
+#ifdef KERBEROS
+ if (use_kerberos) {
+ sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
+ if (sp == NULL) {
+ use_kerberos = 0;
+ warning("can't get entry for %s/tcp service",
+ doencrypt ? "eklogin" : "klogin");
+ }
+ }
+#endif
+ if (sp == NULL)
+ sp = getservbyname("login", "tcp");
+ if (sp == NULL) {
+ (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
+ exit(1);
+ }
+
+ (void)strcpy(term, (p = getenv("TERM")) ? p : "network");
+ if (tcgetattr(0, &tty) == 0) {
+ (void)strcat(term, "/");
+ (void)sprintf(term + strlen(term), "%d", cfgetospeed(&tty));
+ }
+
+ (void)get_window_size(0, &winsize);
+
+ (void)signal(SIGPIPE, lostpeer);
+ /* will use SIGUSR1 for window size hack, so hold it off */
+ omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
+ /*
+ * We set SIGURG and SIGUSR1 below so that an
+ * incoming signal will be held pending rather than being
+ * discarded. Note that these routines will be ready to get
+ * a signal by the time that they are unblocked below.
+ */
+ (void)signal(SIGURG, copytochild);
+ (void)signal(SIGUSR1, writeroob);
+
+#ifdef KERBEROS
+try_connect:
+ if (use_kerberos) {
+ struct hostent *hp;
+
+ /* Fully qualify hostname (needed for krb_realmofhost). */
+ hp = gethostbyname(host);
+ if (hp != NULL && !(host = strdup(hp->h_name))) {
+ (void)fprintf(stderr, "rlogin: %s\n",
+ strerror(ENOMEM));
+ exit(1);
+ }
+
+ rem = KSUCCESS;
+ errno = 0;
+ if (dest_realm == NULL)
+ dest_realm = krb_realmofhost(host);
+
+#ifdef CRYPT
+ if (doencrypt)
+ rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
+ dest_realm, &cred, schedule);
+ else
+#endif /* CRYPT */
+ rem = krcmd(&host, sp->s_port, user, term, 0,
+ dest_realm);
+ if (rem < 0) {
+ use_kerberos = 0;
+ sp = getservbyname("login", "tcp");
+ if (sp == NULL) {
+ (void)fprintf(stderr,
+ "rlogin: unknown service login/tcp.\n");
+ exit(1);
+ }
+ if (errno == ECONNREFUSED)
+ warning("remote host doesn't support Kerberos");
+ if (errno == ENOENT)
+ warning("can't provide Kerberos auth data");
+ goto try_connect;
+ }
+ } else {
+#ifdef CRYPT
+ if (doencrypt) {
+ (void)fprintf(stderr,
+ "rlogin: the -x flag requires Kerberos authentication.\n");
+ exit(1);
+ }
+#endif /* CRYPT */
+ rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
+ }
+#else
+ rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
+#endif /* KERBEROS */
+
+ if (rem < 0)
+ exit(1);
+
+ if (dflag &&
+ setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
+ (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
+ strerror(errno));
+ one = IPTOS_LOWDELAY;
+ if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
+ perror("rlogin: setsockopt TOS (ignored)");
+
+ (void)setuid(uid);
+ doit(omask);
+ /*NOTREACHED*/
+}
+
+int child;
+
+void
+doit(omask)
+ long omask;
+{
+
+ (void)signal(SIGINT, SIG_IGN);
+ setsignal(SIGHUP);
+ setsignal(SIGQUIT);
+ mode(1);
+ child = fork();
+ if (child == -1) {
+ (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
+ done(1);
+ }
+ if (child == 0) {
+ if (reader(omask) == 0) {
+ msg("connection closed.");
+ exit(0);
+ }
+ sleep(1);
+ msg("\aconnection closed.");
+ exit(1);
+ }
+
+ /*
+ * We may still own the socket, and may have a pending SIGURG (or might
+ * receive one soon) that we really want to send to the reader. When
+ * one of these comes in, the trap copytochild simply copies such
+ * signals to the child. We can now unblock SIGURG and SIGUSR1
+ * that were set above.
+ */
+ (void)sigsetmask(omask);
+ (void)signal(SIGCHLD, catch_child);
+ writer();
+ msg("closed connection.");
+ done(0);
+}
+
+/* trap a signal, unless it is being ignored. */
+void
+setsignal(sig)
+ int sig;
+{
+ int omask = sigblock(sigmask(sig));
+
+ if (signal(sig, exit) == SIG_IGN)
+ (void)signal(sig, SIG_IGN);
+ (void)sigsetmask(omask);
+}
+
+__dead void
+done(status)
+ int status;
+{
+ int w, wstatus;
+
+ mode(0);
+ if (child > 0) {
+ /* make sure catch_child does not snap it up */
+ (void)signal(SIGCHLD, SIG_DFL);
+ if (kill(child, SIGKILL) >= 0)
+ while ((w = wait(&wstatus)) > 0 && w != child);
+ }
+ exit(status);
+}
+
+int dosigwinch;
+
+/*
+ * This is called when the reader process gets the out-of-band (urgent)
+ * request to turn on the window-changing protocol.
+ */
+void
+writeroob(signo)
+ int signo;
+{
+ if (dosigwinch == 0) {
+ sendwindow();
+ (void)signal(SIGWINCH, sigwinch);
+ }
+ dosigwinch = 1;
+}
+
+void
+catch_child(signo)
+ int signo;
+{
+ union wait status;
+ int pid;
+
+ for (;;) {
+ pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
+ if (pid == 0)
+ return;
+ /* if the child (reader) dies, just quit */
+ if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
+ done((int)(status.w_termsig | status.w_retcode));
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * writer: write to remote: 0 -> line.
+ * ~. terminate
+ * ~^Z suspend rlogin process.
+ * ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
+ */
+void
+writer()
+{
+ register int bol, local, n;
+ char c;
+
+ bol = 1; /* beginning of line */
+ local = 0;
+ for (;;) {
+ n = read(STDIN_FILENO, &c, 1);
+ if (n <= 0) {
+ if (n < 0 && errno == EINTR)
+ continue;
+ break;
+ }
+ /*
+ * If we're at the beginning of the line and recognize a
+ * command character, then we echo locally. Otherwise,
+ * characters are echo'd remotely. If the command character
+ * is doubled, this acts as a force and local echo is
+ * suppressed.
+ */
+ if (bol) {
+ bol = 0;
+ if (!noescape && c == escapechar) {
+ local = 1;
+ continue;
+ }
+ } else if (local) {
+ local = 0;
+ if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) {
+ echo(c);
+ break;
+ }
+ if (CCEQ(deftty.c_cc[VSUSP], c)) {
+ bol = 1;
+ echo(c);
+ stop(1);
+ continue;
+ }
+ if (CCEQ(deftty.c_cc[VDSUSP], c)) {
+ bol = 1;
+ echo(c);
+ stop(0);
+ continue;
+ }
+ if (c != escapechar)
+#ifdef CRYPT
+#ifdef KERBEROS
+ if (doencrypt)
+ (void)des_write(rem,
+ (char *)&escapechar, 1);
+ else
+#endif
+#endif
+ (void)write(rem, &escapechar, 1);
+ }
+
+#ifdef CRYPT
+#ifdef KERBEROS
+ if (doencrypt) {
+ if (des_write(rem, &c, 1) == 0) {
+ msg("line gone");
+ break;
+ }
+ } else
+#endif
+#endif
+ if (write(rem, &c, 1) == 0) {
+ msg("line gone");
+ break;
+ }
+ bol = CCEQ(deftty.c_cc[VKILL], c) ||
+ CCEQ(deftty.c_cc[VEOF], c) ||
+ CCEQ(deftty.c_cc[VINTR], c) ||
+ CCEQ(deftty.c_cc[VSUSP], c) ||
+ c == '\r' || c == '\n';
+ }
+}
+
+void
+#if __STDC__
+echo(register char c)
+#else
+echo(c)
+ register char c;
+#endif
+{
+ register char *p;
+ char buf[8];
+
+ p = buf;
+ c &= 0177;
+ *p++ = escapechar;
+ if (c < ' ') {
+ *p++ = '^';
+ *p++ = c + '@';
+ } else if (c == 0177) {
+ *p++ = '^';
+ *p++ = '?';
+ } else
+ *p++ = c;
+ *p++ = '\r';
+ *p++ = '\n';
+ (void)write(STDOUT_FILENO, buf, p - buf);
+}
+
+void
+stop(all)
+ int all;
+{
+ mode(0);
+ (void)signal(SIGCHLD, SIG_IGN);
+ (void)kill(all ? 0 : getpid(), SIGTSTP);
+ (void)signal(SIGCHLD, catch_child);
+ mode(1);
+ sigwinch(0); /* check for size changes */
+}
+
+void
+sigwinch(signo)
+ int signo;
+{
+ struct winsize ws;
+
+ if (dosigwinch && get_window_size(0, &ws) == 0 &&
+ bcmp(&ws, &winsize, sizeof(ws))) {
+ winsize = ws;
+ sendwindow();
+ }
+}
+
+/*
+ * Send the window size to the server via the magic escape
+ */
+void
+sendwindow()
+{
+ struct winsize *wp;
+ char obuf[4 + sizeof (struct winsize)];
+
+ wp = (struct winsize *)(obuf+4);
+ obuf[0] = 0377;
+ obuf[1] = 0377;
+ obuf[2] = 's';
+ obuf[3] = 's';
+ wp->ws_row = htons(winsize.ws_row);
+ wp->ws_col = htons(winsize.ws_col);
+ wp->ws_xpixel = htons(winsize.ws_xpixel);
+ wp->ws_ypixel = htons(winsize.ws_ypixel);
+
+#ifdef CRYPT
+#ifdef KERBEROS
+ if(doencrypt)
+ (void)des_write(rem, obuf, sizeof(obuf));
+ else
+#endif
+#endif
+ (void)write(rem, obuf, sizeof(obuf));
+}
+
+/*
+ * reader: read from remote: line -> 1
+ */
+#define READING 1
+#define WRITING 2
+
+jmp_buf rcvtop;
+int ppid, rcvcnt, rcvstate;
+char rcvbuf[8 * 1024];
+
+void
+oob(signo)
+ int signo;
+{
+ struct termios tty;
+ int atmark, n, rcvd;
+ char waste[BUFSIZ], mark;
+
+ rcvd = 0;
+ while (recv(rem, &mark, 1, MSG_OOB) < 0) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ /*
+ * Urgent data not here yet. It may not be possible
+ * to send it yet if we are blocked for output and
+ * our input buffer is full.
+ */
+ if (rcvcnt < sizeof(rcvbuf)) {
+ n = read(rem, rcvbuf + rcvcnt,
+ sizeof(rcvbuf) - rcvcnt);
+ if (n <= 0)
+ return;
+ rcvd += n;
+ } else {
+ n = read(rem, waste, sizeof(waste));
+ if (n <= 0)
+ return;
+ }
+ continue;
+ default:
+ return;
+ }
+ }
+ if (mark & TIOCPKT_WINDOW) {
+ /* Let server know about window size changes */
+ (void)kill(ppid, SIGUSR1);
+ }
+ if (!eight && (mark & TIOCPKT_NOSTOP)) {
+ (void)tcgetattr(0, &tty);
+ tty.c_iflag &= ~IXON;
+ (void)tcsetattr(0, TCSANOW, &tty);
+ }
+ if (!eight && (mark & TIOCPKT_DOSTOP)) {
+ (void)tcgetattr(0, &tty);
+ tty.c_iflag |= (deftty.c_iflag & IXON);
+ (void)tcsetattr(0, TCSANOW, &tty);
+ }
+ if (mark & TIOCPKT_FLUSHWRITE) {
+ (void)tcflush(1, TCIOFLUSH);
+ for (;;) {
+ if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
+ (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
+ strerror(errno));
+ break;
+ }
+ if (atmark)
+ break;
+ n = read(rem, waste, sizeof (waste));
+ if (n <= 0)
+ break;
+ }
+ /*
+ * Don't want any pending data to be output, so clear the recv
+ * buffer. If we were hanging on a write when interrupted,
+ * don't want it to restart. If we were reading, restart
+ * anyway.
+ */
+ rcvcnt = 0;
+ longjmp(rcvtop, 1);
+ }
+
+ /* oob does not do FLUSHREAD (alas!) */
+
+ /*
+ * If we filled the receive buffer while a read was pending, longjmp
+ * to the top to restart appropriately. Don't abort a pending write,
+ * however, or we won't know how much was written.
+ */
+ if (rcvd && rcvstate == READING)
+ longjmp(rcvtop, 1);
+}
+
+/* reader: read from remote: line -> 1 */
+int
+reader(omask)
+ int omask;
+{
+ int pid, n, remaining;
+ char *bufp;
+
+#if BSD >= 43 || defined(SUNOS4)
+ pid = getpid(); /* modern systems use positives for pid */
+#else
+ pid = -getpid(); /* old broken systems use negatives */
+#endif
+ (void)signal(SIGTTOU, SIG_IGN);
+ (void)signal(SIGURG, oob);
+ ppid = getppid();
+ (void)fcntl(rem, F_SETOWN, pid);
+ (void)setjmp(rcvtop);
+ (void)sigsetmask(omask);
+ bufp = rcvbuf;
+ for (;;) {
+ while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
+ rcvstate = WRITING;
+ n = write(STDOUT_FILENO, bufp, remaining);
+ if (n < 0) {
+ if (errno != EINTR)
+ return (-1);
+ continue;
+ }
+ bufp += n;
+ }
+ bufp = rcvbuf;
+ rcvcnt = 0;
+ rcvstate = READING;
+
+#ifdef CRYPT
+#ifdef KERBEROS
+ if (doencrypt)
+ rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
+ else
+#endif
+#endif
+ rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
+ if (rcvcnt == 0)
+ return (0);
+ if (rcvcnt < 0) {
+ if (errno == EINTR)
+ continue;
+ (void)fprintf(stderr, "rlogin: read: %s.\n",
+ strerror(errno));
+ return (-1);
+ }
+ }
+}
+
+void
+mode(f)
+ int f;
+{
+ struct termios tty;
+
+ switch (f) {
+ case 0:
+ (void)tcsetattr(0, TCSANOW, &deftty);
+ break;
+ case 1:
+ (void)tcgetattr(0, &deftty);
+ tty = deftty;
+ /* This is loosely derived from sys/compat/tty_compat.c. */
+ tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
+ tty.c_iflag &= ~ICRNL;
+ tty.c_oflag &= ~OPOST;
+ if (eight) {
+ tty.c_iflag &= IXOFF;
+ tty.c_cflag &= ~(CSIZE|PARENB);
+ tty.c_cflag |= CS8;
+ }
+ (void)tcsetattr(0, TCSANOW, &tty);
+ break;
+ default:
+ return;
+ }
+}
+
+void
+lostpeer(signo)
+ int signo;
+{
+ (void)signal(SIGPIPE, SIG_IGN);
+ msg("\aconnection closed.");
+ done(1);
+}
+
+/* copy SIGURGs to the child process. */
+void
+copytochild(signo)
+ int signo;
+{
+ (void)kill(child, SIGURG);
+}
+
+void
+msg(str)
+ char *str;
+{
+ (void)fprintf(stderr, "rlogin: %s\r\n", str);
+}
+
+#ifdef KERBEROS
+/* VARARGS */
+void
+#if __STDC__
+warning(const char *fmt, ...)
+#else
+warning(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, ".\n");
+}
+#endif
+
+__dead void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
+#ifdef KERBEROS
+#ifdef CRYPT
+ "8EKLx", " [-k realm] ");
+#else
+ "8EKL", " [-k realm] ");
+#endif
+#else
+ "8EL", " ");
+#endif
+ exit(1);
+}
+
+/*
+ * The following routine provides compatibility (such as it is) between older
+ * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
+ */
+#ifdef OLDSUN
+int
+get_window_size(fd, wp)
+ int fd;
+ struct winsize *wp;
+{
+ struct ttysize ts;
+ int error;
+
+ if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
+ return (error);
+ wp->ws_row = ts.ts_lines;
+ wp->ws_col = ts.ts_cols;
+ wp->ws_xpixel = 0;
+ wp->ws_ypixel = 0;
+ return (0);
+}
+#endif
+
+u_int
+getescape(p)
+ register char *p;
+{
+ long val;
+ int len;
+
+ if ((len = strlen(p)) == 1) /* use any single char, including '\' */
+ return ((u_int)*p);
+ /* otherwise, \nnn */
+ if (*p == '\\' && len >= 2 && len <= 4) {
+ val = strtol(++p, NULL, 8);
+ for (;;) {
+ if (!*++p)
+ return ((u_int)val);
+ if (*p < '0' || *p > '8')
+ break;
+ }
+ }
+ msg("illegal option value -- e");
+ usage();
+ /* NOTREACHED */
+}