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*54125Sbostic static char sccsid[] = "@(#)rlogin.c 5.35 (Berkeley) 06/20/92"; 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> 4245063Sbostic #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; 5546850Sbostic int use_kerberos = 1, doencrypt; 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 int eight, litout, rem; 7045063Sbostic 7145063Sbostic int noescape; 7245063Sbostic u_char escapechar = '~'; 7345063Sbostic 7440858Sbostic char *speeds[] = { 7540858Sbostic "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 7640858Sbostic "1800", "2400", "4800", "9600", "19200", "38400" 7740858Sbostic }; 7840858Sbostic 7926981Skarels #ifdef sun 8026981Skarels struct winsize { 8126981Skarels unsigned short ws_row, ws_col; 8226981Skarels unsigned short ws_xpixel, ws_ypixel; 8326981Skarels }; 8440858Sbostic #endif 8518358Ssam struct winsize winsize; 866444Swnj 8740858Sbostic #ifndef sun 8840858Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 8940858Sbostic #endif 9029729Smckusick 9140858Sbostic void exit(); 9229729Smckusick 936444Swnj main(argc, argv) 946444Swnj int argc; 956444Swnj char **argv; 966444Swnj { 9740858Sbostic extern char *optarg; 9840858Sbostic extern int optind; 9940858Sbostic struct passwd *pw; 10040858Sbostic struct servent *sp; 1016444Swnj struct sgttyb ttyb; 10240858Sbostic long omask; 10340858Sbostic int argoff, ch, dflag, one, uid; 10440858Sbostic char *host, *p, *user, term[1024]; 10540858Sbostic void lostpeer(); 10645063Sbostic u_char getescape(); 10740858Sbostic char *getenv(); 1086444Swnj 10940858Sbostic argoff = dflag = 0; 11040858Sbostic one = 1; 11140858Sbostic host = user = NULL; 11240858Sbostic 11340858Sbostic if (p = rindex(argv[0], '/')) 11440858Sbostic ++p; 1156444Swnj else 11640858Sbostic p = argv[0]; 11740858Sbostic 11840858Sbostic if (strcmp(p, "rlogin")) 11940858Sbostic host = p; 12040858Sbostic 12140858Sbostic /* handle "rlogin host flags" */ 12240858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 12340858Sbostic host = argv[1]; 12440858Sbostic argoff = 1; 1256444Swnj } 12636511Skfall 12740858Sbostic #ifdef KERBEROS 12845063Sbostic #define OPTIONS "8EKLde:k:l:x" 12940858Sbostic #else 13045063Sbostic #define OPTIONS "8EKLde:l:" 13140858Sbostic #endif 13240858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 13340858Sbostic switch(ch) { 13440858Sbostic case '8': 13540858Sbostic eight = 1; 13640858Sbostic break; 13745063Sbostic case 'E': 13845063Sbostic noescape = 1; 13945063Sbostic break; 14040868Sbostic case 'K': 14140868Sbostic #ifdef KERBEROS 14240868Sbostic use_kerberos = 0; 14340868Sbostic #endif 14440868Sbostic break; 14540858Sbostic case 'L': 14640858Sbostic litout = 1; 14740858Sbostic break; 14840858Sbostic case 'd': 14940858Sbostic dflag = 1; 15040858Sbostic break; 15140858Sbostic case 'e': 15253033Sleres noescape = 0; 15345063Sbostic 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; 16453033Sleres #ifdef CRYPT 16553033Sleres #ifdef KERBEROS 16653033Sleres case 'x': 16753033Sleres doencrypt = 1; 16853033Sleres des_set_key(cred.session, schedule); 16953033Sleres break; 17053033Sleres #endif 17153033Sleres #endif 17240858Sbostic case '?': 17340858Sbostic default: 17440858Sbostic usage(); 17536524Skfall } 17640858Sbostic optind += argoff; 17740858Sbostic argc -= optind; 17840858Sbostic argv += optind; 17936524Skfall 18040858Sbostic /* if haven't gotten a host yet, do so */ 18140858Sbostic if (!host && !(host = *argv++)) 18240858Sbostic usage(); 18336511Skfall 18440858Sbostic if (*argv) 18540858Sbostic usage(); 18640858Sbostic 18740858Sbostic if (!(pw = getpwuid(uid = getuid()))) { 18840858Sbostic (void)fprintf(stderr, "rlogin: unknown user id.\n"); 1896444Swnj exit(1); 1906444Swnj } 19140858Sbostic if (!user) 19240858Sbostic user = pw->pw_name; 19340858Sbostic 19440868Sbostic sp = NULL; 19540858Sbostic #ifdef KERBEROS 19640868Sbostic if (use_kerberos) { 19746850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 19840868Sbostic if (sp == NULL) { 19940868Sbostic use_kerberos = 0; 20040868Sbostic warning("can't get entry for %s/tcp service", 20146850Sbostic doencrypt ? "eklogin" : "klogin"); 20240868Sbostic } 20336512Skfall } 20436512Skfall #endif 20540868Sbostic if (sp == NULL) 20640868Sbostic sp = getservbyname("login", "tcp"); 20740858Sbostic if (sp == NULL) { 20840858Sbostic (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 20940858Sbostic exit(1); 2109365Ssam } 21140858Sbostic 21240858Sbostic (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 21318358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 21440858Sbostic (void)strcat(term, "/"); 21540858Sbostic (void)strcat(term, speeds[ttyb.sg_ospeed]); 2166444Swnj } 21740858Sbostic 21840858Sbostic (void)get_window_size(0, &winsize); 21940858Sbostic 22040858Sbostic (void)signal(SIGPIPE, lostpeer); 22129729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 22240858Sbostic omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 22336511Skfall 22440858Sbostic #ifdef KERBEROS 22536512Skfall try_connect: 22640858Sbostic if (use_kerberos) { 22736512Skfall rem = KSUCCESS; 22840858Sbostic errno = 0; 22938728Skfall if (dest_realm == NULL) 23038728Skfall dest_realm = krb_realmofhost(host); 23138728Skfall 23253033Sleres #ifdef CRYPT 23353033Sleres if (doencrypt) 23453033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 23553033Sleres dest_realm, &cred, schedule); 23653033Sleres else 23753033Sleres #endif /* CRYPT */ 23840858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 23940858Sbostic dest_realm); 24038728Skfall if (rem < 0) { 24136512Skfall use_kerberos = 0; 24236628Skfall sp = getservbyname("login", "tcp"); 24340858Sbostic if (sp == NULL) { 24440858Sbostic (void)fprintf(stderr, 24540858Sbostic "rlogin: unknown service login/tcp.\n"); 24636628Skfall exit(1); 24736628Skfall } 24838728Skfall if (errno == ECONNREFUSED) 24940858Sbostic warning("remote host doesn't support Kerberos"); 25038728Skfall if (errno == ENOENT) 25140858Sbostic warning("can't provide Kerberos auth data"); 25236512Skfall goto try_connect; 25336512Skfall } 25436511Skfall } else { 25553033Sleres #ifdef CRYPT 25653033Sleres if (doencrypt) { 25753033Sleres (void)fprintf(stderr, 25853033Sleres "rlogin: the -x flag requires Kerberos authentication.\n"); 25953033Sleres exit(1); 26053033Sleres } 26153033Sleres #endif /* CRYPT */ 26240858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 26336511Skfall } 26436512Skfall #else 26540858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 26645256Smckusick #endif /* KERBEROS */ 26736511Skfall 26840858Sbostic if (rem < 0) 26936511Skfall exit(1); 27036511Skfall 27140858Sbostic if (dflag && 27240858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 27340858Sbostic (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 27440858Sbostic strerror(errno)); 27544346Skarels one = IPTOS_LOWDELAY; 27644346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 27744346Skarels perror("rlogin: setsockopt TOS (ignored)"); 27840858Sbostic 27940858Sbostic (void)setuid(uid); 28040858Sbostic doit(omask); 2819365Ssam /*NOTREACHED*/ 2826444Swnj } 2836444Swnj 28440858Sbostic int child, defflags, deflflags, tabflag; 28540858Sbostic char deferase, defkill; 28640858Sbostic struct tchars deftc; 28740858Sbostic struct ltchars defltc; 28840858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 28940858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 2906444Swnj 29140858Sbostic doit(omask) 29240858Sbostic long omask; 2936444Swnj { 29413075Ssam struct sgttyb sb; 29540858Sbostic void catch_child(), copytochild(), exit(), writeroob(); 2966444Swnj 29740858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 29813075Ssam defflags = sb.sg_flags; 29912155Ssam tabflag = defflags & TBDELAY; 3009962Ssam defflags &= ECHO | CRMOD; 30113075Ssam deferase = sb.sg_erase; 30213075Ssam defkill = sb.sg_kill; 30340858Sbostic (void)ioctl(0, TIOCLGET, (char *)&deflflags); 30440858Sbostic (void)ioctl(0, TIOCGETC, (char *)&deftc); 30513075Ssam notc.t_startc = deftc.t_startc; 30613075Ssam notc.t_stopc = deftc.t_stopc; 30740858Sbostic (void)ioctl(0, TIOCGLTC, (char *)&defltc); 30840858Sbostic (void)signal(SIGINT, SIG_IGN); 30929729Smckusick setsignal(SIGHUP, exit); 31029729Smckusick setsignal(SIGQUIT, exit); 3119365Ssam child = fork(); 3129365Ssam if (child == -1) { 31340858Sbostic (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 31425424Skarels done(1); 3159365Ssam } 3169365Ssam if (child == 0) { 31724726Smckusick mode(1); 31840858Sbostic if (reader(omask) == 0) { 31940858Sbostic msg("connection closed."); 32025424Skarels exit(0); 32125424Skarels } 32212155Ssam sleep(1); 32340858Sbostic msg("\007connection closed."); 32440858Sbostic exit(1); 3256444Swnj } 32629729Smckusick 32729729Smckusick /* 32840858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 32940858Sbostic * receive one soon) that we really want to send to the reader. Set a 33040858Sbostic * trap that simply copies such signals to the child. 33129729Smckusick */ 33240858Sbostic (void)signal(SIGURG, copytochild); 33340858Sbostic (void)signal(SIGUSR1, writeroob); 33440858Sbostic (void)sigsetmask(omask); 33540858Sbostic (void)signal(SIGCHLD, catch_child); 3369365Ssam writer(); 33740858Sbostic msg("closed connection."); 33825424Skarels done(0); 3396444Swnj } 3406444Swnj 34140858Sbostic /* trap a signal, unless it is being ignored. */ 34229729Smckusick setsignal(sig, act) 34340858Sbostic int sig; 34440858Sbostic void (*act)(); 34529729Smckusick { 34629729Smckusick int omask = sigblock(sigmask(sig)); 34729729Smckusick 34829729Smckusick if (signal(sig, act) == SIG_IGN) 34940858Sbostic (void)signal(sig, SIG_IGN); 35040858Sbostic (void)sigsetmask(omask); 35129729Smckusick } 35229729Smckusick 35325424Skarels done(status) 35425424Skarels int status; 3556444Swnj { 35646850Sbostic int w, wstatus; 3576444Swnj 3586444Swnj mode(0); 35929729Smckusick if (child > 0) { 36040858Sbostic /* make sure catch_child does not snap it up */ 36140858Sbostic (void)signal(SIGCHLD, SIG_DFL); 36229729Smckusick if (kill(child, SIGKILL) >= 0) 36346850Sbostic while ((w = wait(&wstatus)) > 0 && w != child); 36429729Smckusick } 36525424Skarels exit(status); 3666444Swnj } 3676444Swnj 36840858Sbostic int dosigwinch; 36946850Sbostic void sigwinch(); 37029729Smckusick 37129729Smckusick /* 37224726Smckusick * This is called when the reader process gets the out-of-band (urgent) 37324726Smckusick * request to turn on the window-changing protocol. 37424726Smckusick */ 37540858Sbostic void 37624726Smckusick writeroob() 37724726Smckusick { 37825341Smckusick if (dosigwinch == 0) { 37924919Smckusick sendwindow(); 38040858Sbostic (void)signal(SIGWINCH, sigwinch); 38125341Smckusick } 38224726Smckusick dosigwinch = 1; 38324726Smckusick } 38424726Smckusick 38540858Sbostic void 38640858Sbostic catch_child() 38711803Sedward { 38811803Sedward union wait status; 38911803Sedward int pid; 39011803Sedward 39140858Sbostic for (;;) { 392*54125Sbostic pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 39340858Sbostic if (pid == 0) 39440858Sbostic return; 39540858Sbostic /* if the child (reader) dies, just quit */ 39640858Sbostic if (pid < 0 || pid == child && !WIFSTOPPED(status)) 39740858Sbostic done((int)(status.w_termsig | status.w_retcode)); 39840858Sbostic } 39940858Sbostic /* NOTREACHED */ 40011803Sedward } 40111803Sedward 4026444Swnj /* 4039365Ssam * writer: write to remote: 0 -> line. 40445063Sbostic * ~. terminate 40545063Sbostic * ~^Z suspend rlogin process. 40645063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4076444Swnj */ 4089365Ssam writer() 4096444Swnj { 41045063Sbostic register int bol, local, n; 41123530Sbloom char c; 4126444Swnj 41340858Sbostic bol = 1; /* beginning of line */ 41440858Sbostic local = 0; 41511803Sedward for (;;) { 41640858Sbostic n = read(STDIN_FILENO, &c, 1); 41718358Ssam if (n <= 0) { 41818358Ssam if (n < 0 && errno == EINTR) 41918358Ssam continue; 42011803Sedward break; 42118358Ssam } 4229365Ssam /* 42340858Sbostic * If we're at the beginning of the line and recognize a 42440858Sbostic * command character, then we echo locally. Otherwise, 42540858Sbostic * characters are echo'd remotely. If the command character 42640858Sbostic * is doubled, this acts as a force and local echo is 42740858Sbostic * suppressed. 4289365Ssam */ 42923530Sbloom if (bol) { 43023530Sbloom bol = 0; 43145063Sbostic if (!noescape && c == escapechar) { 43223530Sbloom local = 1; 43323530Sbloom continue; 4346444Swnj } 43523530Sbloom } else if (local) { 43623530Sbloom local = 0; 43723530Sbloom if (c == '.' || c == deftc.t_eofc) { 43823530Sbloom echo(c); 43923530Sbloom break; 4406444Swnj } 44123530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 44223530Sbloom bol = 1; 44323530Sbloom echo(c); 44423530Sbloom stop(c); 44523530Sbloom continue; 44623530Sbloom } 44745063Sbostic if (c != escapechar) 44853033Sleres #ifdef CRYPT 44953033Sleres #ifdef KERBEROS 45053033Sleres if (doencrypt) 45153033Sleres (void)des_write(rem, &escapechar, 1); 45253033Sleres else 45353033Sleres #endif 45453033Sleres #endif 45545063Sbostic (void)write(rem, &escapechar, 1); 4566444Swnj } 45736511Skfall 45853033Sleres #ifdef CRYPT 45953033Sleres #ifdef KERBEROS 46053033Sleres if (doencrypt) { 46153033Sleres if (des_write(rem, &c, 1) == 0) { 46253033Sleres msg("line gone"); 46353033Sleres break; 46453033Sleres } 46553033Sleres } else 46653033Sleres #endif 46753033Sleres #endif 46836511Skfall if (write(rem, &c, 1) == 0) { 46940858Sbostic msg("line gone"); 47036511Skfall break; 47136511Skfall } 47223530Sbloom bol = c == defkill || c == deftc.t_eofc || 47325424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 47423530Sbloom c == '\r' || c == '\n'; 4756444Swnj } 4766444Swnj } 4776444Swnj 47823530Sbloom echo(c) 47923530Sbloom register char c; 48023530Sbloom { 48140858Sbostic register char *p; 48223530Sbloom char buf[8]; 48323530Sbloom 48440858Sbostic p = buf; 48523530Sbloom c &= 0177; 48645063Sbostic *p++ = escapechar; 48723530Sbloom if (c < ' ') { 48823530Sbloom *p++ = '^'; 48923530Sbloom *p++ = c + '@'; 49023530Sbloom } else if (c == 0177) { 49123530Sbloom *p++ = '^'; 49223530Sbloom *p++ = '?'; 49323530Sbloom } else 49423530Sbloom *p++ = c; 49523530Sbloom *p++ = '\r'; 49623530Sbloom *p++ = '\n'; 49745063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 49823530Sbloom } 49923530Sbloom 50018358Ssam stop(cmdc) 50118358Ssam char cmdc; 50218358Ssam { 50318358Ssam mode(0); 50440858Sbostic (void)signal(SIGCHLD, SIG_IGN); 50540858Sbostic (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 50640858Sbostic (void)signal(SIGCHLD, catch_child); 50718358Ssam mode(1); 50818358Ssam sigwinch(); /* check for size changes */ 50918358Ssam } 51018358Ssam 51140858Sbostic void 51218358Ssam sigwinch() 51318358Ssam { 51418358Ssam struct winsize ws; 51518358Ssam 51629729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 51740858Sbostic bcmp(&ws, &winsize, sizeof(ws))) { 51818358Ssam winsize = ws; 51924726Smckusick sendwindow(); 52018358Ssam } 52118358Ssam } 52218358Ssam 52324726Smckusick /* 52424726Smckusick * Send the window size to the server via the magic escape 52524726Smckusick */ 52624726Smckusick sendwindow() 52724726Smckusick { 52840858Sbostic struct winsize *wp; 52924726Smckusick char obuf[4 + sizeof (struct winsize)]; 53024726Smckusick 53140858Sbostic wp = (struct winsize *)(obuf+4); 53224726Smckusick obuf[0] = 0377; 53324726Smckusick obuf[1] = 0377; 53424726Smckusick obuf[2] = 's'; 53524726Smckusick obuf[3] = 's'; 53624726Smckusick wp->ws_row = htons(winsize.ws_row); 53724726Smckusick wp->ws_col = htons(winsize.ws_col); 53824726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 53924726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 54036511Skfall 54153033Sleres #ifdef CRYPT 54253033Sleres #ifdef KERBEROS 54353033Sleres if(doencrypt) 54453033Sleres (void)des_write(rem, obuf, sizeof(obuf)); 54553033Sleres else 54653033Sleres #endif 54753033Sleres #endif 54840858Sbostic (void)write(rem, obuf, sizeof(obuf)); 54924726Smckusick } 55024726Smckusick 55125424Skarels /* 55225424Skarels * reader: read from remote: line -> 1 55325424Skarels */ 55425424Skarels #define READING 1 55525424Skarels #define WRITING 2 55625424Skarels 55740858Sbostic jmp_buf rcvtop; 55840858Sbostic int ppid, rcvcnt, rcvstate; 55940858Sbostic char rcvbuf[8 * 1024]; 56025424Skarels 56140858Sbostic void 5626444Swnj oob() 5636444Swnj { 56440858Sbostic struct sgttyb sb; 56540858Sbostic int atmark, n, out, rcvd; 5669365Ssam char waste[BUFSIZ], mark; 5676444Swnj 56842230Sbostic out = O_RDWR; 56940858Sbostic rcvd = 0; 57025424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 57125424Skarels switch (errno) { 57225424Skarels case EWOULDBLOCK: 57325424Skarels /* 57440858Sbostic * Urgent data not here yet. It may not be possible 57540858Sbostic * to send it yet if we are blocked for output and 57640858Sbostic * our input buffer is full. 57725424Skarels */ 57825424Skarels if (rcvcnt < sizeof(rcvbuf)) { 57925424Skarels n = read(rem, rcvbuf + rcvcnt, 58040858Sbostic sizeof(rcvbuf) - rcvcnt); 58125424Skarels if (n <= 0) 58225424Skarels return; 58325424Skarels rcvd += n; 58425424Skarels } else { 58525424Skarels n = read(rem, waste, sizeof(waste)); 58625424Skarels if (n <= 0) 58725424Skarels return; 58825424Skarels } 58925424Skarels continue; 59025424Skarels default: 59125424Skarels return; 5926444Swnj } 59325424Skarels if (mark & TIOCPKT_WINDOW) { 59440858Sbostic /* Let server know about window size changes */ 59540858Sbostic (void)kill(ppid, SIGUSR1); 59624726Smckusick } 59725424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 59840858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 59924726Smckusick sb.sg_flags &= ~CBREAK; 60024726Smckusick sb.sg_flags |= RAW; 60140858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 60213075Ssam notc.t_stopc = -1; 60313075Ssam notc.t_startc = -1; 60440858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6056444Swnj } 60625424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 60740858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 60824726Smckusick sb.sg_flags &= ~RAW; 60924726Smckusick sb.sg_flags |= CBREAK; 61040858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 61113075Ssam notc.t_stopc = deftc.t_stopc; 61213075Ssam notc.t_startc = deftc.t_startc; 61340858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6146444Swnj } 61525424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 61640858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 61725424Skarels for (;;) { 61825424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 61940858Sbostic (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 62040858Sbostic strerror(errno)); 62125424Skarels break; 62225424Skarels } 62325424Skarels if (atmark) 62425424Skarels break; 62525424Skarels n = read(rem, waste, sizeof (waste)); 62625424Skarels if (n <= 0) 62725424Skarels break; 62825424Skarels } 62925424Skarels /* 63040858Sbostic * Don't want any pending data to be output, so clear the recv 63140858Sbostic * buffer. If we were hanging on a write when interrupted, 63240858Sbostic * don't want it to restart. If we were reading, restart 63340858Sbostic * anyway. 63425424Skarels */ 63525424Skarels rcvcnt = 0; 63625424Skarels longjmp(rcvtop, 1); 63725424Skarels } 63829729Smckusick 63940858Sbostic /* oob does not do FLUSHREAD (alas!) */ 64029729Smckusick 64129729Smckusick /* 64240858Sbostic * If we filled the receive buffer while a read was pending, longjmp 64340858Sbostic * to the top to restart appropriately. Don't abort a pending write, 64440858Sbostic * however, or we won't know how much was written. 64525424Skarels */ 64625424Skarels if (rcvd && rcvstate == READING) 64725424Skarels longjmp(rcvtop, 1); 6486444Swnj } 6496444Swnj 65040858Sbostic /* reader: read from remote: line -> 1 */ 65140858Sbostic reader(omask) 65240858Sbostic int omask; 6536444Swnj { 65440858Sbostic void oob(); 65540858Sbostic 65626981Skarels #if !defined(BSD) || BSD < 43 65726981Skarels int pid = -getpid(); 65826981Skarels #else 65925424Skarels int pid = getpid(); 66026981Skarels #endif 66125424Skarels int n, remaining; 66225424Skarels char *bufp = rcvbuf; 6636444Swnj 66440858Sbostic (void)signal(SIGTTOU, SIG_IGN); 66540858Sbostic (void)signal(SIGURG, oob); 66626981Skarels ppid = getppid(); 66740858Sbostic (void)fcntl(rem, F_SETOWN, pid); 66840858Sbostic (void)setjmp(rcvtop); 66940858Sbostic (void)sigsetmask(omask); 6706444Swnj for (;;) { 67125424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 67225424Skarels rcvstate = WRITING; 67345063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 67425424Skarels if (n < 0) { 67525424Skarels if (errno != EINTR) 67640858Sbostic return(-1); 67725424Skarels continue; 67825424Skarels } 67925424Skarels bufp += n; 68025424Skarels } 68125424Skarels bufp = rcvbuf; 68225424Skarels rcvcnt = 0; 68325424Skarels rcvstate = READING; 68436511Skfall 68553033Sleres #ifdef CRYPT 68653033Sleres #ifdef KERBEROS 68753033Sleres if (doencrypt) 68853033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 68953033Sleres else 69053033Sleres #endif 69153033Sleres #endif 69236511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 69325424Skarels if (rcvcnt == 0) 69425424Skarels return (0); 69525424Skarels if (rcvcnt < 0) { 6969365Ssam if (errno == EINTR) 6976444Swnj continue; 69840858Sbostic (void)fprintf(stderr, "rlogin: read: %s.\n", 69940858Sbostic strerror(errno)); 70040858Sbostic return(-1); 7016444Swnj } 7026444Swnj } 7036444Swnj } 7046444Swnj 7056444Swnj mode(f) 7066444Swnj { 70713075Ssam struct ltchars *ltc; 70813075Ssam struct sgttyb sb; 70940858Sbostic struct tchars *tc; 71040858Sbostic int lflags; 7119365Ssam 71240858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 71340858Sbostic (void)ioctl(0, TIOCLGET, (char *)&lflags); 71440858Sbostic switch(f) { 7159962Ssam case 0: 71613075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 71713075Ssam sb.sg_flags |= defflags|tabflag; 7189962Ssam tc = &deftc; 71913075Ssam ltc = &defltc; 72013075Ssam sb.sg_kill = defkill; 72113075Ssam sb.sg_erase = deferase; 72221583Sbloom lflags = deflflags; 7239962Ssam break; 7249962Ssam case 1: 72513075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 72613075Ssam sb.sg_flags &= ~defflags; 72712155Ssam /* preserve tab delays, but turn off XTABS */ 72813075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 72913075Ssam sb.sg_flags &= ~TBDELAY; 7309962Ssam tc = ¬c; 73113075Ssam ltc = &noltc; 73213075Ssam sb.sg_kill = sb.sg_erase = -1; 73321583Sbloom if (litout) 73421583Sbloom lflags |= LLITOUT; 7359962Ssam break; 7369962Ssam default: 7379962Ssam return; 7386444Swnj } 73940858Sbostic (void)ioctl(0, TIOCSLTC, (char *)ltc); 74040858Sbostic (void)ioctl(0, TIOCSETC, (char *)tc); 74140858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 74240858Sbostic (void)ioctl(0, TIOCLSET, (char *)&lflags); 7436444Swnj } 7446444Swnj 74540858Sbostic void 74640858Sbostic lostpeer() 7476444Swnj { 74840858Sbostic (void)signal(SIGPIPE, SIG_IGN); 74940858Sbostic msg("\007connection closed."); 75040858Sbostic done(1); 75140858Sbostic } 75229729Smckusick 75340858Sbostic /* copy SIGURGs to the child process. */ 75440858Sbostic void 75540858Sbostic copytochild() 75640858Sbostic { 75740858Sbostic (void)kill(child, SIGURG); 7586444Swnj } 7596444Swnj 76040858Sbostic msg(str) 76140858Sbostic char *str; 7626444Swnj { 76340858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 76440858Sbostic } 76529729Smckusick 76640858Sbostic #ifdef KERBEROS 76740858Sbostic /* VARARGS */ 76840858Sbostic warning(va_alist) 76940858Sbostic va_dcl 77040858Sbostic { 77140858Sbostic va_list ap; 77240858Sbostic char *fmt; 77340858Sbostic 77440858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 77540858Sbostic va_start(ap); 77640858Sbostic fmt = va_arg(ap, char *); 77740858Sbostic vfprintf(stderr, fmt, ap); 77840858Sbostic va_end(ap); 77940858Sbostic (void)fprintf(stderr, ".\n"); 7806444Swnj } 78140858Sbostic #endif 78236512Skfall 78340858Sbostic usage() 78436512Skfall { 78540858Sbostic (void)fprintf(stderr, 78640858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 78740858Sbostic #ifdef KERBEROS 78853033Sleres #ifdef CRYPT 789*54125Sbostic "8EKLx", " [-k realm] "); 79053033Sleres #else 791*54125Sbostic "8EKL", " [-k realm] "); 79253033Sleres #endif 79345256Smckusick #else 79445063Sbostic "8EL", " "); 79540858Sbostic #endif 79640858Sbostic exit(1); 79736512Skfall } 79840858Sbostic 79940858Sbostic /* 80040858Sbostic * The following routine provides compatibility (such as it is) between 4.2BSD 80140858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 80240858Sbostic */ 80340858Sbostic #ifdef sun 80440858Sbostic get_window_size(fd, wp) 80540858Sbostic int fd; 80640858Sbostic struct winsize *wp; 80740858Sbostic { 80840858Sbostic struct ttysize ts; 80940858Sbostic int error; 81040858Sbostic 81140858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 81240858Sbostic return(error); 81340858Sbostic wp->ws_row = ts.ts_lines; 81440858Sbostic wp->ws_col = ts.ts_cols; 81540858Sbostic wp->ws_xpixel = 0; 81640858Sbostic wp->ws_ypixel = 0; 81740858Sbostic return(0); 81840858Sbostic } 81940858Sbostic #endif 82045063Sbostic 82145063Sbostic u_char 82245063Sbostic getescape(p) 82345063Sbostic register char *p; 82445063Sbostic { 82545063Sbostic long val; 82645063Sbostic int len; 82745063Sbostic 82845063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 82945063Sbostic return((u_char)*p); 83045063Sbostic /* otherwise, \nnn */ 83145063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 83245063Sbostic val = strtol(++p, (char **)NULL, 8); 83345063Sbostic for (;;) { 83445063Sbostic if (!*++p) 83545063Sbostic return((u_char)val); 83645063Sbostic if (*p < '0' || *p > '8') 83745063Sbostic break; 83845063Sbostic } 83945063Sbostic } 84045063Sbostic msg("illegal option value -- e"); 84145063Sbostic usage(); 84245063Sbostic /* NOTREACHED */ 84345063Sbostic } 844