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; 5536512Skfall 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 } 17436524Skfall if (argc > 0 && !strcmp(*argv, "-k")) { 17536524Skfall argv++, argc--; 17636524Skfall if(argc <= 0 || (**argv == '-')) { 17736524Skfall fprintf(stderr, "-k option requires an argument\n"); 17836524Skfall exit(1); 17936524Skfall } 18036524Skfall strncpy(krb_realm, *argv, REALM_SZ); 18136524Skfall argv++, argc--; 18236524Skfall goto another; 18336524Skfall } 18436524Skfall 18536511Skfall #endif /* KERBEROS */ 18636511Skfall 1876444Swnj if (host == 0) 1886444Swnj goto usage; 1896444Swnj if (argc > 0) 1906444Swnj goto usage; 1916444Swnj pwd = getpwuid(getuid()); 1926444Swnj if (pwd == 0) { 1936444Swnj fprintf(stderr, "Who are you?\n"); 1946444Swnj exit(1); 1956444Swnj } 19636512Skfall #ifdef KERBEROS 19736512Skfall sp = getservbyname("klogin", "tcp"); 19836512Skfall if(sp == NULL) { 19936512Skfall use_kerberos = 0; 20036512Skfall old_warning("klogin service unknown"); 20136512Skfall sp = getservbyname("login", "tcp"); 20236512Skfall } 20336512Skfall #else 2049365Ssam sp = getservbyname("login", "tcp"); 20536512Skfall #endif 2069365Ssam if (sp == 0) { 2079365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 2089365Ssam exit(2); 2099365Ssam } 2109241Ssam cp = getenv("TERM"); 2119241Ssam if (cp) 21229729Smckusick (void) strcpy(term, cp); 21318358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 21429729Smckusick (void) strcat(term, "/"); 21529729Smckusick (void) strcat(term, speeds[ttyb.sg_ospeed]); 2166444Swnj } 21729729Smckusick (void) get_window_size(0, &winsize); 21829729Smckusick (void) signal(SIGPIPE, lostpeer); 21929729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 22029729Smckusick oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 22136511Skfall 22236511Skfall #ifdef KERBEROS 22336512Skfall try_connect: 22436512Skfall if(use_kerberos) { 22536512Skfall rem = KSUCCESS; 22636512Skfall if(krb_realm[0] == '\0') { 227*36628Skfall rem = krb_get_lrealm(krb_realm, 1); 22836512Skfall } 22936512Skfall if(rem == KSUCCESS) { 23036512Skfall if(encrypt) { 23136512Skfall rem = krcmd_mutual( 23236512Skfall &host, sp->s_port, 23336512Skfall name ? name : pwd->pw_name, term, 23436512Skfall 0, krb_realm, 23536512Skfall &cred, schedule 23636512Skfall ); 23736512Skfall } else { 23836512Skfall rem = krcmd( 23936512Skfall &host, sp->s_port, 24036512Skfall name ? name : pwd->pw_name, term, 24136512Skfall 0, krb_realm 24236512Skfall ); 24336512Skfall } 24436511Skfall } else { 24536512Skfall fprintf( 24636512Skfall stderr, 24736512Skfall "rlogin: Kerberos error getting local realm %s\n", 24836512Skfall krb_err_txt[rem] 24936511Skfall ); 25036512Skfall exit(1); 25136511Skfall } 25236512Skfall if((rem < 0) && errno == ECONNREFUSED) { 25336512Skfall use_kerberos = 0; 254*36628Skfall sp = getservbyname("login", "tcp"); 255*36628Skfall if(sp == NULL) { 256*36628Skfall fprintf(stderr, "unknown service login/tcp\n"); 257*36628Skfall exit(1); 258*36628Skfall } 25936512Skfall old_warning("remote host doesn't support Kerberos"); 26036512Skfall goto try_connect; 26136512Skfall } 26236511Skfall } else { 26336512Skfall if(encrypt) { 26436512Skfall fprintf(stderr, "The -x flag requires Kerberos authencation\n"); 26536512Skfall exit(1); 26636512Skfall } 26736512Skfall rem = rcmd(&host, sp->s_port, pwd->pw_name, 26836512Skfall name ? name : pwd->pw_name, term, 0); 26936511Skfall } 27036512Skfall #else 27136512Skfall rem = rcmd(&host, sp->s_port, pwd->pw_name, 27236512Skfall name ? name : pwd->pw_name, term, 0); 27336512Skfall #endif 27436511Skfall 27536511Skfall if(rem < 0) 27636511Skfall exit(1); 27736511Skfall 27810415Ssam if (options & SO_DEBUG && 27917449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 28010415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 2819365Ssam uid = getuid(); 2829365Ssam if (setuid(uid) < 0) { 2839365Ssam perror("rlogin: setuid"); 2849365Ssam exit(1); 2859365Ssam } 28624726Smckusick doit(oldmask); 2879365Ssam /*NOTREACHED*/ 2886444Swnj usage: 2896444Swnj fprintf(stderr, 29036511Skfall #ifdef KERBEROS 29136592Skfall "usage: rlogin host [ -ex ] [ -l username ] [ -k realm ] [ -8 ] [ -L ] [ -x ]\n"); 29236511Skfall #else 29325341Smckusick "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); 29436511Skfall #endif 2956444Swnj exit(1); 2966444Swnj } 2976444Swnj 2986444Swnj #define CRLF "\r\n" 2996444Swnj 3009365Ssam int child; 30111803Sedward int catchild(); 30229729Smckusick int copytochild(), writeroob(); 3039365Ssam 30413075Ssam int defflags, tabflag; 30521583Sbloom int deflflags; 30613075Ssam char deferase, defkill; 30713075Ssam struct tchars deftc; 30813075Ssam struct ltchars defltc; 30913075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 31013075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3116444Swnj 31224726Smckusick doit(oldmask) 3136444Swnj { 3146444Swnj int exit(); 31513075Ssam struct sgttyb sb; 3166444Swnj 31729729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 31813075Ssam defflags = sb.sg_flags; 31912155Ssam tabflag = defflags & TBDELAY; 3209962Ssam defflags &= ECHO | CRMOD; 32113075Ssam deferase = sb.sg_erase; 32213075Ssam defkill = sb.sg_kill; 32329729Smckusick (void) ioctl(0, TIOCLGET, (char *)&deflflags); 32429729Smckusick (void) ioctl(0, TIOCGETC, (char *)&deftc); 32513075Ssam notc.t_startc = deftc.t_startc; 32613075Ssam notc.t_stopc = deftc.t_stopc; 32729729Smckusick (void) ioctl(0, TIOCGLTC, (char *)&defltc); 32829729Smckusick (void) signal(SIGINT, SIG_IGN); 32929729Smckusick setsignal(SIGHUP, exit); 33029729Smckusick setsignal(SIGQUIT, exit); 3319365Ssam child = fork(); 3329365Ssam if (child == -1) { 3339365Ssam perror("rlogin: fork"); 33425424Skarels done(1); 3359365Ssam } 3369365Ssam if (child == 0) { 33724726Smckusick mode(1); 33829729Smckusick if (reader(oldmask) == 0) { 33925424Skarels prf("Connection closed."); 34025424Skarels exit(0); 34125424Skarels } 34212155Ssam sleep(1); 34312155Ssam prf("\007Connection closed."); 3446444Swnj exit(3); 3456444Swnj } 34629729Smckusick 34729729Smckusick /* 34829729Smckusick * We may still own the socket, and may have a pending SIGURG 34929729Smckusick * (or might receive one soon) that we really want to send to 35029729Smckusick * the reader. Set a trap that simply copies such signals to 35129729Smckusick * the child. 35229729Smckusick */ 35329729Smckusick (void) signal(SIGURG, copytochild); 35429729Smckusick (void) signal(SIGUSR1, writeroob); 35529729Smckusick (void) sigsetmask(oldmask); 35629729Smckusick (void) signal(SIGCHLD, catchild); 3579365Ssam writer(); 35812155Ssam prf("Closed connection."); 35925424Skarels done(0); 3606444Swnj } 3616444Swnj 36229729Smckusick /* 36329729Smckusick * Trap a signal, unless it is being ignored. 36429729Smckusick */ 36529729Smckusick setsignal(sig, act) 36629729Smckusick int sig, (*act)(); 36729729Smckusick { 36829729Smckusick int omask = sigblock(sigmask(sig)); 36929729Smckusick 37029729Smckusick if (signal(sig, act) == SIG_IGN) 37129729Smckusick (void) signal(sig, SIG_IGN); 37229729Smckusick (void) sigsetmask(omask); 37329729Smckusick } 37429729Smckusick 37525424Skarels done(status) 37625424Skarels int status; 3776444Swnj { 37829729Smckusick int w; 3796444Swnj 3806444Swnj mode(0); 38129729Smckusick if (child > 0) { 38229729Smckusick /* make sure catchild does not snap it up */ 38329729Smckusick (void) signal(SIGCHLD, SIG_DFL); 38429729Smckusick if (kill(child, SIGKILL) >= 0) 38529729Smckusick while ((w = wait((union wait *)0)) > 0 && w != child) 38629729Smckusick /*void*/; 38729729Smckusick } 38825424Skarels exit(status); 3896444Swnj } 3906444Swnj 39124726Smckusick /* 39229729Smckusick * Copy SIGURGs to the child process. 39329729Smckusick */ 39429729Smckusick copytochild() 39529729Smckusick { 39629729Smckusick 39729729Smckusick (void) kill(child, SIGURG); 39829729Smckusick } 39929729Smckusick 40029729Smckusick /* 40124726Smckusick * This is called when the reader process gets the out-of-band (urgent) 40224726Smckusick * request to turn on the window-changing protocol. 40324726Smckusick */ 40424726Smckusick writeroob() 40524726Smckusick { 40624726Smckusick 40725341Smckusick if (dosigwinch == 0) { 40824919Smckusick sendwindow(); 40929729Smckusick (void) signal(SIGWINCH, sigwinch); 41025341Smckusick } 41124726Smckusick dosigwinch = 1; 41224726Smckusick } 41324726Smckusick 41411803Sedward catchild() 41511803Sedward { 41611803Sedward union wait status; 41711803Sedward int pid; 41811803Sedward 41911803Sedward again: 42029729Smckusick pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); 42111803Sedward if (pid == 0) 42211803Sedward return; 42311803Sedward /* 42411803Sedward * if the child (reader) dies, just quit 42511803Sedward */ 42611803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 42729729Smckusick done((int)(status.w_termsig | status.w_retcode)); 42811803Sedward goto again; 42911803Sedward } 43011803Sedward 4316444Swnj /* 4329365Ssam * writer: write to remote: 0 -> line. 4339365Ssam * ~. terminate 4349365Ssam * ~^Z suspend rlogin process. 43510415Ssam * ~^Y suspend rlogin process, but leave reader alone. 4366444Swnj */ 4379365Ssam writer() 4386444Swnj { 43923530Sbloom char c; 44011803Sedward register n; 44123530Sbloom register bol = 1; /* beginning of line */ 44223530Sbloom register local = 0; 4436444Swnj 44411803Sedward for (;;) { 44511803Sedward n = read(0, &c, 1); 44618358Ssam if (n <= 0) { 44718358Ssam if (n < 0 && errno == EINTR) 44818358Ssam continue; 44911803Sedward break; 45018358Ssam } 4519365Ssam /* 4529365Ssam * If we're at the beginning of the line 4539365Ssam * and recognize a command character, then 4549365Ssam * we echo locally. Otherwise, characters 4559365Ssam * are echo'd remotely. If the command 4569365Ssam * character is doubled, this acts as a 4579365Ssam * force and local echo is suppressed. 4589365Ssam */ 45923530Sbloom if (bol) { 46023530Sbloom bol = 0; 46123530Sbloom if (c == cmdchar) { 46223530Sbloom bol = 0; 46323530Sbloom local = 1; 46423530Sbloom continue; 4656444Swnj } 46623530Sbloom } else if (local) { 46723530Sbloom local = 0; 46823530Sbloom if (c == '.' || c == deftc.t_eofc) { 46923530Sbloom echo(c); 47023530Sbloom break; 4716444Swnj } 47223530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 47323530Sbloom bol = 1; 47423530Sbloom echo(c); 47523530Sbloom stop(c); 47623530Sbloom continue; 47723530Sbloom } 47836511Skfall if (c != cmdchar) { 47936511Skfall #ifdef KERBEROS 48036511Skfall if(encrypt) { 48136511Skfall (void) des_write( 48236511Skfall rem, 48336511Skfall &cmdchar, 48436511Skfall 1 48536511Skfall ); 48636511Skfall } else 48736511Skfall #endif 48836511Skfall (void) write( 48936511Skfall rem, 49036511Skfall &cmdchar, 49136511Skfall 1 49236511Skfall ); 49336511Skfall } 4946444Swnj } 49536511Skfall 49636511Skfall #ifdef KERBEROS 49736511Skfall if(encrypt) { 49836511Skfall if (des_write(rem, &c, 1) == 0) { 49936511Skfall prf("line gone"); 50036511Skfall break; 50136511Skfall } 50236511Skfall } else 50336511Skfall #endif 50436511Skfall if (write(rem, &c, 1) == 0) { 50536511Skfall prf("line gone"); 50636511Skfall break; 50736511Skfall } 50823530Sbloom bol = c == defkill || c == deftc.t_eofc || 50925424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 51023530Sbloom c == '\r' || c == '\n'; 5116444Swnj } 5126444Swnj } 5136444Swnj 51423530Sbloom echo(c) 51523530Sbloom register char c; 51623530Sbloom { 51723530Sbloom char buf[8]; 51823530Sbloom register char *p = buf; 51923530Sbloom 52023530Sbloom c &= 0177; 52123530Sbloom *p++ = cmdchar; 52223530Sbloom if (c < ' ') { 52323530Sbloom *p++ = '^'; 52423530Sbloom *p++ = c + '@'; 52523530Sbloom } else if (c == 0177) { 52623530Sbloom *p++ = '^'; 52723530Sbloom *p++ = '?'; 52823530Sbloom } else 52923530Sbloom *p++ = c; 53023530Sbloom *p++ = '\r'; 53123530Sbloom *p++ = '\n'; 53229729Smckusick (void) write(1, buf, p - buf); 53323530Sbloom } 53423530Sbloom 53518358Ssam stop(cmdc) 53618358Ssam char cmdc; 53718358Ssam { 53818358Ssam mode(0); 53929729Smckusick (void) signal(SIGCHLD, SIG_IGN); 54029729Smckusick (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 54129729Smckusick (void) signal(SIGCHLD, catchild); 54218358Ssam mode(1); 54318358Ssam sigwinch(); /* check for size changes */ 54418358Ssam } 54518358Ssam 54618358Ssam sigwinch() 54718358Ssam { 54818358Ssam struct winsize ws; 54918358Ssam 55029729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 55118358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 55218358Ssam winsize = ws; 55324726Smckusick sendwindow(); 55418358Ssam } 55518358Ssam } 55618358Ssam 55724726Smckusick /* 55824726Smckusick * Send the window size to the server via the magic escape 55924726Smckusick */ 56024726Smckusick sendwindow() 56124726Smckusick { 56224726Smckusick char obuf[4 + sizeof (struct winsize)]; 56324726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 56424726Smckusick 56524726Smckusick obuf[0] = 0377; 56624726Smckusick obuf[1] = 0377; 56724726Smckusick obuf[2] = 's'; 56824726Smckusick obuf[3] = 's'; 56924726Smckusick wp->ws_row = htons(winsize.ws_row); 57024726Smckusick wp->ws_col = htons(winsize.ws_col); 57124726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 57224726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 57336511Skfall 57436511Skfall #ifdef KERBEROS 57536511Skfall if(encrypt) 57636511Skfall (void) des_write(rem, obuf, sizeof(obuf)); 57736511Skfall else 57836511Skfall #endif 57936511Skfall (void) write(rem, obuf, sizeof(obuf)); 58024726Smckusick } 58124726Smckusick 58225424Skarels /* 58325424Skarels * reader: read from remote: line -> 1 58425424Skarels */ 58525424Skarels #define READING 1 58625424Skarels #define WRITING 2 58725424Skarels 58825424Skarels char rcvbuf[8 * 1024]; 58925424Skarels int rcvcnt; 59025424Skarels int rcvstate; 59126981Skarels int ppid; 59225424Skarels jmp_buf rcvtop; 59325424Skarels 5946444Swnj oob() 5956444Swnj { 59625424Skarels int out = FWRITE, atmark, n; 59725424Skarels int rcvd = 0; 5989365Ssam char waste[BUFSIZ], mark; 59924726Smckusick struct sgttyb sb; 6006444Swnj 60125424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 60225424Skarels switch (errno) { 60325424Skarels 60425424Skarels case EWOULDBLOCK: 60525424Skarels /* 60625424Skarels * Urgent data not here yet. 60725424Skarels * It may not be possible to send it yet 60825424Skarels * if we are blocked for output 60925424Skarels * and our input buffer is full. 61025424Skarels */ 61125424Skarels if (rcvcnt < sizeof(rcvbuf)) { 61225424Skarels n = read(rem, rcvbuf + rcvcnt, 61325424Skarels sizeof(rcvbuf) - rcvcnt); 61425424Skarels if (n <= 0) 61525424Skarels return; 61625424Skarels rcvd += n; 61725424Skarels } else { 61825424Skarels n = read(rem, waste, sizeof(waste)); 61925424Skarels if (n <= 0) 62025424Skarels return; 62125424Skarels } 62225424Skarels continue; 62325424Skarels 62425424Skarels default: 62525424Skarels return; 6266444Swnj } 62725424Skarels if (mark & TIOCPKT_WINDOW) { 62824726Smckusick /* 62924726Smckusick * Let server know about window size changes 63024726Smckusick */ 63129729Smckusick (void) kill(ppid, SIGUSR1); 63224726Smckusick } 63325424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 63429729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 63524726Smckusick sb.sg_flags &= ~CBREAK; 63624726Smckusick sb.sg_flags |= RAW; 63729729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 63813075Ssam notc.t_stopc = -1; 63913075Ssam notc.t_startc = -1; 64029729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6416444Swnj } 64225424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 64329729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 64424726Smckusick sb.sg_flags &= ~RAW; 64524726Smckusick sb.sg_flags |= CBREAK; 64629729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 64713075Ssam notc.t_stopc = deftc.t_stopc; 64813075Ssam notc.t_startc = deftc.t_startc; 64929729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6506444Swnj } 65125424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 65229729Smckusick (void) ioctl(1, TIOCFLUSH, (char *)&out); 65325424Skarels for (;;) { 65425424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 65525424Skarels perror("ioctl"); 65625424Skarels break; 65725424Skarels } 65825424Skarels if (atmark) 65925424Skarels break; 66025424Skarels n = read(rem, waste, sizeof (waste)); 66125424Skarels if (n <= 0) 66225424Skarels break; 66325424Skarels } 66425424Skarels /* 66525424Skarels * Don't want any pending data to be output, 66625424Skarels * so clear the recv buffer. 66725424Skarels * If we were hanging on a write when interrupted, 66825424Skarels * don't want it to restart. If we were reading, 66925424Skarels * restart anyway. 67025424Skarels */ 67125424Skarels rcvcnt = 0; 67225424Skarels longjmp(rcvtop, 1); 67325424Skarels } 67429729Smckusick 67525424Skarels /* 67629729Smckusick * oob does not do FLUSHREAD (alas!) 67729729Smckusick */ 67829729Smckusick 67929729Smckusick /* 68025424Skarels * If we filled the receive buffer while a read was pending, 68125424Skarels * longjmp to the top to restart appropriately. Don't abort 68225424Skarels * a pending write, however, or we won't know how much was written. 68325424Skarels */ 68425424Skarels if (rcvd && rcvstate == READING) 68525424Skarels longjmp(rcvtop, 1); 6866444Swnj } 6876444Swnj 6889365Ssam /* 6899365Ssam * reader: read from remote: line -> 1 6909365Ssam */ 69129729Smckusick reader(oldmask) 69229729Smckusick int oldmask; 6936444Swnj { 69426981Skarels #if !defined(BSD) || BSD < 43 69526981Skarels int pid = -getpid(); 69626981Skarels #else 69725424Skarels int pid = getpid(); 69826981Skarels #endif 69925424Skarels int n, remaining; 70025424Skarels char *bufp = rcvbuf; 7016444Swnj 70229729Smckusick (void) signal(SIGTTOU, SIG_IGN); 70329729Smckusick (void) signal(SIGURG, oob); 70426981Skarels ppid = getppid(); 70529729Smckusick (void) fcntl(rem, F_SETOWN, pid); 70625424Skarels (void) setjmp(rcvtop); 70729729Smckusick (void) sigsetmask(oldmask); 7086444Swnj for (;;) { 70925424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 71025424Skarels rcvstate = WRITING; 71125424Skarels n = write(1, bufp, remaining); 71225424Skarels if (n < 0) { 71325424Skarels if (errno != EINTR) 71426189Slepreau return (-1); 71525424Skarels continue; 71625424Skarels } 71725424Skarels bufp += n; 71825424Skarels } 71925424Skarels bufp = rcvbuf; 72025424Skarels rcvcnt = 0; 72125424Skarels rcvstate = READING; 72236511Skfall 72336511Skfall #ifdef KERBEROS 72436511Skfall if(encrypt) 72536511Skfall rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 72636511Skfall else 72736511Skfall #endif 72836511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 72925424Skarels if (rcvcnt == 0) 73025424Skarels return (0); 73125424Skarels if (rcvcnt < 0) { 7329365Ssam if (errno == EINTR) 7336444Swnj continue; 73426981Skarels perror("read"); 73525424Skarels return (-1); 7366444Swnj } 7376444Swnj } 7386444Swnj } 7396444Swnj 7406444Swnj mode(f) 7416444Swnj { 74213075Ssam struct tchars *tc; 74313075Ssam struct ltchars *ltc; 74413075Ssam struct sgttyb sb; 74521583Sbloom int lflags; 7469365Ssam 74729729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 74829729Smckusick (void) ioctl(0, TIOCLGET, (char *)&lflags); 7499962Ssam switch (f) { 7509962Ssam 7519962Ssam case 0: 75213075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 75313075Ssam sb.sg_flags |= defflags|tabflag; 7549962Ssam tc = &deftc; 75513075Ssam ltc = &defltc; 75613075Ssam sb.sg_kill = defkill; 75713075Ssam sb.sg_erase = deferase; 75821583Sbloom lflags = deflflags; 7599962Ssam break; 7609962Ssam 7619962Ssam case 1: 76213075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 76313075Ssam sb.sg_flags &= ~defflags; 76412155Ssam /* preserve tab delays, but turn off XTABS */ 76513075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 76613075Ssam sb.sg_flags &= ~TBDELAY; 7679962Ssam tc = ¬c; 76813075Ssam ltc = &noltc; 76913075Ssam sb.sg_kill = sb.sg_erase = -1; 77021583Sbloom if (litout) 77121583Sbloom lflags |= LLITOUT; 7729962Ssam break; 7739962Ssam 7749962Ssam default: 7759962Ssam return; 7766444Swnj } 77729729Smckusick (void) ioctl(0, TIOCSLTC, (char *)ltc); 77829729Smckusick (void) ioctl(0, TIOCSETC, (char *)tc); 77929729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 78029729Smckusick (void) ioctl(0, TIOCLSET, (char *)&lflags); 7816444Swnj } 7826444Swnj 7839365Ssam /*VARARGS*/ 78424726Smckusick prf(f, a1, a2, a3, a4, a5) 7859365Ssam char *f; 7866444Swnj { 78729729Smckusick 78824726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 7896444Swnj fprintf(stderr, CRLF); 7906444Swnj } 7916444Swnj 7929365Ssam lostpeer() 7936444Swnj { 79429729Smckusick 79529729Smckusick (void) signal(SIGPIPE, SIG_IGN); 79612155Ssam prf("\007Connection closed."); 79725424Skarels done(1); 7986444Swnj } 79936512Skfall 80036512Skfall old_warning(str) 80136512Skfall char *str; 80236512Skfall { 80336512Skfall prf("Warning: %s, using standard rlogin", str); 80436512Skfall } 805