* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
static char sccsid
[] = "@(#)rlogin.c 5.12 (Berkeley) %G%";
#include <sys/resource.h>
# define TIOCPKT_WINDOW 0x80
char *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
struct passwd
*getpwuid();
{ "0", "50", "75", "110", "134", "150", "200", "300",
"600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
char term
[256] = "network";
#define sigmask(m) (1 << ((m)-1))
unsigned short ws_row
, ws_col
;
unsigned short ws_xpixel
, ws_ypixel
;
* 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
;
#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
int uid
, options
= 0, oldmask
;
host
= rindex(argv
[0], '/');
if (!strcmp(host
, "rlogin"))
if (argc
> 0 && !strcmp(*argv
, "-d")) {
if (argc
> 0 && !strcmp(*argv
, "-l")) {
if (argc
> 0 && !strncmp(*argv
, "-e", 2)) {
if (argc
> 0 && !strcmp(*argv
, "-8")) {
if (argc
> 0 && !strcmp(*argv
, "-L")) {
pwd
= getpwuid(getuid());
fprintf(stderr
, "Who are you?\n");
sp
= getservbyname("login", "tcp");
fprintf(stderr
, "rlogin: login/tcp: unknown service\n");
if (ioctl(0, TIOCGETP
, &ttyb
) == 0) {
(void) strcat(term
, "/");
(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 */
oldmask
= sigblock(sigmask(SIGURG
) | sigmask(SIGUSR1
));
rem
= rcmd(&host
, sp
->s_port
, pwd
->pw_name
,
name
? name
: pwd
->pw_name
, term
, 0);
if (options
& SO_DEBUG
&&
setsockopt(rem
, SOL_SOCKET
, SO_DEBUG
, &on
, sizeof (on
)) < 0)
perror("rlogin: setsockopt (SO_DEBUG)");
perror("rlogin: setuid");
"usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
int copytochild(), writeroob();
struct tchars notc
= { -1, -1, -1, -1, -1, -1 };
struct ltchars noltc
= { -1, -1, -1, -1, -1, -1 };
(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
);
if (reader(oldmask
) == 0) {
prf("Connection closed.");
prf("\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
(void) signal(SIGURG
, copytochild
);
(void) signal(SIGUSR1
, writeroob
);
(void) sigsetmask(oldmask
);
(void) signal(SIGCHLD
, catchild
);
prf("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
);
(void) sigsetmask(omask
);
/* make sure catchild does not snap it up */
(void) signal(SIGCHLD
, SIG_DFL
);
if (kill(child
, SIGKILL
) >= 0)
while ((w
= wait((union wait
*)0)) > 0 && w
!= child
)
* Copy SIGURGs to the child process.
(void) kill(child
, SIGURG
);
* 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(&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.
* ~^Y suspend rlogin process, but leave reader alone.
register bol
= 1; /* beginning of line */
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 suppressed.
if (c
== '.' || c
== deftc
.t_eofc
) {
if (c
== defltc
.t_suspc
|| c
== defltc
.t_dsuspc
) {
(void) write(rem
, &cmdchar
, 1);
if (write(rem
, &c
, 1) == 0) {
bol
= c
== defkill
|| c
== deftc
.t_eofc
||
c
== deftc
.t_intrc
|| c
== defltc
.t_suspc
||
(void) write(1, buf
, p
- buf
);
(void) signal(SIGCHLD
, SIG_IGN
);
(void) kill(cmdc
== defltc
.t_suspc
? 0 : getpid(), SIGTSTP
);
(void) signal(SIGCHLD
, catchild
);
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
)];
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 out
= FWRITE
, atmark
, n
;
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) {
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,
* 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
);
(void) sigsetmask(oldmask
);
while ((remaining
= rcvcnt
- (bufp
- rcvbuf
)) > 0) {
n
= write(1, bufp
, remaining
);
rcvcnt
= read(rem
, rcvbuf
, sizeof (rcvbuf
));
(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
);
prf(f
, a1
, a2
, a3
, a4
, a5
)
fprintf(stderr
, f
, a1
, a2
, a3
, a4
, a5
);
(void) signal(SIGPIPE
, SIG_IGN
);
prf("\007Connection closed.");