144346Skarels /* 240858Sbostic * Copyright (c) 1983, 1990 The Regents of the University of California. 335539Sbostic * All rights reserved. 435539Sbostic * 542763Sbostic * %sccs.include.redist.c% 621595Sdist */ 721595Sdist 86444Swnj #ifndef lint 921595Sdist char copyright[] = 1040858Sbostic "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ 1121595Sdist All rights reserved.\n"; 1235539Sbostic #endif /* not lint */ 136444Swnj 1421595Sdist #ifndef lint 15*45063Sbostic static char sccsid[] = "@(#)rlogin.c 5.30 (Berkeley) 08/23/90"; 1635539Sbostic #endif /* not lint */ 1721595Sdist 1812990Ssam /* 1940858Sbostic * $Source: mit/rlogin/RCS/rlogin.c,v $ 2042763Sbostic * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall 2142763Sbostic * Exp Locker: kfall $ 2240858Sbostic */ 2340858Sbostic 2440858Sbostic /* 2512990Ssam * rlogin - remote login 2612990Ssam */ 2726981Skarels #include <sys/param.h> 2824727Smckusick #include <sys/file.h> 296444Swnj #include <sys/socket.h> 3040858Sbostic #include <sys/signal.h> 3129729Smckusick #include <sys/time.h> 3229729Smckusick #include <sys/resource.h> 3313620Ssam #include <sys/wait.h> 349365Ssam 359207Ssam #include <netinet/in.h> 3644346Skarels #include <netinet/in_systm.h> 3744346Skarels #include <netinet/ip.h> 3840858Sbostic #include <netdb.h> 399365Ssam 409365Ssam #include <sgtty.h> 4140858Sbostic #include <setjmp.h> 42*45063Sbostic #include <varargs.h> 436444Swnj #include <errno.h> 446444Swnj #include <pwd.h> 4540858Sbostic #include <stdio.h> 4640858Sbostic #include <unistd.h> 4742058Sbostic #include <string.h> 486444Swnj 4940858Sbostic #ifdef KERBEROS 5041760Skfall #include <kerberosIV/des.h> 5140683Sbostic #include <kerberosIV/krb.h> 5236511Skfall 5340858Sbostic CREDENTIALS cred; 5440858Sbostic Key_schedule schedule; 5540858Sbostic int use_kerberos = 1, encrypt; 5640858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 5740858Sbostic extern char *krb_realmofhost(); 5840858Sbostic #endif 5924726Smckusick 6040858Sbostic #ifndef TIOCPKT_WINDOW 6140858Sbostic #define TIOCPKT_WINDOW 0x80 6240858Sbostic #endif 6329729Smckusick 6440858Sbostic /* concession to Sun */ 6540858Sbostic #ifndef SIGUSR1 6640858Sbostic #define SIGUSR1 30 6726981Skarels #endif 6840858Sbostic 6940858Sbostic extern int errno; 7040858Sbostic int eight, litout, rem; 71*45063Sbostic 72*45063Sbostic int noescape; 73*45063Sbostic u_char escapechar = '~'; 74*45063Sbostic 7540858Sbostic char *speeds[] = { 7640858Sbostic "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 7740858Sbostic "1800", "2400", "4800", "9600", "19200", "38400" 7840858Sbostic }; 7940858Sbostic 8026981Skarels #ifdef sun 8126981Skarels struct winsize { 8226981Skarels unsigned short ws_row, ws_col; 8326981Skarels unsigned short ws_xpixel, ws_ypixel; 8426981Skarels }; 8540858Sbostic #endif 8618358Ssam struct winsize winsize; 876444Swnj 8840858Sbostic #ifndef sun 8940858Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 9040858Sbostic #endif 9129729Smckusick 9240858Sbostic void exit(); 9329729Smckusick 946444Swnj main(argc, argv) 956444Swnj int argc; 966444Swnj char **argv; 976444Swnj { 9840858Sbostic extern char *optarg; 9940858Sbostic extern int optind; 10040858Sbostic struct passwd *pw; 10140858Sbostic struct servent *sp; 1026444Swnj struct sgttyb ttyb; 10340858Sbostic long omask; 10440858Sbostic int argoff, ch, dflag, one, uid; 10540858Sbostic char *host, *p, *user, term[1024]; 10640858Sbostic void lostpeer(); 107*45063Sbostic u_char getescape(); 10840858Sbostic char *getenv(); 1096444Swnj 11040858Sbostic argoff = dflag = 0; 11140858Sbostic one = 1; 11240858Sbostic host = user = NULL; 11340858Sbostic 11440858Sbostic if (p = rindex(argv[0], '/')) 11540858Sbostic ++p; 1166444Swnj else 11740858Sbostic p = argv[0]; 11840858Sbostic 11940858Sbostic if (strcmp(p, "rlogin")) 12040858Sbostic host = p; 12140858Sbostic 12240858Sbostic /* handle "rlogin host flags" */ 12340858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 12440858Sbostic host = argv[1]; 12540858Sbostic argoff = 1; 1266444Swnj } 12736511Skfall 12840858Sbostic #ifdef KERBEROS 129*45063Sbostic #define OPTIONS "8EKLde:k:l:x" 13040858Sbostic #else 131*45063Sbostic #define OPTIONS "8EKLde:l:" 13240858Sbostic #endif 13340858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 13440858Sbostic switch(ch) { 13540858Sbostic case '8': 13640858Sbostic eight = 1; 13740858Sbostic break; 138*45063Sbostic case 'E': 139*45063Sbostic noescape = 1; 140*45063Sbostic break; 14140868Sbostic case 'K': 14240868Sbostic #ifdef KERBEROS 14340868Sbostic use_kerberos = 0; 14440868Sbostic #endif 14540868Sbostic break; 14640858Sbostic case 'L': 14740858Sbostic litout = 1; 14840858Sbostic break; 14940858Sbostic case 'd': 15040858Sbostic dflag = 1; 15140858Sbostic break; 15240858Sbostic case 'e': 153*45063Sbostic escapechar = getescape(optarg); 15440858Sbostic break; 15540858Sbostic #ifdef KERBEROS 15640858Sbostic case 'k': 15740858Sbostic dest_realm = dst_realm_buf; 15840858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 15940858Sbostic break; 16040858Sbostic #endif 16140858Sbostic case 'l': 16240858Sbostic user = optarg; 16340858Sbostic break; 16440858Sbostic #ifdef KERBEROS 16540858Sbostic case 'x': 16640858Sbostic encrypt = 1; 16740858Sbostic des_set_key(cred.session, schedule); 16840858Sbostic break; 16940858Sbostic #endif 17040858Sbostic case '?': 17140858Sbostic default: 17240858Sbostic usage(); 17336524Skfall } 17440858Sbostic optind += argoff; 17540858Sbostic argc -= optind; 17640858Sbostic argv += optind; 17736524Skfall 17840858Sbostic /* if haven't gotten a host yet, do so */ 17940858Sbostic if (!host && !(host = *argv++)) 18040858Sbostic usage(); 18136511Skfall 18240858Sbostic if (*argv) 18340858Sbostic usage(); 18440858Sbostic 18540858Sbostic if (!(pw = getpwuid(uid = getuid()))) { 18640858Sbostic (void)fprintf(stderr, "rlogin: unknown user id.\n"); 1876444Swnj exit(1); 1886444Swnj } 18940858Sbostic if (!user) 19040858Sbostic user = pw->pw_name; 19140858Sbostic 19240868Sbostic sp = NULL; 19340858Sbostic #ifdef KERBEROS 19440868Sbostic if (use_kerberos) { 19540868Sbostic sp = getservbyname((encrypt ? "eklogin" : "klogin"), "tcp"); 19640868Sbostic if (sp == NULL) { 19740868Sbostic use_kerberos = 0; 19840868Sbostic warning("can't get entry for %s/tcp service", 19940868Sbostic encrypt ? "eklogin" : "klogin"); 20040868Sbostic } 20136512Skfall } 20236512Skfall #endif 20340868Sbostic if (sp == NULL) 20440868Sbostic sp = getservbyname("login", "tcp"); 20540858Sbostic if (sp == NULL) { 20640858Sbostic (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 20740858Sbostic exit(1); 2089365Ssam } 20940858Sbostic 21040858Sbostic (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 21118358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 21240858Sbostic (void)strcat(term, "/"); 21340858Sbostic (void)strcat(term, speeds[ttyb.sg_ospeed]); 2146444Swnj } 21540858Sbostic 21640858Sbostic (void)get_window_size(0, &winsize); 21740858Sbostic 21840858Sbostic (void)signal(SIGPIPE, lostpeer); 21929729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 22040858Sbostic omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 22136511Skfall 22240858Sbostic #ifdef KERBEROS 22336512Skfall try_connect: 22440858Sbostic if (use_kerberos) { 22536512Skfall rem = KSUCCESS; 22640858Sbostic errno = 0; 22738728Skfall if (dest_realm == NULL) 22838728Skfall dest_realm = krb_realmofhost(host); 22938728Skfall 23040858Sbostic if (encrypt) 23140858Sbostic rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 23240858Sbostic dest_realm, &cred, schedule); 23340858Sbostic else 23440858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 23540858Sbostic dest_realm); 23638728Skfall if (rem < 0) { 23736512Skfall use_kerberos = 0; 23836628Skfall sp = getservbyname("login", "tcp"); 23940858Sbostic if (sp == NULL) { 24040858Sbostic (void)fprintf(stderr, 24140858Sbostic "rlogin: unknown service login/tcp.\n"); 24236628Skfall exit(1); 24336628Skfall } 24438728Skfall if (errno == ECONNREFUSED) 24540858Sbostic warning("remote host doesn't support Kerberos"); 24638728Skfall if (errno == ENOENT) 24740858Sbostic warning("can't provide Kerberos auth data"); 24836512Skfall goto try_connect; 24936512Skfall } 25036511Skfall } else { 25140858Sbostic if (encrypt) { 25240858Sbostic (void)fprintf(stderr, 25340858Sbostic "rlogin: the -x flag requires Kerberos authentication.\n"); 25436512Skfall exit(1); 25536512Skfall } 25640858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 25736511Skfall } 25836512Skfall #else 25940858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 26036512Skfall #endif 26136511Skfall 26240858Sbostic if (rem < 0) 26336511Skfall exit(1); 26436511Skfall 26540858Sbostic if (dflag && 26640858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 26740858Sbostic (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 26840858Sbostic strerror(errno)); 26944346Skarels one = IPTOS_LOWDELAY; 27044346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 27144346Skarels perror("rlogin: setsockopt TOS (ignored)"); 27240858Sbostic 27340858Sbostic (void)setuid(uid); 27440858Sbostic doit(omask); 2759365Ssam /*NOTREACHED*/ 2766444Swnj } 2776444Swnj 27840858Sbostic int child, defflags, deflflags, tabflag; 27940858Sbostic char deferase, defkill; 28040858Sbostic struct tchars deftc; 28140858Sbostic struct ltchars defltc; 28240858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 28340858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 2846444Swnj 28540858Sbostic doit(omask) 28640858Sbostic long omask; 2876444Swnj { 28813075Ssam struct sgttyb sb; 28940858Sbostic void catch_child(), copytochild(), exit(), writeroob(); 2906444Swnj 29140858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 29213075Ssam defflags = sb.sg_flags; 29312155Ssam tabflag = defflags & TBDELAY; 2949962Ssam defflags &= ECHO | CRMOD; 29513075Ssam deferase = sb.sg_erase; 29613075Ssam defkill = sb.sg_kill; 29740858Sbostic (void)ioctl(0, TIOCLGET, (char *)&deflflags); 29840858Sbostic (void)ioctl(0, TIOCGETC, (char *)&deftc); 29913075Ssam notc.t_startc = deftc.t_startc; 30013075Ssam notc.t_stopc = deftc.t_stopc; 30140858Sbostic (void)ioctl(0, TIOCGLTC, (char *)&defltc); 30240858Sbostic (void)signal(SIGINT, SIG_IGN); 30329729Smckusick setsignal(SIGHUP, exit); 30429729Smckusick setsignal(SIGQUIT, exit); 3059365Ssam child = fork(); 3069365Ssam if (child == -1) { 30740858Sbostic (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 30825424Skarels done(1); 3099365Ssam } 3109365Ssam if (child == 0) { 31124726Smckusick mode(1); 31240858Sbostic if (reader(omask) == 0) { 31340858Sbostic msg("connection closed."); 31425424Skarels exit(0); 31525424Skarels } 31612155Ssam sleep(1); 31740858Sbostic msg("\007connection closed."); 31840858Sbostic exit(1); 3196444Swnj } 32029729Smckusick 32129729Smckusick /* 32240858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 32340858Sbostic * receive one soon) that we really want to send to the reader. Set a 32440858Sbostic * trap that simply copies such signals to the child. 32529729Smckusick */ 32640858Sbostic (void)signal(SIGURG, copytochild); 32740858Sbostic (void)signal(SIGUSR1, writeroob); 32840858Sbostic (void)sigsetmask(omask); 32940858Sbostic (void)signal(SIGCHLD, catch_child); 3309365Ssam writer(); 33140858Sbostic msg("closed connection."); 33225424Skarels done(0); 3336444Swnj } 3346444Swnj 33540858Sbostic /* trap a signal, unless it is being ignored. */ 33629729Smckusick setsignal(sig, act) 33740858Sbostic int sig; 33840858Sbostic void (*act)(); 33929729Smckusick { 34029729Smckusick int omask = sigblock(sigmask(sig)); 34129729Smckusick 34229729Smckusick if (signal(sig, act) == SIG_IGN) 34340858Sbostic (void)signal(sig, SIG_IGN); 34440858Sbostic (void)sigsetmask(omask); 34529729Smckusick } 34629729Smckusick 34725424Skarels done(status) 34825424Skarels int status; 3496444Swnj { 35029729Smckusick int w; 3516444Swnj 3526444Swnj mode(0); 35329729Smckusick if (child > 0) { 35440858Sbostic /* make sure catch_child does not snap it up */ 35540858Sbostic (void)signal(SIGCHLD, SIG_DFL); 35629729Smckusick if (kill(child, SIGKILL) >= 0) 35740858Sbostic while ((w = wait((union wait *)0)) > 0 && w != child); 35829729Smckusick } 35925424Skarels exit(status); 3606444Swnj } 3616444Swnj 36240858Sbostic int dosigwinch; 36329729Smckusick 36429729Smckusick /* 36524726Smckusick * This is called when the reader process gets the out-of-band (urgent) 36624726Smckusick * request to turn on the window-changing protocol. 36724726Smckusick */ 36840858Sbostic void 36924726Smckusick writeroob() 37024726Smckusick { 37140858Sbostic void sigwinch(); 37224726Smckusick 37325341Smckusick if (dosigwinch == 0) { 37424919Smckusick sendwindow(); 37540858Sbostic (void)signal(SIGWINCH, sigwinch); 37625341Smckusick } 37724726Smckusick dosigwinch = 1; 37824726Smckusick } 37924726Smckusick 38040858Sbostic void 38140858Sbostic catch_child() 38211803Sedward { 38311803Sedward union wait status; 38411803Sedward int pid; 38511803Sedward 38640858Sbostic for (;;) { 38740858Sbostic pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); 38840858Sbostic if (pid == 0) 38940858Sbostic return; 39040858Sbostic /* if the child (reader) dies, just quit */ 39140858Sbostic if (pid < 0 || pid == child && !WIFSTOPPED(status)) 39240858Sbostic done((int)(status.w_termsig | status.w_retcode)); 39340858Sbostic } 39440858Sbostic /* NOTREACHED */ 39511803Sedward } 39611803Sedward 3976444Swnj /* 3989365Ssam * writer: write to remote: 0 -> line. 399*45063Sbostic * ~. terminate 400*45063Sbostic * ~^Z suspend rlogin process. 401*45063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4026444Swnj */ 4039365Ssam writer() 4046444Swnj { 405*45063Sbostic register int bol, local, n; 40623530Sbloom char c; 4076444Swnj 40840858Sbostic bol = 1; /* beginning of line */ 40940858Sbostic local = 0; 41011803Sedward for (;;) { 41140858Sbostic n = read(STDIN_FILENO, &c, 1); 41218358Ssam if (n <= 0) { 41318358Ssam if (n < 0 && errno == EINTR) 41418358Ssam continue; 41511803Sedward break; 41618358Ssam } 4179365Ssam /* 41840858Sbostic * If we're at the beginning of the line and recognize a 41940858Sbostic * command character, then we echo locally. Otherwise, 42040858Sbostic * characters are echo'd remotely. If the command character 42140858Sbostic * is doubled, this acts as a force and local echo is 42240858Sbostic * suppressed. 4239365Ssam */ 42423530Sbloom if (bol) { 42523530Sbloom bol = 0; 426*45063Sbostic if (!noescape && c == escapechar) { 42723530Sbloom local = 1; 42823530Sbloom continue; 4296444Swnj } 43023530Sbloom } else if (local) { 43123530Sbloom local = 0; 43223530Sbloom if (c == '.' || c == deftc.t_eofc) { 43323530Sbloom echo(c); 43423530Sbloom break; 4356444Swnj } 43623530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 43723530Sbloom bol = 1; 43823530Sbloom echo(c); 43923530Sbloom stop(c); 44023530Sbloom continue; 44123530Sbloom } 442*45063Sbostic if (c != escapechar) 44340858Sbostic #ifdef KERBEROS 444*45063Sbostic if (encrypt) 445*45063Sbostic (void)des_write(rem, &escapechar, 1); 446*45063Sbostic else 44736511Skfall #endif 448*45063Sbostic (void)write(rem, &escapechar, 1); 4496444Swnj } 45036511Skfall 45140858Sbostic #ifdef KERBEROS 45240858Sbostic if (encrypt) { 45336511Skfall if (des_write(rem, &c, 1) == 0) { 45440858Sbostic msg("line gone"); 45536511Skfall break; 45636511Skfall } 45736511Skfall } else 45836511Skfall #endif 45936511Skfall if (write(rem, &c, 1) == 0) { 46040858Sbostic msg("line gone"); 46136511Skfall break; 46236511Skfall } 46323530Sbloom bol = c == defkill || c == deftc.t_eofc || 46425424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 46523530Sbloom c == '\r' || c == '\n'; 4666444Swnj } 4676444Swnj } 4686444Swnj 46923530Sbloom echo(c) 47023530Sbloom register char c; 47123530Sbloom { 47240858Sbostic register char *p; 47323530Sbloom char buf[8]; 47423530Sbloom 47540858Sbostic p = buf; 47623530Sbloom c &= 0177; 477*45063Sbostic *p++ = escapechar; 47823530Sbloom if (c < ' ') { 47923530Sbloom *p++ = '^'; 48023530Sbloom *p++ = c + '@'; 48123530Sbloom } else if (c == 0177) { 48223530Sbloom *p++ = '^'; 48323530Sbloom *p++ = '?'; 48423530Sbloom } else 48523530Sbloom *p++ = c; 48623530Sbloom *p++ = '\r'; 48723530Sbloom *p++ = '\n'; 488*45063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 48923530Sbloom } 49023530Sbloom 49118358Ssam stop(cmdc) 49218358Ssam char cmdc; 49318358Ssam { 49418358Ssam mode(0); 49540858Sbostic (void)signal(SIGCHLD, SIG_IGN); 49640858Sbostic (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 49740858Sbostic (void)signal(SIGCHLD, catch_child); 49818358Ssam mode(1); 49918358Ssam sigwinch(); /* check for size changes */ 50018358Ssam } 50118358Ssam 50240858Sbostic void 50318358Ssam sigwinch() 50418358Ssam { 50518358Ssam struct winsize ws; 50618358Ssam 50729729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 50840858Sbostic bcmp(&ws, &winsize, sizeof(ws))) { 50918358Ssam winsize = ws; 51024726Smckusick sendwindow(); 51118358Ssam } 51218358Ssam } 51318358Ssam 51424726Smckusick /* 51524726Smckusick * Send the window size to the server via the magic escape 51624726Smckusick */ 51724726Smckusick sendwindow() 51824726Smckusick { 51940858Sbostic struct winsize *wp; 52024726Smckusick char obuf[4 + sizeof (struct winsize)]; 52124726Smckusick 52240858Sbostic wp = (struct winsize *)(obuf+4); 52324726Smckusick obuf[0] = 0377; 52424726Smckusick obuf[1] = 0377; 52524726Smckusick obuf[2] = 's'; 52624726Smckusick obuf[3] = 's'; 52724726Smckusick wp->ws_row = htons(winsize.ws_row); 52824726Smckusick wp->ws_col = htons(winsize.ws_col); 52924726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 53024726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 53136511Skfall 53240858Sbostic #ifdef KERBEROS 53336511Skfall if(encrypt) 53440858Sbostic (void)des_write(rem, obuf, sizeof(obuf)); 53536511Skfall else 53636511Skfall #endif 53740858Sbostic (void)write(rem, obuf, sizeof(obuf)); 53824726Smckusick } 53924726Smckusick 54025424Skarels /* 54125424Skarels * reader: read from remote: line -> 1 54225424Skarels */ 54325424Skarels #define READING 1 54425424Skarels #define WRITING 2 54525424Skarels 54640858Sbostic jmp_buf rcvtop; 54740858Sbostic int ppid, rcvcnt, rcvstate; 54840858Sbostic char rcvbuf[8 * 1024]; 54925424Skarels 55040858Sbostic void 5516444Swnj oob() 5526444Swnj { 55340858Sbostic struct sgttyb sb; 55440858Sbostic int atmark, n, out, rcvd; 5559365Ssam char waste[BUFSIZ], mark; 5566444Swnj 55742230Sbostic out = O_RDWR; 55840858Sbostic rcvd = 0; 55925424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 56025424Skarels switch (errno) { 56125424Skarels case EWOULDBLOCK: 56225424Skarels /* 56340858Sbostic * Urgent data not here yet. It may not be possible 56440858Sbostic * to send it yet if we are blocked for output and 56540858Sbostic * our input buffer is full. 56625424Skarels */ 56725424Skarels if (rcvcnt < sizeof(rcvbuf)) { 56825424Skarels n = read(rem, rcvbuf + rcvcnt, 56940858Sbostic sizeof(rcvbuf) - rcvcnt); 57025424Skarels if (n <= 0) 57125424Skarels return; 57225424Skarels rcvd += n; 57325424Skarels } else { 57425424Skarels n = read(rem, waste, sizeof(waste)); 57525424Skarels if (n <= 0) 57625424Skarels return; 57725424Skarels } 57825424Skarels continue; 57925424Skarels default: 58025424Skarels return; 5816444Swnj } 58225424Skarels if (mark & TIOCPKT_WINDOW) { 58340858Sbostic /* Let server know about window size changes */ 58440858Sbostic (void)kill(ppid, SIGUSR1); 58524726Smckusick } 58625424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 58740858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 58824726Smckusick sb.sg_flags &= ~CBREAK; 58924726Smckusick sb.sg_flags |= RAW; 59040858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 59113075Ssam notc.t_stopc = -1; 59213075Ssam notc.t_startc = -1; 59340858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 5946444Swnj } 59525424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 59640858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 59724726Smckusick sb.sg_flags &= ~RAW; 59824726Smckusick sb.sg_flags |= CBREAK; 59940858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 60013075Ssam notc.t_stopc = deftc.t_stopc; 60113075Ssam notc.t_startc = deftc.t_startc; 60240858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6036444Swnj } 60425424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 60540858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 60625424Skarels for (;;) { 60725424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 60840858Sbostic (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 60940858Sbostic strerror(errno)); 61025424Skarels break; 61125424Skarels } 61225424Skarels if (atmark) 61325424Skarels break; 61425424Skarels n = read(rem, waste, sizeof (waste)); 61525424Skarels if (n <= 0) 61625424Skarels break; 61725424Skarels } 61825424Skarels /* 61940858Sbostic * Don't want any pending data to be output, so clear the recv 62040858Sbostic * buffer. If we were hanging on a write when interrupted, 62140858Sbostic * don't want it to restart. If we were reading, restart 62240858Sbostic * anyway. 62325424Skarels */ 62425424Skarels rcvcnt = 0; 62525424Skarels longjmp(rcvtop, 1); 62625424Skarels } 62729729Smckusick 62840858Sbostic /* oob does not do FLUSHREAD (alas!) */ 62929729Smckusick 63029729Smckusick /* 63140858Sbostic * If we filled the receive buffer while a read was pending, longjmp 63240858Sbostic * to the top to restart appropriately. Don't abort a pending write, 63340858Sbostic * however, or we won't know how much was written. 63425424Skarels */ 63525424Skarels if (rcvd && rcvstate == READING) 63625424Skarels longjmp(rcvtop, 1); 6376444Swnj } 6386444Swnj 63940858Sbostic /* reader: read from remote: line -> 1 */ 64040858Sbostic reader(omask) 64140858Sbostic int omask; 6426444Swnj { 64340858Sbostic void oob(); 64440858Sbostic 64526981Skarels #if !defined(BSD) || BSD < 43 64626981Skarels int pid = -getpid(); 64726981Skarels #else 64825424Skarels int pid = getpid(); 64926981Skarels #endif 65025424Skarels int n, remaining; 65125424Skarels char *bufp = rcvbuf; 6526444Swnj 65340858Sbostic (void)signal(SIGTTOU, SIG_IGN); 65440858Sbostic (void)signal(SIGURG, oob); 65526981Skarels ppid = getppid(); 65640858Sbostic (void)fcntl(rem, F_SETOWN, pid); 65740858Sbostic (void)setjmp(rcvtop); 65840858Sbostic (void)sigsetmask(omask); 6596444Swnj for (;;) { 66025424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 66125424Skarels rcvstate = WRITING; 662*45063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 66325424Skarels if (n < 0) { 66425424Skarels if (errno != EINTR) 66540858Sbostic return(-1); 66625424Skarels continue; 66725424Skarels } 66825424Skarels bufp += n; 66925424Skarels } 67025424Skarels bufp = rcvbuf; 67125424Skarels rcvcnt = 0; 67225424Skarels rcvstate = READING; 67336511Skfall 67440858Sbostic #ifdef KERBEROS 67540858Sbostic if (encrypt) 67636511Skfall rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 67736511Skfall else 67836511Skfall #endif 67936511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 68025424Skarels if (rcvcnt == 0) 68125424Skarels return (0); 68225424Skarels if (rcvcnt < 0) { 6839365Ssam if (errno == EINTR) 6846444Swnj continue; 68540858Sbostic (void)fprintf(stderr, "rlogin: read: %s.\n", 68640858Sbostic strerror(errno)); 68740858Sbostic return(-1); 6886444Swnj } 6896444Swnj } 6906444Swnj } 6916444Swnj 6926444Swnj mode(f) 6936444Swnj { 69413075Ssam struct ltchars *ltc; 69513075Ssam struct sgttyb sb; 69640858Sbostic struct tchars *tc; 69740858Sbostic int lflags; 6989365Ssam 69940858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 70040858Sbostic (void)ioctl(0, TIOCLGET, (char *)&lflags); 70140858Sbostic switch(f) { 7029962Ssam case 0: 70313075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 70413075Ssam sb.sg_flags |= defflags|tabflag; 7059962Ssam tc = &deftc; 70613075Ssam ltc = &defltc; 70713075Ssam sb.sg_kill = defkill; 70813075Ssam sb.sg_erase = deferase; 70921583Sbloom lflags = deflflags; 7109962Ssam break; 7119962Ssam case 1: 71213075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 71313075Ssam sb.sg_flags &= ~defflags; 71412155Ssam /* preserve tab delays, but turn off XTABS */ 71513075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 71613075Ssam sb.sg_flags &= ~TBDELAY; 7179962Ssam tc = ¬c; 71813075Ssam ltc = &noltc; 71913075Ssam sb.sg_kill = sb.sg_erase = -1; 72021583Sbloom if (litout) 72121583Sbloom lflags |= LLITOUT; 7229962Ssam break; 7239962Ssam default: 7249962Ssam return; 7256444Swnj } 72640858Sbostic (void)ioctl(0, TIOCSLTC, (char *)ltc); 72740858Sbostic (void)ioctl(0, TIOCSETC, (char *)tc); 72840858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 72940858Sbostic (void)ioctl(0, TIOCLSET, (char *)&lflags); 7306444Swnj } 7316444Swnj 73240858Sbostic void 73340858Sbostic lostpeer() 7346444Swnj { 73540858Sbostic (void)signal(SIGPIPE, SIG_IGN); 73640858Sbostic msg("\007connection closed."); 73740858Sbostic done(1); 73840858Sbostic } 73929729Smckusick 74040858Sbostic /* copy SIGURGs to the child process. */ 74140858Sbostic void 74240858Sbostic copytochild() 74340858Sbostic { 74440858Sbostic (void)kill(child, SIGURG); 7456444Swnj } 7466444Swnj 74740858Sbostic msg(str) 74840858Sbostic char *str; 7496444Swnj { 75040858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 75140858Sbostic } 75229729Smckusick 75340858Sbostic #ifdef KERBEROS 75440858Sbostic /* VARARGS */ 75540858Sbostic warning(va_alist) 75640858Sbostic va_dcl 75740858Sbostic { 75840858Sbostic va_list ap; 75940858Sbostic char *fmt; 76040858Sbostic 76140858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 76240858Sbostic va_start(ap); 76340858Sbostic fmt = va_arg(ap, char *); 76440858Sbostic vfprintf(stderr, fmt, ap); 76540858Sbostic va_end(ap); 76640858Sbostic (void)fprintf(stderr, ".\n"); 7676444Swnj } 76840858Sbostic #endif 76936512Skfall 77040858Sbostic usage() 77136512Skfall { 77240858Sbostic (void)fprintf(stderr, 77340858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 77440858Sbostic #ifdef KERBEROS 775*45063Sbostic "8ELx", " [-k realm] "); 77640858Sbostic #else 777*45063Sbostic "8EL", " "); 77840858Sbostic #endif 77940858Sbostic exit(1); 78036512Skfall } 78140858Sbostic 78240858Sbostic /* 78340858Sbostic * The following routine provides compatibility (such as it is) between 4.2BSD 78440858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 78540858Sbostic */ 78640858Sbostic #ifdef sun 78740858Sbostic get_window_size(fd, wp) 78840858Sbostic int fd; 78940858Sbostic struct winsize *wp; 79040858Sbostic { 79140858Sbostic struct ttysize ts; 79240858Sbostic int error; 79340858Sbostic 79440858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 79540858Sbostic return(error); 79640858Sbostic wp->ws_row = ts.ts_lines; 79740858Sbostic wp->ws_col = ts.ts_cols; 79840858Sbostic wp->ws_xpixel = 0; 79940858Sbostic wp->ws_ypixel = 0; 80040858Sbostic return(0); 80140858Sbostic } 80240858Sbostic #endif 803*45063Sbostic 804*45063Sbostic u_char 805*45063Sbostic getescape(p) 806*45063Sbostic register char *p; 807*45063Sbostic { 808*45063Sbostic long val; 809*45063Sbostic int len; 810*45063Sbostic 811*45063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 812*45063Sbostic return((u_char)*p); 813*45063Sbostic /* otherwise, \nnn */ 814*45063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 815*45063Sbostic val = strtol(++p, (char **)NULL, 8); 816*45063Sbostic for (;;) { 817*45063Sbostic if (!*++p) 818*45063Sbostic return((u_char)val); 819*45063Sbostic if (*p < '0' || *p > '8') 820*45063Sbostic break; 821*45063Sbostic } 822*45063Sbostic } 823*45063Sbostic msg("illegal option value -- e"); 824*45063Sbostic usage(); 825*45063Sbostic /* NOTREACHED */ 826*45063Sbostic } 827