version 1.14, 1996/08/10 19:47:32 |
version 1.15, 1997/01/09 06:57:46 |
Line 41 static char copyright[] = |
|
Line 41 static char copyright[] = |
|
|
|
#ifndef lint |
#ifndef lint |
#if 0 |
#if 0 |
static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; |
static char sccsid[] = "@(#)rlogin.c 8.4 (Berkeley) 4/29/95"; |
#else |
#else |
static char rcsid[] = "$NetBSD$"; |
static char rcsid[] = "$NetBSD$"; |
#endif |
#endif |
Line 56 static char rcsid[] = "$NetBSD$"; |
|
Line 56 static char rcsid[] = "$NetBSD$"; |
|
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/resource.h> |
#include <sys/resource.h> |
#include <sys/wait.h> |
#include <sys/wait.h> |
|
#include <sys/ioctl.h> |
|
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <netinet/in_systm.h> |
#include <netinet/in_systm.h> |
Line 122 struct winsize winsize; |
|
Line 123 struct winsize winsize; |
|
|
|
void catch_child __P((int)); |
void catch_child __P((int)); |
void copytochild __P((int)); |
void copytochild __P((int)); |
__dead void doit __P((long)); |
__dead void doit __P((sigset_t *)); |
__dead void done __P((int)); |
__dead void done __P((int)); |
void echo __P((char)); |
void echo __P((char)); |
u_int getescape __P((char *)); |
u_int getescape __P((char *)); |
Line 130 void lostpeer __P((int)); |
|
Line 131 void lostpeer __P((int)); |
|
void mode __P((int)); |
void mode __P((int)); |
void msg __P((char *)); |
void msg __P((char *)); |
void oob __P((int)); |
void oob __P((int)); |
int reader __P((int)); |
int reader __P((sigset_t *)); |
void sendwindow __P((void)); |
void sendwindow __P((void)); |
void setsignal __P((int)); |
void setsignal __P((int)); |
|
int speed __P((int)); |
void sigwinch __P((int)); |
void sigwinch __P((int)); |
void stop __P((int)); |
void stop __P((int)); |
__dead void usage __P((void)); |
__dead void usage __P((void)); |
Line 151 main(argc, argv) |
|
Line 153 main(argc, argv) |
|
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
extern char *optarg; |
|
extern int optind; |
|
struct passwd *pw; |
struct passwd *pw; |
struct servent *sp; |
struct servent *sp; |
struct termios tty; |
struct termios tty; |
long omask; |
sigset_t smask; |
int argoff, ch, dflag, one, uid; |
int argoff, ch, dflag, one, uid; |
int i, len, len2; |
int i, len, len2; |
char *host, *p, *user, term[1024] = "network"; |
char *host, *p, *user, term[1024] = "network"; |
speed_t ospeed; |
speed_t ospeed; |
|
struct sigaction sa; |
|
|
argoff = dflag = 0; |
argoff = dflag = 0; |
one = 1; |
one = 1; |
host = user = NULL; |
host = user = NULL; |
|
|
if (p = rindex(argv[0], '/')) |
if (p = strrchr(argv[0], '/')) |
++p; |
++p; |
else |
else |
p = argv[0]; |
p = argv[0]; |
|
|
if (strcmp(p, "rlogin")) |
if (strcmp(p, "rlogin") != 0) |
host = p; |
host = p; |
|
|
/* handle "rlogin host flags" */ |
/* handle "rlogin host flags" */ |
Line 237 main(argc, argv) |
|
Line 238 main(argc, argv) |
|
if (*argv) |
if (*argv) |
usage(); |
usage(); |
|
|
if (!(pw = getpwuid(uid = getuid()))) { |
if (!(pw = getpwuid(uid = getuid()))) |
(void)fprintf(stderr, "rlogin: unknown user id.\n"); |
errx(1, "unknown user id."); |
exit(1); |
/* Accept user1@host format, though "-l user2" overrides user1 */ |
|
p = strchr(host, '@'); |
|
if (p) { |
|
*p = '\0'; |
|
if (!user && p > host) |
|
user = host; |
|
host = p + 1; |
|
if (*host == '\0') |
|
usage(); |
} |
} |
if (!user) |
if (!user) |
user = pw->pw_name; |
user = pw->pw_name; |
Line 257 main(argc, argv) |
|
Line 266 main(argc, argv) |
|
#endif |
#endif |
if (sp == NULL) |
if (sp == NULL) |
sp = getservbyname("login", "tcp"); |
sp = getservbyname("login", "tcp"); |
if (sp == NULL) { |
if (sp == NULL) |
(void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); |
errx(1, "login/tcp: unknown service."); |
exit(1); |
|
} |
|
|
|
if (p = getenv("TERM")) { |
if (p = getenv("TERM")) { |
(void)strncpy(term, p, sizeof(term) - 1); |
(void)strncpy(term, p, sizeof(term) - 1); |
Line 278 main(argc, argv) |
|
Line 285 main(argc, argv) |
|
|
|
(void)get_window_size(0, &winsize); |
(void)get_window_size(0, &winsize); |
|
|
(void)signal(SIGPIPE, lostpeer); |
sigemptyset(&sa.sa_mask); |
|
sa.sa_flags = SA_RESTART; |
|
sa.sa_handler = lostpeer; |
|
(void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); |
/* will use SIGUSR1 for window size hack, so hold it off */ |
/* will use SIGUSR1 for window size hack, so hold it off */ |
omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); |
sigemptyset(&smask); |
|
sigaddset(&smask, SIGURG); |
|
sigaddset(&smask, SIGUSR1); |
|
(void)sigprocmask(SIG_SETMASK, &smask, &smask); |
/* |
/* |
* We set SIGURG and SIGUSR1 below so that an |
* We set SIGURG and SIGUSR1 below so that an |
* incoming signal will be held pending rather than being |
* incoming signal will be held pending rather than being |
* discarded. Note that these routines will be ready to get |
* discarded. Note that these routines will be ready to get |
* a signal by the time that they are unblocked below. |
* a signal by the time that they are unblocked below. |
*/ |
*/ |
(void)signal(SIGURG, copytochild); |
sa.sa_handler = copytochild; |
(void)signal(SIGUSR1, writeroob); |
(void)sigaction(SIGURG, &sa, (struct sigaction *) 0); |
|
sa.sa_handler = writeroob; |
|
(void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0); |
|
|
#ifdef KERBEROS |
#ifdef KERBEROS |
try_connect: |
try_connect: |
|
|
|
|
/* Fully qualify hostname (needed for krb_realmofhost). */ |
/* Fully qualify hostname (needed for krb_realmofhost). */ |
hp = gethostbyname(host); |
hp = gethostbyname(host); |
if (hp != NULL && !(host = strdup(hp->h_name))) { |
if (hp != NULL && !(host = strdup(hp->h_name))) |
(void)fprintf(stderr, "rlogin: %s\n", |
errx(1, "%s", strerror(ENOMEM)); |
strerror(ENOMEM)); |
|
exit(1); |
|
} |
|
|
|
rem = KSUCCESS; |
rem = KSUCCESS; |
errno = 0; |
errno = 0; |
|
|
if (rem < 0) { |
if (rem < 0) { |
use_kerberos = 0; |
use_kerberos = 0; |
sp = getservbyname("login", "tcp"); |
sp = getservbyname("login", "tcp"); |
if (sp == NULL) { |
if (sp == NULL) |
(void)fprintf(stderr, |
errx(1, "unknown service login/tcp."); |
"rlogin: unknown service login/tcp.\n"); |
|
exit(1); |
|
} |
|
if (errno == ECONNREFUSED) |
if (errno == ECONNREFUSED) |
warning("remote host doesn't support Kerberos"); |
warning("remote host doesn't support Kerberos"); |
if (errno == ENOENT) |
if (errno == ENOENT) |
|
|
} |
} |
} else { |
} else { |
#ifdef CRYPT |
#ifdef CRYPT |
if (doencrypt) { |
if (doencrypt) |
(void)fprintf(stderr, |
errx(1, "the -x flag requires Kerberos authentication."); |
"rlogin: the -x flag requires Kerberos authentication.\n"); |
|
exit(1); |
|
} |
|
#endif /* CRYPT */ |
#endif /* CRYPT */ |
rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); |
rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); |
} |
} |
|
|
|
|
if (dflag && |
if (dflag && |
setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) |
setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) |
(void)fprintf(stderr, "rlogin: setsockopt: %s.\n", |
warn("setsockopt DEBUG (ignored)"); |
strerror(errno)); |
|
one = IPTOS_LOWDELAY; |
one = IPTOS_LOWDELAY; |
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) |
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) |
perror("rlogin: setsockopt TOS (ignored)"); |
warn("setsockopt TOS (ignored)"); |
|
|
(void)setuid(uid); |
(void)setuid(uid); |
doit(omask); |
doit(&smask); |
/*NOTREACHED*/ |
/*NOTREACHED*/ |
} |
} |
|
|
int child; |
#if BSD >= 198810 |
|
int |
|
speed(fd) |
|
int fd; |
|
{ |
|
struct termios tt; |
|
|
|
(void)tcgetattr(fd, &tt); |
|
|
|
return ((int) cfgetispeed(&tt)); |
|
} |
|
#else |
|
int speeds[] = { /* for older systems, B0 .. EXTB */ |
|
0, 50, 75, 110, |
|
134, 150, 200, 300, |
|
600, 1200, 1800, 2400, |
|
4800, 9600, 19200, 38400 |
|
}; |
|
|
|
int |
|
speed(fd) |
|
int fd; |
|
{ |
|
struct termios tt; |
|
|
|
(void)tcgetattr(fd, &tt); |
|
|
|
return (speeds[(int)cfgetispeed(&tt)]); |
|
} |
|
#endif |
|
|
|
pid_t child; |
|
struct termios deftt; |
|
struct termios nott; |
|
|
void |
void |
doit(omask) |
doit(smask) |
long omask; |
sigset_t *smask; |
{ |
{ |
|
int i; |
|
struct sigaction sa; |
|
|
(void)signal(SIGINT, SIG_IGN); |
for (i = 0; i < NCCS; i++) |
|
nott.c_cc[i] = _POSIX_VDISABLE; |
|
tcgetattr(0, &deftt); |
|
nott.c_cc[VSTART] = deftt.c_cc[VSTART]; |
|
nott.c_cc[VSTOP] = deftt.c_cc[VSTOP]; |
|
sigemptyset(&sa.sa_mask); |
|
sa.sa_flags = SA_RESTART; |
|
sa.sa_handler = SIG_IGN; |
|
(void)sigaction(SIGINT, &sa, (struct sigaction *) 0); |
setsignal(SIGHUP); |
setsignal(SIGHUP); |
setsignal(SIGQUIT); |
setsignal(SIGQUIT); |
mode(1); |
mode(1); |
child = fork(); |
child = fork(); |
if (child == -1) { |
if (child == -1) { |
(void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); |
warn("fork"); |
done(1); |
done(1); |
} |
} |
if (child == 0) { |
if (child == 0) { |
if (reader(omask) == 0) { |
mode(1); |
|
if (reader(smask) == 0) { |
msg("connection closed."); |
msg("connection closed."); |
exit(0); |
exit(0); |
} |
} |
|
|
* signals to the child. We can now unblock SIGURG and SIGUSR1 |
* signals to the child. We can now unblock SIGURG and SIGUSR1 |
* that were set above. |
* that were set above. |
*/ |
*/ |
(void)sigsetmask(omask); |
(void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); |
(void)signal(SIGCHLD, catch_child); |
sa.sa_handler = catch_child; |
|
(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); |
writer(); |
writer(); |
msg("closed connection."); |
msg("closed connection."); |
done(0); |
done(0); |
|
|
setsignal(sig) |
setsignal(sig) |
int sig; |
int sig; |
{ |
{ |
int omask = sigblock(sigmask(sig)); |
struct sigaction sa; |
|
sigset_t sigs; |
|
|
|
sigemptyset(&sigs); |
|
sigaddset(&sigs, sig); |
|
sigprocmask(SIG_BLOCK, &sigs, &sigs); |
|
|
|
sigemptyset(&sa.sa_mask); |
|
sa.sa_handler = exit; |
|
sa.sa_flags = SA_RESTART; |
|
(void)sigaction(sig, &sa, &sa); |
|
if (sa.sa_handler == SIG_IGN) |
|
(void)sigaction(sig, &sa, (struct sigaction *) 0); |
|
|
if (signal(sig, exit) == SIG_IGN) |
(void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0); |
(void)signal(sig, SIG_IGN); |
|
(void)sigsetmask(omask); |
|
} |
} |
|
|
__dead void |
__dead void |
done(status) |
done(status) |
int status; |
int status; |
{ |
{ |
int w, wstatus; |
pid_t w; |
|
int wstatus; |
|
struct sigaction sa; |
|
|
mode(0); |
mode(0); |
if (child > 0) { |
if (child > 0) { |
/* make sure catch_child does not snap it up */ |
/* make sure catch_child does not snap it up */ |
(void)signal(SIGCHLD, SIG_DFL); |
sigemptyset(&sa.sa_mask); |
|
sa.sa_handler = SIG_DFL; |
|
sa.sa_flags = 0; |
|
(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); |
if (kill(child, SIGKILL) >= 0) |
if (kill(child, SIGKILL) >= 0) |
while ((w = wait(&wstatus)) > 0 && w != child); |
while ((w = wait(&wstatus)) > 0 && w != child) |
|
continue; |
} |
} |
exit(status); |
exit(status); |
} |
} |
|
|
writeroob(signo) |
writeroob(signo) |
int signo; |
int signo; |
{ |
{ |
|
struct sigaction sa; |
|
|
if (dosigwinch == 0) { |
if (dosigwinch == 0) { |
sendwindow(); |
sendwindow(); |
(void)signal(SIGWINCH, sigwinch); |
sigemptyset(&sa.sa_mask); |
|
sa.sa_handler = sigwinch; |
|
sa.sa_flags = SA_RESTART; |
|
(void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0); |
} |
} |
dosigwinch = 1; |
dosigwinch = 1; |
} |
} |
|
|
catch_child(signo) |
catch_child(signo) |
int signo; |
int signo; |
{ |
{ |
union wait status; |
int status; |
int pid; |
pid_t pid; |
|
|
for (;;) { |
for (;;) { |
pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); |
pid = waitpid(-1, &status, WNOHANG|WUNTRACED); |
if (pid == 0) |
if (pid == 0) |
return; |
return; |
/* if the child (reader) dies, just quit */ |
/* if the child (reader) dies, just quit */ |
if (pid < 0 || (pid == child && !WIFSTOPPED(status))) |
if (pid < 0 || (pid == child && !WIFSTOPPED(status))) |
done((int)(status.w_termsig | status.w_retcode)); |
done(WEXITSTATUS(status) | WTERMSIG(status)); |
} |
} |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
stop(all) |
stop(all) |
int all; |
int all; |
{ |
{ |
|
struct sigaction sa; |
|
|
mode(0); |
mode(0); |
(void)signal(SIGCHLD, SIG_IGN); |
sigemptyset(&sa.sa_mask); |
|
sa.sa_handler = SIG_IGN; |
|
sa.sa_flags = SA_RESTART; |
|
(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); |
(void)kill(all ? 0 : getpid(), SIGTSTP); |
(void)kill(all ? 0 : getpid(), SIGTSTP); |
(void)signal(SIGCHLD, catch_child); |
sa.sa_handler = catch_child; |
|
(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); |
mode(1); |
mode(1); |
sigwinch(0); /* check for size changes */ |
sigwinch(0); /* check for size changes */ |
} |
} |
|
|
struct winsize ws; |
struct winsize ws; |
|
|
if (dosigwinch && get_window_size(0, &ws) == 0 && |
if (dosigwinch && get_window_size(0, &ws) == 0 && |
bcmp(&ws, &winsize, sizeof(ws))) { |
memcmp(&ws, &winsize, sizeof(ws))) { |
winsize = ws; |
winsize = ws; |
sendwindow(); |
sendwindow(); |
} |
} |
|
|
#define WRITING 2 |
#define WRITING 2 |
|
|
jmp_buf rcvtop; |
jmp_buf rcvtop; |
int ppid, rcvcnt, rcvstate; |
pid_t ppid; |
|
int rcvcnt, rcvstate; |
char rcvbuf[8 * 1024]; |
char rcvbuf[8 * 1024]; |
|
|
void |
void |
|
|
(void)tcflush(1, TCIOFLUSH); |
(void)tcflush(1, TCIOFLUSH); |
for (;;) { |
for (;;) { |
if (ioctl(rem, SIOCATMARK, &atmark) < 0) { |
if (ioctl(rem, SIOCATMARK, &atmark) < 0) { |
(void)fprintf(stderr, "rlogin: ioctl: %s.\n", |
warn("ioctl SIOCATMARK (ignored)"); |
strerror(errno)); |
|
break; |
break; |
} |
} |
if (atmark) |
if (atmark) |
|
|
|
|
/* reader: read from remote: line -> 1 */ |
/* reader: read from remote: line -> 1 */ |
int |
int |
reader(omask) |
reader(smask) |
int omask; |
sigset_t *smask; |
{ |
{ |
int pid, n, remaining; |
pid_t pid; |
|
int n, remaining; |
char *bufp; |
char *bufp; |
|
struct sigaction sa; |
|
|
#if BSD >= 43 || defined(SUNOS4) |
#if BSD >= 43 || defined(SUNOS4) |
pid = getpid(); /* modern systems use positives for pid */ |
pid = getpid(); /* modern systems use positives for pid */ |
#else |
#else |
pid = -getpid(); /* old broken systems use negatives */ |
pid = -getpid(); /* old broken systems use negatives */ |
#endif |
#endif |
(void)signal(SIGTTOU, SIG_IGN); |
sigemptyset(&sa.sa_mask); |
(void)signal(SIGURG, oob); |
sa.sa_flags = SA_RESTART; |
|
sa.sa_handler = SIG_IGN; |
|
(void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0); |
|
sa.sa_handler = oob; |
|
(void)sigaction(SIGURG, &sa, (struct sigaction *) 0); |
ppid = getppid(); |
ppid = getppid(); |
(void)fcntl(rem, F_SETOWN, pid); |
(void)fcntl(rem, F_SETOWN, pid); |
(void)setjmp(rcvtop); |
(void)setjmp(rcvtop); |
(void)sigsetmask(omask); |
(void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); |
bufp = rcvbuf; |
bufp = rcvbuf; |
for (;;) { |
for (;;) { |
while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { |
while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { |
|
|
if (rcvcnt < 0) { |
if (rcvcnt < 0) { |
if (errno == EINTR) |
if (errno == EINTR) |
continue; |
continue; |
(void)fprintf(stderr, "rlogin: read: %s.\n", |
warn("read"); |
strerror(errno)); |
|
return (-1); |
return (-1); |
} |
} |
} |
} |
|
|
} |
} |
(void)tcsetattr(0, TCSANOW, &tty); |
(void)tcsetattr(0, TCSANOW, &tty); |
break; |
break; |
|
|
default: |
default: |
return; |
return; |
} |
} |
|
|
lostpeer(signo) |
lostpeer(signo) |
int signo; |
int signo; |
{ |
{ |
(void)signal(SIGPIPE, SIG_IGN); |
struct sigaction sa; |
|
sa.sa_flags = SA_RESTART; |
|
sa.sa_handler = SIG_IGN; |
|
(void)sigaction(SIGPIPE, &sa, (struct sigaction *)0); |
msg("\aconnection closed."); |
msg("\aconnection closed."); |
done(1); |
done(1); |
} |
} |
|
|
copytochild(signo) |
copytochild(signo) |
int signo; |
int signo; |
{ |
{ |
|
|
(void)kill(child, SIGURG); |
(void)kill(child, SIGURG); |
} |
} |
|
|
|
|
msg(str) |
msg(str) |
char *str; |
char *str; |
{ |
{ |
|
|
(void)fprintf(stderr, "rlogin: %s\r\n", str); |
(void)fprintf(stderr, "rlogin: %s\r\n", str); |
} |
} |
|
|
|
|
usage() |
usage() |
{ |
{ |
(void)fprintf(stderr, |
(void)fprintf(stderr, |
"usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", |
"usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n", |
#ifdef KERBEROS |
#ifdef KERBEROS |
#ifdef CRYPT |
#ifdef CRYPT |
"8EKLx", " [-k realm] "); |
"8EKLx", " [-k realm] "); |