144346Skarels /*
262213Sbostic * Copyright (c) 1983, 1990, 1993
362213Sbostic * The Regents of the University of California. All rights reserved.
435539Sbostic *
542763Sbostic * %sccs.include.redist.c%
621595Sdist */
721595Sdist
86444Swnj #ifndef lint
962213Sbostic static char copyright[] =
1062213Sbostic "@(#) Copyright (c) 1983, 1990, 1993\n\
1162213Sbostic The Regents of the University of California. All rights reserved.\n";
1235539Sbostic #endif /* not lint */
136444Swnj
1421595Sdist #ifndef lint
15*69118Svjs static char sccsid[] = "@(#)rlogin.c 8.4 (Berkeley) 04/29/95";
1635539Sbostic #endif /* not lint */
1721595Sdist
1812990Ssam /*
1912990Ssam * rlogin - remote login
2012990Ssam */
2126981Skarels #include <sys/param.h>
226444Swnj #include <sys/socket.h>
2329729Smckusick #include <sys/time.h>
2429729Smckusick #include <sys/resource.h>
2513620Ssam #include <sys/wait.h>
2667737Spendry #include <sys/ioctl.h>
279365Ssam
289207Ssam #include <netinet/in.h>
2944346Skarels #include <netinet/in_systm.h>
3044346Skarels #include <netinet/ip.h>
319365Ssam
326444Swnj #include <errno.h>
3358470Sbostic #include <fcntl.h>
3458470Sbostic #include <netdb.h>
356444Swnj #include <pwd.h>
3658470Sbostic #include <setjmp.h>
3767737Spendry #include <termios.h>
3858470Sbostic #include <signal.h>
3940858Sbostic #include <stdio.h>
4058470Sbostic #include <stdlib.h>
4158470Sbostic #include <string.h>
4240858Sbostic #include <unistd.h>
436444Swnj
4458766Sbostic #ifdef __STDC__
4558766Sbostic #include <stdarg.h>
4658766Sbostic #else
4758766Sbostic #include <varargs.h>
4858766Sbostic #endif
4958766Sbostic
5040858Sbostic #ifdef KERBEROS
5141760Skfall #include <kerberosIV/des.h>
5240683Sbostic #include <kerberosIV/krb.h>
5336511Skfall
5458470Sbostic #include "krb.h"
5558470Sbostic
5640858Sbostic CREDENTIALS cred;
5740858Sbostic Key_schedule schedule;
5846850Sbostic int use_kerberos = 1, doencrypt;
5940858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
6040858Sbostic #endif
6124726Smckusick
6240858Sbostic #ifndef TIOCPKT_WINDOW
6340858Sbostic #define TIOCPKT_WINDOW 0x80
6440858Sbostic #endif
6529729Smckusick
6640858Sbostic /* concession to Sun */
6740858Sbostic #ifndef SIGUSR1
6840858Sbostic #define SIGUSR1 30
6926981Skarels #endif
7040858Sbostic
7140858Sbostic int eight, litout, rem;
7245063Sbostic
7345063Sbostic int noescape;
7445063Sbostic u_char escapechar = '~';
7545063Sbostic
7659175Storek #ifdef OLDSUN
7726981Skarels struct winsize {
7826981Skarels unsigned short ws_row, ws_col;
7926981Skarels unsigned short ws_xpixel, ws_ypixel;
8026981Skarels };
8158470Sbostic #else
8258470Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
8340858Sbostic #endif
8418358Ssam struct winsize winsize;
856444Swnj
8658470Sbostic void catch_child __P((int));
8758470Sbostic void copytochild __P((int));
8867737Spendry __dead void doit __P((sigset_t *));
8958470Sbostic __dead void done __P((int));
9058470Sbostic void echo __P((char));
9158470Sbostic u_int getescape __P((char *));
9258470Sbostic void lostpeer __P((int));
9358470Sbostic void mode __P((int));
9458470Sbostic void msg __P((char *));
9558470Sbostic void oob __P((int));
9667737Spendry int reader __P((sigset_t *));
9758470Sbostic void sendwindow __P((void));
9858470Sbostic void setsignal __P((int));
9967749Spendry int speed __P((int));
10058470Sbostic void sigwinch __P((int));
10158470Sbostic void stop __P((char));
10258470Sbostic __dead void usage __P((void));
10358470Sbostic void writer __P((void));
10458470Sbostic void writeroob __P((int));
10558470Sbostic
10658470Sbostic #ifdef KERBEROS
10758470Sbostic void warning __P((const char *, ...));
10840858Sbostic #endif
10959175Storek #ifdef OLDSUN
11058470Sbostic int get_window_size __P((int, struct winsize *));
11158470Sbostic #endif
11229729Smckusick
11358470Sbostic int
main(argc,argv)1146444Swnj main(argc, argv)
1156444Swnj int argc;
11658470Sbostic char *argv[];
1176444Swnj {
11840858Sbostic struct passwd *pw;
11940858Sbostic struct servent *sp;
12067737Spendry sigset_t smask;
12167737Spendry uid_t uid;
12267737Spendry int argoff, ch, dflag, one;
12340858Sbostic char *host, *p, *user, term[1024];
12467737Spendry struct sigaction sa;
1256444Swnj
12640858Sbostic argoff = dflag = 0;
12740858Sbostic one = 1;
12840858Sbostic host = user = NULL;
12940858Sbostic
13067737Spendry if (p = strrchr(argv[0], '/'))
13140858Sbostic ++p;
1326444Swnj else
13340858Sbostic p = argv[0];
13440858Sbostic
13567737Spendry if (strcmp(p, "rlogin") != 0)
13640858Sbostic host = p;
13740858Sbostic
13840858Sbostic /* handle "rlogin host flags" */
13940858Sbostic if (!host && argc > 2 && argv[1][0] != '-') {
14040858Sbostic host = argv[1];
14140858Sbostic argoff = 1;
1426444Swnj }
14336511Skfall
14440858Sbostic #ifdef KERBEROS
14545063Sbostic #define OPTIONS "8EKLde:k:l:x"
14640858Sbostic #else
14745063Sbostic #define OPTIONS "8EKLde:l:"
14840858Sbostic #endif
14940858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
15040858Sbostic switch(ch) {
15140858Sbostic case '8':
15240858Sbostic eight = 1;
15340858Sbostic break;
15445063Sbostic case 'E':
15545063Sbostic noescape = 1;
15645063Sbostic break;
15740868Sbostic case 'K':
15840868Sbostic #ifdef KERBEROS
15940868Sbostic use_kerberos = 0;
16040868Sbostic #endif
16140868Sbostic break;
16240858Sbostic case 'L':
16340858Sbostic litout = 1;
16440858Sbostic break;
16540858Sbostic case 'd':
16640858Sbostic dflag = 1;
16740858Sbostic break;
16840858Sbostic case 'e':
16953033Sleres noescape = 0;
17045063Sbostic escapechar = getescape(optarg);
17140858Sbostic break;
17240858Sbostic #ifdef KERBEROS
17340858Sbostic case 'k':
17440858Sbostic dest_realm = dst_realm_buf;
17540858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ);
17640858Sbostic break;
17740858Sbostic #endif
17840858Sbostic case 'l':
17940858Sbostic user = optarg;
18040858Sbostic break;
18153033Sleres #ifdef CRYPT
18253033Sleres #ifdef KERBEROS
18353033Sleres case 'x':
18453033Sleres doencrypt = 1;
18553033Sleres des_set_key(cred.session, schedule);
18653033Sleres break;
18753033Sleres #endif
18853033Sleres #endif
18940858Sbostic case '?':
19040858Sbostic default:
19140858Sbostic usage();
19236524Skfall }
19340858Sbostic optind += argoff;
19440858Sbostic argc -= optind;
19540858Sbostic argv += optind;
19636524Skfall
19740858Sbostic /* if haven't gotten a host yet, do so */
19840858Sbostic if (!host && !(host = *argv++))
19940858Sbostic usage();
20036511Skfall
20140858Sbostic if (*argv)
20240858Sbostic usage();
20340858Sbostic
20467737Spendry if (!(pw = getpwuid(uid = getuid())))
20567737Spendry errx(1, "unknown user id.");
206*69118Svjs /* Accept user1@host format, though "-l user2" overrides user1 */
207*69118Svjs p = strchr(host, '@');
208*69118Svjs if (p) {
209*69118Svjs *p = '\0';
210*69118Svjs if (!user && p > host)
211*69118Svjs user = host;
212*69118Svjs host = p + 1;
213*69118Svjs if (*host == '\0')
214*69118Svjs usage();
215*69118Svjs }
21640858Sbostic if (!user)
21740858Sbostic user = pw->pw_name;
21840858Sbostic
21940868Sbostic sp = NULL;
22040858Sbostic #ifdef KERBEROS
22140868Sbostic if (use_kerberos) {
22246850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
22340868Sbostic if (sp == NULL) {
22440868Sbostic use_kerberos = 0;
22540868Sbostic warning("can't get entry for %s/tcp service",
22646850Sbostic doencrypt ? "eklogin" : "klogin");
22740868Sbostic }
22836512Skfall }
22936512Skfall #endif
23040868Sbostic if (sp == NULL)
23140868Sbostic sp = getservbyname("login", "tcp");
23267737Spendry if (sp == NULL)
23367737Spendry errx(1, "login/tcp: unknown service.");
23440858Sbostic
23567737Spendry (void)snprintf(term, sizeof(term), "%s/%d",
23667737Spendry ((p = getenv("TERM")) ? p : "network"),
23767749Spendry speed(0));
23840858Sbostic
23940858Sbostic (void)get_window_size(0, &winsize);
24040858Sbostic
24167737Spendry sigemptyset(&sa.sa_mask);
24267737Spendry sa.sa_flags = SA_RESTART;
24367737Spendry sa.sa_handler = lostpeer;
24467737Spendry (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
24529729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */
24667737Spendry sigemptyset(&smask);
24767737Spendry sigaddset(&smask, SIGURG);
24867737Spendry sigaddset(&smask, SIGUSR1);
24967737Spendry (void)sigprocmask(SIG_SETMASK, &smask, &smask);
25058261Smckusick /*
25158261Smckusick * We set SIGURG and SIGUSR1 below so that an
25258261Smckusick * incoming signal will be held pending rather than being
25358261Smckusick * discarded. Note that these routines will be ready to get
25458261Smckusick * a signal by the time that they are unblocked below.
25558261Smckusick */
25667737Spendry sa.sa_handler = copytochild;
25767737Spendry (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
25867737Spendry sa.sa_handler = writeroob;
25967737Spendry (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0);
26036511Skfall
26140858Sbostic #ifdef KERBEROS
26236512Skfall try_connect:
26340858Sbostic if (use_kerberos) {
26458470Sbostic struct hostent *hp;
26558470Sbostic
26658470Sbostic /* Fully qualify hostname (needed for krb_realmofhost). */
26756960Seric hp = gethostbyname(host);
26867737Spendry if (hp != NULL && !(host = strdup(hp->h_name)))
26967737Spendry errx(1, "%s", strerror(ENOMEM));
27056960Seric
27136512Skfall rem = KSUCCESS;
27240858Sbostic errno = 0;
27338728Skfall if (dest_realm == NULL)
27438728Skfall dest_realm = krb_realmofhost(host);
27538728Skfall
27653033Sleres #ifdef CRYPT
27753033Sleres if (doencrypt)
27853033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
27953033Sleres dest_realm, &cred, schedule);
28053033Sleres else
28153033Sleres #endif /* CRYPT */
28240858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0,
28340858Sbostic dest_realm);
28438728Skfall if (rem < 0) {
28536512Skfall use_kerberos = 0;
28636628Skfall sp = getservbyname("login", "tcp");
28767737Spendry if (sp == NULL)
28867737Spendry errx(1, "unknown service login/tcp.");
28938728Skfall if (errno == ECONNREFUSED)
29040858Sbostic warning("remote host doesn't support Kerberos");
29138728Skfall if (errno == ENOENT)
29240858Sbostic warning("can't provide Kerberos auth data");
29336512Skfall goto try_connect;
29436512Skfall }
29536511Skfall } else {
29653033Sleres #ifdef CRYPT
29767737Spendry if (doencrypt)
29867737Spendry errx(1, "the -x flag requires Kerberos authentication.");
29953033Sleres #endif /* CRYPT */
30040858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
30136511Skfall }
30236512Skfall #else
30340858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
30445256Smckusick #endif /* KERBEROS */
30536511Skfall
30640858Sbostic if (rem < 0)
30736511Skfall exit(1);
30836511Skfall
30940858Sbostic if (dflag &&
31040858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
31167737Spendry warn("setsockopt DEBUG (ignored)");
31244346Skarels one = IPTOS_LOWDELAY;
31344346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
31467737Spendry warn("setsockopt TOS (ignored)");
31540858Sbostic
31640858Sbostic (void)setuid(uid);
31767737Spendry doit(&smask);
3189365Ssam /*NOTREACHED*/
3196444Swnj }
3206444Swnj
32167749Spendry #if BSD >= 198810
32267749Spendry int
speed(fd)32367749Spendry speed(fd)
32467749Spendry int fd;
32567749Spendry {
32667749Spendry struct termios tt;
32767749Spendry
32867749Spendry (void)tcgetattr(fd, &tt);
32967749Spendry
33067749Spendry return ((int) cfgetispeed(&tt));
33167749Spendry }
33267749Spendry #else
33367749Spendry int speeds[] = { /* for older systems, B0 .. EXTB */
33467749Spendry 0, 50, 75, 110,
33567749Spendry 134, 150, 200, 300,
33667749Spendry 600, 1200, 1800, 2400,
33767749Spendry 4800, 9600, 19200, 38400
33867749Spendry };
33967749Spendry
34067749Spendry int
speed(fd)34167749Spendry speed(fd)
34267749Spendry int fd;
34367749Spendry {
34467749Spendry struct termios tt;
34567749Spendry
34667749Spendry (void)tcgetattr(fd, &tt);
34767749Spendry
34867749Spendry return (speeds[(int)cfgetispeed(&tt)]);
34967749Spendry }
35067749Spendry #endif
35167749Spendry
35267737Spendry pid_t child;
35367737Spendry struct termios deftt;
35467737Spendry struct termios nott;
3556444Swnj
35658470Sbostic void
doit(smask)35767737Spendry doit(smask)
35867737Spendry sigset_t *smask;
3596444Swnj {
36067737Spendry int i;
36167737Spendry struct sigaction sa;
3626444Swnj
36367737Spendry for (i = 0; i < NCCS; i++)
36467737Spendry nott.c_cc[i] = _POSIX_VDISABLE;
36567737Spendry tcgetattr(0, &deftt);
36667737Spendry nott.c_cc[VSTART] = deftt.c_cc[VSTART];
36767737Spendry nott.c_cc[VSTOP] = deftt.c_cc[VSTOP];
36867737Spendry sigemptyset(&sa.sa_mask);
36967737Spendry sa.sa_flags = SA_RESTART;
37067737Spendry sa.sa_handler = SIG_IGN;
37167737Spendry (void)sigaction(SIGINT, &sa, (struct sigaction *) 0);
37258470Sbostic setsignal(SIGHUP);
37358470Sbostic setsignal(SIGQUIT);
3749365Ssam child = fork();
3759365Ssam if (child == -1) {
37667737Spendry warn("fork");
37725424Skarels done(1);
3789365Ssam }
3799365Ssam if (child == 0) {
38024726Smckusick mode(1);
38167737Spendry if (reader(smask) == 0) {
38240858Sbostic msg("connection closed.");
38325424Skarels exit(0);
38425424Skarels }
38512155Ssam sleep(1);
38640858Sbostic msg("\007connection closed.");
38740858Sbostic exit(1);
3886444Swnj }
38929729Smckusick
39029729Smckusick /*
39140858Sbostic * We may still own the socket, and may have a pending SIGURG (or might
39258261Smckusick * receive one soon) that we really want to send to the reader. When
39358261Smckusick * one of these comes in, the trap copytochild simply copies such
39458261Smckusick * signals to the child. We can now unblock SIGURG and SIGUSR1
39558261Smckusick * that were set above.
39629729Smckusick */
39767737Spendry (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
39867737Spendry sa.sa_handler = catch_child;
39967737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
4009365Ssam writer();
40140858Sbostic msg("closed connection.");
40225424Skarels done(0);
4036444Swnj }
4046444Swnj
40540858Sbostic /* trap a signal, unless it is being ignored. */
40658470Sbostic void
setsignal(sig)40758470Sbostic setsignal(sig)
40840858Sbostic int sig;
40929729Smckusick {
41067737Spendry struct sigaction sa;
41167737Spendry sigset_t sigs;
41229729Smckusick
41367737Spendry sigemptyset(&sigs);
41467737Spendry sigaddset(&sigs, sig);
41567737Spendry sigprocmask(SIG_BLOCK, &sigs, &sigs);
41667737Spendry
41767737Spendry sigemptyset(&sa.sa_mask);
41867737Spendry sa.sa_handler = exit;
41967737Spendry sa.sa_flags = SA_RESTART;
42067737Spendry (void)sigaction(sig, &sa, &sa);
42167737Spendry if (sa.sa_handler == SIG_IGN)
42267737Spendry (void)sigaction(sig, &sa, (struct sigaction *) 0);
42367737Spendry
42467737Spendry (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);
42529729Smckusick }
42629729Smckusick
42758470Sbostic __dead void
done(status)42825424Skarels done(status)
42925424Skarels int status;
4306444Swnj {
43167737Spendry pid_t w;
43267737Spendry int wstatus;
43367737Spendry struct sigaction sa;
4346444Swnj
4356444Swnj mode(0);
43629729Smckusick if (child > 0) {
43740858Sbostic /* make sure catch_child does not snap it up */
43867737Spendry sigemptyset(&sa.sa_mask);
43967737Spendry sa.sa_handler = SIG_DFL;
44067737Spendry sa.sa_flags = 0;
44167737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
44229729Smckusick if (kill(child, SIGKILL) >= 0)
44367737Spendry while ((w = wait(&wstatus)) > 0 && w != child)
44467737Spendry continue;
44529729Smckusick }
44625424Skarels exit(status);
4476444Swnj }
4486444Swnj
44940858Sbostic int dosigwinch;
45029729Smckusick
45129729Smckusick /*
45224726Smckusick * This is called when the reader process gets the out-of-band (urgent)
45324726Smckusick * request to turn on the window-changing protocol.
45424726Smckusick */
45540858Sbostic void
writeroob(signo)45658470Sbostic writeroob(signo)
45758470Sbostic int signo;
45824726Smckusick {
45967737Spendry struct sigaction sa;
46067737Spendry
46125341Smckusick if (dosigwinch == 0) {
46224919Smckusick sendwindow();
46367737Spendry sigemptyset(&sa.sa_mask);
46467737Spendry sa.sa_handler = sigwinch;
46567737Spendry sa.sa_flags = SA_RESTART;
46667737Spendry (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0);
46725341Smckusick }
46824726Smckusick dosigwinch = 1;
46924726Smckusick }
47024726Smckusick
47140858Sbostic void
catch_child(signo)47258470Sbostic catch_child(signo)
47358470Sbostic int signo;
47411803Sedward {
47567737Spendry int status;
47667737Spendry pid_t pid;
47711803Sedward
47840858Sbostic for (;;) {
47967737Spendry pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
48040858Sbostic if (pid == 0)
48140858Sbostic return;
48240858Sbostic /* if the child (reader) dies, just quit */
48358470Sbostic if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
48467737Spendry done(WEXITSTATUS(status) | WTERMSIG(status));
48540858Sbostic }
48640858Sbostic /* NOTREACHED */
48711803Sedward }
48811803Sedward
4896444Swnj /*
4909365Ssam * writer: write to remote: 0 -> line.
49145063Sbostic * ~. terminate
49245063Sbostic * ~^Z suspend rlogin process.
49345063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
4946444Swnj */
49558470Sbostic void
writer()4969365Ssam writer()
4976444Swnj {
49845063Sbostic register int bol, local, n;
49923530Sbloom char c;
5006444Swnj
50140858Sbostic bol = 1; /* beginning of line */
50240858Sbostic local = 0;
50311803Sedward for (;;) {
50440858Sbostic n = read(STDIN_FILENO, &c, 1);
50518358Ssam if (n <= 0) {
50618358Ssam if (n < 0 && errno == EINTR)
50718358Ssam continue;
50811803Sedward break;
50918358Ssam }
5109365Ssam /*
51140858Sbostic * If we're at the beginning of the line and recognize a
51240858Sbostic * command character, then we echo locally. Otherwise,
51340858Sbostic * characters are echo'd remotely. If the command character
51440858Sbostic * is doubled, this acts as a force and local echo is
51540858Sbostic * suppressed.
5169365Ssam */
51723530Sbloom if (bol) {
51823530Sbloom bol = 0;
51945063Sbostic if (!noescape && c == escapechar) {
52023530Sbloom local = 1;
52123530Sbloom continue;
5226444Swnj }
52323530Sbloom } else if (local) {
52423530Sbloom local = 0;
52567737Spendry if (c == '.' || c == deftt.c_cc[VEOF]) {
52623530Sbloom echo(c);
52723530Sbloom break;
5286444Swnj }
52967737Spendry if (c == deftt.c_cc[VSUSP] || c == deftt.c_cc[VDSUSP]) {
53023530Sbloom bol = 1;
53123530Sbloom echo(c);
53223530Sbloom stop(c);
53323530Sbloom continue;
53423530Sbloom }
53545063Sbostic if (c != escapechar)
53653033Sleres #ifdef CRYPT
53753033Sleres #ifdef KERBEROS
53853033Sleres if (doencrypt)
53958470Sbostic (void)des_write(rem,
54058470Sbostic (char *)&escapechar, 1);
54153033Sleres else
54253033Sleres #endif
54353033Sleres #endif
54445063Sbostic (void)write(rem, &escapechar, 1);
5456444Swnj }
54636511Skfall
54753033Sleres #ifdef CRYPT
54853033Sleres #ifdef KERBEROS
54953033Sleres if (doencrypt) {
55053033Sleres if (des_write(rem, &c, 1) == 0) {
55153033Sleres msg("line gone");
55253033Sleres break;
55353033Sleres }
55453033Sleres } else
55553033Sleres #endif
55653033Sleres #endif
55736511Skfall if (write(rem, &c, 1) == 0) {
55840858Sbostic msg("line gone");
55936511Skfall break;
56036511Skfall }
56167737Spendry bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] ||
56267737Spendry c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] ||
56323530Sbloom c == '\r' || c == '\n';
5646444Swnj }
5656444Swnj }
5666444Swnj
56758470Sbostic void
56858470Sbostic #if __STDC__
echo(register char c)56958470Sbostic echo(register char c)
57058470Sbostic #else
57123530Sbloom echo(c)
57258470Sbostic register char c;
57358470Sbostic #endif
57423530Sbloom {
57540858Sbostic register char *p;
57623530Sbloom char buf[8];
57723530Sbloom
57840858Sbostic p = buf;
57923530Sbloom c &= 0177;
58045063Sbostic *p++ = escapechar;
58123530Sbloom if (c < ' ') {
58223530Sbloom *p++ = '^';
58323530Sbloom *p++ = c + '@';
58423530Sbloom } else if (c == 0177) {
58523530Sbloom *p++ = '^';
58623530Sbloom *p++ = '?';
58723530Sbloom } else
58823530Sbloom *p++ = c;
58923530Sbloom *p++ = '\r';
59023530Sbloom *p++ = '\n';
59145063Sbostic (void)write(STDOUT_FILENO, buf, p - buf);
59223530Sbloom }
59323530Sbloom
59458470Sbostic void
59558470Sbostic #if __STDC__
stop(char cmdc)59658470Sbostic stop(char cmdc)
59758470Sbostic #else
59818358Ssam stop(cmdc)
59918358Ssam char cmdc;
60058470Sbostic #endif
60118358Ssam {
60267737Spendry struct sigaction sa;
60367737Spendry
60418358Ssam mode(0);
60567737Spendry sigemptyset(&sa.sa_mask);
60667737Spendry sa.sa_handler = SIG_IGN;
60767737Spendry sa.sa_flags = SA_RESTART;
60867737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
60967737Spendry (void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
61067737Spendry sa.sa_handler = catch_child;
61167737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
61218358Ssam mode(1);
61358470Sbostic sigwinch(0); /* check for size changes */
61418358Ssam }
61518358Ssam
61640858Sbostic void
sigwinch(signo)61758470Sbostic sigwinch(signo)
61858470Sbostic int signo;
61918358Ssam {
62018358Ssam struct winsize ws;
62118358Ssam
62229729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 &&
62367737Spendry memcmp(&ws, &winsize, sizeof(ws))) {
62418358Ssam winsize = ws;
62524726Smckusick sendwindow();
62618358Ssam }
62718358Ssam }
62818358Ssam
62924726Smckusick /*
63024726Smckusick * Send the window size to the server via the magic escape
63124726Smckusick */
63258470Sbostic void
sendwindow()63324726Smckusick sendwindow()
63424726Smckusick {
63540858Sbostic struct winsize *wp;
63624726Smckusick char obuf[4 + sizeof (struct winsize)];
63724726Smckusick
63840858Sbostic wp = (struct winsize *)(obuf+4);
63924726Smckusick obuf[0] = 0377;
64024726Smckusick obuf[1] = 0377;
64124726Smckusick obuf[2] = 's';
64224726Smckusick obuf[3] = 's';
64324726Smckusick wp->ws_row = htons(winsize.ws_row);
64424726Smckusick wp->ws_col = htons(winsize.ws_col);
64524726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel);
64624726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel);
64736511Skfall
64853033Sleres #ifdef CRYPT
64953033Sleres #ifdef KERBEROS
65053033Sleres if(doencrypt)
65153033Sleres (void)des_write(rem, obuf, sizeof(obuf));
65253033Sleres else
65353033Sleres #endif
65453033Sleres #endif
65540858Sbostic (void)write(rem, obuf, sizeof(obuf));
65624726Smckusick }
65724726Smckusick
65825424Skarels /*
65925424Skarels * reader: read from remote: line -> 1
66025424Skarels */
66125424Skarels #define READING 1
66225424Skarels #define WRITING 2
66325424Skarels
66440858Sbostic jmp_buf rcvtop;
66567737Spendry pid_t ppid;
66667737Spendry int rcvcnt, rcvstate;
66740858Sbostic char rcvbuf[8 * 1024];
66825424Skarels
66940858Sbostic void
oob(signo)67058470Sbostic oob(signo)
67158470Sbostic int signo;
6726444Swnj {
67367737Spendry struct termios tt;
67440858Sbostic int atmark, n, out, rcvd;
6759365Ssam char waste[BUFSIZ], mark;
6766444Swnj
67742230Sbostic out = O_RDWR;
67840858Sbostic rcvd = 0;
67959175Storek while (recv(rem, &mark, 1, MSG_OOB) < 0) {
68025424Skarels switch (errno) {
68125424Skarels case EWOULDBLOCK:
68225424Skarels /*
68340858Sbostic * Urgent data not here yet. It may not be possible
68440858Sbostic * to send it yet if we are blocked for output and
68540858Sbostic * our input buffer is full.
68625424Skarels */
68725424Skarels if (rcvcnt < sizeof(rcvbuf)) {
68825424Skarels n = read(rem, rcvbuf + rcvcnt,
68940858Sbostic sizeof(rcvbuf) - rcvcnt);
69025424Skarels if (n <= 0)
69125424Skarels return;
69225424Skarels rcvd += n;
69325424Skarels } else {
69425424Skarels n = read(rem, waste, sizeof(waste));
69525424Skarels if (n <= 0)
69625424Skarels return;
69725424Skarels }
69825424Skarels continue;
69925424Skarels default:
70025424Skarels return;
70159175Storek }
7026444Swnj }
70325424Skarels if (mark & TIOCPKT_WINDOW) {
70440858Sbostic /* Let server know about window size changes */
70540858Sbostic (void)kill(ppid, SIGUSR1);
70624726Smckusick }
70725424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) {
70867737Spendry tcgetattr(0, &tt);
70967749Spendry tt.c_iflag &= ~(IXON | IXOFF);
71067737Spendry tt.c_cc[VSTOP] = _POSIX_VDISABLE;
71167737Spendry tt.c_cc[VSTART] = _POSIX_VDISABLE;
71267737Spendry tcsetattr(0, TCSANOW, &tt);
7136444Swnj }
71425424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) {
71567737Spendry tcgetattr(0, &tt);
71667737Spendry tt.c_iflag |= (IXON|IXOFF);
71767737Spendry tt.c_cc[VSTOP] = deftt.c_cc[VSTOP];
71867737Spendry tt.c_cc[VSTART] = deftt.c_cc[VSTART];
71967737Spendry tcsetattr(0, TCSANOW, &tt);
7206444Swnj }
72125424Skarels if (mark & TIOCPKT_FLUSHWRITE) {
72240858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out);
72325424Skarels for (;;) {
72425424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
72567737Spendry warn("ioctl SIOCATMARK (ignored)");
72625424Skarels break;
72725424Skarels }
72825424Skarels if (atmark)
72925424Skarels break;
73025424Skarels n = read(rem, waste, sizeof (waste));
73125424Skarels if (n <= 0)
73225424Skarels break;
73325424Skarels }
73425424Skarels /*
73540858Sbostic * Don't want any pending data to be output, so clear the recv
73640858Sbostic * buffer. If we were hanging on a write when interrupted,
73740858Sbostic * don't want it to restart. If we were reading, restart
73840858Sbostic * anyway.
73925424Skarels */
74025424Skarels rcvcnt = 0;
74125424Skarels longjmp(rcvtop, 1);
74225424Skarels }
74329729Smckusick
74440858Sbostic /* oob does not do FLUSHREAD (alas!) */
74529729Smckusick
74629729Smckusick /*
74740858Sbostic * If we filled the receive buffer while a read was pending, longjmp
74840858Sbostic * to the top to restart appropriately. Don't abort a pending write,
74940858Sbostic * however, or we won't know how much was written.
75025424Skarels */
75125424Skarels if (rcvd && rcvstate == READING)
75225424Skarels longjmp(rcvtop, 1);
7536444Swnj }
7546444Swnj
75540858Sbostic /* reader: read from remote: line -> 1 */
75658470Sbostic int
reader(smask)75767737Spendry reader(smask)
75867737Spendry sigset_t *smask;
7596444Swnj {
76067737Spendry pid_t pid;
76167737Spendry int n, remaining;
76259175Storek char *bufp;
76367737Spendry struct sigaction sa;
76440858Sbostic
76559175Storek #if BSD >= 43 || defined(SUNOS4)
76659175Storek pid = getpid(); /* modern systems use positives for pid */
76726981Skarels #else
76859175Storek pid = -getpid(); /* old broken systems use negatives */
76926981Skarels #endif
77067737Spendry sigemptyset(&sa.sa_mask);
77167737Spendry sa.sa_flags = SA_RESTART;
77267737Spendry sa.sa_handler = SIG_IGN;
77367737Spendry (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0);
77467737Spendry sa.sa_handler = oob;
77567737Spendry (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
77626981Skarels ppid = getppid();
77740858Sbostic (void)fcntl(rem, F_SETOWN, pid);
77840858Sbostic (void)setjmp(rcvtop);
77967737Spendry (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
78059175Storek bufp = rcvbuf;
7816444Swnj for (;;) {
78225424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
78325424Skarels rcvstate = WRITING;
78445063Sbostic n = write(STDOUT_FILENO, bufp, remaining);
78525424Skarels if (n < 0) {
78625424Skarels if (errno != EINTR)
78758470Sbostic return (-1);
78825424Skarels continue;
78925424Skarels }
79025424Skarels bufp += n;
79125424Skarels }
79225424Skarels bufp = rcvbuf;
79325424Skarels rcvcnt = 0;
79425424Skarels rcvstate = READING;
79536511Skfall
79653033Sleres #ifdef CRYPT
79753033Sleres #ifdef KERBEROS
79853033Sleres if (doencrypt)
79953033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
80053033Sleres else
80153033Sleres #endif
80253033Sleres #endif
80336511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
80425424Skarels if (rcvcnt == 0)
80525424Skarels return (0);
80625424Skarels if (rcvcnt < 0) {
8079365Ssam if (errno == EINTR)
8086444Swnj continue;
80967737Spendry warn("read");
81058470Sbostic return (-1);
8116444Swnj }
8126444Swnj }
8136444Swnj }
8146444Swnj
81558470Sbostic void
mode(f)8166444Swnj mode(f)
81758470Sbostic int f;
8186444Swnj {
81967737Spendry struct termios tt;
8209365Ssam
82167737Spendry switch (f) {
8229962Ssam case 0:
82367737Spendry tcsetattr(0, TCSADRAIN, &deftt);
8249962Ssam break;
8259962Ssam case 1:
82667737Spendry tt = deftt;
82767749Spendry tt.c_oflag &= ~(OPOST);
82867737Spendry tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
82967749Spendry tt.c_iflag &= ~(ICRNL);
83067737Spendry tt.c_cc[VMIN] = 1;
83167737Spendry tt.c_cc[VTIME] = 0;
83267737Spendry if (eight) {
83367749Spendry tt.c_iflag &= ~(IXON | IXOFF | ISTRIP);
83467737Spendry tt.c_cc[VSTOP] = _POSIX_VDISABLE;
83567737Spendry tt.c_cc[VSTART] = _POSIX_VDISABLE;
83667737Spendry }
83767737Spendry /*if (litout)
83867737Spendry lflags |= LLITOUT;*/
83967737Spendry tcsetattr(0, TCSADRAIN, &tt);
8409962Ssam break;
84167737Spendry
8429962Ssam default:
8439962Ssam return;
8446444Swnj }
8456444Swnj }
8466444Swnj
84740858Sbostic void
lostpeer(signo)84858470Sbostic lostpeer(signo)
84958470Sbostic int signo;
8506444Swnj {
85167737Spendry struct sigaction sa;
85267737Spendry
85367737Spendry sigemptyset(&sa.sa_mask);
85467737Spendry sa.sa_flags = SA_RESTART;
85567737Spendry sa.sa_handler = SIG_IGN;
85667737Spendry (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
85740858Sbostic msg("\007connection closed.");
85840858Sbostic done(1);
85940858Sbostic }
86029729Smckusick
86140858Sbostic /* copy SIGURGs to the child process. */
86240858Sbostic void
copytochild(signo)86358470Sbostic copytochild(signo)
86458470Sbostic int signo;
86540858Sbostic {
86667737Spendry
86740858Sbostic (void)kill(child, SIGURG);
8686444Swnj }
8696444Swnj
87058470Sbostic void
msg(str)87140858Sbostic msg(str)
87240858Sbostic char *str;
8736444Swnj {
87467737Spendry
87540858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str);
87640858Sbostic }
87729729Smckusick
87840858Sbostic #ifdef KERBEROS
87940858Sbostic /* VARARGS */
88058470Sbostic void
88158470Sbostic #if __STDC__
warning(const char * fmt,...)88258470Sbostic warning(const char *fmt, ...)
88358470Sbostic #else
88458470Sbostic warning(fmt, va_alist)
88558470Sbostic char *fmt;
88658470Sbostic va_dcl
88758470Sbostic #endif
88840858Sbostic {
88940858Sbostic va_list ap;
89040858Sbostic
89140858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
89258470Sbostic #ifdef __STDC__
89358470Sbostic va_start(ap, fmt);
89458470Sbostic #else
89540858Sbostic va_start(ap);
89658470Sbostic #endif
89740858Sbostic vfprintf(stderr, fmt, ap);
89840858Sbostic va_end(ap);
89940858Sbostic (void)fprintf(stderr, ".\n");
9006444Swnj }
90140858Sbostic #endif
90236512Skfall
90358470Sbostic __dead void
usage()90440858Sbostic usage()
90536512Skfall {
90640858Sbostic (void)fprintf(stderr,
907*69118Svjs "usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",
90840858Sbostic #ifdef KERBEROS
90953033Sleres #ifdef CRYPT
91054125Sbostic "8EKLx", " [-k realm] ");
91153033Sleres #else
91254125Sbostic "8EKL", " [-k realm] ");
91353033Sleres #endif
91445256Smckusick #else
91545063Sbostic "8EL", " ");
91640858Sbostic #endif
91740858Sbostic exit(1);
91836512Skfall }
91940858Sbostic
92040858Sbostic /*
92159175Storek * The following routine provides compatibility (such as it is) between older
92240858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
92340858Sbostic */
92459175Storek #ifdef OLDSUN
92558470Sbostic int
get_window_size(fd,wp)92640858Sbostic get_window_size(fd, wp)
92740858Sbostic int fd;
92840858Sbostic struct winsize *wp;
92940858Sbostic {
93040858Sbostic struct ttysize ts;
93140858Sbostic int error;
93240858Sbostic
93340858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
93458470Sbostic return (error);
93540858Sbostic wp->ws_row = ts.ts_lines;
93640858Sbostic wp->ws_col = ts.ts_cols;
93740858Sbostic wp->ws_xpixel = 0;
93840858Sbostic wp->ws_ypixel = 0;
93958470Sbostic return (0);
94040858Sbostic }
94140858Sbostic #endif
94245063Sbostic
94358470Sbostic u_int
getescape(p)94445063Sbostic getescape(p)
94545063Sbostic register char *p;
94645063Sbostic {
94745063Sbostic long val;
94845063Sbostic int len;
94945063Sbostic
95045063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */
95158470Sbostic return ((u_int)*p);
95245063Sbostic /* otherwise, \nnn */
95345063Sbostic if (*p == '\\' && len >= 2 && len <= 4) {
95458470Sbostic val = strtol(++p, NULL, 8);
95545063Sbostic for (;;) {
95645063Sbostic if (!*++p)
95758470Sbostic return ((u_int)val);
95845063Sbostic if (*p < '0' || *p > '8')
95945063Sbostic break;
96045063Sbostic }
96145063Sbostic }
96245063Sbostic msg("illegal option value -- e");
96345063Sbostic usage();
96445063Sbostic /* NOTREACHED */
96545063Sbostic }
966