* Copyright (c) 1983, 1990 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
"@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)rlogin.c 5.33.1.1 (Berkeley) 8/20/91";
* $Source: mit/rlogin/RCS/rlogin.c,v $
* $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall
#include <sys/resource.h>
#include <netinet/in_systm.h>
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
int use_kerberos
= 1, doencrypt
;
char dst_realm_buf
[REALM_SZ
], *dest_realm
= NULL
;
extern char *krb_realmofhost();
#define TIOCPKT_WINDOW 0x80
"0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
"1800", "2400", "4800", "9600", "19200", "38400"
unsigned short ws_row
, ws_col
;
unsigned short ws_xpixel
, ws_ypixel
;
#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
int argoff
, ch
, dflag
, one
, uid
;
char *host
, *p
, *user
, term
[1024];
if (p
= rindex(argv
[0], '/'))
/* handle "rlogin host flags" */
if (!host
&& argc
> 2 && argv
[1][0] != '-') {
#define OPTIONS "8EKLde:k:l:x"
#define OPTIONS "8EKLde:l:"
while ((ch
= getopt(argc
- argoff
, argv
+ argoff
, OPTIONS
)) != EOF
)
escapechar
= getescape(optarg
);
dest_realm
= dst_realm_buf
;
(void)strncpy(dest_realm
, optarg
, REALM_SZ
);
/* if haven't gotten a host yet, do so */
if (!host
&& !(host
= *argv
++))
if (!(pw
= getpwuid(uid
= getuid()))) {
(void)fprintf(stderr
, "rlogin: unknown user id.\n");
sp
= getservbyname((doencrypt
? "eklogin" : "klogin"), "tcp");
warning("can't get entry for %s/tcp service",
doencrypt
? "eklogin" : "klogin");
sp
= getservbyname("login", "tcp");
(void)fprintf(stderr
, "rlogin: login/tcp: unknown service.\n");
(void)strcpy(term
, (p
= getenv("TERM")) ? p
: "network");
if (ioctl(0, TIOCGETP
, &ttyb
) == 0) {
(void)strcat(term
, speeds
[ttyb
.sg_ospeed
]);
(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
));
dest_realm
= krb_realmofhost(host
);
rem
= krcmd(&host
, sp
->s_port
, user
, term
, 0,
sp
= getservbyname("login", "tcp");
"rlogin: unknown service login/tcp.\n");
if (errno
== ECONNREFUSED
)
warning("remote host doesn't support Kerberos");
warning("can't provide Kerberos auth data");
rem
= rcmd(&host
, sp
->s_port
, pw
->pw_name
, user
, term
, 0);
rem
= rcmd(&host
, sp
->s_port
, pw
->pw_name
, user
, term
, 0);
setsockopt(rem
, SOL_SOCKET
, SO_DEBUG
, &one
, sizeof(one
)) < 0)
(void)fprintf(stderr
, "rlogin: setsockopt: %s.\n",
if (setsockopt(rem
, IPPROTO_IP
, IP_TOS
, (char *)&one
, sizeof(int)) < 0)
perror("rlogin: setsockopt TOS (ignored)");
int child
, defflags
, deflflags
, tabflag
;
struct tchars notc
= { -1, -1, -1, -1, -1, -1 };
struct ltchars noltc
= { -1, -1, -1, -1, -1, -1 };
void catch_child(), copytochild(), exit(), writeroob();
(void)ioctl(0, TIOCGETP
, (char *)&sb
);
tabflag
= defflags
& TBDELAY
;
defflags
&= ECHO
| CRMOD
;
(void)ioctl(0, TIOCLGET
, (char *)&deflflags
);
(void)ioctl(0, TIOCGETC
, (char *)&deftc
);
notc
.t_startc
= deftc
.t_startc
;
notc
.t_stopc
= deftc
.t_stopc
;
(void)ioctl(0, TIOCGLTC
, (char *)&defltc
);
(void)signal(SIGINT
, SIG_IGN
);
setsignal(SIGQUIT
, exit
);
(void)fprintf(stderr
, "rlogin: fork: %s.\n", strerror(errno
));
if (reader(omask
) == 0) {
msg("connection closed.");
msg("\007connection closed.");
* 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. Set a
* trap that simply copies such signals to the child.
(void)signal(SIGURG
, copytochild
);
(void)signal(SIGUSR1
, writeroob
);
(void)signal(SIGCHLD
, catch_child
);
msg("closed connection.");
/* trap a signal, unless it is being ignored. */
int omask
= sigblock(sigmask(sig
));
if (signal(sig
, act
) == SIG_IGN
)
(void)signal(sig
, SIG_IGN
);
/* 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
);
* This is called when the reader process gets the out-of-band (urgent)
* request to turn on the window-changing protocol.
(void)signal(SIGWINCH
, sigwinch
);
pid
= wait3((int *)&status
,
WNOHANG
|WUNTRACED
, (struct rusage
*)0);
/* if the child (reader) dies, just quit */
if (pid
< 0 || pid
== child
&& !WIFSTOPPED(status
))
done((int)(status
.w_termsig
| status
.w_retcode
));
* writer: write to remote: 0 -> line.
* ~^Z suspend rlogin process.
* ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
register int bol
, local
, n
;
bol
= 1; /* beginning of line */
n
= read(STDIN_FILENO
, &c
, 1);
if (n
< 0 && errno
== EINTR
)
* 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
if (!noescape
&& c
== escapechar
) {
if (c
== '.' || c
== deftc
.t_eofc
) {
if (c
== defltc
.t_suspc
|| c
== defltc
.t_dsuspc
) {
(void)write(rem
, &escapechar
, 1);
if (write(rem
, &c
, 1) == 0) {
bol
= c
== defkill
|| c
== deftc
.t_eofc
||
c
== deftc
.t_intrc
|| c
== defltc
.t_suspc
||
(void)write(STDOUT_FILENO
, buf
, p
- buf
);
(void)signal(SIGCHLD
, SIG_IGN
);
(void)kill(cmdc
== defltc
.t_suspc
? 0 : getpid(), SIGTSTP
);
(void)signal(SIGCHLD
, catch_child
);
sigwinch(); /* check for size changes */
if (dosigwinch
&& get_window_size(0, &ws
) == 0 &&
bcmp(&ws
, &winsize
, sizeof(ws
))) {
* Send the window size to the server via the magic escape
char obuf
[4 + sizeof (struct winsize
)];
wp
= (struct winsize
*)(obuf
+4);
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
);
(void)write(rem
, obuf
, sizeof(obuf
));
* reader: read from remote: line -> 1
int ppid
, rcvcnt
, rcvstate
;
int atmark
, n
, out
, rcvd
;
char waste
[BUFSIZ
], mark
;
while (recv(rem
, &mark
, 1, MSG_OOB
) < 0)
* 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
);
n
= read(rem
, waste
, sizeof(waste
));
if (mark
& TIOCPKT_WINDOW
) {
/* Let server know about window size changes */
(void)kill(ppid
, SIGUSR1
);
if (!eight
&& (mark
& TIOCPKT_NOSTOP
)) {
(void)ioctl(0, TIOCGETP
, (char *)&sb
);
(void)ioctl(0, TIOCSETN
, (char *)&sb
);
(void)ioctl(0, TIOCSETC
, (char *)¬c
);
if (!eight
&& (mark
& TIOCPKT_DOSTOP
)) {
(void)ioctl(0, TIOCGETP
, (char *)&sb
);
(void)ioctl(0, TIOCSETN
, (char *)&sb
);
notc
.t_stopc
= deftc
.t_stopc
;
notc
.t_startc
= deftc
.t_startc
;
(void)ioctl(0, TIOCSETC
, (char *)¬c
);
if (mark
& TIOCPKT_FLUSHWRITE
) {
(void)ioctl(1, TIOCFLUSH
, (char *)&out
);
if (ioctl(rem
, SIOCATMARK
, &atmark
) < 0) {
(void)fprintf(stderr
, "rlogin: ioctl: %s.\n",
n
= read(rem
, waste
, sizeof (waste
));
* 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
/* 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
)
/* reader: read from remote: line -> 1 */
#if !defined(BSD) || BSD < 43
(void)signal(SIGTTOU
, SIG_IGN
);
(void)signal(SIGURG
, oob
);
(void)fcntl(rem
, F_SETOWN
, pid
);
while ((remaining
= rcvcnt
- (bufp
- rcvbuf
)) > 0) {
n
= write(STDOUT_FILENO
, bufp
, remaining
);
rcvcnt
= read(rem
, rcvbuf
, sizeof (rcvbuf
));
(void)fprintf(stderr
, "rlogin: read: %s.\n",
(void)ioctl(0, TIOCGETP
, (char *)&sb
);
(void)ioctl(0, TIOCLGET
, (char *)&lflags
);
sb
.sg_flags
&= ~(CBREAK
|RAW
|TBDELAY
);
sb
.sg_flags
|= defflags
|tabflag
;
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_kill
= sb
.sg_erase
= -1;
(void)ioctl(0, TIOCSLTC
, (char *)ltc
);
(void)ioctl(0, TIOCSETC
, (char *)tc
);
(void)ioctl(0, TIOCSETN
, (char *)&sb
);
(void)ioctl(0, TIOCLSET
, (char *)&lflags
);
(void)signal(SIGPIPE
, SIG_IGN
);
msg("\007connection closed.");
/* copy SIGURGs to the child process. */
(void)kill(child
, SIGURG
);
(void)fprintf(stderr
, "rlogin: %s\r\n", str
);
(void)fprintf(stderr
, "rlogin: warning, using standard rlogin: ");
fmt
= va_arg(ap
, char *);
vfprintf(stderr
, fmt
, ap
);
(void)fprintf(stderr
, ".\n");
"usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
* The following routine provides compatibility (such as it is) between 4.2BSD
* Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
if ((error
= ioctl(0, TIOCGSIZE
, &ts
)) != 0)
wp
->ws_row
= ts
.ts_lines
;
if ((len
= strlen(p
)) == 1) /* use any single char, including '\' */
if (*p
== '\\' && len
>= 2 && len
<= 4) {
val
= strtol(++p
, (char **)NULL
, 8);
if (*p
< '0' || *p
> '8')
msg("illegal option value -- e");