138728Skfall 221595Sdist /* 338728Skfall * $Source: /a/staff/kfall/mit/rlogin/RCS/rlogin.c,v $ 438728Skfall * $Header: /a/staff/kfall/mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall Exp Locker: kfall $ 538728Skfall */ 638728Skfall 738728Skfall /* 835539Sbostic * Copyright (c) 1983 The Regents of the University of California. 935539Sbostic * All rights reserved. 1035539Sbostic * 1135539Sbostic * Redistribution and use in source and binary forms are permitted 1235539Sbostic * provided that the above copyright notice and this paragraph are 1335539Sbostic * duplicated in all such forms and that any documentation, 1435539Sbostic * advertising materials, and other materials related to such 1535539Sbostic * distribution and use acknowledge that the software was developed 1635539Sbostic * by the University of California, Berkeley. The name of the 1735539Sbostic * University may not be used to endorse or promote products derived 1835539Sbostic * from this software without specific prior written permission. 1935539Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 2035539Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 2135539Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2221595Sdist */ 2321595Sdist 246444Swnj #ifndef lint 2521595Sdist char copyright[] = 2635539Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2721595Sdist All rights reserved.\n"; 2835539Sbostic #endif /* not lint */ 296444Swnj 3021595Sdist #ifndef lint 3136511Skfall static char sccsid[] = "@(#)rlogin.c 5.12 (Berkeley) 9/19/88"; 3235539Sbostic #endif /* not lint */ 3321595Sdist 3412990Ssam /* 3512990Ssam * rlogin - remote login 3612990Ssam */ 3726981Skarels #include <sys/param.h> 3825424Skarels #include <sys/errno.h> 3924727Smckusick #include <sys/file.h> 406444Swnj #include <sys/socket.h> 4129729Smckusick #include <sys/time.h> 4229729Smckusick #include <sys/resource.h> 4313620Ssam #include <sys/wait.h> 449365Ssam 459207Ssam #include <netinet/in.h> 469365Ssam 479365Ssam #include <stdio.h> 489365Ssam #include <sgtty.h> 496444Swnj #include <errno.h> 506444Swnj #include <pwd.h> 519365Ssam #include <signal.h> 5225424Skarels #include <setjmp.h> 539365Ssam #include <netdb.h> 546444Swnj 5536511Skfall #ifdef KERBEROS 56*40683Sbostic #include <kerberosIV/krb.h> 5736511Skfall int encrypt = 0; 5838728Skfall char dst_realm_buf[REALM_SZ]; 5938728Skfall char *dest_realm = NULL; 6036511Skfall CREDENTIALS cred; 6136511Skfall Key_schedule schedule; 6236512Skfall int use_kerberos = 1; 6338728Skfall extern char *krb_realmofhost(); 6436511Skfall #endif /* KERBEROS */ 6536511Skfall 6624726Smckusick # ifndef TIOCPKT_WINDOW 6724726Smckusick # define TIOCPKT_WINDOW 0x80 6824726Smckusick # endif TIOCPKT_WINDOW 6924726Smckusick 7029729Smckusick /* concession to sun */ 7129729Smckusick # ifndef SIGUSR1 7229729Smckusick # define SIGUSR1 30 7329729Smckusick # endif SIGUSR1 7429729Smckusick 7529729Smckusick char *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy(); 766444Swnj struct passwd *getpwuid(); 779365Ssam char *name; 786444Swnj int rem; 796444Swnj char cmdchar = '~'; 806444Swnj int eight; 8121583Sbloom int litout; 826444Swnj char *speeds[] = 836444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 846444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 8518358Ssam char term[256] = "network"; 869365Ssam extern int errno; 879365Ssam int lostpeer(); 8824726Smckusick int dosigwinch = 0; 8926981Skarels #ifndef sigmask 9026981Skarels #define sigmask(m) (1 << ((m)-1)) 9126981Skarels #endif 9226981Skarels #ifdef sun 9326981Skarels struct winsize { 9426981Skarels unsigned short ws_row, ws_col; 9526981Skarels unsigned short ws_xpixel, ws_ypixel; 9626981Skarels }; 9729729Smckusick #endif sun 9818358Ssam struct winsize winsize; 9924726Smckusick int sigwinch(), oob(); 1006444Swnj 10129729Smckusick /* 10229729Smckusick * The following routine provides compatibility (such as it is) 10329729Smckusick * between 4.2BSD Suns and others. Suns have only a `ttysize', 10429729Smckusick * so we convert it to a winsize. 10529729Smckusick */ 10629729Smckusick #ifdef sun 10729729Smckusick int 10829729Smckusick get_window_size(fd, wp) 10929729Smckusick int fd; 11029729Smckusick struct winsize *wp; 11129729Smckusick { 11229729Smckusick struct ttysize ts; 11329729Smckusick int error; 11429729Smckusick 11529729Smckusick if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 11629729Smckusick return (error); 11729729Smckusick wp->ws_row = ts.ts_lines; 11829729Smckusick wp->ws_col = ts.ts_cols; 11929729Smckusick wp->ws_xpixel = 0; 12029729Smckusick wp->ws_ypixel = 0; 12129729Smckusick return (0); 12229729Smckusick } 12329729Smckusick #else sun 12429729Smckusick #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 12529729Smckusick #endif sun 12629729Smckusick 1276444Swnj main(argc, argv) 1286444Swnj int argc; 1296444Swnj char **argv; 1306444Swnj { 1319365Ssam char *host, *cp; 1326444Swnj struct sgttyb ttyb; 1336444Swnj struct passwd *pwd; 1349365Ssam struct servent *sp; 13524726Smckusick int uid, options = 0, oldmask; 13617449Slepreau int on = 1; 1376444Swnj 1386444Swnj host = rindex(argv[0], '/'); 1396444Swnj if (host) 1406444Swnj host++; 1416444Swnj else 1426444Swnj host = argv[0]; 1436444Swnj argv++, --argc; 1446444Swnj if (!strcmp(host, "rlogin")) 1456444Swnj host = *argv++, --argc; 1466444Swnj another: 14710839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 1486444Swnj argv++, argc--; 14910415Ssam options |= SO_DEBUG; 1506444Swnj goto another; 1516444Swnj } 15210839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 1536444Swnj argv++, argc--; 1546444Swnj if (argc == 0) 1556444Swnj goto usage; 1566444Swnj name = *argv++; argc--; 1576444Swnj goto another; 1586444Swnj } 15910839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 1606444Swnj cmdchar = argv[0][2]; 1616444Swnj argv++, argc--; 1626444Swnj goto another; 1636444Swnj } 16410839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 1656444Swnj eight = 1; 1666444Swnj argv++, argc--; 1676444Swnj goto another; 1686444Swnj } 16921583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 17021583Sbloom litout = 1; 17121583Sbloom argv++, argc--; 17221583Sbloom goto another; 17321583Sbloom } 17436511Skfall 17536511Skfall #ifdef KERBEROS 17636511Skfall if (argc > 0 && !strcmp(*argv, "-x")) { 17736511Skfall encrypt = 1; 17836511Skfall des_set_key(cred.session, schedule); 17936511Skfall argv++, argc--; 18036511Skfall goto another; 18136511Skfall } 18236524Skfall if (argc > 0 && !strcmp(*argv, "-k")) { 18336524Skfall argv++, argc--; 18436524Skfall if(argc <= 0 || (**argv == '-')) { 18536524Skfall fprintf(stderr, "-k option requires an argument\n"); 18636524Skfall exit(1); 18736524Skfall } 18838728Skfall dest_realm = dst_realm_buf; 18938728Skfall strncpy(dest_realm, *argv, REALM_SZ); 19036524Skfall argv++, argc--; 19136524Skfall goto another; 19236524Skfall } 19336524Skfall 19436511Skfall #endif /* KERBEROS */ 19536511Skfall 1966444Swnj if (host == 0) 1976444Swnj goto usage; 1986444Swnj if (argc > 0) 1996444Swnj goto usage; 20038728Skfall uid = getuid(); 20138728Skfall pwd = getpwuid(uid); 2026444Swnj if (pwd == 0) { 2036444Swnj fprintf(stderr, "Who are you?\n"); 2046444Swnj exit(1); 2056444Swnj } 20636512Skfall #ifdef KERBEROS 20736716Skfall sp = getservbyname((encrypt ? "eklogin" : "klogin"), "tcp"); 20836512Skfall if(sp == NULL) { 20936512Skfall use_kerberos = 0; 21036512Skfall old_warning("klogin service unknown"); 21136512Skfall sp = getservbyname("login", "tcp"); 21236512Skfall } 21336512Skfall #else 2149365Ssam sp = getservbyname("login", "tcp"); 21536512Skfall #endif 2169365Ssam if (sp == 0) { 2179365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 2189365Ssam exit(2); 2199365Ssam } 2209241Ssam cp = getenv("TERM"); 2219241Ssam if (cp) 22229729Smckusick (void) strcpy(term, cp); 22318358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 22429729Smckusick (void) strcat(term, "/"); 22529729Smckusick (void) strcat(term, speeds[ttyb.sg_ospeed]); 2266444Swnj } 22729729Smckusick (void) get_window_size(0, &winsize); 22829729Smckusick (void) signal(SIGPIPE, lostpeer); 22929729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 23029729Smckusick oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 23136511Skfall 23236511Skfall #ifdef KERBEROS 23336512Skfall try_connect: 23436512Skfall if(use_kerberos) { 23536512Skfall rem = KSUCCESS; 23638728Skfall if (dest_realm == NULL) 23738728Skfall dest_realm = krb_realmofhost(host); 23838728Skfall 23938728Skfall errno = 0; 24038728Skfall if(encrypt) { 24138728Skfall rem = krcmd_mutual( 24238728Skfall &host, sp->s_port, 24338728Skfall name ? name : pwd->pw_name, term, 24438728Skfall 0, dest_realm, 24538728Skfall &cred, schedule 24638728Skfall ); 24736511Skfall } else { 24838728Skfall rem = krcmd( 24938728Skfall &host, sp->s_port, 25038728Skfall name ? name : pwd->pw_name, term, 25138728Skfall 0, dest_realm 25236511Skfall ); 25336511Skfall } 25438728Skfall if (rem < 0) { 25536512Skfall use_kerberos = 0; 25636628Skfall sp = getservbyname("login", "tcp"); 25736628Skfall if(sp == NULL) { 25838728Skfall fprintf(stderr, 25938728Skfall "unknown service login/tcp\n"); 26036628Skfall exit(1); 26136628Skfall } 26238728Skfall if (errno == ECONNREFUSED) 26338728Skfall old_warning("remote host doesn't support Kerberos"); 26438728Skfall if (errno == ENOENT) 26538728Skfall old_warning("Can't provide Kerberos auth data"); 26636512Skfall goto try_connect; 26736512Skfall } 26836511Skfall } else { 26936512Skfall if(encrypt) { 27038728Skfall fprintf(stderr, "The -x flag requires Kerberos authentication\n"); 27136512Skfall exit(1); 27236512Skfall } 27336512Skfall rem = rcmd(&host, sp->s_port, pwd->pw_name, 27436512Skfall name ? name : pwd->pw_name, term, 0); 27536511Skfall } 27636512Skfall #else 27736512Skfall rem = rcmd(&host, sp->s_port, pwd->pw_name, 27836512Skfall name ? name : pwd->pw_name, term, 0); 27936512Skfall #endif 28036511Skfall 28136511Skfall if(rem < 0) 28236511Skfall exit(1); 28336511Skfall 28410415Ssam if (options & SO_DEBUG && 28517449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 28610415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 2879365Ssam if (setuid(uid) < 0) { 2889365Ssam perror("rlogin: setuid"); 2899365Ssam exit(1); 2909365Ssam } 29124726Smckusick doit(oldmask); 2929365Ssam /*NOTREACHED*/ 2936444Swnj usage: 2946444Swnj fprintf(stderr, 29536511Skfall #ifdef KERBEROS 29636592Skfall "usage: rlogin host [ -ex ] [ -l username ] [ -k realm ] [ -8 ] [ -L ] [ -x ]\n"); 29736511Skfall #else 29825341Smckusick "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); 29936511Skfall #endif 3006444Swnj exit(1); 3016444Swnj } 3026444Swnj 3036444Swnj #define CRLF "\r\n" 3046444Swnj 3059365Ssam int child; 30611803Sedward int catchild(); 30729729Smckusick int copytochild(), writeroob(); 3089365Ssam 30913075Ssam int defflags, tabflag; 31021583Sbloom int deflflags; 31113075Ssam char deferase, defkill; 31213075Ssam struct tchars deftc; 31313075Ssam struct ltchars defltc; 31413075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 31513075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3166444Swnj 31724726Smckusick doit(oldmask) 3186444Swnj { 3196444Swnj int exit(); 32013075Ssam struct sgttyb sb; 3216444Swnj 32229729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 32313075Ssam defflags = sb.sg_flags; 32412155Ssam tabflag = defflags & TBDELAY; 3259962Ssam defflags &= ECHO | CRMOD; 32613075Ssam deferase = sb.sg_erase; 32713075Ssam defkill = sb.sg_kill; 32829729Smckusick (void) ioctl(0, TIOCLGET, (char *)&deflflags); 32929729Smckusick (void) ioctl(0, TIOCGETC, (char *)&deftc); 33013075Ssam notc.t_startc = deftc.t_startc; 33113075Ssam notc.t_stopc = deftc.t_stopc; 33229729Smckusick (void) ioctl(0, TIOCGLTC, (char *)&defltc); 33329729Smckusick (void) signal(SIGINT, SIG_IGN); 33429729Smckusick setsignal(SIGHUP, exit); 33529729Smckusick setsignal(SIGQUIT, exit); 3369365Ssam child = fork(); 3379365Ssam if (child == -1) { 3389365Ssam perror("rlogin: fork"); 33925424Skarels done(1); 3409365Ssam } 3419365Ssam if (child == 0) { 34224726Smckusick mode(1); 34329729Smckusick if (reader(oldmask) == 0) { 34425424Skarels prf("Connection closed."); 34525424Skarels exit(0); 34625424Skarels } 34712155Ssam sleep(1); 34812155Ssam prf("\007Connection closed."); 3496444Swnj exit(3); 3506444Swnj } 35129729Smckusick 35229729Smckusick /* 35329729Smckusick * We may still own the socket, and may have a pending SIGURG 35429729Smckusick * (or might receive one soon) that we really want to send to 35529729Smckusick * the reader. Set a trap that simply copies such signals to 35629729Smckusick * the child. 35729729Smckusick */ 35829729Smckusick (void) signal(SIGURG, copytochild); 35929729Smckusick (void) signal(SIGUSR1, writeroob); 36029729Smckusick (void) sigsetmask(oldmask); 36129729Smckusick (void) signal(SIGCHLD, catchild); 3629365Ssam writer(); 36312155Ssam prf("Closed connection."); 36425424Skarels done(0); 3656444Swnj } 3666444Swnj 36729729Smckusick /* 36829729Smckusick * Trap a signal, unless it is being ignored. 36929729Smckusick */ 37029729Smckusick setsignal(sig, act) 37129729Smckusick int sig, (*act)(); 37229729Smckusick { 37329729Smckusick int omask = sigblock(sigmask(sig)); 37429729Smckusick 37529729Smckusick if (signal(sig, act) == SIG_IGN) 37629729Smckusick (void) signal(sig, SIG_IGN); 37729729Smckusick (void) sigsetmask(omask); 37829729Smckusick } 37929729Smckusick 38025424Skarels done(status) 38125424Skarels int status; 3826444Swnj { 38329729Smckusick int w; 3846444Swnj 3856444Swnj mode(0); 38629729Smckusick if (child > 0) { 38729729Smckusick /* make sure catchild does not snap it up */ 38829729Smckusick (void) signal(SIGCHLD, SIG_DFL); 38929729Smckusick if (kill(child, SIGKILL) >= 0) 39029729Smckusick while ((w = wait((union wait *)0)) > 0 && w != child) 39129729Smckusick /*void*/; 39229729Smckusick } 39325424Skarels exit(status); 3946444Swnj } 3956444Swnj 39624726Smckusick /* 39729729Smckusick * Copy SIGURGs to the child process. 39829729Smckusick */ 39929729Smckusick copytochild() 40029729Smckusick { 40129729Smckusick 40229729Smckusick (void) kill(child, SIGURG); 40329729Smckusick } 40429729Smckusick 40529729Smckusick /* 40624726Smckusick * This is called when the reader process gets the out-of-band (urgent) 40724726Smckusick * request to turn on the window-changing protocol. 40824726Smckusick */ 40924726Smckusick writeroob() 41024726Smckusick { 41124726Smckusick 41225341Smckusick if (dosigwinch == 0) { 41324919Smckusick sendwindow(); 41429729Smckusick (void) signal(SIGWINCH, sigwinch); 41525341Smckusick } 41624726Smckusick dosigwinch = 1; 41724726Smckusick } 41824726Smckusick 41911803Sedward catchild() 42011803Sedward { 42111803Sedward union wait status; 42211803Sedward int pid; 42311803Sedward 42411803Sedward again: 42529729Smckusick pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); 42611803Sedward if (pid == 0) 42711803Sedward return; 42811803Sedward /* 42911803Sedward * if the child (reader) dies, just quit 43011803Sedward */ 43111803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 43229729Smckusick done((int)(status.w_termsig | status.w_retcode)); 43311803Sedward goto again; 43411803Sedward } 43511803Sedward 4366444Swnj /* 4379365Ssam * writer: write to remote: 0 -> line. 4389365Ssam * ~. terminate 4399365Ssam * ~^Z suspend rlogin process. 44010415Ssam * ~^Y suspend rlogin process, but leave reader alone. 4416444Swnj */ 4429365Ssam writer() 4436444Swnj { 44423530Sbloom char c; 44511803Sedward register n; 44623530Sbloom register bol = 1; /* beginning of line */ 44723530Sbloom register local = 0; 4486444Swnj 44911803Sedward for (;;) { 45011803Sedward n = read(0, &c, 1); 45118358Ssam if (n <= 0) { 45218358Ssam if (n < 0 && errno == EINTR) 45318358Ssam continue; 45411803Sedward break; 45518358Ssam } 4569365Ssam /* 4579365Ssam * If we're at the beginning of the line 4589365Ssam * and recognize a command character, then 4599365Ssam * we echo locally. Otherwise, characters 4609365Ssam * are echo'd remotely. If the command 4619365Ssam * character is doubled, this acts as a 4629365Ssam * force and local echo is suppressed. 4639365Ssam */ 46423530Sbloom if (bol) { 46523530Sbloom bol = 0; 46623530Sbloom if (c == cmdchar) { 46723530Sbloom bol = 0; 46823530Sbloom local = 1; 46923530Sbloom continue; 4706444Swnj } 47123530Sbloom } else if (local) { 47223530Sbloom local = 0; 47323530Sbloom if (c == '.' || c == deftc.t_eofc) { 47423530Sbloom echo(c); 47523530Sbloom break; 4766444Swnj } 47723530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 47823530Sbloom bol = 1; 47923530Sbloom echo(c); 48023530Sbloom stop(c); 48123530Sbloom continue; 48223530Sbloom } 48336511Skfall if (c != cmdchar) { 48436511Skfall #ifdef KERBEROS 48536511Skfall if(encrypt) { 48636511Skfall (void) des_write( 48736511Skfall rem, 48836511Skfall &cmdchar, 48936511Skfall 1 49036511Skfall ); 49136511Skfall } else 49236511Skfall #endif 49336511Skfall (void) write( 49436511Skfall rem, 49536511Skfall &cmdchar, 49636511Skfall 1 49736511Skfall ); 49836511Skfall } 4996444Swnj } 50036511Skfall 50136511Skfall #ifdef KERBEROS 50236511Skfall if(encrypt) { 50336511Skfall if (des_write(rem, &c, 1) == 0) { 50436511Skfall prf("line gone"); 50536511Skfall break; 50636511Skfall } 50736511Skfall } else 50836511Skfall #endif 50936511Skfall if (write(rem, &c, 1) == 0) { 51036511Skfall prf("line gone"); 51136511Skfall break; 51236511Skfall } 51323530Sbloom bol = c == defkill || c == deftc.t_eofc || 51425424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 51523530Sbloom c == '\r' || c == '\n'; 5166444Swnj } 5176444Swnj } 5186444Swnj 51923530Sbloom echo(c) 52023530Sbloom register char c; 52123530Sbloom { 52223530Sbloom char buf[8]; 52323530Sbloom register char *p = buf; 52423530Sbloom 52523530Sbloom c &= 0177; 52623530Sbloom *p++ = cmdchar; 52723530Sbloom if (c < ' ') { 52823530Sbloom *p++ = '^'; 52923530Sbloom *p++ = c + '@'; 53023530Sbloom } else if (c == 0177) { 53123530Sbloom *p++ = '^'; 53223530Sbloom *p++ = '?'; 53323530Sbloom } else 53423530Sbloom *p++ = c; 53523530Sbloom *p++ = '\r'; 53623530Sbloom *p++ = '\n'; 53729729Smckusick (void) write(1, buf, p - buf); 53823530Sbloom } 53923530Sbloom 54018358Ssam stop(cmdc) 54118358Ssam char cmdc; 54218358Ssam { 54318358Ssam mode(0); 54429729Smckusick (void) signal(SIGCHLD, SIG_IGN); 54529729Smckusick (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 54629729Smckusick (void) signal(SIGCHLD, catchild); 54718358Ssam mode(1); 54818358Ssam sigwinch(); /* check for size changes */ 54918358Ssam } 55018358Ssam 55118358Ssam sigwinch() 55218358Ssam { 55318358Ssam struct winsize ws; 55418358Ssam 55529729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 55618358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 55718358Ssam winsize = ws; 55824726Smckusick sendwindow(); 55918358Ssam } 56018358Ssam } 56118358Ssam 56224726Smckusick /* 56324726Smckusick * Send the window size to the server via the magic escape 56424726Smckusick */ 56524726Smckusick sendwindow() 56624726Smckusick { 56724726Smckusick char obuf[4 + sizeof (struct winsize)]; 56824726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 56924726Smckusick 57024726Smckusick obuf[0] = 0377; 57124726Smckusick obuf[1] = 0377; 57224726Smckusick obuf[2] = 's'; 57324726Smckusick obuf[3] = 's'; 57424726Smckusick wp->ws_row = htons(winsize.ws_row); 57524726Smckusick wp->ws_col = htons(winsize.ws_col); 57624726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 57724726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 57836511Skfall 57936511Skfall #ifdef KERBEROS 58036511Skfall if(encrypt) 58136511Skfall (void) des_write(rem, obuf, sizeof(obuf)); 58236511Skfall else 58336511Skfall #endif 58436511Skfall (void) write(rem, obuf, sizeof(obuf)); 58524726Smckusick } 58624726Smckusick 58725424Skarels /* 58825424Skarels * reader: read from remote: line -> 1 58925424Skarels */ 59025424Skarels #define READING 1 59125424Skarels #define WRITING 2 59225424Skarels 59325424Skarels char rcvbuf[8 * 1024]; 59425424Skarels int rcvcnt; 59525424Skarels int rcvstate; 59626981Skarels int ppid; 59725424Skarels jmp_buf rcvtop; 59825424Skarels 5996444Swnj oob() 6006444Swnj { 60125424Skarels int out = FWRITE, atmark, n; 60225424Skarels int rcvd = 0; 6039365Ssam char waste[BUFSIZ], mark; 60424726Smckusick struct sgttyb sb; 6056444Swnj 60625424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 60725424Skarels switch (errno) { 60825424Skarels 60925424Skarels case EWOULDBLOCK: 61025424Skarels /* 61125424Skarels * Urgent data not here yet. 61225424Skarels * It may not be possible to send it yet 61325424Skarels * if we are blocked for output 61425424Skarels * and our input buffer is full. 61525424Skarels */ 61625424Skarels if (rcvcnt < sizeof(rcvbuf)) { 61725424Skarels n = read(rem, rcvbuf + rcvcnt, 61825424Skarels sizeof(rcvbuf) - rcvcnt); 61925424Skarels if (n <= 0) 62025424Skarels return; 62125424Skarels rcvd += n; 62225424Skarels } else { 62325424Skarels n = read(rem, waste, sizeof(waste)); 62425424Skarels if (n <= 0) 62525424Skarels return; 62625424Skarels } 62725424Skarels continue; 62825424Skarels 62925424Skarels default: 63025424Skarels return; 6316444Swnj } 63225424Skarels if (mark & TIOCPKT_WINDOW) { 63324726Smckusick /* 63424726Smckusick * Let server know about window size changes 63524726Smckusick */ 63629729Smckusick (void) kill(ppid, SIGUSR1); 63724726Smckusick } 63825424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 63929729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 64024726Smckusick sb.sg_flags &= ~CBREAK; 64124726Smckusick sb.sg_flags |= RAW; 64229729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 64313075Ssam notc.t_stopc = -1; 64413075Ssam notc.t_startc = -1; 64529729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6466444Swnj } 64725424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 64829729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 64924726Smckusick sb.sg_flags &= ~RAW; 65024726Smckusick sb.sg_flags |= CBREAK; 65129729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 65213075Ssam notc.t_stopc = deftc.t_stopc; 65313075Ssam notc.t_startc = deftc.t_startc; 65429729Smckusick (void) ioctl(0, TIOCSETC, (char *)¬c); 6556444Swnj } 65625424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 65729729Smckusick (void) ioctl(1, TIOCFLUSH, (char *)&out); 65825424Skarels for (;;) { 65925424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 66025424Skarels perror("ioctl"); 66125424Skarels break; 66225424Skarels } 66325424Skarels if (atmark) 66425424Skarels break; 66525424Skarels n = read(rem, waste, sizeof (waste)); 66625424Skarels if (n <= 0) 66725424Skarels break; 66825424Skarels } 66925424Skarels /* 67025424Skarels * Don't want any pending data to be output, 67125424Skarels * so clear the recv buffer. 67225424Skarels * If we were hanging on a write when interrupted, 67325424Skarels * don't want it to restart. If we were reading, 67425424Skarels * restart anyway. 67525424Skarels */ 67625424Skarels rcvcnt = 0; 67725424Skarels longjmp(rcvtop, 1); 67825424Skarels } 67929729Smckusick 68025424Skarels /* 68129729Smckusick * oob does not do FLUSHREAD (alas!) 68229729Smckusick */ 68329729Smckusick 68429729Smckusick /* 68525424Skarels * If we filled the receive buffer while a read was pending, 68625424Skarels * longjmp to the top to restart appropriately. Don't abort 68725424Skarels * a pending write, however, or we won't know how much was written. 68825424Skarels */ 68925424Skarels if (rcvd && rcvstate == READING) 69025424Skarels longjmp(rcvtop, 1); 6916444Swnj } 6926444Swnj 6939365Ssam /* 6949365Ssam * reader: read from remote: line -> 1 6959365Ssam */ 69629729Smckusick reader(oldmask) 69729729Smckusick int oldmask; 6986444Swnj { 69926981Skarels #if !defined(BSD) || BSD < 43 70026981Skarels int pid = -getpid(); 70126981Skarels #else 70225424Skarels int pid = getpid(); 70326981Skarels #endif 70425424Skarels int n, remaining; 70525424Skarels char *bufp = rcvbuf; 7066444Swnj 70729729Smckusick (void) signal(SIGTTOU, SIG_IGN); 70829729Smckusick (void) signal(SIGURG, oob); 70926981Skarels ppid = getppid(); 71029729Smckusick (void) fcntl(rem, F_SETOWN, pid); 71125424Skarels (void) setjmp(rcvtop); 71229729Smckusick (void) sigsetmask(oldmask); 7136444Swnj for (;;) { 71425424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 71525424Skarels rcvstate = WRITING; 71625424Skarels n = write(1, bufp, remaining); 71725424Skarels if (n < 0) { 71825424Skarels if (errno != EINTR) 71926189Slepreau return (-1); 72025424Skarels continue; 72125424Skarels } 72225424Skarels bufp += n; 72325424Skarels } 72425424Skarels bufp = rcvbuf; 72525424Skarels rcvcnt = 0; 72625424Skarels rcvstate = READING; 72736511Skfall 72836511Skfall #ifdef KERBEROS 72936511Skfall if(encrypt) 73036511Skfall rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 73136511Skfall else 73236511Skfall #endif 73336511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 73425424Skarels if (rcvcnt == 0) 73525424Skarels return (0); 73625424Skarels if (rcvcnt < 0) { 7379365Ssam if (errno == EINTR) 7386444Swnj continue; 73926981Skarels perror("read"); 74025424Skarels return (-1); 7416444Swnj } 7426444Swnj } 7436444Swnj } 7446444Swnj 7456444Swnj mode(f) 7466444Swnj { 74713075Ssam struct tchars *tc; 74813075Ssam struct ltchars *ltc; 74913075Ssam struct sgttyb sb; 75021583Sbloom int lflags; 7519365Ssam 75229729Smckusick (void) ioctl(0, TIOCGETP, (char *)&sb); 75329729Smckusick (void) ioctl(0, TIOCLGET, (char *)&lflags); 7549962Ssam switch (f) { 7559962Ssam 7569962Ssam case 0: 75713075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 75813075Ssam sb.sg_flags |= defflags|tabflag; 7599962Ssam tc = &deftc; 76013075Ssam ltc = &defltc; 76113075Ssam sb.sg_kill = defkill; 76213075Ssam sb.sg_erase = deferase; 76321583Sbloom lflags = deflflags; 7649962Ssam break; 7659962Ssam 7669962Ssam case 1: 76713075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 76813075Ssam sb.sg_flags &= ~defflags; 76912155Ssam /* preserve tab delays, but turn off XTABS */ 77013075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 77113075Ssam sb.sg_flags &= ~TBDELAY; 7729962Ssam tc = ¬c; 77313075Ssam ltc = &noltc; 77413075Ssam sb.sg_kill = sb.sg_erase = -1; 77521583Sbloom if (litout) 77621583Sbloom lflags |= LLITOUT; 7779962Ssam break; 7789962Ssam 7799962Ssam default: 7809962Ssam return; 7816444Swnj } 78229729Smckusick (void) ioctl(0, TIOCSLTC, (char *)ltc); 78329729Smckusick (void) ioctl(0, TIOCSETC, (char *)tc); 78429729Smckusick (void) ioctl(0, TIOCSETN, (char *)&sb); 78529729Smckusick (void) ioctl(0, TIOCLSET, (char *)&lflags); 7866444Swnj } 7876444Swnj 7889365Ssam /*VARARGS*/ 78924726Smckusick prf(f, a1, a2, a3, a4, a5) 7909365Ssam char *f; 7916444Swnj { 79229729Smckusick 79324726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 7946444Swnj fprintf(stderr, CRLF); 7956444Swnj } 7966444Swnj 7979365Ssam lostpeer() 7986444Swnj { 79929729Smckusick 80029729Smckusick (void) signal(SIGPIPE, SIG_IGN); 80112155Ssam prf("\007Connection closed."); 80225424Skarels done(1); 8036444Swnj } 80436512Skfall 80536512Skfall old_warning(str) 80636512Skfall char *str; 80736512Skfall { 80836512Skfall prf("Warning: %s, using standard rlogin", str); 80936512Skfall } 810