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*58261Smckusick static char sccsid[] = "@(#)rlogin.c 5.37 (Berkeley) 02/26/93"; 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; 10156960Seric struct hostent *hp; 1026444Swnj struct sgttyb ttyb; 10340858Sbostic long omask; 10440858Sbostic int argoff, ch, dflag, one, uid; 10540858Sbostic char *host, *p, *user, term[1024]; 106*58261Smckusick void lostpeer(), copytochild(), writeroob(); 10745063Sbostic 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 12945063Sbostic #define OPTIONS "8EKLde:k:l:x" 13040858Sbostic #else 13145063Sbostic #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; 13845063Sbostic case 'E': 13945063Sbostic noescape = 1; 14045063Sbostic 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': 15353033Sleres noescape = 0; 15445063Sbostic escapechar = getescape(optarg); 15540858Sbostic break; 15640858Sbostic #ifdef KERBEROS 15740858Sbostic case 'k': 15840858Sbostic dest_realm = dst_realm_buf; 15940858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 16040858Sbostic break; 16140858Sbostic #endif 16240858Sbostic case 'l': 16340858Sbostic user = optarg; 16440858Sbostic break; 16553033Sleres #ifdef CRYPT 16653033Sleres #ifdef KERBEROS 16753033Sleres case 'x': 16853033Sleres doencrypt = 1; 16953033Sleres des_set_key(cred.session, schedule); 17053033Sleres break; 17153033Sleres #endif 17253033Sleres #endif 17340858Sbostic case '?': 17440858Sbostic default: 17540858Sbostic usage(); 17636524Skfall } 17740858Sbostic optind += argoff; 17840858Sbostic argc -= optind; 17940858Sbostic argv += optind; 18036524Skfall 18140858Sbostic /* if haven't gotten a host yet, do so */ 18240858Sbostic if (!host && !(host = *argv++)) 18340858Sbostic usage(); 18436511Skfall 18540858Sbostic if (*argv) 18640858Sbostic usage(); 18740858Sbostic 18840858Sbostic if (!(pw = getpwuid(uid = getuid()))) { 18940858Sbostic (void)fprintf(stderr, "rlogin: unknown user id.\n"); 1906444Swnj exit(1); 1916444Swnj } 19240858Sbostic if (!user) 19340858Sbostic user = pw->pw_name; 19440858Sbostic 19540868Sbostic sp = NULL; 19640858Sbostic #ifdef KERBEROS 19740868Sbostic if (use_kerberos) { 19846850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 19940868Sbostic if (sp == NULL) { 20040868Sbostic use_kerberos = 0; 20140868Sbostic warning("can't get entry for %s/tcp service", 20246850Sbostic doencrypt ? "eklogin" : "klogin"); 20340868Sbostic } 20436512Skfall } 20536512Skfall #endif 20640868Sbostic if (sp == NULL) 20740868Sbostic sp = getservbyname("login", "tcp"); 20840858Sbostic if (sp == NULL) { 20940858Sbostic (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 21040858Sbostic exit(1); 2119365Ssam } 21240858Sbostic 21340858Sbostic (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 21418358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 21540858Sbostic (void)strcat(term, "/"); 21640858Sbostic (void)strcat(term, speeds[ttyb.sg_ospeed]); 2176444Swnj } 21840858Sbostic 21940858Sbostic (void)get_window_size(0, &winsize); 22040858Sbostic 22140858Sbostic (void)signal(SIGPIPE, lostpeer); 22229729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 22340858Sbostic omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 224*58261Smckusick /* 225*58261Smckusick * We set SIGURG and SIGUSR1 below so that an 226*58261Smckusick * incoming signal will be held pending rather than being 227*58261Smckusick * discarded. Note that these routines will be ready to get 228*58261Smckusick * a signal by the time that they are unblocked below. 229*58261Smckusick */ 230*58261Smckusick (void)signal(SIGURG, copytochild); 231*58261Smckusick (void)signal(SIGUSR1, writeroob); 23236511Skfall 23340858Sbostic #ifdef KERBEROS 23436512Skfall try_connect: 23540858Sbostic if (use_kerberos) { 23656960Seric /* fully qualify hostname (needed for krb_realmofhost) */ 23756960Seric hp = gethostbyname(host); 23856960Seric if (hp != NULL && !(host = strdup(hp->h_name))) { 23956960Seric (void)fprintf(stderr, "rlogin: %s.\n", strerror(ENOMEM)); 24056960Seric exit(1); 24156960Seric } 24256960Seric 24336512Skfall rem = KSUCCESS; 24440858Sbostic errno = 0; 24538728Skfall if (dest_realm == NULL) 24638728Skfall dest_realm = krb_realmofhost(host); 24738728Skfall 24853033Sleres #ifdef CRYPT 24953033Sleres if (doencrypt) 25053033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 25153033Sleres dest_realm, &cred, schedule); 25253033Sleres else 25353033Sleres #endif /* CRYPT */ 25440858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 25540858Sbostic dest_realm); 25638728Skfall if (rem < 0) { 25736512Skfall use_kerberos = 0; 25836628Skfall sp = getservbyname("login", "tcp"); 25940858Sbostic if (sp == NULL) { 26040858Sbostic (void)fprintf(stderr, 26140858Sbostic "rlogin: unknown service login/tcp.\n"); 26236628Skfall exit(1); 26336628Skfall } 26438728Skfall if (errno == ECONNREFUSED) 26540858Sbostic warning("remote host doesn't support Kerberos"); 26638728Skfall if (errno == ENOENT) 26740858Sbostic warning("can't provide Kerberos auth data"); 26836512Skfall goto try_connect; 26936512Skfall } 27036511Skfall } else { 27153033Sleres #ifdef CRYPT 27253033Sleres if (doencrypt) { 27353033Sleres (void)fprintf(stderr, 27453033Sleres "rlogin: the -x flag requires Kerberos authentication.\n"); 27553033Sleres exit(1); 27653033Sleres } 27753033Sleres #endif /* CRYPT */ 27840858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 27936511Skfall } 28036512Skfall #else 28140858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 28245256Smckusick #endif /* KERBEROS */ 28336511Skfall 28440858Sbostic if (rem < 0) 28536511Skfall exit(1); 28636511Skfall 28740858Sbostic if (dflag && 28840858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 28940858Sbostic (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 29040858Sbostic strerror(errno)); 29144346Skarels one = IPTOS_LOWDELAY; 29244346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 29344346Skarels perror("rlogin: setsockopt TOS (ignored)"); 29440858Sbostic 29540858Sbostic (void)setuid(uid); 29640858Sbostic doit(omask); 2979365Ssam /*NOTREACHED*/ 2986444Swnj } 2996444Swnj 30040858Sbostic int child, defflags, deflflags, tabflag; 30140858Sbostic char deferase, defkill; 30240858Sbostic struct tchars deftc; 30340858Sbostic struct ltchars defltc; 30440858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 30540858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3066444Swnj 30740858Sbostic doit(omask) 30840858Sbostic long omask; 3096444Swnj { 31013075Ssam struct sgttyb sb; 311*58261Smckusick void catch_child(), exit(); 3126444Swnj 31340858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 31413075Ssam defflags = sb.sg_flags; 31512155Ssam tabflag = defflags & TBDELAY; 3169962Ssam defflags &= ECHO | CRMOD; 31713075Ssam deferase = sb.sg_erase; 31813075Ssam defkill = sb.sg_kill; 31940858Sbostic (void)ioctl(0, TIOCLGET, (char *)&deflflags); 32040858Sbostic (void)ioctl(0, TIOCGETC, (char *)&deftc); 32113075Ssam notc.t_startc = deftc.t_startc; 32213075Ssam notc.t_stopc = deftc.t_stopc; 32340858Sbostic (void)ioctl(0, TIOCGLTC, (char *)&defltc); 32440858Sbostic (void)signal(SIGINT, SIG_IGN); 32529729Smckusick setsignal(SIGHUP, exit); 32629729Smckusick setsignal(SIGQUIT, exit); 3279365Ssam child = fork(); 3289365Ssam if (child == -1) { 32940858Sbostic (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 33025424Skarels done(1); 3319365Ssam } 3329365Ssam if (child == 0) { 33324726Smckusick mode(1); 33440858Sbostic if (reader(omask) == 0) { 33540858Sbostic msg("connection closed."); 33625424Skarels exit(0); 33725424Skarels } 33812155Ssam sleep(1); 33940858Sbostic msg("\007connection closed."); 34040858Sbostic exit(1); 3416444Swnj } 34229729Smckusick 34329729Smckusick /* 34440858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 345*58261Smckusick * receive one soon) that we really want to send to the reader. When 346*58261Smckusick * one of these comes in, the trap copytochild simply copies such 347*58261Smckusick * signals to the child. We can now unblock SIGURG and SIGUSR1 348*58261Smckusick * that were set above. 34929729Smckusick */ 35040858Sbostic (void)sigsetmask(omask); 35140858Sbostic (void)signal(SIGCHLD, catch_child); 3529365Ssam writer(); 35340858Sbostic msg("closed connection."); 35425424Skarels done(0); 3556444Swnj } 3566444Swnj 35740858Sbostic /* trap a signal, unless it is being ignored. */ 35829729Smckusick setsignal(sig, act) 35940858Sbostic int sig; 36040858Sbostic void (*act)(); 36129729Smckusick { 36229729Smckusick int omask = sigblock(sigmask(sig)); 36329729Smckusick 36429729Smckusick if (signal(sig, act) == SIG_IGN) 36540858Sbostic (void)signal(sig, SIG_IGN); 36640858Sbostic (void)sigsetmask(omask); 36729729Smckusick } 36829729Smckusick 36925424Skarels done(status) 37025424Skarels int status; 3716444Swnj { 37246850Sbostic int w, wstatus; 3736444Swnj 3746444Swnj mode(0); 37529729Smckusick if (child > 0) { 37640858Sbostic /* make sure catch_child does not snap it up */ 37740858Sbostic (void)signal(SIGCHLD, SIG_DFL); 37829729Smckusick if (kill(child, SIGKILL) >= 0) 37946850Sbostic while ((w = wait(&wstatus)) > 0 && w != child); 38029729Smckusick } 38125424Skarels exit(status); 3826444Swnj } 3836444Swnj 38440858Sbostic int dosigwinch; 38546850Sbostic void sigwinch(); 38629729Smckusick 38729729Smckusick /* 38824726Smckusick * This is called when the reader process gets the out-of-band (urgent) 38924726Smckusick * request to turn on the window-changing protocol. 39024726Smckusick */ 39140858Sbostic void 39224726Smckusick writeroob() 39324726Smckusick { 39425341Smckusick if (dosigwinch == 0) { 39524919Smckusick sendwindow(); 39640858Sbostic (void)signal(SIGWINCH, sigwinch); 39725341Smckusick } 39824726Smckusick dosigwinch = 1; 39924726Smckusick } 40024726Smckusick 40140858Sbostic void 40240858Sbostic catch_child() 40311803Sedward { 40411803Sedward union wait status; 40511803Sedward int pid; 40611803Sedward 40740858Sbostic for (;;) { 40854125Sbostic pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 40940858Sbostic if (pid == 0) 41040858Sbostic return; 41140858Sbostic /* if the child (reader) dies, just quit */ 41240858Sbostic if (pid < 0 || pid == child && !WIFSTOPPED(status)) 41340858Sbostic done((int)(status.w_termsig | status.w_retcode)); 41440858Sbostic } 41540858Sbostic /* NOTREACHED */ 41611803Sedward } 41711803Sedward 4186444Swnj /* 4199365Ssam * writer: write to remote: 0 -> line. 42045063Sbostic * ~. terminate 42145063Sbostic * ~^Z suspend rlogin process. 42245063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4236444Swnj */ 4249365Ssam writer() 4256444Swnj { 42645063Sbostic register int bol, local, n; 42723530Sbloom char c; 4286444Swnj 42940858Sbostic bol = 1; /* beginning of line */ 43040858Sbostic local = 0; 43111803Sedward for (;;) { 43240858Sbostic n = read(STDIN_FILENO, &c, 1); 43318358Ssam if (n <= 0) { 43418358Ssam if (n < 0 && errno == EINTR) 43518358Ssam continue; 43611803Sedward break; 43718358Ssam } 4389365Ssam /* 43940858Sbostic * If we're at the beginning of the line and recognize a 44040858Sbostic * command character, then we echo locally. Otherwise, 44140858Sbostic * characters are echo'd remotely. If the command character 44240858Sbostic * is doubled, this acts as a force and local echo is 44340858Sbostic * suppressed. 4449365Ssam */ 44523530Sbloom if (bol) { 44623530Sbloom bol = 0; 44745063Sbostic if (!noescape && c == escapechar) { 44823530Sbloom local = 1; 44923530Sbloom continue; 4506444Swnj } 45123530Sbloom } else if (local) { 45223530Sbloom local = 0; 45323530Sbloom if (c == '.' || c == deftc.t_eofc) { 45423530Sbloom echo(c); 45523530Sbloom break; 4566444Swnj } 45723530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 45823530Sbloom bol = 1; 45923530Sbloom echo(c); 46023530Sbloom stop(c); 46123530Sbloom continue; 46223530Sbloom } 46345063Sbostic if (c != escapechar) 46453033Sleres #ifdef CRYPT 46553033Sleres #ifdef KERBEROS 46653033Sleres if (doencrypt) 46753033Sleres (void)des_write(rem, &escapechar, 1); 46853033Sleres else 46953033Sleres #endif 47053033Sleres #endif 47145063Sbostic (void)write(rem, &escapechar, 1); 4726444Swnj } 47336511Skfall 47453033Sleres #ifdef CRYPT 47553033Sleres #ifdef KERBEROS 47653033Sleres if (doencrypt) { 47753033Sleres if (des_write(rem, &c, 1) == 0) { 47853033Sleres msg("line gone"); 47953033Sleres break; 48053033Sleres } 48153033Sleres } else 48253033Sleres #endif 48353033Sleres #endif 48436511Skfall if (write(rem, &c, 1) == 0) { 48540858Sbostic msg("line gone"); 48636511Skfall break; 48736511Skfall } 48823530Sbloom bol = c == defkill || c == deftc.t_eofc || 48925424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 49023530Sbloom c == '\r' || c == '\n'; 4916444Swnj } 4926444Swnj } 4936444Swnj 49423530Sbloom echo(c) 49523530Sbloom register char c; 49623530Sbloom { 49740858Sbostic register char *p; 49823530Sbloom char buf[8]; 49923530Sbloom 50040858Sbostic p = buf; 50123530Sbloom c &= 0177; 50245063Sbostic *p++ = escapechar; 50323530Sbloom if (c < ' ') { 50423530Sbloom *p++ = '^'; 50523530Sbloom *p++ = c + '@'; 50623530Sbloom } else if (c == 0177) { 50723530Sbloom *p++ = '^'; 50823530Sbloom *p++ = '?'; 50923530Sbloom } else 51023530Sbloom *p++ = c; 51123530Sbloom *p++ = '\r'; 51223530Sbloom *p++ = '\n'; 51345063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 51423530Sbloom } 51523530Sbloom 51618358Ssam stop(cmdc) 51718358Ssam char cmdc; 51818358Ssam { 51918358Ssam mode(0); 52040858Sbostic (void)signal(SIGCHLD, SIG_IGN); 52140858Sbostic (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 52240858Sbostic (void)signal(SIGCHLD, catch_child); 52318358Ssam mode(1); 52418358Ssam sigwinch(); /* check for size changes */ 52518358Ssam } 52618358Ssam 52740858Sbostic void 52818358Ssam sigwinch() 52918358Ssam { 53018358Ssam struct winsize ws; 53118358Ssam 53229729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 53340858Sbostic bcmp(&ws, &winsize, sizeof(ws))) { 53418358Ssam winsize = ws; 53524726Smckusick sendwindow(); 53618358Ssam } 53718358Ssam } 53818358Ssam 53924726Smckusick /* 54024726Smckusick * Send the window size to the server via the magic escape 54124726Smckusick */ 54224726Smckusick sendwindow() 54324726Smckusick { 54440858Sbostic struct winsize *wp; 54524726Smckusick char obuf[4 + sizeof (struct winsize)]; 54624726Smckusick 54740858Sbostic wp = (struct winsize *)(obuf+4); 54824726Smckusick obuf[0] = 0377; 54924726Smckusick obuf[1] = 0377; 55024726Smckusick obuf[2] = 's'; 55124726Smckusick obuf[3] = 's'; 55224726Smckusick wp->ws_row = htons(winsize.ws_row); 55324726Smckusick wp->ws_col = htons(winsize.ws_col); 55424726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 55524726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 55636511Skfall 55753033Sleres #ifdef CRYPT 55853033Sleres #ifdef KERBEROS 55953033Sleres if(doencrypt) 56053033Sleres (void)des_write(rem, obuf, sizeof(obuf)); 56153033Sleres else 56253033Sleres #endif 56353033Sleres #endif 56440858Sbostic (void)write(rem, obuf, sizeof(obuf)); 56524726Smckusick } 56624726Smckusick 56725424Skarels /* 56825424Skarels * reader: read from remote: line -> 1 56925424Skarels */ 57025424Skarels #define READING 1 57125424Skarels #define WRITING 2 57225424Skarels 57340858Sbostic jmp_buf rcvtop; 57440858Sbostic int ppid, rcvcnt, rcvstate; 57540858Sbostic char rcvbuf[8 * 1024]; 57625424Skarels 57740858Sbostic void 5786444Swnj oob() 5796444Swnj { 58040858Sbostic struct sgttyb sb; 58140858Sbostic int atmark, n, out, rcvd; 5829365Ssam char waste[BUFSIZ], mark; 5836444Swnj 58442230Sbostic out = O_RDWR; 58540858Sbostic rcvd = 0; 58625424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 58725424Skarels switch (errno) { 58825424Skarels case EWOULDBLOCK: 58925424Skarels /* 59040858Sbostic * Urgent data not here yet. It may not be possible 59140858Sbostic * to send it yet if we are blocked for output and 59240858Sbostic * our input buffer is full. 59325424Skarels */ 59425424Skarels if (rcvcnt < sizeof(rcvbuf)) { 59525424Skarels n = read(rem, rcvbuf + rcvcnt, 59640858Sbostic sizeof(rcvbuf) - rcvcnt); 59725424Skarels if (n <= 0) 59825424Skarels return; 59925424Skarels rcvd += n; 60025424Skarels } else { 60125424Skarels n = read(rem, waste, sizeof(waste)); 60225424Skarels if (n <= 0) 60325424Skarels return; 60425424Skarels } 60525424Skarels continue; 60625424Skarels default: 60725424Skarels return; 6086444Swnj } 60925424Skarels if (mark & TIOCPKT_WINDOW) { 61040858Sbostic /* Let server know about window size changes */ 61140858Sbostic (void)kill(ppid, SIGUSR1); 61224726Smckusick } 61325424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 61440858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 61524726Smckusick sb.sg_flags &= ~CBREAK; 61624726Smckusick sb.sg_flags |= RAW; 61740858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 61813075Ssam notc.t_stopc = -1; 61913075Ssam notc.t_startc = -1; 62040858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6216444Swnj } 62225424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 62340858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 62424726Smckusick sb.sg_flags &= ~RAW; 62524726Smckusick sb.sg_flags |= CBREAK; 62640858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 62713075Ssam notc.t_stopc = deftc.t_stopc; 62813075Ssam notc.t_startc = deftc.t_startc; 62940858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6306444Swnj } 63125424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 63240858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 63325424Skarels for (;;) { 63425424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 63540858Sbostic (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 63640858Sbostic strerror(errno)); 63725424Skarels break; 63825424Skarels } 63925424Skarels if (atmark) 64025424Skarels break; 64125424Skarels n = read(rem, waste, sizeof (waste)); 64225424Skarels if (n <= 0) 64325424Skarels break; 64425424Skarels } 64525424Skarels /* 64640858Sbostic * Don't want any pending data to be output, so clear the recv 64740858Sbostic * buffer. If we were hanging on a write when interrupted, 64840858Sbostic * don't want it to restart. If we were reading, restart 64940858Sbostic * anyway. 65025424Skarels */ 65125424Skarels rcvcnt = 0; 65225424Skarels longjmp(rcvtop, 1); 65325424Skarels } 65429729Smckusick 65540858Sbostic /* oob does not do FLUSHREAD (alas!) */ 65629729Smckusick 65729729Smckusick /* 65840858Sbostic * If we filled the receive buffer while a read was pending, longjmp 65940858Sbostic * to the top to restart appropriately. Don't abort a pending write, 66040858Sbostic * however, or we won't know how much was written. 66125424Skarels */ 66225424Skarels if (rcvd && rcvstate == READING) 66325424Skarels longjmp(rcvtop, 1); 6646444Swnj } 6656444Swnj 66640858Sbostic /* reader: read from remote: line -> 1 */ 66740858Sbostic reader(omask) 66840858Sbostic int omask; 6696444Swnj { 67040858Sbostic void oob(); 67140858Sbostic 67226981Skarels #if !defined(BSD) || BSD < 43 67326981Skarels int pid = -getpid(); 67426981Skarels #else 67525424Skarels int pid = getpid(); 67626981Skarels #endif 67725424Skarels int n, remaining; 67825424Skarels char *bufp = rcvbuf; 6796444Swnj 68040858Sbostic (void)signal(SIGTTOU, SIG_IGN); 68140858Sbostic (void)signal(SIGURG, oob); 68226981Skarels ppid = getppid(); 68340858Sbostic (void)fcntl(rem, F_SETOWN, pid); 68440858Sbostic (void)setjmp(rcvtop); 68540858Sbostic (void)sigsetmask(omask); 6866444Swnj for (;;) { 68725424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 68825424Skarels rcvstate = WRITING; 68945063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 69025424Skarels if (n < 0) { 69125424Skarels if (errno != EINTR) 69240858Sbostic return(-1); 69325424Skarels continue; 69425424Skarels } 69525424Skarels bufp += n; 69625424Skarels } 69725424Skarels bufp = rcvbuf; 69825424Skarels rcvcnt = 0; 69925424Skarels rcvstate = READING; 70036511Skfall 70153033Sleres #ifdef CRYPT 70253033Sleres #ifdef KERBEROS 70353033Sleres if (doencrypt) 70453033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 70553033Sleres else 70653033Sleres #endif 70753033Sleres #endif 70836511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 70925424Skarels if (rcvcnt == 0) 71025424Skarels return (0); 71125424Skarels if (rcvcnt < 0) { 7129365Ssam if (errno == EINTR) 7136444Swnj continue; 71440858Sbostic (void)fprintf(stderr, "rlogin: read: %s.\n", 71540858Sbostic strerror(errno)); 71640858Sbostic return(-1); 7176444Swnj } 7186444Swnj } 7196444Swnj } 7206444Swnj 7216444Swnj mode(f) 7226444Swnj { 72313075Ssam struct ltchars *ltc; 72413075Ssam struct sgttyb sb; 72540858Sbostic struct tchars *tc; 72640858Sbostic int lflags; 7279365Ssam 72840858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 72940858Sbostic (void)ioctl(0, TIOCLGET, (char *)&lflags); 73040858Sbostic switch(f) { 7319962Ssam case 0: 73213075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 73313075Ssam sb.sg_flags |= defflags|tabflag; 7349962Ssam tc = &deftc; 73513075Ssam ltc = &defltc; 73613075Ssam sb.sg_kill = defkill; 73713075Ssam sb.sg_erase = deferase; 73821583Sbloom lflags = deflflags; 7399962Ssam break; 7409962Ssam case 1: 74113075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 74213075Ssam sb.sg_flags &= ~defflags; 74312155Ssam /* preserve tab delays, but turn off XTABS */ 74413075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 74513075Ssam sb.sg_flags &= ~TBDELAY; 7469962Ssam tc = ¬c; 74713075Ssam ltc = &noltc; 74813075Ssam sb.sg_kill = sb.sg_erase = -1; 74921583Sbloom if (litout) 75021583Sbloom lflags |= LLITOUT; 7519962Ssam break; 7529962Ssam default: 7539962Ssam return; 7546444Swnj } 75540858Sbostic (void)ioctl(0, TIOCSLTC, (char *)ltc); 75640858Sbostic (void)ioctl(0, TIOCSETC, (char *)tc); 75740858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 75840858Sbostic (void)ioctl(0, TIOCLSET, (char *)&lflags); 7596444Swnj } 7606444Swnj 76140858Sbostic void 76240858Sbostic lostpeer() 7636444Swnj { 76440858Sbostic (void)signal(SIGPIPE, SIG_IGN); 76540858Sbostic msg("\007connection closed."); 76640858Sbostic done(1); 76740858Sbostic } 76829729Smckusick 76940858Sbostic /* copy SIGURGs to the child process. */ 77040858Sbostic void 77140858Sbostic copytochild() 77240858Sbostic { 77340858Sbostic (void)kill(child, SIGURG); 7746444Swnj } 7756444Swnj 77640858Sbostic msg(str) 77740858Sbostic char *str; 7786444Swnj { 77940858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 78040858Sbostic } 78129729Smckusick 78240858Sbostic #ifdef KERBEROS 78340858Sbostic /* VARARGS */ 78440858Sbostic warning(va_alist) 78540858Sbostic va_dcl 78640858Sbostic { 78740858Sbostic va_list ap; 78840858Sbostic char *fmt; 78940858Sbostic 79040858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 79140858Sbostic va_start(ap); 79240858Sbostic fmt = va_arg(ap, char *); 79340858Sbostic vfprintf(stderr, fmt, ap); 79440858Sbostic va_end(ap); 79540858Sbostic (void)fprintf(stderr, ".\n"); 7966444Swnj } 79740858Sbostic #endif 79836512Skfall 79940858Sbostic usage() 80036512Skfall { 80140858Sbostic (void)fprintf(stderr, 80240858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 80340858Sbostic #ifdef KERBEROS 80453033Sleres #ifdef CRYPT 80554125Sbostic "8EKLx", " [-k realm] "); 80653033Sleres #else 80754125Sbostic "8EKL", " [-k realm] "); 80853033Sleres #endif 80945256Smckusick #else 81045063Sbostic "8EL", " "); 81140858Sbostic #endif 81240858Sbostic exit(1); 81336512Skfall } 81440858Sbostic 81540858Sbostic /* 81640858Sbostic * The following routine provides compatibility (such as it is) between 4.2BSD 81740858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 81840858Sbostic */ 81940858Sbostic #ifdef sun 82040858Sbostic get_window_size(fd, wp) 82140858Sbostic int fd; 82240858Sbostic struct winsize *wp; 82340858Sbostic { 82440858Sbostic struct ttysize ts; 82540858Sbostic int error; 82640858Sbostic 82740858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 82840858Sbostic return(error); 82940858Sbostic wp->ws_row = ts.ts_lines; 83040858Sbostic wp->ws_col = ts.ts_cols; 83140858Sbostic wp->ws_xpixel = 0; 83240858Sbostic wp->ws_ypixel = 0; 83340858Sbostic return(0); 83440858Sbostic } 83540858Sbostic #endif 83645063Sbostic 83745063Sbostic u_char 83845063Sbostic getescape(p) 83945063Sbostic register char *p; 84045063Sbostic { 84145063Sbostic long val; 84245063Sbostic int len; 84345063Sbostic 84445063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 84545063Sbostic return((u_char)*p); 84645063Sbostic /* otherwise, \nnn */ 84745063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 84845063Sbostic val = strtol(++p, (char **)NULL, 8); 84945063Sbostic for (;;) { 85045063Sbostic if (!*++p) 85145063Sbostic return((u_char)val); 85245063Sbostic if (*p < '0' || *p > '8') 85345063Sbostic break; 85445063Sbostic } 85545063Sbostic } 85645063Sbostic msg("illegal option value -- e"); 85745063Sbostic usage(); 85845063Sbostic /* NOTREACHED */ 85945063Sbostic } 860