Initial commit of rlogin utility

This commit is contained in:
taubert 1998-01-24 08:31:02 +00:00
parent 767546b525
commit d352e8757c
8 changed files with 1735 additions and 0 deletions

22
usr.bin/rlogin/Makefile Normal file
View File

@ -0,0 +1,22 @@
# @(#)Makefile 8.1 (Berkeley) 7/19/93
# $Id: Makefile,v 1.1 1998/01/24 08:30:54 taubert Exp $
PROG= rlogin
SRCS= rlogin.c
LDADD= -lnetdb
OPTIMIZE=79
#.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
# || defined(MAKE_EBONES))
#SRCS+= krcmd.c kcmd.c
#DPADD= ${LIBKRB} ${LIBDES}
#CFLAGS+=-DKERBEROS -DCRYPT
#LDADD= -lkrb -ldes
#DISTRIBUTION= krb
#.endif
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
.INCLUDE: /src/gno/prog.mk

307
usr.bin/rlogin/kcmd.c Normal file
View File

@ -0,0 +1,307 @@
/*
* 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
static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88";
static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93";
#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);
}
}
}

38
usr.bin/rlogin/krb.h Normal file
View File

@ -0,0 +1,38 @@
/*-
* 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
*/
int krcmd __P((char **, u_short, char *, char *, int *, char *));
int krcmd_mutual __P((char **, u_short, char *, char *, int *,
char *, CREDENTIALS *, Key_schedule));

158
usr.bin/rlogin/krcmd.c Normal file
View File

@ -0,0 +1,158 @@
/*
* 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
static char sccsid[] = "@(#)krcmd.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* $Source: /nobackup/gdr/copy-of-cvs-from-tekarra/gno/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 */
0, /* 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 */

188
usr.bin/rlogin/rlogin.1 Normal file
View File

@ -0,0 +1,188 @@
.\" 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 8DEKLdx
.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 D
The
.Fl D
option sets the TCP_NODELAY socket option which can improve interactive response
at the expense of increased network load.
.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.

982
usr.bin/rlogin/rlogin.c Normal file
View File

@ -0,0 +1,982 @@
/*
* 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
static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* rlogin - remote login
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#ifndef __GNO__
#include <sys/resource.h>
#endif
#include <sys/wait.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <sgtty.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
int eight, litout, rem;
int noescape;
u_char escapechar = '~';
char *speeds[] = {
"0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
"1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200"
};
#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, int));
void copytochild __P((int, int));
__dead void doit __P((long));
__dead void done __P((int));
void echo __P((char));
u_int getescape __P((char *));
void lostpeer __P((int, int));
void mode __P((int));
void msg __P((char *));
void oob __P((int, int));
int reader __P((long));
void sendwindow __P((void));
void setsignal __P((int));
void sigwinch __P((int, int));
void stop __P((char));
__dead void usage __P((void));
void writer __P((void));
void writeroob __P((int, int));
#ifdef KERBEROS
void warning __P((const char *, ...));
#endif
#ifdef OLDSUN
int get_window_size __P((int, struct winsize *));
#endif
int
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
struct passwd *pw;
struct servent *sp;
static struct sgttyb ttyb;
long omask;
int argoff, ch, dflag, Dflag, one, uid;
char *host, *p, *user;
static char term[1024];
argoff = dflag = 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 "8DEKLde:k:l:x"
#else
#define OPTIONS "8DEKLde:l:"
#endif
while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
switch(ch) {
case '8':
eight = 1;
break;
case 'D':
Dflag = 1;
break;
case 'E':
noescape = 1;
break;
case 'K':
#ifdef KERBEROS
use_kerberos = 0;
#endif
break;
case 'L':
litout = 1;
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;
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 (ioctl(STDIN_FILENO, TIOCGETP, &ttyb) == 0) {
(void)strcat(term, "/");
(void)strcat(term, speeds[(int)ttyb.sg_ospeed]);
}
(void)get_window_size(STDIN_FILENO, &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);
des_set_key(cred.session, 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));
if (Dflag &&
setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
perror("rlogin: setsockopt NODELAY (ignored)");
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, defflags, deflflags, tabflag;
char deferase, defkill;
struct tchars deftc;
struct ltchars defltc;
struct tchars notc = { -1, -1, -1, -1, -1, -1 };
struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
#ifdef __ORCAC__
#pragma databank 1
#endif
void
doit_child(long omask)
{
mode(1);
if (reader(omask) == 0) {
msg("connection closed.");
_exit(0);
}
sleep(1);
msg("\007connection closed.");
_exit(1);
}
#ifdef __ORCAC__
#pragma databank 0
#endif
void
doit(long omask)
{
static struct sgttyb sb;
(void)ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb);
defflags = sb.sg_flags;
tabflag = defflags & TBDELAY;
defflags &= ECHO | CRMOD;
deferase = sb.sg_erase;
defkill = sb.sg_kill;
(void)ioctl(STDIN_FILENO, TIOCLGET, &deflflags);
(void)ioctl(STDIN_FILENO, TIOCGETC, &deftc);
notc.t_startc = deftc.t_startc;
notc.t_stopc = deftc.t_stopc;
(void)ioctl(STDIN_FILENO, TIOCGLTC, &defltc);
(void)signal(SIGINT, SIG_IGN);
setsignal(SIGHUP);
setsignal(SIGQUIT);
child = fork2(doit_child, 1024, 0, "rlogin child", 2, omask);
if (child == -1) {
(void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
done(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(int sig)
{
long omask = sigblock(sigmask(sig));
if (signal(sig, exit) == SIG_IGN)
(void)signal(sig, SIG_IGN);
(void)sigsetmask(omask);
}
__dead void
done(int status)
{
int w;
union wait 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;
#ifdef __ORCAC__
#pragma databank 1
#endif
/*
* This is called when the reader process gets the out-of-band (urgent)
* request to turn on the window-changing protocol.
*/
void
writeroob(int signo, int code)
{
if (dosigwinch == 0) {
sendwindow();
(void)signal(SIGWINCH, sigwinch);
}
dosigwinch = 1;
}
void
catch_child(int signo, int code)
{
union wait status;
int pid;
for (;;) {
#ifdef __GNO__
pid = wait(&status);
#else
pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
#endif
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 */
}
#ifdef __ORCAC__
#pragma databank 0
#endif
/*
* writer: write to remote: 0 -> line.
* ~. terminate
* ~^Z suspend rlogin process.
* ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
*/
void
writer(void)
{
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 == '.' || c == deftc.t_eofc) {
echo(c);
break;
}
if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
bol = 1;
echo(c);
stop(c);
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 = c == defkill || c == deftc.t_eofc ||
c == deftc.t_intrc || c == defltc.t_suspc ||
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
#if __STDC__
stop(char cmdc)
#else
stop(cmdc)
char cmdc;
#endif
{
mode(0);
(void)signal(SIGCHLD, SIG_IGN);
(void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
(void)signal(SIGCHLD, catch_child);
mode(1);
sigwinch(0, 0); /* check for size changes */
}
#ifdef __ORCAC__
#pragma databank 1
#endif
void
sigwinch(int signo, int code)
{
static struct winsize ws;
#ifdef __GNO__
#define bcmp(__a, __b, __l) memcmp(__a, __b, __l)
#endif
if (dosigwinch && get_window_size(STDIN_FILENO, &ws) == 0 &&
bcmp(&ws, &winsize, sizeof(ws))) {
winsize = ws;
sendwindow();
}
}
#ifdef __ORCAC__
#pragma databank 0
#endif
/*
* Send the window size to the server via the magic escape
*/
void
sendwindow(void)
{
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];
#ifdef __ORCAC__
#pragma databank 1
#endif
void
oob(int signo, int code)
{
static struct sgttyb sb;
int atmark, n, out, rcvd;
static char waste[BUFSIZ];
char mark;
out = O_RDWR;
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)ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb);
sb.sg_flags &= ~CBREAK;
sb.sg_flags |= RAW;
(void)ioctl(STDIN_FILENO, TIOCSETN, (char *)&sb);
notc.t_stopc = -1;
notc.t_startc = -1;
(void)ioctl(STDIN_FILENO, TIOCSETC, (char *)&notc);
}
if (!eight && (mark & TIOCPKT_DOSTOP)) {
(void)ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb);
sb.sg_flags &= ~RAW;
sb.sg_flags |= CBREAK;
(void)ioctl(STDIN_FILENO, TIOCSETN, (char *)&sb);
notc.t_stopc = deftc.t_stopc;
notc.t_startc = deftc.t_startc;
(void)ioctl(STDIN_FILENO, TIOCSETC, (char *)&notc);
}
if (mark & TIOCPKT_FLUSHWRITE) {
(void)ioctl(STDOUT_FILENO, TIOCFLUSH, (char *)&out);
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);
}
#ifdef __ORCAC__
#pragma databank 0
#endif
/* reader: read from remote: line -> 1 */
int
reader(long 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();
#ifndef __GNO__
(void)fcntl(rem, F_SETOWN, pid);
#endif
(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(int f)
{
struct ltchars *ltc;
static struct sgttyb sb;
struct tchars *tc;
int lflags;
(void)ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb);
(void)ioctl(STDIN_FILENO, TIOCLGET, (char *)&lflags);
switch(f) {
case 0:
sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
sb.sg_flags |= defflags|tabflag;
tc = &deftc;
ltc = &defltc;
sb.sg_kill = defkill;
sb.sg_erase = deferase;
lflags = deflflags;
break;
case 1:
sb.sg_flags |= (eight ? RAW : CBREAK);
sb.sg_flags &= ~defflags;
/* preserve tab delays, but turn off XTABS */
if ((sb.sg_flags & TBDELAY) == XTABS)
sb.sg_flags &= ~TBDELAY;
tc = &notc;
ltc = &noltc;
sb.sg_kill = sb.sg_erase = -1;
if (litout)
lflags |= LLITOUT;
break;
default:
return;
}
(void)ioctl(STDIN_FILENO, TIOCSLTC, (char *)ltc);
(void)ioctl(STDIN_FILENO, TIOCSETC, (char *)tc);
(void)ioctl(STDIN_FILENO, TIOCSETN, (char *)&sb);
(void)ioctl(STDIN_FILENO, TIOCLSET, (char *)&lflags);
}
#ifdef __ORCAC__
#pragma databank 1
#endif
void
lostpeer(int signo, int code)
{
(void)signal(SIGPIPE, SIG_IGN);
msg("\007connection closed.");
done(1);
}
/* copy SIGURGs to the child process. */
void
copytochild(int signo, int code)
{
(void)kill(child, SIGURG);
}
#ifdef __ORCAC__
#pragma databank 0
#endif
void
msg(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)
{
(void)fprintf(stderr,
"usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
#ifdef KERBEROS
#ifdef CRYPT
"8DEKLx", " [-k realm] ");
#else
"8DEKL", " [-k realm] ");
#endif
#else
"8DEL", " ");
#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(STDIN_FILENO, 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(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 */
}

View File

@ -0,0 +1,9 @@
Name: rlogin
Version: 1.0 (November 1997)
Shell: GNO & GS/TCP
Author: Derek Taubert (from FreeBSD 2.1.0 code)
Contact: taubert@geeks.org
Where: /usr/bin
FTP: ground.isca.uiowa.edu apple2.caltech.edu trenco.myrias.com
Remote login.

31
usr.bin/rlogin/rlogin.rez Normal file
View File

@ -0,0 +1,31 @@
/*
* Resources for rlogin version and comment
*
* $Id: rlogin.rez,v 1.1 1998/01/24 08:31:02 taubert Exp $
*/
#define PROG "rlogin"
#define DESC "Remote login."
#include "Types.rez"
/*
* Version
*/
resource rVersion (1, purgeable3) {
{ 1, 0, 0, /* Version 1.0.0 */
release, /* development|alpha|beta|final|release */
0 }, /* non-final release number */
verUS, /* Country */
PROG, /* Program name */
DESC " Released with GNO/ME and GS/TCP."
};
/*
* Comment
*/
resource rComment (1, purgeable3) {
PROG " v1.0 (November 1997)\n"
"GNO utility: " DESC "\n"
"Ported from FreeBSD 2.1.0 code by Derek Taubert."
};