1*44346Skarels /* 240858Sbostic * Copyright (c) 1983, 1990 The Regents of the University of California. 335539Sbostic * All rights reserved. 435539Sbostic * 542763Sbostic * %sccs.include.redist.c% 621595Sdist */ 721595Sdist 86444Swnj #ifndef lint 921595Sdist char copyright[] = 1040858Sbostic "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ 1121595Sdist All rights reserved.\n"; 1235539Sbostic #endif /* not lint */ 136444Swnj 1421595Sdist #ifndef lint 15*44346Skarels static char sccsid[] = "@(#)rlogin.c 5.29 (Berkeley) 06/27/90"; 1635539Sbostic #endif /* not lint */ 1721595Sdist 1812990Ssam /* 1940858Sbostic * $Source: mit/rlogin/RCS/rlogin.c,v $ 2042763Sbostic * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall 2142763Sbostic * Exp Locker: kfall $ 2240858Sbostic */ 2340858Sbostic 2440858Sbostic /* 2512990Ssam * rlogin - remote login 2612990Ssam */ 2726981Skarels #include <sys/param.h> 2824727Smckusick #include <sys/file.h> 296444Swnj #include <sys/socket.h> 3040858Sbostic #include <sys/signal.h> 3129729Smckusick #include <sys/time.h> 3229729Smckusick #include <sys/resource.h> 3313620Ssam #include <sys/wait.h> 349365Ssam 359207Ssam #include <netinet/in.h> 36*44346Skarels #include <netinet/in_systm.h> 37*44346Skarels #include <netinet/ip.h> 3840858Sbostic #include <netdb.h> 399365Ssam 409365Ssam #include <sgtty.h> 4140858Sbostic #include <setjmp.h> 426444Swnj #include <errno.h> 4340858Sbostic #include <varargs.h> 446444Swnj #include <pwd.h> 4540858Sbostic #include <stdio.h> 4640858Sbostic #include <unistd.h> 4742058Sbostic #include <string.h> 486444Swnj 4940858Sbostic #ifdef KERBEROS 5041760Skfall #include <kerberosIV/des.h> 5140683Sbostic #include <kerberosIV/krb.h> 5236511Skfall 5340858Sbostic CREDENTIALS cred; 5440858Sbostic Key_schedule schedule; 5540858Sbostic int use_kerberos = 1, encrypt; 5640858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 5740858Sbostic extern char *krb_realmofhost(); 5840858Sbostic #endif 5924726Smckusick 6040858Sbostic #ifndef TIOCPKT_WINDOW 6140858Sbostic #define TIOCPKT_WINDOW 0x80 6240858Sbostic #endif 6329729Smckusick 6440858Sbostic /* concession to Sun */ 6540858Sbostic #ifndef SIGUSR1 6640858Sbostic #define SIGUSR1 30 6726981Skarels #endif 6840858Sbostic 6940858Sbostic extern int errno; 7040858Sbostic int eight, litout, rem; 7140858Sbostic char cmdchar; 7240858Sbostic char *speeds[] = { 7340858Sbostic "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 7440858Sbostic "1800", "2400", "4800", "9600", "19200", "38400" 7540858Sbostic }; 7640858Sbostic 7726981Skarels #ifdef sun 7826981Skarels struct winsize { 7926981Skarels unsigned short ws_row, ws_col; 8026981Skarels unsigned short ws_xpixel, ws_ypixel; 8126981Skarels }; 8240858Sbostic #endif 8318358Ssam struct winsize winsize; 846444Swnj 8540858Sbostic #ifndef sun 8640858Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 8740858Sbostic #endif 8829729Smckusick 8940858Sbostic void exit(); 9029729Smckusick 916444Swnj main(argc, argv) 926444Swnj int argc; 936444Swnj char **argv; 946444Swnj { 9540858Sbostic extern char *optarg; 9640858Sbostic extern int optind; 9740858Sbostic struct passwd *pw; 9840858Sbostic struct servent *sp; 996444Swnj struct sgttyb ttyb; 10040858Sbostic long omask; 10140858Sbostic int argoff, ch, dflag, one, uid; 10240858Sbostic char *host, *p, *user, term[1024]; 10340858Sbostic void lostpeer(); 10440858Sbostic char *getenv(); 1056444Swnj 10640858Sbostic argoff = dflag = 0; 10740858Sbostic one = 1; 10840858Sbostic host = user = NULL; 10940858Sbostic cmdchar = '~'; 11040858Sbostic 11140858Sbostic if (p = rindex(argv[0], '/')) 11240858Sbostic ++p; 1136444Swnj else 11440858Sbostic p = argv[0]; 11540858Sbostic 11640858Sbostic if (strcmp(p, "rlogin")) 11740858Sbostic host = p; 11840858Sbostic 11940858Sbostic /* handle "rlogin host flags" */ 12040858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 12140858Sbostic host = argv[1]; 12240858Sbostic argoff = 1; 1236444Swnj } 12436511Skfall 12540858Sbostic #ifdef KERBEROS 12640868Sbostic #define OPTIONS "8KLde:k:l:x" 12740858Sbostic #else 12840868Sbostic #define OPTIONS "8KLde:l:" 12940858Sbostic #endif 13040858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 13140858Sbostic switch(ch) { 13240858Sbostic case '8': 13340858Sbostic eight = 1; 13440858Sbostic break; 13540868Sbostic case 'K': 13640868Sbostic #ifdef KERBEROS 13740868Sbostic use_kerberos = 0; 13840868Sbostic #endif 13940868Sbostic break; 14040858Sbostic case 'L': 14140858Sbostic litout = 1; 14240858Sbostic break; 14340858Sbostic case 'd': 14440858Sbostic dflag = 1; 14540858Sbostic break; 14640858Sbostic case 'e': 14740858Sbostic cmdchar = optarg[0]; 14840858Sbostic break; 14940858Sbostic #ifdef KERBEROS 15040858Sbostic case 'k': 15140858Sbostic dest_realm = dst_realm_buf; 15240858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 15340858Sbostic break; 15440858Sbostic #endif 15540858Sbostic case 'l': 15640858Sbostic user = optarg; 15740858Sbostic break; 15840858Sbostic #ifdef KERBEROS 15940858Sbostic case 'x': 16040858Sbostic encrypt = 1; 16140858Sbostic des_set_key(cred.session, schedule); 16240858Sbostic break; 16340858Sbostic #endif 16440858Sbostic case '?': 16540858Sbostic default: 16640858Sbostic usage(); 16736524Skfall } 16840858Sbostic optind += argoff; 16940858Sbostic argc -= optind; 17040858Sbostic argv += optind; 17136524Skfall 17240858Sbostic /* if haven't gotten a host yet, do so */ 17340858Sbostic if (!host && !(host = *argv++)) 17440858Sbostic usage(); 17536511Skfall 17640858Sbostic if (*argv) 17740858Sbostic usage(); 17840858Sbostic 17940858Sbostic if (!(pw = getpwuid(uid = getuid()))) { 18040858Sbostic (void)fprintf(stderr, "rlogin: unknown user id.\n"); 1816444Swnj exit(1); 1826444Swnj } 18340858Sbostic if (!user) 18440858Sbostic user = pw->pw_name; 18540858Sbostic 18640868Sbostic sp = NULL; 18740858Sbostic #ifdef KERBEROS 18840868Sbostic if (use_kerberos) { 18940868Sbostic sp = getservbyname((encrypt ? "eklogin" : "klogin"), "tcp"); 19040868Sbostic if (sp == NULL) { 19140868Sbostic use_kerberos = 0; 19240868Sbostic warning("can't get entry for %s/tcp service", 19340868Sbostic encrypt ? "eklogin" : "klogin"); 19440868Sbostic } 19536512Skfall } 19636512Skfall #endif 19740868Sbostic if (sp == NULL) 19840868Sbostic sp = getservbyname("login", "tcp"); 19940858Sbostic if (sp == NULL) { 20040858Sbostic (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 20140858Sbostic exit(1); 2029365Ssam } 20340858Sbostic 20440858Sbostic (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 20518358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 20640858Sbostic (void)strcat(term, "/"); 20740858Sbostic (void)strcat(term, speeds[ttyb.sg_ospeed]); 2086444Swnj } 20940858Sbostic 21040858Sbostic (void)get_window_size(0, &winsize); 21140858Sbostic 21240858Sbostic (void)signal(SIGPIPE, lostpeer); 21329729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 21440858Sbostic omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 21536511Skfall 21640858Sbostic #ifdef KERBEROS 21736512Skfall try_connect: 21840858Sbostic if (use_kerberos) { 21936512Skfall rem = KSUCCESS; 22040858Sbostic errno = 0; 22138728Skfall if (dest_realm == NULL) 22238728Skfall dest_realm = krb_realmofhost(host); 22338728Skfall 22440858Sbostic if (encrypt) 22540858Sbostic rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 22640858Sbostic dest_realm, &cred, schedule); 22740858Sbostic else 22840858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 22940858Sbostic dest_realm); 23038728Skfall if (rem < 0) { 23136512Skfall use_kerberos = 0; 23236628Skfall sp = getservbyname("login", "tcp"); 23340858Sbostic if (sp == NULL) { 23440858Sbostic (void)fprintf(stderr, 23540858Sbostic "rlogin: unknown service login/tcp.\n"); 23636628Skfall exit(1); 23736628Skfall } 23838728Skfall if (errno == ECONNREFUSED) 23940858Sbostic warning("remote host doesn't support Kerberos"); 24038728Skfall if (errno == ENOENT) 24140858Sbostic warning("can't provide Kerberos auth data"); 24236512Skfall goto try_connect; 24336512Skfall } 24436511Skfall } else { 24540858Sbostic if (encrypt) { 24640858Sbostic (void)fprintf(stderr, 24740858Sbostic "rlogin: the -x flag requires Kerberos authentication.\n"); 24836512Skfall exit(1); 24936512Skfall } 25040858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 25136511Skfall } 25236512Skfall #else 25340858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 25436512Skfall #endif 25536511Skfall 25640858Sbostic if (rem < 0) 25736511Skfall exit(1); 25836511Skfall 25940858Sbostic if (dflag && 26040858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 26140858Sbostic (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 26240858Sbostic strerror(errno)); 263*44346Skarels one = IPTOS_LOWDELAY; 264*44346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 265*44346Skarels perror("rlogin: setsockopt TOS (ignored)"); 26640858Sbostic 26740858Sbostic (void)setuid(uid); 26840858Sbostic doit(omask); 2699365Ssam /*NOTREACHED*/ 2706444Swnj } 2716444Swnj 27240858Sbostic int child, defflags, deflflags, tabflag; 27340858Sbostic char deferase, defkill; 27440858Sbostic struct tchars deftc; 27540858Sbostic struct ltchars defltc; 27640858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 27740858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 2786444Swnj 27940858Sbostic doit(omask) 28040858Sbostic long omask; 2816444Swnj { 28213075Ssam struct sgttyb sb; 28340858Sbostic void catch_child(), copytochild(), exit(), writeroob(); 2846444Swnj 28540858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 28613075Ssam defflags = sb.sg_flags; 28712155Ssam tabflag = defflags & TBDELAY; 2889962Ssam defflags &= ECHO | CRMOD; 28913075Ssam deferase = sb.sg_erase; 29013075Ssam defkill = sb.sg_kill; 29140858Sbostic (void)ioctl(0, TIOCLGET, (char *)&deflflags); 29240858Sbostic (void)ioctl(0, TIOCGETC, (char *)&deftc); 29313075Ssam notc.t_startc = deftc.t_startc; 29413075Ssam notc.t_stopc = deftc.t_stopc; 29540858Sbostic (void)ioctl(0, TIOCGLTC, (char *)&defltc); 29640858Sbostic (void)signal(SIGINT, SIG_IGN); 29729729Smckusick setsignal(SIGHUP, exit); 29829729Smckusick setsignal(SIGQUIT, exit); 2999365Ssam child = fork(); 3009365Ssam if (child == -1) { 30140858Sbostic (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 30225424Skarels done(1); 3039365Ssam } 3049365Ssam if (child == 0) { 30524726Smckusick mode(1); 30640858Sbostic if (reader(omask) == 0) { 30740858Sbostic msg("connection closed."); 30825424Skarels exit(0); 30925424Skarels } 31012155Ssam sleep(1); 31140858Sbostic msg("\007connection closed."); 31240858Sbostic exit(1); 3136444Swnj } 31429729Smckusick 31529729Smckusick /* 31640858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 31740858Sbostic * receive one soon) that we really want to send to the reader. Set a 31840858Sbostic * trap that simply copies such signals to the child. 31929729Smckusick */ 32040858Sbostic (void)signal(SIGURG, copytochild); 32140858Sbostic (void)signal(SIGUSR1, writeroob); 32240858Sbostic (void)sigsetmask(omask); 32340858Sbostic (void)signal(SIGCHLD, catch_child); 3249365Ssam writer(); 32540858Sbostic msg("closed connection."); 32625424Skarels done(0); 3276444Swnj } 3286444Swnj 32940858Sbostic /* trap a signal, unless it is being ignored. */ 33029729Smckusick setsignal(sig, act) 33140858Sbostic int sig; 33240858Sbostic void (*act)(); 33329729Smckusick { 33429729Smckusick int omask = sigblock(sigmask(sig)); 33529729Smckusick 33629729Smckusick if (signal(sig, act) == SIG_IGN) 33740858Sbostic (void)signal(sig, SIG_IGN); 33840858Sbostic (void)sigsetmask(omask); 33929729Smckusick } 34029729Smckusick 34125424Skarels done(status) 34225424Skarels int status; 3436444Swnj { 34429729Smckusick int w; 3456444Swnj 3466444Swnj mode(0); 34729729Smckusick if (child > 0) { 34840858Sbostic /* make sure catch_child does not snap it up */ 34940858Sbostic (void)signal(SIGCHLD, SIG_DFL); 35029729Smckusick if (kill(child, SIGKILL) >= 0) 35140858Sbostic while ((w = wait((union wait *)0)) > 0 && w != child); 35229729Smckusick } 35325424Skarels exit(status); 3546444Swnj } 3556444Swnj 35640858Sbostic int dosigwinch; 35729729Smckusick 35829729Smckusick /* 35924726Smckusick * This is called when the reader process gets the out-of-band (urgent) 36024726Smckusick * request to turn on the window-changing protocol. 36124726Smckusick */ 36240858Sbostic void 36324726Smckusick writeroob() 36424726Smckusick { 36540858Sbostic void sigwinch(); 36624726Smckusick 36725341Smckusick if (dosigwinch == 0) { 36824919Smckusick sendwindow(); 36940858Sbostic (void)signal(SIGWINCH, sigwinch); 37025341Smckusick } 37124726Smckusick dosigwinch = 1; 37224726Smckusick } 37324726Smckusick 37440858Sbostic void 37540858Sbostic catch_child() 37611803Sedward { 37711803Sedward union wait status; 37811803Sedward int pid; 37911803Sedward 38040858Sbostic for (;;) { 38140858Sbostic pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); 38240858Sbostic if (pid == 0) 38340858Sbostic return; 38440858Sbostic /* if the child (reader) dies, just quit */ 38540858Sbostic if (pid < 0 || pid == child && !WIFSTOPPED(status)) 38640858Sbostic done((int)(status.w_termsig | status.w_retcode)); 38740858Sbostic } 38840858Sbostic /* NOTREACHED */ 38911803Sedward } 39011803Sedward 3916444Swnj /* 3929365Ssam * writer: write to remote: 0 -> line. 3939365Ssam * ~. terminate 3949365Ssam * ~^Z suspend rlogin process. 39510415Ssam * ~^Y suspend rlogin process, but leave reader alone. 3966444Swnj */ 3979365Ssam writer() 3986444Swnj { 39923530Sbloom char c; 40040858Sbostic register int bol, local, n; 4016444Swnj 40240858Sbostic bol = 1; /* beginning of line */ 40340858Sbostic local = 0; 40411803Sedward for (;;) { 40540858Sbostic n = read(STDIN_FILENO, &c, 1); 40618358Ssam if (n <= 0) { 40718358Ssam if (n < 0 && errno == EINTR) 40818358Ssam continue; 40911803Sedward break; 41018358Ssam } 4119365Ssam /* 41240858Sbostic * If we're at the beginning of the line and recognize a 41340858Sbostic * command character, then we echo locally. Otherwise, 41440858Sbostic * characters are echo'd remotely. If the command character 41540858Sbostic * is doubled, this acts as a force and local echo is 41640858Sbostic * suppressed. 4179365Ssam */ 41823530Sbloom if (bol) { 41923530Sbloom bol = 0; 42023530Sbloom if (c == cmdchar) { 42123530Sbloom bol = 0; 42223530Sbloom local = 1; 42323530Sbloom continue; 4246444Swnj } 42523530Sbloom } else if (local) { 42623530Sbloom local = 0; 42723530Sbloom if (c == '.' || c == deftc.t_eofc) { 42823530Sbloom echo(c); 42923530Sbloom break; 4306444Swnj } 43123530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 43223530Sbloom bol = 1; 43323530Sbloom echo(c); 43423530Sbloom stop(c); 43523530Sbloom continue; 43623530Sbloom } 43736511Skfall if (c != cmdchar) { 43840858Sbostic #ifdef KERBEROS 43940858Sbostic if (encrypt) { 44040858Sbostic (void)des_write(rem, &cmdchar, 1); 44136511Skfall } else 44236511Skfall #endif 44340858Sbostic (void)write(rem, &cmdchar, 1); 44436511Skfall } 4456444Swnj } 44636511Skfall 44740858Sbostic #ifdef KERBEROS 44840858Sbostic if (encrypt) { 44936511Skfall if (des_write(rem, &c, 1) == 0) { 45040858Sbostic msg("line gone"); 45136511Skfall break; 45236511Skfall } 45336511Skfall } else 45436511Skfall #endif 45536511Skfall if (write(rem, &c, 1) == 0) { 45640858Sbostic msg("line gone"); 45736511Skfall break; 45836511Skfall } 45923530Sbloom bol = c == defkill || c == deftc.t_eofc || 46025424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 46123530Sbloom c == '\r' || c == '\n'; 4626444Swnj } 4636444Swnj } 4646444Swnj 46523530Sbloom echo(c) 46623530Sbloom register char c; 46723530Sbloom { 46840858Sbostic register char *p; 46923530Sbloom char buf[8]; 47023530Sbloom 47140858Sbostic p = buf; 47223530Sbloom c &= 0177; 47323530Sbloom *p++ = cmdchar; 47423530Sbloom if (c < ' ') { 47523530Sbloom *p++ = '^'; 47623530Sbloom *p++ = c + '@'; 47723530Sbloom } else if (c == 0177) { 47823530Sbloom *p++ = '^'; 47923530Sbloom *p++ = '?'; 48023530Sbloom } else 48123530Sbloom *p++ = c; 48223530Sbloom *p++ = '\r'; 48323530Sbloom *p++ = '\n'; 48440858Sbostic (void)write(1, buf, p - buf); 48523530Sbloom } 48623530Sbloom 48718358Ssam stop(cmdc) 48818358Ssam char cmdc; 48918358Ssam { 49018358Ssam mode(0); 49140858Sbostic (void)signal(SIGCHLD, SIG_IGN); 49240858Sbostic (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 49340858Sbostic (void)signal(SIGCHLD, catch_child); 49418358Ssam mode(1); 49518358Ssam sigwinch(); /* check for size changes */ 49618358Ssam } 49718358Ssam 49840858Sbostic void 49918358Ssam sigwinch() 50018358Ssam { 50118358Ssam struct winsize ws; 50218358Ssam 50329729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 50440858Sbostic bcmp(&ws, &winsize, sizeof(ws))) { 50518358Ssam winsize = ws; 50624726Smckusick sendwindow(); 50718358Ssam } 50818358Ssam } 50918358Ssam 51024726Smckusick /* 51124726Smckusick * Send the window size to the server via the magic escape 51224726Smckusick */ 51324726Smckusick sendwindow() 51424726Smckusick { 51540858Sbostic struct winsize *wp; 51624726Smckusick char obuf[4 + sizeof (struct winsize)]; 51724726Smckusick 51840858Sbostic wp = (struct winsize *)(obuf+4); 51924726Smckusick obuf[0] = 0377; 52024726Smckusick obuf[1] = 0377; 52124726Smckusick obuf[2] = 's'; 52224726Smckusick obuf[3] = 's'; 52324726Smckusick wp->ws_row = htons(winsize.ws_row); 52424726Smckusick wp->ws_col = htons(winsize.ws_col); 52524726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 52624726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 52736511Skfall 52840858Sbostic #ifdef KERBEROS 52936511Skfall if(encrypt) 53040858Sbostic (void)des_write(rem, obuf, sizeof(obuf)); 53136511Skfall else 53236511Skfall #endif 53340858Sbostic (void)write(rem, obuf, sizeof(obuf)); 53424726Smckusick } 53524726Smckusick 53625424Skarels /* 53725424Skarels * reader: read from remote: line -> 1 53825424Skarels */ 53925424Skarels #define READING 1 54025424Skarels #define WRITING 2 54125424Skarels 54240858Sbostic jmp_buf rcvtop; 54340858Sbostic int ppid, rcvcnt, rcvstate; 54440858Sbostic char rcvbuf[8 * 1024]; 54525424Skarels 54640858Sbostic void 5476444Swnj oob() 5486444Swnj { 54940858Sbostic struct sgttyb sb; 55040858Sbostic int atmark, n, out, rcvd; 5519365Ssam char waste[BUFSIZ], mark; 5526444Swnj 55342230Sbostic out = O_RDWR; 55440858Sbostic rcvd = 0; 55525424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 55625424Skarels switch (errno) { 55725424Skarels case EWOULDBLOCK: 55825424Skarels /* 55940858Sbostic * Urgent data not here yet. It may not be possible 56040858Sbostic * to send it yet if we are blocked for output and 56140858Sbostic * our input buffer is full. 56225424Skarels */ 56325424Skarels if (rcvcnt < sizeof(rcvbuf)) { 56425424Skarels n = read(rem, rcvbuf + rcvcnt, 56540858Sbostic sizeof(rcvbuf) - rcvcnt); 56625424Skarels if (n <= 0) 56725424Skarels return; 56825424Skarels rcvd += n; 56925424Skarels } else { 57025424Skarels n = read(rem, waste, sizeof(waste)); 57125424Skarels if (n <= 0) 57225424Skarels return; 57325424Skarels } 57425424Skarels continue; 57525424Skarels default: 57625424Skarels return; 5776444Swnj } 57825424Skarels if (mark & TIOCPKT_WINDOW) { 57940858Sbostic /* Let server know about window size changes */ 58040858Sbostic (void)kill(ppid, SIGUSR1); 58124726Smckusick } 58225424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 58340858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 58424726Smckusick sb.sg_flags &= ~CBREAK; 58524726Smckusick sb.sg_flags |= RAW; 58640858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 58713075Ssam notc.t_stopc = -1; 58813075Ssam notc.t_startc = -1; 58940858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 5906444Swnj } 59125424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 59240858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 59324726Smckusick sb.sg_flags &= ~RAW; 59424726Smckusick sb.sg_flags |= CBREAK; 59540858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 59613075Ssam notc.t_stopc = deftc.t_stopc; 59713075Ssam notc.t_startc = deftc.t_startc; 59840858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 5996444Swnj } 60025424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 60140858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 60225424Skarels for (;;) { 60325424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 60440858Sbostic (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 60540858Sbostic strerror(errno)); 60625424Skarels break; 60725424Skarels } 60825424Skarels if (atmark) 60925424Skarels break; 61025424Skarels n = read(rem, waste, sizeof (waste)); 61125424Skarels if (n <= 0) 61225424Skarels break; 61325424Skarels } 61425424Skarels /* 61540858Sbostic * Don't want any pending data to be output, so clear the recv 61640858Sbostic * buffer. If we were hanging on a write when interrupted, 61740858Sbostic * don't want it to restart. If we were reading, restart 61840858Sbostic * anyway. 61925424Skarels */ 62025424Skarels rcvcnt = 0; 62125424Skarels longjmp(rcvtop, 1); 62225424Skarels } 62329729Smckusick 62440858Sbostic /* oob does not do FLUSHREAD (alas!) */ 62529729Smckusick 62629729Smckusick /* 62740858Sbostic * If we filled the receive buffer while a read was pending, longjmp 62840858Sbostic * to the top to restart appropriately. Don't abort a pending write, 62940858Sbostic * however, or we won't know how much was written. 63025424Skarels */ 63125424Skarels if (rcvd && rcvstate == READING) 63225424Skarels longjmp(rcvtop, 1); 6336444Swnj } 6346444Swnj 63540858Sbostic /* reader: read from remote: line -> 1 */ 63640858Sbostic reader(omask) 63740858Sbostic int omask; 6386444Swnj { 63940858Sbostic void oob(); 64040858Sbostic 64126981Skarels #if !defined(BSD) || BSD < 43 64226981Skarels int pid = -getpid(); 64326981Skarels #else 64425424Skarels int pid = getpid(); 64526981Skarels #endif 64625424Skarels int n, remaining; 64725424Skarels char *bufp = rcvbuf; 6486444Swnj 64940858Sbostic (void)signal(SIGTTOU, SIG_IGN); 65040858Sbostic (void)signal(SIGURG, oob); 65126981Skarels ppid = getppid(); 65240858Sbostic (void)fcntl(rem, F_SETOWN, pid); 65340858Sbostic (void)setjmp(rcvtop); 65440858Sbostic (void)sigsetmask(omask); 6556444Swnj for (;;) { 65625424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 65725424Skarels rcvstate = WRITING; 65825424Skarels n = write(1, bufp, remaining); 65925424Skarels if (n < 0) { 66025424Skarels if (errno != EINTR) 66140858Sbostic return(-1); 66225424Skarels continue; 66325424Skarels } 66425424Skarels bufp += n; 66525424Skarels } 66625424Skarels bufp = rcvbuf; 66725424Skarels rcvcnt = 0; 66825424Skarels rcvstate = READING; 66936511Skfall 67040858Sbostic #ifdef KERBEROS 67140858Sbostic if (encrypt) 67236511Skfall rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 67336511Skfall else 67436511Skfall #endif 67536511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 67625424Skarels if (rcvcnt == 0) 67725424Skarels return (0); 67825424Skarels if (rcvcnt < 0) { 6799365Ssam if (errno == EINTR) 6806444Swnj continue; 68140858Sbostic (void)fprintf(stderr, "rlogin: read: %s.\n", 68240858Sbostic strerror(errno)); 68340858Sbostic return(-1); 6846444Swnj } 6856444Swnj } 6866444Swnj } 6876444Swnj 6886444Swnj mode(f) 6896444Swnj { 69013075Ssam struct ltchars *ltc; 69113075Ssam struct sgttyb sb; 69240858Sbostic struct tchars *tc; 69340858Sbostic int lflags; 6949365Ssam 69540858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 69640858Sbostic (void)ioctl(0, TIOCLGET, (char *)&lflags); 69740858Sbostic switch(f) { 6989962Ssam case 0: 69913075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 70013075Ssam sb.sg_flags |= defflags|tabflag; 7019962Ssam tc = &deftc; 70213075Ssam ltc = &defltc; 70313075Ssam sb.sg_kill = defkill; 70413075Ssam sb.sg_erase = deferase; 70521583Sbloom lflags = deflflags; 7069962Ssam break; 7079962Ssam case 1: 70813075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 70913075Ssam sb.sg_flags &= ~defflags; 71012155Ssam /* preserve tab delays, but turn off XTABS */ 71113075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 71213075Ssam sb.sg_flags &= ~TBDELAY; 7139962Ssam tc = ¬c; 71413075Ssam ltc = &noltc; 71513075Ssam sb.sg_kill = sb.sg_erase = -1; 71621583Sbloom if (litout) 71721583Sbloom lflags |= LLITOUT; 7189962Ssam break; 7199962Ssam default: 7209962Ssam return; 7216444Swnj } 72240858Sbostic (void)ioctl(0, TIOCSLTC, (char *)ltc); 72340858Sbostic (void)ioctl(0, TIOCSETC, (char *)tc); 72440858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 72540858Sbostic (void)ioctl(0, TIOCLSET, (char *)&lflags); 7266444Swnj } 7276444Swnj 72840858Sbostic void 72940858Sbostic lostpeer() 7306444Swnj { 73140858Sbostic (void)signal(SIGPIPE, SIG_IGN); 73240858Sbostic msg("\007connection closed."); 73340858Sbostic done(1); 73440858Sbostic } 73529729Smckusick 73640858Sbostic /* copy SIGURGs to the child process. */ 73740858Sbostic void 73840858Sbostic copytochild() 73940858Sbostic { 74040858Sbostic (void)kill(child, SIGURG); 7416444Swnj } 7426444Swnj 74340858Sbostic msg(str) 74440858Sbostic char *str; 7456444Swnj { 74640858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 74740858Sbostic } 74829729Smckusick 74940858Sbostic #ifdef KERBEROS 75040858Sbostic /* VARARGS */ 75140858Sbostic warning(va_alist) 75240858Sbostic va_dcl 75340858Sbostic { 75440858Sbostic va_list ap; 75540858Sbostic char *fmt; 75640858Sbostic 75740858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 75840858Sbostic va_start(ap); 75940858Sbostic fmt = va_arg(ap, char *); 76040858Sbostic vfprintf(stderr, fmt, ap); 76140858Sbostic va_end(ap); 76240858Sbostic (void)fprintf(stderr, ".\n"); 7636444Swnj } 76440858Sbostic #endif 76536512Skfall 76640858Sbostic usage() 76736512Skfall { 76840858Sbostic (void)fprintf(stderr, 76940858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 77040858Sbostic #ifdef KERBEROS 77140858Sbostic "8Lx", " [-k realm] "); 77240858Sbostic #else 77340858Sbostic "8L", " "); 77440858Sbostic #endif 77540858Sbostic exit(1); 77636512Skfall } 77740858Sbostic 77840858Sbostic /* 77940858Sbostic * The following routine provides compatibility (such as it is) between 4.2BSD 78040858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 78140858Sbostic */ 78240858Sbostic #ifdef sun 78340858Sbostic int 78440858Sbostic get_window_size(fd, wp) 78540858Sbostic int fd; 78640858Sbostic struct winsize *wp; 78740858Sbostic { 78840858Sbostic struct ttysize ts; 78940858Sbostic int error; 79040858Sbostic 79140858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 79240858Sbostic return(error); 79340858Sbostic wp->ws_row = ts.ts_lines; 79440858Sbostic wp->ws_col = ts.ts_cols; 79540858Sbostic wp->ws_xpixel = 0; 79640858Sbostic wp->ws_ypixel = 0; 79740858Sbostic return(0); 79840858Sbostic } 79940858Sbostic #endif 800