144346Skarels /* 2*62213Sbostic * Copyright (c) 1983, 1990, 1993 3*62213Sbostic * The Regents of the University of California. All rights reserved. 435539Sbostic * 542763Sbostic * %sccs.include.redist.c% 621595Sdist */ 721595Sdist 86444Swnj #ifndef lint 9*62213Sbostic static char copyright[] = 10*62213Sbostic "@(#) Copyright (c) 1983, 1990, 1993\n\ 11*62213Sbostic The Regents of the University of California. All rights reserved.\n"; 1235539Sbostic #endif /* not lint */ 136444Swnj 1421595Sdist #ifndef lint 15*62213Sbostic static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 06/06/93"; 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> 269365Ssam 279207Ssam #include <netinet/in.h> 2844346Skarels #include <netinet/in_systm.h> 2944346Skarels #include <netinet/ip.h> 309365Ssam 316444Swnj #include <errno.h> 3258470Sbostic #include <fcntl.h> 3358470Sbostic #include <netdb.h> 346444Swnj #include <pwd.h> 3558470Sbostic #include <setjmp.h> 3658470Sbostic #include <sgtty.h> 3758470Sbostic #include <signal.h> 3840858Sbostic #include <stdio.h> 3958470Sbostic #include <stdlib.h> 4058470Sbostic #include <string.h> 4140858Sbostic #include <unistd.h> 426444Swnj 4358766Sbostic #ifdef __STDC__ 4458766Sbostic #include <stdarg.h> 4558766Sbostic #else 4658766Sbostic #include <varargs.h> 4758766Sbostic #endif 4858766Sbostic 4940858Sbostic #ifdef KERBEROS 5041760Skfall #include <kerberosIV/des.h> 5140683Sbostic #include <kerberosIV/krb.h> 5236511Skfall 5358470Sbostic #include "krb.h" 5458470Sbostic 5540858Sbostic CREDENTIALS cred; 5640858Sbostic Key_schedule schedule; 5746850Sbostic int use_kerberos = 1, doencrypt; 5840858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 5940858Sbostic #endif 6024726Smckusick 6140858Sbostic #ifndef TIOCPKT_WINDOW 6240858Sbostic #define TIOCPKT_WINDOW 0x80 6340858Sbostic #endif 6429729Smckusick 6540858Sbostic /* concession to Sun */ 6640858Sbostic #ifndef SIGUSR1 6740858Sbostic #define SIGUSR1 30 6826981Skarels #endif 6940858Sbostic 7040858Sbostic int eight, litout, rem; 7145063Sbostic 7245063Sbostic int noescape; 7345063Sbostic u_char escapechar = '~'; 7445063Sbostic 7540858Sbostic char *speeds[] = { 7640858Sbostic "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 7740858Sbostic "1800", "2400", "4800", "9600", "19200", "38400" 7840858Sbostic }; 7940858Sbostic 8059175Storek #ifdef OLDSUN 8126981Skarels struct winsize { 8226981Skarels unsigned short ws_row, ws_col; 8326981Skarels unsigned short ws_xpixel, ws_ypixel; 8426981Skarels }; 8558470Sbostic #else 8658470Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 8740858Sbostic #endif 8818358Ssam struct winsize winsize; 896444Swnj 9058470Sbostic void catch_child __P((int)); 9158470Sbostic void copytochild __P((int)); 9258470Sbostic __dead void doit __P((long)); 9358470Sbostic __dead void done __P((int)); 9458470Sbostic void echo __P((char)); 9558470Sbostic u_int getescape __P((char *)); 9658470Sbostic void lostpeer __P((int)); 9758470Sbostic void mode __P((int)); 9858470Sbostic void msg __P((char *)); 9958470Sbostic void oob __P((int)); 10058470Sbostic int reader __P((int)); 10158470Sbostic void sendwindow __P((void)); 10258470Sbostic void setsignal __P((int)); 10358470Sbostic void sigwinch __P((int)); 10458470Sbostic void stop __P((char)); 10558470Sbostic __dead void usage __P((void)); 10658470Sbostic void writer __P((void)); 10758470Sbostic void writeroob __P((int)); 10858470Sbostic 10958470Sbostic #ifdef KERBEROS 11058470Sbostic void warning __P((const char *, ...)); 11140858Sbostic #endif 11259175Storek #ifdef OLDSUN 11358470Sbostic int get_window_size __P((int, struct winsize *)); 11458470Sbostic #endif 11529729Smckusick 11658470Sbostic int 1176444Swnj main(argc, argv) 1186444Swnj int argc; 11958470Sbostic char *argv[]; 1206444Swnj { 12140858Sbostic extern char *optarg; 12240858Sbostic extern int optind; 12340858Sbostic struct passwd *pw; 12440858Sbostic struct servent *sp; 1256444Swnj struct sgttyb ttyb; 12640858Sbostic long omask; 12740858Sbostic int argoff, ch, dflag, one, uid; 12840858Sbostic char *host, *p, *user, term[1024]; 1296444Swnj 13040858Sbostic argoff = dflag = 0; 13140858Sbostic one = 1; 13240858Sbostic host = user = NULL; 13340858Sbostic 13440858Sbostic if (p = rindex(argv[0], '/')) 13540858Sbostic ++p; 1366444Swnj else 13740858Sbostic p = argv[0]; 13840858Sbostic 13940858Sbostic if (strcmp(p, "rlogin")) 14040858Sbostic host = p; 14140858Sbostic 14240858Sbostic /* handle "rlogin host flags" */ 14340858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 14440858Sbostic host = argv[1]; 14540858Sbostic argoff = 1; 1466444Swnj } 14736511Skfall 14840858Sbostic #ifdef KERBEROS 14945063Sbostic #define OPTIONS "8EKLde:k:l:x" 15040858Sbostic #else 15145063Sbostic #define OPTIONS "8EKLde:l:" 15240858Sbostic #endif 15340858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 15440858Sbostic switch(ch) { 15540858Sbostic case '8': 15640858Sbostic eight = 1; 15740858Sbostic break; 15845063Sbostic case 'E': 15945063Sbostic noescape = 1; 16045063Sbostic break; 16140868Sbostic case 'K': 16240868Sbostic #ifdef KERBEROS 16340868Sbostic use_kerberos = 0; 16440868Sbostic #endif 16540868Sbostic break; 16640858Sbostic case 'L': 16740858Sbostic litout = 1; 16840858Sbostic break; 16940858Sbostic case 'd': 17040858Sbostic dflag = 1; 17140858Sbostic break; 17240858Sbostic case 'e': 17353033Sleres noescape = 0; 17445063Sbostic escapechar = getescape(optarg); 17540858Sbostic break; 17640858Sbostic #ifdef KERBEROS 17740858Sbostic case 'k': 17840858Sbostic dest_realm = dst_realm_buf; 17940858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 18040858Sbostic break; 18140858Sbostic #endif 18240858Sbostic case 'l': 18340858Sbostic user = optarg; 18440858Sbostic break; 18553033Sleres #ifdef CRYPT 18653033Sleres #ifdef KERBEROS 18753033Sleres case 'x': 18853033Sleres doencrypt = 1; 18953033Sleres des_set_key(cred.session, schedule); 19053033Sleres break; 19153033Sleres #endif 19253033Sleres #endif 19340858Sbostic case '?': 19440858Sbostic default: 19540858Sbostic usage(); 19636524Skfall } 19740858Sbostic optind += argoff; 19840858Sbostic argc -= optind; 19940858Sbostic argv += optind; 20036524Skfall 20140858Sbostic /* if haven't gotten a host yet, do so */ 20240858Sbostic if (!host && !(host = *argv++)) 20340858Sbostic usage(); 20436511Skfall 20540858Sbostic if (*argv) 20640858Sbostic usage(); 20740858Sbostic 20840858Sbostic if (!(pw = getpwuid(uid = getuid()))) { 20940858Sbostic (void)fprintf(stderr, "rlogin: unknown user id.\n"); 2106444Swnj exit(1); 2116444Swnj } 21240858Sbostic if (!user) 21340858Sbostic user = pw->pw_name; 21440858Sbostic 21540868Sbostic sp = NULL; 21640858Sbostic #ifdef KERBEROS 21740868Sbostic if (use_kerberos) { 21846850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 21940868Sbostic if (sp == NULL) { 22040868Sbostic use_kerberos = 0; 22140868Sbostic warning("can't get entry for %s/tcp service", 22246850Sbostic doencrypt ? "eklogin" : "klogin"); 22340868Sbostic } 22436512Skfall } 22536512Skfall #endif 22640868Sbostic if (sp == NULL) 22740868Sbostic sp = getservbyname("login", "tcp"); 22840858Sbostic if (sp == NULL) { 22940858Sbostic (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 23040858Sbostic exit(1); 2319365Ssam } 23240858Sbostic 23340858Sbostic (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 23418358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 23540858Sbostic (void)strcat(term, "/"); 23658470Sbostic (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 2376444Swnj } 23840858Sbostic 23940858Sbostic (void)get_window_size(0, &winsize); 24040858Sbostic 24140858Sbostic (void)signal(SIGPIPE, lostpeer); 24229729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 24340858Sbostic omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 24458261Smckusick /* 24558261Smckusick * We set SIGURG and SIGUSR1 below so that an 24658261Smckusick * incoming signal will be held pending rather than being 24758261Smckusick * discarded. Note that these routines will be ready to get 24858261Smckusick * a signal by the time that they are unblocked below. 24958261Smckusick */ 25058261Smckusick (void)signal(SIGURG, copytochild); 25158261Smckusick (void)signal(SIGUSR1, writeroob); 25236511Skfall 25340858Sbostic #ifdef KERBEROS 25436512Skfall try_connect: 25540858Sbostic if (use_kerberos) { 25658470Sbostic struct hostent *hp; 25758470Sbostic 25858470Sbostic /* Fully qualify hostname (needed for krb_realmofhost). */ 25956960Seric hp = gethostbyname(host); 26056960Seric if (hp != NULL && !(host = strdup(hp->h_name))) { 26158470Sbostic (void)fprintf(stderr, "rlogin: %s\n", 26258470Sbostic strerror(ENOMEM)); 26356960Seric exit(1); 26456960Seric } 26556960Seric 26636512Skfall rem = KSUCCESS; 26740858Sbostic errno = 0; 26838728Skfall if (dest_realm == NULL) 26938728Skfall dest_realm = krb_realmofhost(host); 27038728Skfall 27153033Sleres #ifdef CRYPT 27253033Sleres if (doencrypt) 27353033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 27453033Sleres dest_realm, &cred, schedule); 27553033Sleres else 27653033Sleres #endif /* CRYPT */ 27740858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 27840858Sbostic dest_realm); 27938728Skfall if (rem < 0) { 28036512Skfall use_kerberos = 0; 28136628Skfall sp = getservbyname("login", "tcp"); 28240858Sbostic if (sp == NULL) { 28340858Sbostic (void)fprintf(stderr, 28440858Sbostic "rlogin: unknown service login/tcp.\n"); 28536628Skfall exit(1); 28636628Skfall } 28738728Skfall if (errno == ECONNREFUSED) 28840858Sbostic warning("remote host doesn't support Kerberos"); 28938728Skfall if (errno == ENOENT) 29040858Sbostic warning("can't provide Kerberos auth data"); 29136512Skfall goto try_connect; 29236512Skfall } 29336511Skfall } else { 29453033Sleres #ifdef CRYPT 29553033Sleres if (doencrypt) { 29653033Sleres (void)fprintf(stderr, 29753033Sleres "rlogin: the -x flag requires Kerberos authentication.\n"); 29853033Sleres exit(1); 29953033Sleres } 30053033Sleres #endif /* CRYPT */ 30140858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 30236511Skfall } 30336512Skfall #else 30440858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 30545256Smckusick #endif /* KERBEROS */ 30636511Skfall 30740858Sbostic if (rem < 0) 30836511Skfall exit(1); 30936511Skfall 31040858Sbostic if (dflag && 31140858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 31240858Sbostic (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 31340858Sbostic strerror(errno)); 31444346Skarels one = IPTOS_LOWDELAY; 31544346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 31644346Skarels perror("rlogin: setsockopt TOS (ignored)"); 31740858Sbostic 31840858Sbostic (void)setuid(uid); 31940858Sbostic doit(omask); 3209365Ssam /*NOTREACHED*/ 3216444Swnj } 3226444Swnj 32340858Sbostic int child, defflags, deflflags, tabflag; 32440858Sbostic char deferase, defkill; 32540858Sbostic struct tchars deftc; 32640858Sbostic struct ltchars defltc; 32740858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 32840858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3296444Swnj 33058470Sbostic void 33140858Sbostic doit(omask) 33240858Sbostic long omask; 3336444Swnj { 33413075Ssam struct sgttyb sb; 3356444Swnj 33640858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 33713075Ssam defflags = sb.sg_flags; 33812155Ssam tabflag = defflags & TBDELAY; 3399962Ssam defflags &= ECHO | CRMOD; 34013075Ssam deferase = sb.sg_erase; 34113075Ssam defkill = sb.sg_kill; 34258470Sbostic (void)ioctl(0, TIOCLGET, &deflflags); 34358470Sbostic (void)ioctl(0, TIOCGETC, &deftc); 34413075Ssam notc.t_startc = deftc.t_startc; 34513075Ssam notc.t_stopc = deftc.t_stopc; 34658470Sbostic (void)ioctl(0, TIOCGLTC, &defltc); 34740858Sbostic (void)signal(SIGINT, SIG_IGN); 34858470Sbostic setsignal(SIGHUP); 34958470Sbostic setsignal(SIGQUIT); 3509365Ssam child = fork(); 3519365Ssam if (child == -1) { 35240858Sbostic (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 35325424Skarels done(1); 3549365Ssam } 3559365Ssam if (child == 0) { 35624726Smckusick mode(1); 35740858Sbostic if (reader(omask) == 0) { 35840858Sbostic msg("connection closed."); 35925424Skarels exit(0); 36025424Skarels } 36112155Ssam sleep(1); 36240858Sbostic msg("\007connection closed."); 36340858Sbostic exit(1); 3646444Swnj } 36529729Smckusick 36629729Smckusick /* 36740858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 36858261Smckusick * receive one soon) that we really want to send to the reader. When 36958261Smckusick * one of these comes in, the trap copytochild simply copies such 37058261Smckusick * signals to the child. We can now unblock SIGURG and SIGUSR1 37158261Smckusick * that were set above. 37229729Smckusick */ 37340858Sbostic (void)sigsetmask(omask); 37440858Sbostic (void)signal(SIGCHLD, catch_child); 3759365Ssam writer(); 37640858Sbostic msg("closed connection."); 37725424Skarels done(0); 3786444Swnj } 3796444Swnj 38040858Sbostic /* trap a signal, unless it is being ignored. */ 38158470Sbostic void 38258470Sbostic setsignal(sig) 38340858Sbostic int sig; 38429729Smckusick { 38529729Smckusick int omask = sigblock(sigmask(sig)); 38629729Smckusick 38758470Sbostic if (signal(sig, exit) == SIG_IGN) 38840858Sbostic (void)signal(sig, SIG_IGN); 38940858Sbostic (void)sigsetmask(omask); 39029729Smckusick } 39129729Smckusick 39258470Sbostic __dead void 39325424Skarels done(status) 39425424Skarels int status; 3956444Swnj { 39646850Sbostic int w, wstatus; 3976444Swnj 3986444Swnj mode(0); 39929729Smckusick if (child > 0) { 40040858Sbostic /* make sure catch_child does not snap it up */ 40140858Sbostic (void)signal(SIGCHLD, SIG_DFL); 40229729Smckusick if (kill(child, SIGKILL) >= 0) 40346850Sbostic while ((w = wait(&wstatus)) > 0 && w != child); 40429729Smckusick } 40525424Skarels exit(status); 4066444Swnj } 4076444Swnj 40840858Sbostic int dosigwinch; 40929729Smckusick 41029729Smckusick /* 41124726Smckusick * This is called when the reader process gets the out-of-band (urgent) 41224726Smckusick * request to turn on the window-changing protocol. 41324726Smckusick */ 41440858Sbostic void 41558470Sbostic writeroob(signo) 41658470Sbostic int signo; 41724726Smckusick { 41825341Smckusick if (dosigwinch == 0) { 41924919Smckusick sendwindow(); 42040858Sbostic (void)signal(SIGWINCH, sigwinch); 42125341Smckusick } 42224726Smckusick dosigwinch = 1; 42324726Smckusick } 42424726Smckusick 42540858Sbostic void 42658470Sbostic catch_child(signo) 42758470Sbostic int signo; 42811803Sedward { 42911803Sedward union wait status; 43011803Sedward int pid; 43111803Sedward 43240858Sbostic for (;;) { 43354125Sbostic pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 43440858Sbostic if (pid == 0) 43540858Sbostic return; 43640858Sbostic /* if the child (reader) dies, just quit */ 43758470Sbostic if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 43840858Sbostic done((int)(status.w_termsig | status.w_retcode)); 43940858Sbostic } 44040858Sbostic /* NOTREACHED */ 44111803Sedward } 44211803Sedward 4436444Swnj /* 4449365Ssam * writer: write to remote: 0 -> line. 44545063Sbostic * ~. terminate 44645063Sbostic * ~^Z suspend rlogin process. 44745063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4486444Swnj */ 44958470Sbostic void 4509365Ssam writer() 4516444Swnj { 45245063Sbostic register int bol, local, n; 45323530Sbloom char c; 4546444Swnj 45540858Sbostic bol = 1; /* beginning of line */ 45640858Sbostic local = 0; 45711803Sedward for (;;) { 45840858Sbostic n = read(STDIN_FILENO, &c, 1); 45918358Ssam if (n <= 0) { 46018358Ssam if (n < 0 && errno == EINTR) 46118358Ssam continue; 46211803Sedward break; 46318358Ssam } 4649365Ssam /* 46540858Sbostic * If we're at the beginning of the line and recognize a 46640858Sbostic * command character, then we echo locally. Otherwise, 46740858Sbostic * characters are echo'd remotely. If the command character 46840858Sbostic * is doubled, this acts as a force and local echo is 46940858Sbostic * suppressed. 4709365Ssam */ 47123530Sbloom if (bol) { 47223530Sbloom bol = 0; 47345063Sbostic if (!noescape && c == escapechar) { 47423530Sbloom local = 1; 47523530Sbloom continue; 4766444Swnj } 47723530Sbloom } else if (local) { 47823530Sbloom local = 0; 47923530Sbloom if (c == '.' || c == deftc.t_eofc) { 48023530Sbloom echo(c); 48123530Sbloom break; 4826444Swnj } 48323530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 48423530Sbloom bol = 1; 48523530Sbloom echo(c); 48623530Sbloom stop(c); 48723530Sbloom continue; 48823530Sbloom } 48945063Sbostic if (c != escapechar) 49053033Sleres #ifdef CRYPT 49153033Sleres #ifdef KERBEROS 49253033Sleres if (doencrypt) 49358470Sbostic (void)des_write(rem, 49458470Sbostic (char *)&escapechar, 1); 49553033Sleres else 49653033Sleres #endif 49753033Sleres #endif 49845063Sbostic (void)write(rem, &escapechar, 1); 4996444Swnj } 50036511Skfall 50153033Sleres #ifdef CRYPT 50253033Sleres #ifdef KERBEROS 50353033Sleres if (doencrypt) { 50453033Sleres if (des_write(rem, &c, 1) == 0) { 50553033Sleres msg("line gone"); 50653033Sleres break; 50753033Sleres } 50853033Sleres } else 50953033Sleres #endif 51053033Sleres #endif 51136511Skfall if (write(rem, &c, 1) == 0) { 51240858Sbostic msg("line gone"); 51336511Skfall break; 51436511Skfall } 51523530Sbloom bol = c == defkill || c == deftc.t_eofc || 51625424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 51723530Sbloom c == '\r' || c == '\n'; 5186444Swnj } 5196444Swnj } 5206444Swnj 52158470Sbostic void 52258470Sbostic #if __STDC__ 52358470Sbostic echo(register char c) 52458470Sbostic #else 52523530Sbloom echo(c) 52658470Sbostic register char c; 52758470Sbostic #endif 52823530Sbloom { 52940858Sbostic register char *p; 53023530Sbloom char buf[8]; 53123530Sbloom 53240858Sbostic p = buf; 53323530Sbloom c &= 0177; 53445063Sbostic *p++ = escapechar; 53523530Sbloom if (c < ' ') { 53623530Sbloom *p++ = '^'; 53723530Sbloom *p++ = c + '@'; 53823530Sbloom } else if (c == 0177) { 53923530Sbloom *p++ = '^'; 54023530Sbloom *p++ = '?'; 54123530Sbloom } else 54223530Sbloom *p++ = c; 54323530Sbloom *p++ = '\r'; 54423530Sbloom *p++ = '\n'; 54545063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 54623530Sbloom } 54723530Sbloom 54858470Sbostic void 54958470Sbostic #if __STDC__ 55058470Sbostic stop(char cmdc) 55158470Sbostic #else 55218358Ssam stop(cmdc) 55318358Ssam char cmdc; 55458470Sbostic #endif 55518358Ssam { 55618358Ssam mode(0); 55740858Sbostic (void)signal(SIGCHLD, SIG_IGN); 55840858Sbostic (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 55940858Sbostic (void)signal(SIGCHLD, catch_child); 56018358Ssam mode(1); 56158470Sbostic sigwinch(0); /* check for size changes */ 56218358Ssam } 56318358Ssam 56440858Sbostic void 56558470Sbostic sigwinch(signo) 56658470Sbostic int signo; 56718358Ssam { 56818358Ssam struct winsize ws; 56918358Ssam 57029729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 57140858Sbostic bcmp(&ws, &winsize, sizeof(ws))) { 57218358Ssam winsize = ws; 57324726Smckusick sendwindow(); 57418358Ssam } 57518358Ssam } 57618358Ssam 57724726Smckusick /* 57824726Smckusick * Send the window size to the server via the magic escape 57924726Smckusick */ 58058470Sbostic void 58124726Smckusick sendwindow() 58224726Smckusick { 58340858Sbostic struct winsize *wp; 58424726Smckusick char obuf[4 + sizeof (struct winsize)]; 58524726Smckusick 58640858Sbostic wp = (struct winsize *)(obuf+4); 58724726Smckusick obuf[0] = 0377; 58824726Smckusick obuf[1] = 0377; 58924726Smckusick obuf[2] = 's'; 59024726Smckusick obuf[3] = 's'; 59124726Smckusick wp->ws_row = htons(winsize.ws_row); 59224726Smckusick wp->ws_col = htons(winsize.ws_col); 59324726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 59424726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 59536511Skfall 59653033Sleres #ifdef CRYPT 59753033Sleres #ifdef KERBEROS 59853033Sleres if(doencrypt) 59953033Sleres (void)des_write(rem, obuf, sizeof(obuf)); 60053033Sleres else 60153033Sleres #endif 60253033Sleres #endif 60340858Sbostic (void)write(rem, obuf, sizeof(obuf)); 60424726Smckusick } 60524726Smckusick 60625424Skarels /* 60725424Skarels * reader: read from remote: line -> 1 60825424Skarels */ 60925424Skarels #define READING 1 61025424Skarels #define WRITING 2 61125424Skarels 61240858Sbostic jmp_buf rcvtop; 61340858Sbostic int ppid, rcvcnt, rcvstate; 61440858Sbostic char rcvbuf[8 * 1024]; 61525424Skarels 61640858Sbostic void 61758470Sbostic oob(signo) 61858470Sbostic int signo; 6196444Swnj { 62040858Sbostic struct sgttyb sb; 62140858Sbostic int atmark, n, out, rcvd; 6229365Ssam char waste[BUFSIZ], mark; 6236444Swnj 62442230Sbostic out = O_RDWR; 62540858Sbostic rcvd = 0; 62659175Storek while (recv(rem, &mark, 1, MSG_OOB) < 0) { 62725424Skarels switch (errno) { 62825424Skarels case EWOULDBLOCK: 62925424Skarels /* 63040858Sbostic * Urgent data not here yet. It may not be possible 63140858Sbostic * to send it yet if we are blocked for output and 63240858Sbostic * our input buffer is full. 63325424Skarels */ 63425424Skarels if (rcvcnt < sizeof(rcvbuf)) { 63525424Skarels n = read(rem, rcvbuf + rcvcnt, 63640858Sbostic sizeof(rcvbuf) - rcvcnt); 63725424Skarels if (n <= 0) 63825424Skarels return; 63925424Skarels rcvd += n; 64025424Skarels } else { 64125424Skarels n = read(rem, waste, sizeof(waste)); 64225424Skarels if (n <= 0) 64325424Skarels return; 64425424Skarels } 64525424Skarels continue; 64625424Skarels default: 64725424Skarels return; 64859175Storek } 6496444Swnj } 65025424Skarels if (mark & TIOCPKT_WINDOW) { 65140858Sbostic /* Let server know about window size changes */ 65240858Sbostic (void)kill(ppid, SIGUSR1); 65324726Smckusick } 65425424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 65540858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 65624726Smckusick sb.sg_flags &= ~CBREAK; 65724726Smckusick sb.sg_flags |= RAW; 65840858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 65913075Ssam notc.t_stopc = -1; 66013075Ssam notc.t_startc = -1; 66140858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6626444Swnj } 66325424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 66440858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 66524726Smckusick sb.sg_flags &= ~RAW; 66624726Smckusick sb.sg_flags |= CBREAK; 66740858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 66813075Ssam notc.t_stopc = deftc.t_stopc; 66913075Ssam notc.t_startc = deftc.t_startc; 67040858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6716444Swnj } 67225424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 67340858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 67425424Skarels for (;;) { 67525424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 67640858Sbostic (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 67740858Sbostic strerror(errno)); 67825424Skarels break; 67925424Skarels } 68025424Skarels if (atmark) 68125424Skarels break; 68225424Skarels n = read(rem, waste, sizeof (waste)); 68325424Skarels if (n <= 0) 68425424Skarels break; 68525424Skarels } 68625424Skarels /* 68740858Sbostic * Don't want any pending data to be output, so clear the recv 68840858Sbostic * buffer. If we were hanging on a write when interrupted, 68940858Sbostic * don't want it to restart. If we were reading, restart 69040858Sbostic * anyway. 69125424Skarels */ 69225424Skarels rcvcnt = 0; 69325424Skarels longjmp(rcvtop, 1); 69425424Skarels } 69529729Smckusick 69640858Sbostic /* oob does not do FLUSHREAD (alas!) */ 69729729Smckusick 69829729Smckusick /* 69940858Sbostic * If we filled the receive buffer while a read was pending, longjmp 70040858Sbostic * to the top to restart appropriately. Don't abort a pending write, 70140858Sbostic * however, or we won't know how much was written. 70225424Skarels */ 70325424Skarels if (rcvd && rcvstate == READING) 70425424Skarels longjmp(rcvtop, 1); 7056444Swnj } 7066444Swnj 70740858Sbostic /* reader: read from remote: line -> 1 */ 70858470Sbostic int 70940858Sbostic reader(omask) 71040858Sbostic int omask; 7116444Swnj { 71259175Storek int pid, n, remaining; 71359175Storek char *bufp; 71440858Sbostic 71559175Storek #if BSD >= 43 || defined(SUNOS4) 71659175Storek pid = getpid(); /* modern systems use positives for pid */ 71726981Skarels #else 71859175Storek pid = -getpid(); /* old broken systems use negatives */ 71926981Skarels #endif 72040858Sbostic (void)signal(SIGTTOU, SIG_IGN); 72140858Sbostic (void)signal(SIGURG, oob); 72226981Skarels ppid = getppid(); 72340858Sbostic (void)fcntl(rem, F_SETOWN, pid); 72440858Sbostic (void)setjmp(rcvtop); 72540858Sbostic (void)sigsetmask(omask); 72659175Storek bufp = rcvbuf; 7276444Swnj for (;;) { 72825424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 72925424Skarels rcvstate = WRITING; 73045063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 73125424Skarels if (n < 0) { 73225424Skarels if (errno != EINTR) 73358470Sbostic return (-1); 73425424Skarels continue; 73525424Skarels } 73625424Skarels bufp += n; 73725424Skarels } 73825424Skarels bufp = rcvbuf; 73925424Skarels rcvcnt = 0; 74025424Skarels rcvstate = READING; 74136511Skfall 74253033Sleres #ifdef CRYPT 74353033Sleres #ifdef KERBEROS 74453033Sleres if (doencrypt) 74553033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 74653033Sleres else 74753033Sleres #endif 74853033Sleres #endif 74936511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 75025424Skarels if (rcvcnt == 0) 75125424Skarels return (0); 75225424Skarels if (rcvcnt < 0) { 7539365Ssam if (errno == EINTR) 7546444Swnj continue; 75540858Sbostic (void)fprintf(stderr, "rlogin: read: %s.\n", 75640858Sbostic strerror(errno)); 75758470Sbostic return (-1); 7586444Swnj } 7596444Swnj } 7606444Swnj } 7616444Swnj 76258470Sbostic void 7636444Swnj mode(f) 76458470Sbostic int f; 7656444Swnj { 76613075Ssam struct ltchars *ltc; 76713075Ssam struct sgttyb sb; 76840858Sbostic struct tchars *tc; 76940858Sbostic int lflags; 7709365Ssam 77140858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 77240858Sbostic (void)ioctl(0, TIOCLGET, (char *)&lflags); 77340858Sbostic switch(f) { 7749962Ssam case 0: 77513075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 77613075Ssam sb.sg_flags |= defflags|tabflag; 7779962Ssam tc = &deftc; 77813075Ssam ltc = &defltc; 77913075Ssam sb.sg_kill = defkill; 78013075Ssam sb.sg_erase = deferase; 78121583Sbloom lflags = deflflags; 7829962Ssam break; 7839962Ssam case 1: 78413075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 78513075Ssam sb.sg_flags &= ~defflags; 78612155Ssam /* preserve tab delays, but turn off XTABS */ 78713075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 78813075Ssam sb.sg_flags &= ~TBDELAY; 7899962Ssam tc = ¬c; 79013075Ssam ltc = &noltc; 79113075Ssam sb.sg_kill = sb.sg_erase = -1; 79221583Sbloom if (litout) 79321583Sbloom lflags |= LLITOUT; 7949962Ssam break; 7959962Ssam default: 7969962Ssam return; 7976444Swnj } 79840858Sbostic (void)ioctl(0, TIOCSLTC, (char *)ltc); 79940858Sbostic (void)ioctl(0, TIOCSETC, (char *)tc); 80040858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 80140858Sbostic (void)ioctl(0, TIOCLSET, (char *)&lflags); 8026444Swnj } 8036444Swnj 80440858Sbostic void 80558470Sbostic lostpeer(signo) 80658470Sbostic int signo; 8076444Swnj { 80840858Sbostic (void)signal(SIGPIPE, SIG_IGN); 80940858Sbostic msg("\007connection closed."); 81040858Sbostic done(1); 81140858Sbostic } 81229729Smckusick 81340858Sbostic /* copy SIGURGs to the child process. */ 81440858Sbostic void 81558470Sbostic copytochild(signo) 81658470Sbostic int signo; 81740858Sbostic { 81840858Sbostic (void)kill(child, SIGURG); 8196444Swnj } 8206444Swnj 82158470Sbostic void 82240858Sbostic msg(str) 82340858Sbostic char *str; 8246444Swnj { 82540858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 82640858Sbostic } 82729729Smckusick 82840858Sbostic #ifdef KERBEROS 82940858Sbostic /* VARARGS */ 83058470Sbostic void 83158470Sbostic #if __STDC__ 83258470Sbostic warning(const char *fmt, ...) 83358470Sbostic #else 83458470Sbostic warning(fmt, va_alist) 83558470Sbostic char *fmt; 83658470Sbostic va_dcl 83758470Sbostic #endif 83840858Sbostic { 83940858Sbostic va_list ap; 84040858Sbostic 84140858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 84258470Sbostic #ifdef __STDC__ 84358470Sbostic va_start(ap, fmt); 84458470Sbostic #else 84540858Sbostic va_start(ap); 84658470Sbostic #endif 84740858Sbostic vfprintf(stderr, fmt, ap); 84840858Sbostic va_end(ap); 84940858Sbostic (void)fprintf(stderr, ".\n"); 8506444Swnj } 85140858Sbostic #endif 85236512Skfall 85358470Sbostic __dead void 85440858Sbostic usage() 85536512Skfall { 85640858Sbostic (void)fprintf(stderr, 85740858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 85840858Sbostic #ifdef KERBEROS 85953033Sleres #ifdef CRYPT 86054125Sbostic "8EKLx", " [-k realm] "); 86153033Sleres #else 86254125Sbostic "8EKL", " [-k realm] "); 86353033Sleres #endif 86445256Smckusick #else 86545063Sbostic "8EL", " "); 86640858Sbostic #endif 86740858Sbostic exit(1); 86836512Skfall } 86940858Sbostic 87040858Sbostic /* 87159175Storek * The following routine provides compatibility (such as it is) between older 87240858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 87340858Sbostic */ 87459175Storek #ifdef OLDSUN 87558470Sbostic int 87640858Sbostic get_window_size(fd, wp) 87740858Sbostic int fd; 87840858Sbostic struct winsize *wp; 87940858Sbostic { 88040858Sbostic struct ttysize ts; 88140858Sbostic int error; 88240858Sbostic 88340858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 88458470Sbostic return (error); 88540858Sbostic wp->ws_row = ts.ts_lines; 88640858Sbostic wp->ws_col = ts.ts_cols; 88740858Sbostic wp->ws_xpixel = 0; 88840858Sbostic wp->ws_ypixel = 0; 88958470Sbostic return (0); 89040858Sbostic } 89140858Sbostic #endif 89245063Sbostic 89358470Sbostic u_int 89445063Sbostic getescape(p) 89545063Sbostic register char *p; 89645063Sbostic { 89745063Sbostic long val; 89845063Sbostic int len; 89945063Sbostic 90045063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 90158470Sbostic return ((u_int)*p); 90245063Sbostic /* otherwise, \nnn */ 90345063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 90458470Sbostic val = strtol(++p, NULL, 8); 90545063Sbostic for (;;) { 90645063Sbostic if (!*++p) 90758470Sbostic return ((u_int)val); 90845063Sbostic if (*p < '0' || *p > '8') 90945063Sbostic break; 91045063Sbostic } 91145063Sbostic } 91245063Sbostic msg("illegal option value -- e"); 91345063Sbostic usage(); 91445063Sbostic /* NOTREACHED */ 91545063Sbostic } 916