121595Sdist /* 235539Sbostic * Copyright (c) 1983 The Regents of the University of California. 335539Sbostic * All rights reserved. 435539Sbostic * 535539Sbostic * Redistribution and use in source and binary forms are permitted 635539Sbostic * provided that the above copyright notice and this paragraph are 735539Sbostic * duplicated in all such forms and that any documentation, 835539Sbostic * advertising materials, and other materials related to such 935539Sbostic * distribution and use acknowledge that the software was developed 1035539Sbostic * by the University of California, Berkeley. The name of the 1135539Sbostic * University may not be used to endorse or promote products derived 1235539Sbostic * from this software without specific prior written permission. 1335539Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435539Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535539Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621595Sdist */ 1721595Sdist 186444Swnj #ifndef lint 1921595Sdist char copyright[] = 2035539Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121595Sdist All rights reserved.\n"; 2235539Sbostic #endif /* not lint */ 236444Swnj 2421595Sdist #ifndef lint 25*36511Skfall static char sccsid[] = "@(#)rlogin.c 5.12 (Berkeley) 9/19/88"; 2635539Sbostic #endif /* not lint */ 2721595Sdist 2812990Ssam /* 2912990Ssam * rlogin - remote login 3012990Ssam */ 3126981Skarels #include <sys/param.h> 3225424Skarels #include <sys/errno.h> 3324727Smckusick #include <sys/file.h> 346444Swnj #include <sys/socket.h> 3529729Smckusick #include <sys/time.h> 3629729Smckusick #include <sys/resource.h> 3713620Ssam #include <sys/wait.h> 389365Ssam 399207Ssam #include <netinet/in.h> 409365Ssam 419365Ssam #include <stdio.h> 429365Ssam #include <sgtty.h> 436444Swnj #include <errno.h> 446444Swnj #include <pwd.h> 459365Ssam #include <signal.h> 4625424Skarels #include <setjmp.h> 479365Ssam #include <netdb.h> 486444Swnj 49*36511Skfall #ifdef KERBEROS 50*36511Skfall #include <kerberos/krb.h> 51*36511Skfall int encrypt = 0; 52*36511Skfall char krb_realm[REALM_SZ]; 53*36511Skfall CREDENTIALS cred; 54*36511Skfall Key_schedule schedule; 55*36511Skfall #endif /* KERBEROS */ 56*36511Skfall 5724726Smckusick # ifndef TIOCPKT_WINDOW 5824726Smckusick # define TIOCPKT_WINDOW 0x80 5924726Smckusick # endif TIOCPKT_WINDOW 6024726Smckusick 6129729Smckusick /* concession to sun */ 6229729Smckusick # ifndef SIGUSR1 6329729Smckusick # define SIGUSR1 30 6429729Smckusick # endif SIGUSR1 6529729Smckusick 6629729Smckusick char *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy(); 676444Swnj struct passwd *getpwuid(); 689365Ssam char *name; 696444Swnj int rem; 706444Swnj char cmdchar = '~'; 716444Swnj int eight; 7221583Sbloom int litout; 736444Swnj char *speeds[] = 746444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 756444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 7618358Ssam char term[256] = "network"; 779365Ssam extern int errno; 789365Ssam int lostpeer(); 7924726Smckusick int dosigwinch = 0; 8026981Skarels #ifndef sigmask 8126981Skarels #define sigmask(m) (1 << ((m)-1)) 8226981Skarels #endif 8326981Skarels #ifdef sun 8426981Skarels struct winsize { 8526981Skarels unsigned short ws_row, ws_col; 8626981Skarels unsigned short ws_xpixel, ws_ypixel; 8726981Skarels }; 8829729Smckusick #endif sun 8918358Ssam struct winsize winsize; 9024726Smckusick int sigwinch(), oob(); 916444Swnj 9229729Smckusick /* 9329729Smckusick * The following routine provides compatibility (such as it is) 9429729Smckusick * between 4.2BSD Suns and others. Suns have only a `ttysize', 9529729Smckusick * so we convert it to a winsize. 9629729Smckusick */ 9729729Smckusick #ifdef sun 9829729Smckusick int 9929729Smckusick get_window_size(fd, wp) 10029729Smckusick int fd; 10129729Smckusick struct winsize *wp; 10229729Smckusick { 10329729Smckusick struct ttysize ts; 10429729Smckusick int error; 10529729Smckusick 10629729Smckusick if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 10729729Smckusick return (error); 10829729Smckusick wp->ws_row = ts.ts_lines; 10929729Smckusick wp->ws_col = ts.ts_cols; 11029729Smckusick wp->ws_xpixel = 0; 11129729Smckusick wp->ws_ypixel = 0; 11229729Smckusick return (0); 11329729Smckusick } 11429729Smckusick #else sun 11529729Smckusick #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 11629729Smckusick #endif sun 11729729Smckusick 1186444Swnj main(argc, argv) 1196444Swnj int argc; 1206444Swnj char **argv; 1216444Swnj { 1229365Ssam char *host, *cp; 1236444Swnj struct sgttyb ttyb; 1246444Swnj struct passwd *pwd; 1259365Ssam struct servent *sp; 12624726Smckusick int uid, options = 0, oldmask; 12717449Slepreau int on = 1; 1286444Swnj 1296444Swnj host = rindex(argv[0], '/'); 1306444Swnj if (host) 1316444Swnj host++; 1326444Swnj else 1336444Swnj host = argv[0]; 1346444Swnj argv++, --argc; 1356444Swnj if (!strcmp(host, "rlogin")) 1366444Swnj host = *argv++, --argc; 1376444Swnj another: 13810839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 1396444Swnj argv++, argc--; 14010415Ssam options |= SO_DEBUG; 1416444Swnj goto another; 1426444Swnj } 14310839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 1446444Swnj argv++, argc--; 1456444Swnj if (argc == 0) 1466444Swnj goto usage; 1476444Swnj name = *argv++; argc--; 1486444Swnj goto another; 1496444Swnj } 15010839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 1516444Swnj cmdchar = argv[0][2]; 1526444Swnj argv++, argc--; 1536444Swnj goto another; 1546444Swnj } 15510839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 1566444Swnj eight = 1; 1576444Swnj argv++, argc--; 1586444Swnj goto another; 1596444Swnj } 16021583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 16121583Sbloom litout = 1; 16221583Sbloom argv++, argc--; 16321583Sbloom goto another; 16421583Sbloom } 165*36511Skfall 166*36511Skfall #ifdef KERBEROS 167*36511Skfall if (argc > 0 && !strcmp(*argv, "-x")) { 168*36511Skfall encrypt = 1; 169*36511Skfall des_set_key(cred.session, schedule); 170*36511Skfall argv++, argc--; 171*36511Skfall goto another; 172*36511Skfall } 173*36511Skfall #endif /* KERBEROS */ 174*36511Skfall 1756444Swnj if (host == 0) 1766444Swnj goto usage; 1776444Swnj if (argc > 0) 1786444Swnj goto usage; 1796444Swnj pwd = getpwuid(getuid()); 1806444Swnj if (pwd == 0) { 1816444Swnj fprintf(stderr, "Who are you?\n"); 1826444Swnj exit(1); 1836444Swnj } 1849365Ssam sp = getservbyname("login", "tcp"); 1859365Ssam if (sp == 0) { 1869365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1879365Ssam exit(2); 1889365Ssam } 1899241Ssam cp = getenv("TERM"); 1909241Ssam if (cp) 19129729Smckusick (void) strcpy(term, cp); 19218358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 19329729Smckusick (void) strcat(term, "/"); 19429729Smckusick (void) strcat(term, speeds[ttyb.sg_ospeed]); 1956444Swnj } 19629729Smckusick (void) get_window_size(0, &winsize); 19729729Smckusick (void) signal(SIGPIPE, lostpeer); 19829729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 19929729Smckusick oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 200*36511Skfall 201*36511Skfall #ifdef KERBEROS 202*36511Skfall rem = KSUCCESS; 203*36511Skfall if(krb_realm[0] == '\0') { 204*36511Skfall rem = get_krbrlm(krb_realm, 1); 205*36511Skfall } 206*36511Skfall if(rem == KSUCCESS) { 207*36511Skfall if(encrypt) { 208*36511Skfall rem = krcmd_mutual( 209*36511Skfall &host, sp->s_port, 210*36511Skfall name ? name : pwd->pw_name, term, 211*36511Skfall 0, krb_realm, 212*36511Skfall &cred, schedule 213*36511Skfall ); 214*36511Skfall } else { 215*36511Skfall rem = krcmd( 216*36511Skfall &host, sp->s_port, 217*36511Skfall name ? name : pwd->pw_name, term, 218*36511Skfall 0, krb_realm 219*36511Skfall ); 220*36511Skfall } 221*36511Skfall } else { 222*36511Skfall fprintf( 223*36511Skfall stderr, 224*36511Skfall "rlogin: Kerberos error getting local realm %s\n", 225*36511Skfall krb_err_txt[rem] 226*36511Skfall ); 227*36511Skfall exit(1); 228*36511Skfall } 229*36511Skfall 230*36511Skfall #else /* !KERBEROS */ 231*36511Skfall 2329365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 2336444Swnj name ? name : pwd->pw_name, term, 0); 234*36511Skfall 235*36511Skfall #endif /* KERBEROS */ 236*36511Skfall 237*36511Skfall if(rem < 0) 238*36511Skfall exit(1); 239*36511Skfall 24010415Ssam if (options & SO_DEBUG && 24117449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 24210415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 2439365Ssam uid = getuid(); 2449365Ssam if (setuid(uid) < 0) { 2459365Ssam perror("rlogin: setuid"); 2469365Ssam exit(1); 2479365Ssam } 24824726Smckusick doit(oldmask); 2499365Ssam /*NOTREACHED*/ 2506444Swnj usage: 2516444Swnj fprintf(stderr, 252*36511Skfall #ifdef KERBEROS 253*36511Skfall "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -x ]\n"); 254*36511Skfall #else 25525341Smckusick "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); 256*36511Skfall #endif 2576444Swnj exit(1); 2586444Swnj } 2596444Swnj 2606444Swnj #define CRLF "\r\n" 2616444Swnj 2629365Ssam int child; 26311803Sedward int catchild(); 26429729Smckusick int copytochild(), writeroob(); 2659365Ssam 26613075Ssam int defflags, tabflag; 26721583Sbloom int deflflags; 26813075Ssam char deferase, defkill; 26913075Ssam struct tchars deftc; 27013075Ssam struct ltchars defltc; 27113075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 27213075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 2736444Swnj 27424726Smckusick doit(oldmask) 2756444Swnj { 2766444Swnj int exit(); 27713075Ssam struct sgttyb sb; 2786444Swnj 27929729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 28013075Ssam defflags = sb.sg_flags; 28112155Ssam tabflag = defflags & TBDELAY; 2829962Ssam defflags &= ECHO | CRMOD; 28313075Ssam deferase = sb.sg_erase; 28413075Ssam defkill = sb.sg_kill; 28529729Smckusick (void) ioctl(0, TIOCLGET, (char *)&deflflags); 28629729Smckusick (void) ioctl(0, TIOCGETC, (char *)&deftc); 28713075Ssam notc.t_startc = deftc.t_startc; 28813075Ssam notc.t_stopc = deftc.t_stopc; 28929729Smckusick (void) ioctl(0, TIOCGLTC, (char *)&defltc); 29029729Smckusick (void) signal(SIGINT, SIG_IGN); 29129729Smckusick setsignal(SIGHUP, exit); 29229729Smckusick setsignal(SIGQUIT, exit); 2939365Ssam child = fork(); 2949365Ssam if (child == -1) { 2959365Ssam perror("rlogin: fork"); 29625424Skarels done(1); 2979365Ssam } 2989365Ssam if (child == 0) { 29924726Smckusick mode(1); 30029729Smckusick if (reader(oldmask) == 0) { 30125424Skarels prf("Connection closed."); 30225424Skarels exit(0); 30325424Skarels } 30412155Ssam sleep(1); 30512155Ssam prf("\007Connection closed."); 3066444Swnj exit(3); 3076444Swnj } 30829729Smckusick 30929729Smckusick /* 31029729Smckusick * We may still own the socket, and may have a pending SIGURG 31129729Smckusick * (or might receive one soon) that we really want to send to 31229729Smckusick * the reader. Set a trap that simply copies such signals to 31329729Smckusick * the child. 31429729Smckusick */ 31529729Smckusick (void) signal(SIGURG, copytochild); 31629729Smckusick (void) signal(SIGUSR1, writeroob); 31729729Smckusick (void) sigsetmask(oldmask); 31829729Smckusick (void) signal(SIGCHLD, catchild); 3199365Ssam writer(); 32012155Ssam prf("Closed connection."); 32125424Skarels done(0); 3226444Swnj } 3236444Swnj 32429729Smckusick /* 32529729Smckusick * Trap a signal, unless it is being ignored. 32629729Smckusick */ 32729729Smckusick setsignal(sig, act) 32829729Smckusick int sig, (*act)(); 32929729Smckusick { 33029729Smckusick int omask = sigblock(sigmask(sig)); 33129729Smckusick 33229729Smckusick if (signal(sig, act) == SIG_IGN) 33329729Smckusick (void) signal(sig, SIG_IGN); 33429729Smckusick (void) sigsetmask(omask); 33529729Smckusick } 33629729Smckusick 33725424Skarels done(status) 33825424Skarels int status; 3396444Swnj { 34029729Smckusick int w; 3416444Swnj 3426444Swnj mode(0); 34329729Smckusick if (child > 0) { 34429729Smckusick /* make sure catchild does not snap it up */ 34529729Smckusick (void) signal(SIGCHLD, SIG_DFL); 34629729Smckusick if (kill(child, SIGKILL) >= 0) 34729729Smckusick while ((w = wait((union wait *)0)) > 0 && w != child) 34829729Smckusick /*void*/; 34929729Smckusick } 35025424Skarels exit(status); 3516444Swnj } 3526444Swnj 35324726Smckusick /* 35429729Smckusick * Copy SIGURGs to the child process. 35529729Smckusick */ 35629729Smckusick copytochild() 35729729Smckusick { 35829729Smckusick 35929729Smckusick (void) kill(child, SIGURG); 36029729Smckusick } 36129729Smckusick 36229729Smckusick /* 36324726Smckusick * This is called when the reader process gets the out-of-band (urgent) 36424726Smckusick * request to turn on the window-changing protocol. 36524726Smckusick */ 36624726Smckusick writeroob() 36724726Smckusick { 36824726Smckusick 36925341Smckusick if (dosigwinch == 0) { 37024919Smckusick sendwindow(); 37129729Smckusick (void) signal(SIGWINCH, sigwinch); 37225341Smckusick } 37324726Smckusick dosigwinch = 1; 37424726Smckusick } 37524726Smckusick 37611803Sedward catchild() 37711803Sedward { 37811803Sedward union wait status; 37911803Sedward int pid; 38011803Sedward 38111803Sedward again: 38229729Smckusick pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); 38311803Sedward if (pid == 0) 38411803Sedward return; 38511803Sedward /* 38611803Sedward * if the child (reader) dies, just quit 38711803Sedward */ 38811803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 38929729Smckusick done((int)(status.w_termsig | status.w_retcode)); 39011803Sedward goto again; 39111803Sedward } 39211803Sedward 3936444Swnj /* 3949365Ssam * writer: write to remote: 0 -> line. 3959365Ssam * ~. terminate 3969365Ssam * ~^Z suspend rlogin process. 39710415Ssam * ~^Y suspend rlogin process, but leave reader alone. 3986444Swnj */ 3999365Ssam writer() 4006444Swnj { 40123530Sbloom char c; 40211803Sedward register n; 40323530Sbloom register bol = 1; /* beginning of line */ 40423530Sbloom register local = 0; 4056444Swnj 40611803Sedward for (;;) { 40711803Sedward n = read(0, &c, 1); 40818358Ssam if (n <= 0) { 40918358Ssam if (n < 0 && errno == EINTR) 41018358Ssam continue; 41111803Sedward break; 41218358Ssam } 4139365Ssam /* 4149365Ssam * If we're at the beginning of the line 4159365Ssam * and recognize a command character, then 4169365Ssam * we echo locally. Otherwise, characters 4179365Ssam * are echo'd remotely. If the command 4189365Ssam * character is doubled, this acts as a 4199365Ssam * force and local echo is suppressed. 4209365Ssam */ 42123530Sbloom if (bol) { 42223530Sbloom bol = 0; 42323530Sbloom if (c == cmdchar) { 42423530Sbloom bol = 0; 42523530Sbloom local = 1; 42623530Sbloom continue; 4276444Swnj } 42823530Sbloom } else if (local) { 42923530Sbloom local = 0; 43023530Sbloom if (c == '.' || c == deftc.t_eofc) { 43123530Sbloom echo(c); 43223530Sbloom break; 4336444Swnj } 43423530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 43523530Sbloom bol = 1; 43623530Sbloom echo(c); 43723530Sbloom stop(c); 43823530Sbloom continue; 43923530Sbloom } 440*36511Skfall if (c != cmdchar) { 441*36511Skfall #ifdef KERBEROS 442*36511Skfall if(encrypt) { 443*36511Skfall (void) des_write( 444*36511Skfall rem, 445*36511Skfall &cmdchar, 446*36511Skfall 1 447*36511Skfall ); 448*36511Skfall } else 449*36511Skfall #endif 450*36511Skfall (void) write( 451*36511Skfall rem, 452*36511Skfall &cmdchar, 453*36511Skfall 1 454*36511Skfall ); 455*36511Skfall } 4566444Swnj } 457*36511Skfall 458*36511Skfall #ifdef KERBEROS 459*36511Skfall if(encrypt) { 460*36511Skfall if (des_write(rem, &c, 1) == 0) { 461*36511Skfall prf("line gone"); 462*36511Skfall break; 463*36511Skfall } 464*36511Skfall } else 465*36511Skfall #endif 466*36511Skfall if (write(rem, &c, 1) == 0) { 467*36511Skfall prf("line gone"); 468*36511Skfall break; 469*36511Skfall } 47023530Sbloom bol = c == defkill || c == deftc.t_eofc || 47125424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 47223530Sbloom c == '\r' || c == '\n'; 4736444Swnj } 4746444Swnj } 4756444Swnj 47623530Sbloom echo(c) 47723530Sbloom register char c; 47823530Sbloom { 47923530Sbloom char buf[8]; 48023530Sbloom register char *p = buf; 48123530Sbloom 48223530Sbloom c &= 0177; 48323530Sbloom *p++ = cmdchar; 48423530Sbloom if (c < ' ') { 48523530Sbloom *p++ = '^'; 48623530Sbloom *p++ = c + '@'; 48723530Sbloom } else if (c == 0177) { 48823530Sbloom *p++ = '^'; 48923530Sbloom *p++ = '?'; 49023530Sbloom } else 49123530Sbloom *p++ = c; 49223530Sbloom *p++ = '\r'; 49323530Sbloom *p++ = '\n'; 49429729Smckusick (void) write(1, buf, p - buf); 49523530Sbloom } 49623530Sbloom 49718358Ssam stop(cmdc) 49818358Ssam char cmdc; 49918358Ssam { 50018358Ssam mode(0); 50129729Smckusick (void) signal(SIGCHLD, SIG_IGN); 50229729Smckusick (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 50329729Smckusick (void) signal(SIGCHLD, catchild); 50418358Ssam mode(1); 50518358Ssam sigwinch(); /* check for size changes */ 50618358Ssam } 50718358Ssam 50818358Ssam sigwinch() 50918358Ssam { 51018358Ssam struct winsize ws; 51118358Ssam 51229729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 51318358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 51418358Ssam winsize = ws; 51524726Smckusick sendwindow(); 51618358Ssam } 51718358Ssam } 51818358Ssam 51924726Smckusick /* 52024726Smckusick * Send the window size to the server via the magic escape 52124726Smckusick */ 52224726Smckusick sendwindow() 52324726Smckusick { 52424726Smckusick char obuf[4 + sizeof (struct winsize)]; 52524726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 52624726Smckusick 52724726Smckusick obuf[0] = 0377; 52824726Smckusick obuf[1] = 0377; 52924726Smckusick obuf[2] = 's'; 53024726Smckusick obuf[3] = 's'; 53124726Smckusick wp->ws_row = htons(winsize.ws_row); 53224726Smckusick wp->ws_col = htons(winsize.ws_col); 53324726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 53424726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 535*36511Skfall 536*36511Skfall #ifdef KERBEROS 537*36511Skfall if(encrypt) 538*36511Skfall (void) des_write(rem, obuf, sizeof(obuf)); 539*36511Skfall else 540*36511Skfall #endif 541*36511Skfall (void) write(rem, obuf, sizeof(obuf)); 54224726Smckusick } 54324726Smckusick 54425424Skarels /* 54525424Skarels * reader: read from remote: line -> 1 54625424Skarels */ 54725424Skarels #define READING 1 54825424Skarels #define WRITING 2 54925424Skarels 55025424Skarels char rcvbuf[8 * 1024]; 55125424Skarels int rcvcnt; 55225424Skarels int rcvstate; 55326981Skarels int ppid; 55425424Skarels jmp_buf rcvtop; 55525424Skarels 5566444Swnj oob() 5576444Swnj { 55825424Skarels int out = FWRITE, atmark, n; 55925424Skarels int rcvd = 0; 5609365Ssam char waste[BUFSIZ], mark; 56124726Smckusick struct sgttyb sb; 5626444Swnj 56325424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 56425424Skarels switch (errno) { 56525424Skarels 56625424Skarels case EWOULDBLOCK: 56725424Skarels /* 56825424Skarels * Urgent data not here yet. 56925424Skarels * It may not be possible to send it yet 57025424Skarels * if we are blocked for output 57125424Skarels * and our input buffer is full. 57225424Skarels */ 57325424Skarels if (rcvcnt < sizeof(rcvbuf)) { 57425424Skarels n = read(rem, rcvbuf + rcvcnt, 57525424Skarels sizeof(rcvbuf) - rcvcnt); 57625424Skarels if (n <= 0) 57725424Skarels return; 57825424Skarels rcvd += n; 57925424Skarels } else { 58025424Skarels n = read(rem, waste, sizeof(waste)); 58125424Skarels if (n <= 0) 58225424Skarels return; 58325424Skarels } 58425424Skarels continue; 58525424Skarels 58625424Skarels default: 58725424Skarels return; 5886444Swnj } 58925424Skarels if (mark & TIOCPKT_WINDOW) { 59024726Smckusick /* 59124726Smckusick * Let server know about window size changes 59224726Smckusick */ 59329729Smckusick (void) kill(ppid, SIGUSR1); 59424726Smckusick } 59525424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 59629729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 59724726Smckusick sb.sg_flags &= ~CBREAK; 59824726Smckusick sb.sg_flags |= RAW; 59929729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 60013075Ssam notc.t_stopc = -1; 60113075Ssam notc.t_startc = -1; 60229729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6036444Swnj } 60425424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 60529729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 60624726Smckusick sb.sg_flags &= ~RAW; 60724726Smckusick sb.sg_flags |= CBREAK; 60829729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 60913075Ssam notc.t_stopc = deftc.t_stopc; 61013075Ssam notc.t_startc = deftc.t_startc; 61129729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6126444Swnj } 61325424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 61429729Smckusick (void) ioctl(1, TIOCFLUSH, (char *)&out); 61525424Skarels for (;;) { 61625424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 61725424Skarels perror("ioctl"); 61825424Skarels break; 61925424Skarels } 62025424Skarels if (atmark) 62125424Skarels break; 62225424Skarels n = read(rem, waste, sizeof (waste)); 62325424Skarels if (n <= 0) 62425424Skarels break; 62525424Skarels } 62625424Skarels /* 62725424Skarels * Don't want any pending data to be output, 62825424Skarels * so clear the recv buffer. 62925424Skarels * If we were hanging on a write when interrupted, 63025424Skarels * don't want it to restart. If we were reading, 63125424Skarels * restart anyway. 63225424Skarels */ 63325424Skarels rcvcnt = 0; 63425424Skarels longjmp(rcvtop, 1); 63525424Skarels } 63629729Smckusick 63725424Skarels /* 63829729Smckusick * oob does not do FLUSHREAD (alas!) 63929729Smckusick */ 64029729Smckusick 64129729Smckusick /* 64225424Skarels * If we filled the receive buffer while a read was pending, 64325424Skarels * longjmp to the top to restart appropriately. Don't abort 64425424Skarels * a pending write, however, or we won't know how much was written. 64525424Skarels */ 64625424Skarels if (rcvd && rcvstate == READING) 64725424Skarels longjmp(rcvtop, 1); 6486444Swnj } 6496444Swnj 6509365Ssam /* 6519365Ssam * reader: read from remote: line -> 1 6529365Ssam */ 65329729Smckusick reader(oldmask) 65429729Smckusick int oldmask; 6556444Swnj { 65626981Skarels #if !defined(BSD) || BSD < 43 65726981Skarels int pid = -getpid(); 65826981Skarels #else 65925424Skarels int pid = getpid(); 66026981Skarels #endif 66125424Skarels int n, remaining; 66225424Skarels char *bufp = rcvbuf; 6636444Swnj 66429729Smckusick (void) signal(SIGTTOU, SIG_IGN); 66529729Smckusick (void) signal(SIGURG, oob); 66626981Skarels ppid = getppid(); 66729729Smckusick (void) fcntl(rem, F_SETOWN, pid); 66825424Skarels (void) setjmp(rcvtop); 66929729Smckusick (void) sigsetmask(oldmask); 6706444Swnj for (;;) { 67125424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 67225424Skarels rcvstate = WRITING; 67325424Skarels n = write(1, bufp, remaining); 67425424Skarels if (n < 0) { 67525424Skarels if (errno != EINTR) 67626189Slepreau return (-1); 67725424Skarels continue; 67825424Skarels } 67925424Skarels bufp += n; 68025424Skarels } 68125424Skarels bufp = rcvbuf; 68225424Skarels rcvcnt = 0; 68325424Skarels rcvstate = READING; 684*36511Skfall 685*36511Skfall #ifdef KERBEROS 686*36511Skfall if(encrypt) 687*36511Skfall rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 688*36511Skfall else 689*36511Skfall #endif 690*36511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 69125424Skarels if (rcvcnt == 0) 69225424Skarels return (0); 69325424Skarels if (rcvcnt < 0) { 6949365Ssam if (errno == EINTR) 6956444Swnj continue; 69626981Skarels perror("read"); 69725424Skarels return (-1); 6986444Swnj } 6996444Swnj } 7006444Swnj } 7016444Swnj 7026444Swnj mode(f) 7036444Swnj { 70413075Ssam struct tchars *tc; 70513075Ssam struct ltchars *ltc; 70613075Ssam struct sgttyb sb; 70721583Sbloom int lflags; 7089365Ssam 70929729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 71029729Smckusick (void) ioctl(0, TIOCLGET, (char *)&lflags); 7119962Ssam switch (f) { 7129962Ssam 7139962Ssam case 0: 71413075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 71513075Ssam sb.sg_flags |= defflags|tabflag; 7169962Ssam tc = &deftc; 71713075Ssam ltc = &defltc; 71813075Ssam sb.sg_kill = defkill; 71913075Ssam sb.sg_erase = deferase; 72021583Sbloom lflags = deflflags; 7219962Ssam break; 7229962Ssam 7239962Ssam case 1: 72413075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 72513075Ssam sb.sg_flags &= ~defflags; 72612155Ssam /* preserve tab delays, but turn off XTABS */ 72713075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 72813075Ssam sb.sg_flags &= ~TBDELAY; 7299962Ssam tc = ¬c; 73013075Ssam ltc = &noltc; 73113075Ssam sb.sg_kill = sb.sg_erase = -1; 73221583Sbloom if (litout) 73321583Sbloom lflags |= LLITOUT; 7349962Ssam break; 7359962Ssam 7369962Ssam default: 7379962Ssam return; 7386444Swnj } 73929729Smckusick (void) ioctl(0, TIOCSLTC, (char *)ltc); 74029729Smckusick (void) ioctl(0, TIOCSETC, (char *)tc); 74129729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 74229729Smckusick (void) ioctl(0, TIOCLSET, (char *)&lflags); 7436444Swnj } 7446444Swnj 7459365Ssam /*VARARGS*/ 74624726Smckusick prf(f, a1, a2, a3, a4, a5) 7479365Ssam char *f; 7486444Swnj { 74929729Smckusick 75024726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 7516444Swnj fprintf(stderr, CRLF); 7526444Swnj } 7536444Swnj 7549365Ssam lostpeer() 7556444Swnj { 75629729Smckusick 75729729Smckusick (void) signal(SIGPIPE, SIG_IGN); 75812155Ssam prf("\007Connection closed."); 75925424Skarels done(1); 7606444Swnj } 761