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 2536511Skfall 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 4936511Skfall #ifdef KERBEROS 5036511Skfall #include <kerberos/krb.h> 5136511Skfall int encrypt = 0; 5236511Skfall char krb_realm[REALM_SZ]; 5336511Skfall CREDENTIALS cred; 5436511Skfall Key_schedule schedule; 55*36512Skfall int use_kerberos = 1; 5636511Skfall #endif /* KERBEROS */ 5736511Skfall 5824726Smckusick # ifndef TIOCPKT_WINDOW 5924726Smckusick # define TIOCPKT_WINDOW 0x80 6024726Smckusick # endif TIOCPKT_WINDOW 6124726Smckusick 6229729Smckusick /* concession to sun */ 6329729Smckusick # ifndef SIGUSR1 6429729Smckusick # define SIGUSR1 30 6529729Smckusick # endif SIGUSR1 6629729Smckusick 6729729Smckusick char *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy(); 686444Swnj struct passwd *getpwuid(); 699365Ssam char *name; 706444Swnj int rem; 716444Swnj char cmdchar = '~'; 726444Swnj int eight; 7321583Sbloom int litout; 746444Swnj char *speeds[] = 756444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 766444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 7718358Ssam char term[256] = "network"; 789365Ssam extern int errno; 799365Ssam int lostpeer(); 8024726Smckusick int dosigwinch = 0; 8126981Skarels #ifndef sigmask 8226981Skarels #define sigmask(m) (1 << ((m)-1)) 8326981Skarels #endif 8426981Skarels #ifdef sun 8526981Skarels struct winsize { 8626981Skarels unsigned short ws_row, ws_col; 8726981Skarels unsigned short ws_xpixel, ws_ypixel; 8826981Skarels }; 8929729Smckusick #endif sun 9018358Ssam struct winsize winsize; 9124726Smckusick int sigwinch(), oob(); 926444Swnj 9329729Smckusick /* 9429729Smckusick * The following routine provides compatibility (such as it is) 9529729Smckusick * between 4.2BSD Suns and others. Suns have only a `ttysize', 9629729Smckusick * so we convert it to a winsize. 9729729Smckusick */ 9829729Smckusick #ifdef sun 9929729Smckusick int 10029729Smckusick get_window_size(fd, wp) 10129729Smckusick int fd; 10229729Smckusick struct winsize *wp; 10329729Smckusick { 10429729Smckusick struct ttysize ts; 10529729Smckusick int error; 10629729Smckusick 10729729Smckusick if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 10829729Smckusick return (error); 10929729Smckusick wp->ws_row = ts.ts_lines; 11029729Smckusick wp->ws_col = ts.ts_cols; 11129729Smckusick wp->ws_xpixel = 0; 11229729Smckusick wp->ws_ypixel = 0; 11329729Smckusick return (0); 11429729Smckusick } 11529729Smckusick #else sun 11629729Smckusick #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 11729729Smckusick #endif sun 11829729Smckusick 1196444Swnj main(argc, argv) 1206444Swnj int argc; 1216444Swnj char **argv; 1226444Swnj { 1239365Ssam char *host, *cp; 1246444Swnj struct sgttyb ttyb; 1256444Swnj struct passwd *pwd; 1269365Ssam struct servent *sp; 12724726Smckusick int uid, options = 0, oldmask; 12817449Slepreau int on = 1; 1296444Swnj 1306444Swnj host = rindex(argv[0], '/'); 1316444Swnj if (host) 1326444Swnj host++; 1336444Swnj else 1346444Swnj host = argv[0]; 1356444Swnj argv++, --argc; 1366444Swnj if (!strcmp(host, "rlogin")) 1376444Swnj host = *argv++, --argc; 1386444Swnj another: 13910839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 1406444Swnj argv++, argc--; 14110415Ssam options |= SO_DEBUG; 1426444Swnj goto another; 1436444Swnj } 14410839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 1456444Swnj argv++, argc--; 1466444Swnj if (argc == 0) 1476444Swnj goto usage; 1486444Swnj name = *argv++; argc--; 1496444Swnj goto another; 1506444Swnj } 15110839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 1526444Swnj cmdchar = argv[0][2]; 1536444Swnj argv++, argc--; 1546444Swnj goto another; 1556444Swnj } 15610839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 1576444Swnj eight = 1; 1586444Swnj argv++, argc--; 1596444Swnj goto another; 1606444Swnj } 16121583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 16221583Sbloom litout = 1; 16321583Sbloom argv++, argc--; 16421583Sbloom goto another; 16521583Sbloom } 16636511Skfall 16736511Skfall #ifdef KERBEROS 16836511Skfall if (argc > 0 && !strcmp(*argv, "-x")) { 16936511Skfall encrypt = 1; 17036511Skfall des_set_key(cred.session, schedule); 17136511Skfall argv++, argc--; 17236511Skfall goto another; 17336511Skfall } 17436511Skfall #endif /* KERBEROS */ 17536511Skfall 1766444Swnj if (host == 0) 1776444Swnj goto usage; 1786444Swnj if (argc > 0) 1796444Swnj goto usage; 1806444Swnj pwd = getpwuid(getuid()); 1816444Swnj if (pwd == 0) { 1826444Swnj fprintf(stderr, "Who are you?\n"); 1836444Swnj exit(1); 1846444Swnj } 185*36512Skfall #ifdef KERBEROS 186*36512Skfall sp = getservbyname("klogin", "tcp"); 187*36512Skfall if(sp == NULL) { 188*36512Skfall use_kerberos = 0; 189*36512Skfall old_warning("klogin service unknown"); 190*36512Skfall sp = getservbyname("login", "tcp"); 191*36512Skfall } 192*36512Skfall #else 1939365Ssam sp = getservbyname("login", "tcp"); 194*36512Skfall #endif 1959365Ssam if (sp == 0) { 1969365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1979365Ssam exit(2); 1989365Ssam } 1999241Ssam cp = getenv("TERM"); 2009241Ssam if (cp) 20129729Smckusick (void) strcpy(term, cp); 20218358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 20329729Smckusick (void) strcat(term, "/"); 20429729Smckusick (void) strcat(term, speeds[ttyb.sg_ospeed]); 2056444Swnj } 20629729Smckusick (void) get_window_size(0, &winsize); 20729729Smckusick (void) signal(SIGPIPE, lostpeer); 20829729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 20929729Smckusick oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 21036511Skfall 21136511Skfall #ifdef KERBEROS 212*36512Skfall try_connect: 213*36512Skfall if(use_kerberos) { 214*36512Skfall rem = KSUCCESS; 215*36512Skfall if(krb_realm[0] == '\0') { 216*36512Skfall rem = get_krbrlm(krb_realm, 1); 217*36512Skfall } 218*36512Skfall if(rem == KSUCCESS) { 219*36512Skfall if(encrypt) { 220*36512Skfall rem = krcmd_mutual( 221*36512Skfall &host, sp->s_port, 222*36512Skfall name ? name : pwd->pw_name, term, 223*36512Skfall 0, krb_realm, 224*36512Skfall &cred, schedule 225*36512Skfall ); 226*36512Skfall } else { 227*36512Skfall rem = krcmd( 228*36512Skfall &host, sp->s_port, 229*36512Skfall name ? name : pwd->pw_name, term, 230*36512Skfall 0, krb_realm 231*36512Skfall ); 232*36512Skfall } 23336511Skfall } else { 234*36512Skfall fprintf( 235*36512Skfall stderr, 236*36512Skfall "rlogin: Kerberos error getting local realm %s\n", 237*36512Skfall krb_err_txt[rem] 23836511Skfall ); 239*36512Skfall exit(1); 24036511Skfall } 241*36512Skfall if((rem < 0) && errno == ECONNREFUSED) { 242*36512Skfall use_kerberos = 0; 243*36512Skfall old_warning("remote host doesn't support Kerberos"); 244*36512Skfall goto try_connect; 245*36512Skfall } 24636511Skfall } else { 247*36512Skfall if(encrypt) { 248*36512Skfall fprintf(stderr, "The -x flag requires Kerberos authencation\n"); 249*36512Skfall exit(1); 250*36512Skfall } 251*36512Skfall rem = rcmd(&host, sp->s_port, pwd->pw_name, 252*36512Skfall name ? name : pwd->pw_name, term, 0); 25336511Skfall } 254*36512Skfall #else 255*36512Skfall rem = rcmd(&host, sp->s_port, pwd->pw_name, 256*36512Skfall name ? name : pwd->pw_name, term, 0); 257*36512Skfall #endif 25836511Skfall 25936511Skfall if(rem < 0) 26036511Skfall exit(1); 26136511Skfall 26210415Ssam if (options & SO_DEBUG && 26317449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 26410415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 2659365Ssam uid = getuid(); 2669365Ssam if (setuid(uid) < 0) { 2679365Ssam perror("rlogin: setuid"); 2689365Ssam exit(1); 2699365Ssam } 27024726Smckusick doit(oldmask); 2719365Ssam /*NOTREACHED*/ 2726444Swnj usage: 2736444Swnj fprintf(stderr, 27436511Skfall #ifdef KERBEROS 27536511Skfall "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -x ]\n"); 27636511Skfall #else 27725341Smckusick "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); 27836511Skfall #endif 2796444Swnj exit(1); 2806444Swnj } 2816444Swnj 2826444Swnj #define CRLF "\r\n" 2836444Swnj 2849365Ssam int child; 28511803Sedward int catchild(); 28629729Smckusick int copytochild(), writeroob(); 2879365Ssam 28813075Ssam int defflags, tabflag; 28921583Sbloom int deflflags; 29013075Ssam char deferase, defkill; 29113075Ssam struct tchars deftc; 29213075Ssam struct ltchars defltc; 29313075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 29413075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 2956444Swnj 29624726Smckusick doit(oldmask) 2976444Swnj { 2986444Swnj int exit(); 29913075Ssam struct sgttyb sb; 3006444Swnj 30129729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 30213075Ssam defflags = sb.sg_flags; 30312155Ssam tabflag = defflags & TBDELAY; 3049962Ssam defflags &= ECHO | CRMOD; 30513075Ssam deferase = sb.sg_erase; 30613075Ssam defkill = sb.sg_kill; 30729729Smckusick (void) ioctl(0, TIOCLGET, (char *)&deflflags); 30829729Smckusick (void) ioctl(0, TIOCGETC, (char *)&deftc); 30913075Ssam notc.t_startc = deftc.t_startc; 31013075Ssam notc.t_stopc = deftc.t_stopc; 31129729Smckusick (void) ioctl(0, TIOCGLTC, (char *)&defltc); 31229729Smckusick (void) signal(SIGINT, SIG_IGN); 31329729Smckusick setsignal(SIGHUP, exit); 31429729Smckusick setsignal(SIGQUIT, exit); 3159365Ssam child = fork(); 3169365Ssam if (child == -1) { 3179365Ssam perror("rlogin: fork"); 31825424Skarels done(1); 3199365Ssam } 3209365Ssam if (child == 0) { 32124726Smckusick mode(1); 32229729Smckusick if (reader(oldmask) == 0) { 32325424Skarels prf("Connection closed."); 32425424Skarels exit(0); 32525424Skarels } 32612155Ssam sleep(1); 32712155Ssam prf("\007Connection closed."); 3286444Swnj exit(3); 3296444Swnj } 33029729Smckusick 33129729Smckusick /* 33229729Smckusick * We may still own the socket, and may have a pending SIGURG 33329729Smckusick * (or might receive one soon) that we really want to send to 33429729Smckusick * the reader. Set a trap that simply copies such signals to 33529729Smckusick * the child. 33629729Smckusick */ 33729729Smckusick (void) signal(SIGURG, copytochild); 33829729Smckusick (void) signal(SIGUSR1, writeroob); 33929729Smckusick (void) sigsetmask(oldmask); 34029729Smckusick (void) signal(SIGCHLD, catchild); 3419365Ssam writer(); 34212155Ssam prf("Closed connection."); 34325424Skarels done(0); 3446444Swnj } 3456444Swnj 34629729Smckusick /* 34729729Smckusick * Trap a signal, unless it is being ignored. 34829729Smckusick */ 34929729Smckusick setsignal(sig, act) 35029729Smckusick int sig, (*act)(); 35129729Smckusick { 35229729Smckusick int omask = sigblock(sigmask(sig)); 35329729Smckusick 35429729Smckusick if (signal(sig, act) == SIG_IGN) 35529729Smckusick (void) signal(sig, SIG_IGN); 35629729Smckusick (void) sigsetmask(omask); 35729729Smckusick } 35829729Smckusick 35925424Skarels done(status) 36025424Skarels int status; 3616444Swnj { 36229729Smckusick int w; 3636444Swnj 3646444Swnj mode(0); 36529729Smckusick if (child > 0) { 36629729Smckusick /* make sure catchild does not snap it up */ 36729729Smckusick (void) signal(SIGCHLD, SIG_DFL); 36829729Smckusick if (kill(child, SIGKILL) >= 0) 36929729Smckusick while ((w = wait((union wait *)0)) > 0 && w != child) 37029729Smckusick /*void*/; 37129729Smckusick } 37225424Skarels exit(status); 3736444Swnj } 3746444Swnj 37524726Smckusick /* 37629729Smckusick * Copy SIGURGs to the child process. 37729729Smckusick */ 37829729Smckusick copytochild() 37929729Smckusick { 38029729Smckusick 38129729Smckusick (void) kill(child, SIGURG); 38229729Smckusick } 38329729Smckusick 38429729Smckusick /* 38524726Smckusick * This is called when the reader process gets the out-of-band (urgent) 38624726Smckusick * request to turn on the window-changing protocol. 38724726Smckusick */ 38824726Smckusick writeroob() 38924726Smckusick { 39024726Smckusick 39125341Smckusick if (dosigwinch == 0) { 39224919Smckusick sendwindow(); 39329729Smckusick (void) signal(SIGWINCH, sigwinch); 39425341Smckusick } 39524726Smckusick dosigwinch = 1; 39624726Smckusick } 39724726Smckusick 39811803Sedward catchild() 39911803Sedward { 40011803Sedward union wait status; 40111803Sedward int pid; 40211803Sedward 40311803Sedward again: 40429729Smckusick pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); 40511803Sedward if (pid == 0) 40611803Sedward return; 40711803Sedward /* 40811803Sedward * if the child (reader) dies, just quit 40911803Sedward */ 41011803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 41129729Smckusick done((int)(status.w_termsig | status.w_retcode)); 41211803Sedward goto again; 41311803Sedward } 41411803Sedward 4156444Swnj /* 4169365Ssam * writer: write to remote: 0 -> line. 4179365Ssam * ~. terminate 4189365Ssam * ~^Z suspend rlogin process. 41910415Ssam * ~^Y suspend rlogin process, but leave reader alone. 4206444Swnj */ 4219365Ssam writer() 4226444Swnj { 42323530Sbloom char c; 42411803Sedward register n; 42523530Sbloom register bol = 1; /* beginning of line */ 42623530Sbloom register local = 0; 4276444Swnj 42811803Sedward for (;;) { 42911803Sedward n = read(0, &c, 1); 43018358Ssam if (n <= 0) { 43118358Ssam if (n < 0 && errno == EINTR) 43218358Ssam continue; 43311803Sedward break; 43418358Ssam } 4359365Ssam /* 4369365Ssam * If we're at the beginning of the line 4379365Ssam * and recognize a command character, then 4389365Ssam * we echo locally. Otherwise, characters 4399365Ssam * are echo'd remotely. If the command 4409365Ssam * character is doubled, this acts as a 4419365Ssam * force and local echo is suppressed. 4429365Ssam */ 44323530Sbloom if (bol) { 44423530Sbloom bol = 0; 44523530Sbloom if (c == cmdchar) { 44623530Sbloom bol = 0; 44723530Sbloom local = 1; 44823530Sbloom continue; 4496444Swnj } 45023530Sbloom } else if (local) { 45123530Sbloom local = 0; 45223530Sbloom if (c == '.' || c == deftc.t_eofc) { 45323530Sbloom echo(c); 45423530Sbloom break; 4556444Swnj } 45623530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 45723530Sbloom bol = 1; 45823530Sbloom echo(c); 45923530Sbloom stop(c); 46023530Sbloom continue; 46123530Sbloom } 46236511Skfall if (c != cmdchar) { 46336511Skfall #ifdef KERBEROS 46436511Skfall if(encrypt) { 46536511Skfall (void) des_write( 46636511Skfall rem, 46736511Skfall &cmdchar, 46836511Skfall 1 46936511Skfall ); 47036511Skfall } else 47136511Skfall #endif 47236511Skfall (void) write( 47336511Skfall rem, 47436511Skfall &cmdchar, 47536511Skfall 1 47636511Skfall ); 47736511Skfall } 4786444Swnj } 47936511Skfall 48036511Skfall #ifdef KERBEROS 48136511Skfall if(encrypt) { 48236511Skfall if (des_write(rem, &c, 1) == 0) { 48336511Skfall prf("line gone"); 48436511Skfall break; 48536511Skfall } 48636511Skfall } else 48736511Skfall #endif 48836511Skfall if (write(rem, &c, 1) == 0) { 48936511Skfall prf("line gone"); 49036511Skfall break; 49136511Skfall } 49223530Sbloom bol = c == defkill || c == deftc.t_eofc || 49325424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 49423530Sbloom c == '\r' || c == '\n'; 4956444Swnj } 4966444Swnj } 4976444Swnj 49823530Sbloom echo(c) 49923530Sbloom register char c; 50023530Sbloom { 50123530Sbloom char buf[8]; 50223530Sbloom register char *p = buf; 50323530Sbloom 50423530Sbloom c &= 0177; 50523530Sbloom *p++ = cmdchar; 50623530Sbloom if (c < ' ') { 50723530Sbloom *p++ = '^'; 50823530Sbloom *p++ = c + '@'; 50923530Sbloom } else if (c == 0177) { 51023530Sbloom *p++ = '^'; 51123530Sbloom *p++ = '?'; 51223530Sbloom } else 51323530Sbloom *p++ = c; 51423530Sbloom *p++ = '\r'; 51523530Sbloom *p++ = '\n'; 51629729Smckusick (void) write(1, buf, p - buf); 51723530Sbloom } 51823530Sbloom 51918358Ssam stop(cmdc) 52018358Ssam char cmdc; 52118358Ssam { 52218358Ssam mode(0); 52329729Smckusick (void) signal(SIGCHLD, SIG_IGN); 52429729Smckusick (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 52529729Smckusick (void) signal(SIGCHLD, catchild); 52618358Ssam mode(1); 52718358Ssam sigwinch(); /* check for size changes */ 52818358Ssam } 52918358Ssam 53018358Ssam sigwinch() 53118358Ssam { 53218358Ssam struct winsize ws; 53318358Ssam 53429729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 53518358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 53618358Ssam winsize = ws; 53724726Smckusick sendwindow(); 53818358Ssam } 53918358Ssam } 54018358Ssam 54124726Smckusick /* 54224726Smckusick * Send the window size to the server via the magic escape 54324726Smckusick */ 54424726Smckusick sendwindow() 54524726Smckusick { 54624726Smckusick char obuf[4 + sizeof (struct winsize)]; 54724726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 54824726Smckusick 54924726Smckusick obuf[0] = 0377; 55024726Smckusick obuf[1] = 0377; 55124726Smckusick obuf[2] = 's'; 55224726Smckusick obuf[3] = 's'; 55324726Smckusick wp->ws_row = htons(winsize.ws_row); 55424726Smckusick wp->ws_col = htons(winsize.ws_col); 55524726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 55624726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 55736511Skfall 55836511Skfall #ifdef KERBEROS 55936511Skfall if(encrypt) 56036511Skfall (void) des_write(rem, obuf, sizeof(obuf)); 56136511Skfall else 56236511Skfall #endif 56336511Skfall (void) write(rem, obuf, sizeof(obuf)); 56424726Smckusick } 56524726Smckusick 56625424Skarels /* 56725424Skarels * reader: read from remote: line -> 1 56825424Skarels */ 56925424Skarels #define READING 1 57025424Skarels #define WRITING 2 57125424Skarels 57225424Skarels char rcvbuf[8 * 1024]; 57325424Skarels int rcvcnt; 57425424Skarels int rcvstate; 57526981Skarels int ppid; 57625424Skarels jmp_buf rcvtop; 57725424Skarels 5786444Swnj oob() 5796444Swnj { 58025424Skarels int out = FWRITE, atmark, n; 58125424Skarels int rcvd = 0; 5829365Ssam char waste[BUFSIZ], mark; 58324726Smckusick struct sgttyb sb; 5846444Swnj 58525424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 58625424Skarels switch (errno) { 58725424Skarels 58825424Skarels case EWOULDBLOCK: 58925424Skarels /* 59025424Skarels * Urgent data not here yet. 59125424Skarels * It may not be possible to send it yet 59225424Skarels * if we are blocked for output 59325424Skarels * and our input buffer is full. 59425424Skarels */ 59525424Skarels if (rcvcnt < sizeof(rcvbuf)) { 59625424Skarels n = read(rem, rcvbuf + rcvcnt, 59725424Skarels sizeof(rcvbuf) - rcvcnt); 59825424Skarels if (n <= 0) 59925424Skarels return; 60025424Skarels rcvd += n; 60125424Skarels } else { 60225424Skarels n = read(rem, waste, sizeof(waste)); 60325424Skarels if (n <= 0) 60425424Skarels return; 60525424Skarels } 60625424Skarels continue; 60725424Skarels 60825424Skarels default: 60925424Skarels return; 6106444Swnj } 61125424Skarels if (mark & TIOCPKT_WINDOW) { 61224726Smckusick /* 61324726Smckusick * Let server know about window size changes 61424726Smckusick */ 61529729Smckusick (void) kill(ppid, SIGUSR1); 61624726Smckusick } 61725424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 61829729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 61924726Smckusick sb.sg_flags &= ~CBREAK; 62024726Smckusick sb.sg_flags |= RAW; 62129729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 62213075Ssam notc.t_stopc = -1; 62313075Ssam notc.t_startc = -1; 62429729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6256444Swnj } 62625424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 62729729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 62824726Smckusick sb.sg_flags &= ~RAW; 62924726Smckusick sb.sg_flags |= CBREAK; 63029729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 63113075Ssam notc.t_stopc = deftc.t_stopc; 63213075Ssam notc.t_startc = deftc.t_startc; 63329729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6346444Swnj } 63525424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 63629729Smckusick (void) ioctl(1, TIOCFLUSH, (char *)&out); 63725424Skarels for (;;) { 63825424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 63925424Skarels perror("ioctl"); 64025424Skarels break; 64125424Skarels } 64225424Skarels if (atmark) 64325424Skarels break; 64425424Skarels n = read(rem, waste, sizeof (waste)); 64525424Skarels if (n <= 0) 64625424Skarels break; 64725424Skarels } 64825424Skarels /* 64925424Skarels * Don't want any pending data to be output, 65025424Skarels * so clear the recv buffer. 65125424Skarels * If we were hanging on a write when interrupted, 65225424Skarels * don't want it to restart. If we were reading, 65325424Skarels * restart anyway. 65425424Skarels */ 65525424Skarels rcvcnt = 0; 65625424Skarels longjmp(rcvtop, 1); 65725424Skarels } 65829729Smckusick 65925424Skarels /* 66029729Smckusick * oob does not do FLUSHREAD (alas!) 66129729Smckusick */ 66229729Smckusick 66329729Smckusick /* 66425424Skarels * If we filled the receive buffer while a read was pending, 66525424Skarels * longjmp to the top to restart appropriately. Don't abort 66625424Skarels * a pending write, however, or we won't know how much was written. 66725424Skarels */ 66825424Skarels if (rcvd && rcvstate == READING) 66925424Skarels longjmp(rcvtop, 1); 6706444Swnj } 6716444Swnj 6729365Ssam /* 6739365Ssam * reader: read from remote: line -> 1 6749365Ssam */ 67529729Smckusick reader(oldmask) 67629729Smckusick int oldmask; 6776444Swnj { 67826981Skarels #if !defined(BSD) || BSD < 43 67926981Skarels int pid = -getpid(); 68026981Skarels #else 68125424Skarels int pid = getpid(); 68226981Skarels #endif 68325424Skarels int n, remaining; 68425424Skarels char *bufp = rcvbuf; 6856444Swnj 68629729Smckusick (void) signal(SIGTTOU, SIG_IGN); 68729729Smckusick (void) signal(SIGURG, oob); 68826981Skarels ppid = getppid(); 68929729Smckusick (void) fcntl(rem, F_SETOWN, pid); 69025424Skarels (void) setjmp(rcvtop); 69129729Smckusick (void) sigsetmask(oldmask); 6926444Swnj for (;;) { 69325424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 69425424Skarels rcvstate = WRITING; 69525424Skarels n = write(1, bufp, remaining); 69625424Skarels if (n < 0) { 69725424Skarels if (errno != EINTR) 69826189Slepreau return (-1); 69925424Skarels continue; 70025424Skarels } 70125424Skarels bufp += n; 70225424Skarels } 70325424Skarels bufp = rcvbuf; 70425424Skarels rcvcnt = 0; 70525424Skarels rcvstate = READING; 70636511Skfall 70736511Skfall #ifdef KERBEROS 70836511Skfall if(encrypt) 70936511Skfall rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 71036511Skfall else 71136511Skfall #endif 71236511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 71325424Skarels if (rcvcnt == 0) 71425424Skarels return (0); 71525424Skarels if (rcvcnt < 0) { 7169365Ssam if (errno == EINTR) 7176444Swnj continue; 71826981Skarels perror("read"); 71925424Skarels return (-1); 7206444Swnj } 7216444Swnj } 7226444Swnj } 7236444Swnj 7246444Swnj mode(f) 7256444Swnj { 72613075Ssam struct tchars *tc; 72713075Ssam struct ltchars *ltc; 72813075Ssam struct sgttyb sb; 72921583Sbloom int lflags; 7309365Ssam 73129729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 73229729Smckusick (void) ioctl(0, TIOCLGET, (char *)&lflags); 7339962Ssam switch (f) { 7349962Ssam 7359962Ssam case 0: 73613075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 73713075Ssam sb.sg_flags |= defflags|tabflag; 7389962Ssam tc = &deftc; 73913075Ssam ltc = &defltc; 74013075Ssam sb.sg_kill = defkill; 74113075Ssam sb.sg_erase = deferase; 74221583Sbloom lflags = deflflags; 7439962Ssam break; 7449962Ssam 7459962Ssam case 1: 74613075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 74713075Ssam sb.sg_flags &= ~defflags; 74812155Ssam /* preserve tab delays, but turn off XTABS */ 74913075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 75013075Ssam sb.sg_flags &= ~TBDELAY; 7519962Ssam tc = ¬c; 75213075Ssam ltc = &noltc; 75313075Ssam sb.sg_kill = sb.sg_erase = -1; 75421583Sbloom if (litout) 75521583Sbloom lflags |= LLITOUT; 7569962Ssam break; 7579962Ssam 7589962Ssam default: 7599962Ssam return; 7606444Swnj } 76129729Smckusick (void) ioctl(0, TIOCSLTC, (char *)ltc); 76229729Smckusick (void) ioctl(0, TIOCSETC, (char *)tc); 76329729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 76429729Smckusick (void) ioctl(0, TIOCLSET, (char *)&lflags); 7656444Swnj } 7666444Swnj 7679365Ssam /*VARARGS*/ 76824726Smckusick prf(f, a1, a2, a3, a4, a5) 7699365Ssam char *f; 7706444Swnj { 77129729Smckusick 77224726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 7736444Swnj fprintf(stderr, CRLF); 7746444Swnj } 7756444Swnj 7769365Ssam lostpeer() 7776444Swnj { 77829729Smckusick 77929729Smckusick (void) signal(SIGPIPE, SIG_IGN); 78012155Ssam prf("\007Connection closed."); 78125424Skarels done(1); 7826444Swnj } 783*36512Skfall 784*36512Skfall old_warning(str) 785*36512Skfall char *str; 786*36512Skfall { 787*36512Skfall prf("Warning: %s, using standard rlogin", str); 788*36512Skfall } 789