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*58470Sbostic static char sccsid[] = "@(#)rlogin.c 5.38 (Berkeley) 03/04/93"; 1635539Sbostic #endif /* not lint */ 1721595Sdist 1812990Ssam /* 1912990Ssam * rlogin - remote login 2012990Ssam */ 2126981Skarels #include <sys/param.h> 226444Swnj #include <sys/socket.h> 2329729Smckusick #include <sys/time.h> 2429729Smckusick #include <sys/resource.h> 2513620Ssam #include <sys/wait.h> 269365Ssam 279207Ssam #include <netinet/in.h> 2844346Skarels #include <netinet/in_systm.h> 2944346Skarels #include <netinet/ip.h> 309365Ssam 316444Swnj #include <errno.h> 32*58470Sbostic #include <fcntl.h> 33*58470Sbostic #include <netdb.h> 346444Swnj #include <pwd.h> 35*58470Sbostic #include <setjmp.h> 36*58470Sbostic #include <sgtty.h> 37*58470Sbostic #include <signal.h> 38*58470Sbostic #include <stdarg.h> 3940858Sbostic #include <stdio.h> 40*58470Sbostic #include <stdlib.h> 41*58470Sbostic #include <string.h> 4240858Sbostic #include <unistd.h> 436444Swnj 4440858Sbostic #ifdef KERBEROS 4541760Skfall #include <kerberosIV/des.h> 4640683Sbostic #include <kerberosIV/krb.h> 4736511Skfall 48*58470Sbostic #include "krb.h" 49*58470Sbostic 5040858Sbostic CREDENTIALS cred; 5140858Sbostic Key_schedule schedule; 5246850Sbostic int use_kerberos = 1, doencrypt; 5340858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 5440858Sbostic #endif 5524726Smckusick 5640858Sbostic #ifndef TIOCPKT_WINDOW 5740858Sbostic #define TIOCPKT_WINDOW 0x80 5840858Sbostic #endif 5929729Smckusick 6040858Sbostic /* concession to Sun */ 6140858Sbostic #ifndef SIGUSR1 6240858Sbostic #define SIGUSR1 30 6326981Skarels #endif 6440858Sbostic 6540858Sbostic int eight, litout, rem; 6645063Sbostic 6745063Sbostic int noescape; 6845063Sbostic u_char escapechar = '~'; 6945063Sbostic 7040858Sbostic char *speeds[] = { 7140858Sbostic "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 7240858Sbostic "1800", "2400", "4800", "9600", "19200", "38400" 7340858Sbostic }; 7440858Sbostic 75*58470Sbostic #ifdef SUNOS4 7626981Skarels struct winsize { 7726981Skarels unsigned short ws_row, ws_col; 7826981Skarels unsigned short ws_xpixel, ws_ypixel; 7926981Skarels }; 80*58470Sbostic #else 81*58470Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 8240858Sbostic #endif 8318358Ssam struct winsize winsize; 846444Swnj 85*58470Sbostic void catch_child __P((int)); 86*58470Sbostic void copytochild __P((int)); 87*58470Sbostic __dead void doit __P((long)); 88*58470Sbostic __dead void done __P((int)); 89*58470Sbostic void echo __P((char)); 90*58470Sbostic u_int getescape __P((char *)); 91*58470Sbostic void lostpeer __P((int)); 92*58470Sbostic void mode __P((int)); 93*58470Sbostic void msg __P((char *)); 94*58470Sbostic void oob __P((int)); 95*58470Sbostic int reader __P((int)); 96*58470Sbostic void sendwindow __P((void)); 97*58470Sbostic void setsignal __P((int)); 98*58470Sbostic void sigwinch __P((int)); 99*58470Sbostic void stop __P((char)); 100*58470Sbostic __dead void usage __P((void)); 101*58470Sbostic void writer __P((void)); 102*58470Sbostic void writeroob __P((int)); 103*58470Sbostic 104*58470Sbostic #ifdef KERBEROS 105*58470Sbostic void warning __P((const char *, ...)); 10640858Sbostic #endif 107*58470Sbostic #ifdef SUNOS4 108*58470Sbostic int get_window_size __P((int, struct winsize *)); 109*58470Sbostic #endif 11029729Smckusick 111*58470Sbostic int 1126444Swnj main(argc, argv) 1136444Swnj int argc; 114*58470Sbostic char *argv[]; 1156444Swnj { 11640858Sbostic extern char *optarg; 11740858Sbostic extern int optind; 11840858Sbostic struct passwd *pw; 11940858Sbostic struct servent *sp; 1206444Swnj struct sgttyb ttyb; 12140858Sbostic long omask; 12240858Sbostic int argoff, ch, dflag, one, uid; 12340858Sbostic char *host, *p, *user, term[1024]; 1246444Swnj 12540858Sbostic argoff = dflag = 0; 12640858Sbostic one = 1; 12740858Sbostic host = user = NULL; 12840858Sbostic 12940858Sbostic if (p = rindex(argv[0], '/')) 13040858Sbostic ++p; 1316444Swnj else 13240858Sbostic p = argv[0]; 13340858Sbostic 13440858Sbostic if (strcmp(p, "rlogin")) 13540858Sbostic host = p; 13640858Sbostic 13740858Sbostic /* handle "rlogin host flags" */ 13840858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 13940858Sbostic host = argv[1]; 14040858Sbostic argoff = 1; 1416444Swnj } 14236511Skfall 14340858Sbostic #ifdef KERBEROS 14445063Sbostic #define OPTIONS "8EKLde:k:l:x" 14540858Sbostic #else 14645063Sbostic #define OPTIONS "8EKLde:l:" 14740858Sbostic #endif 14840858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 14940858Sbostic switch(ch) { 15040858Sbostic case '8': 15140858Sbostic eight = 1; 15240858Sbostic break; 15345063Sbostic case 'E': 15445063Sbostic noescape = 1; 15545063Sbostic break; 15640868Sbostic case 'K': 15740868Sbostic #ifdef KERBEROS 15840868Sbostic use_kerberos = 0; 15940868Sbostic #endif 16040868Sbostic break; 16140858Sbostic case 'L': 16240858Sbostic litout = 1; 16340858Sbostic break; 16440858Sbostic case 'd': 16540858Sbostic dflag = 1; 16640858Sbostic break; 16740858Sbostic case 'e': 16853033Sleres noescape = 0; 16945063Sbostic escapechar = getescape(optarg); 17040858Sbostic break; 17140858Sbostic #ifdef KERBEROS 17240858Sbostic case 'k': 17340858Sbostic dest_realm = dst_realm_buf; 17440858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 17540858Sbostic break; 17640858Sbostic #endif 17740858Sbostic case 'l': 17840858Sbostic user = optarg; 17940858Sbostic break; 18053033Sleres #ifdef CRYPT 18153033Sleres #ifdef KERBEROS 18253033Sleres case 'x': 18353033Sleres doencrypt = 1; 18453033Sleres des_set_key(cred.session, schedule); 18553033Sleres break; 18653033Sleres #endif 18753033Sleres #endif 18840858Sbostic case '?': 18940858Sbostic default: 19040858Sbostic usage(); 19136524Skfall } 19240858Sbostic optind += argoff; 19340858Sbostic argc -= optind; 19440858Sbostic argv += optind; 19536524Skfall 19640858Sbostic /* if haven't gotten a host yet, do so */ 19740858Sbostic if (!host && !(host = *argv++)) 19840858Sbostic usage(); 19936511Skfall 20040858Sbostic if (*argv) 20140858Sbostic usage(); 20240858Sbostic 20340858Sbostic if (!(pw = getpwuid(uid = getuid()))) { 20440858Sbostic (void)fprintf(stderr, "rlogin: unknown user id.\n"); 2056444Swnj exit(1); 2066444Swnj } 20740858Sbostic if (!user) 20840858Sbostic user = pw->pw_name; 20940858Sbostic 21040868Sbostic sp = NULL; 21140858Sbostic #ifdef KERBEROS 21240868Sbostic if (use_kerberos) { 21346850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 21440868Sbostic if (sp == NULL) { 21540868Sbostic use_kerberos = 0; 21640868Sbostic warning("can't get entry for %s/tcp service", 21746850Sbostic doencrypt ? "eklogin" : "klogin"); 21840868Sbostic } 21936512Skfall } 22036512Skfall #endif 22140868Sbostic if (sp == NULL) 22240868Sbostic sp = getservbyname("login", "tcp"); 22340858Sbostic if (sp == NULL) { 22440858Sbostic (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 22540858Sbostic exit(1); 2269365Ssam } 22740858Sbostic 22840858Sbostic (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 22918358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 23040858Sbostic (void)strcat(term, "/"); 231*58470Sbostic (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 2326444Swnj } 23340858Sbostic 23440858Sbostic (void)get_window_size(0, &winsize); 23540858Sbostic 23640858Sbostic (void)signal(SIGPIPE, lostpeer); 23729729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 23840858Sbostic omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 23958261Smckusick /* 24058261Smckusick * We set SIGURG and SIGUSR1 below so that an 24158261Smckusick * incoming signal will be held pending rather than being 24258261Smckusick * discarded. Note that these routines will be ready to get 24358261Smckusick * a signal by the time that they are unblocked below. 24458261Smckusick */ 24558261Smckusick (void)signal(SIGURG, copytochild); 24658261Smckusick (void)signal(SIGUSR1, writeroob); 24736511Skfall 24840858Sbostic #ifdef KERBEROS 24936512Skfall try_connect: 25040858Sbostic if (use_kerberos) { 251*58470Sbostic struct hostent *hp; 252*58470Sbostic 253*58470Sbostic /* Fully qualify hostname (needed for krb_realmofhost). */ 25456960Seric hp = gethostbyname(host); 25556960Seric if (hp != NULL && !(host = strdup(hp->h_name))) { 256*58470Sbostic (void)fprintf(stderr, "rlogin: %s\n", 257*58470Sbostic strerror(ENOMEM)); 25856960Seric exit(1); 25956960Seric } 26056960Seric 26136512Skfall rem = KSUCCESS; 26240858Sbostic errno = 0; 26338728Skfall if (dest_realm == NULL) 26438728Skfall dest_realm = krb_realmofhost(host); 26538728Skfall 26653033Sleres #ifdef CRYPT 26753033Sleres if (doencrypt) 26853033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 26953033Sleres dest_realm, &cred, schedule); 27053033Sleres else 27153033Sleres #endif /* CRYPT */ 27240858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 27340858Sbostic dest_realm); 27438728Skfall if (rem < 0) { 27536512Skfall use_kerberos = 0; 27636628Skfall sp = getservbyname("login", "tcp"); 27740858Sbostic if (sp == NULL) { 27840858Sbostic (void)fprintf(stderr, 27940858Sbostic "rlogin: unknown service login/tcp.\n"); 28036628Skfall exit(1); 28136628Skfall } 28238728Skfall if (errno == ECONNREFUSED) 28340858Sbostic warning("remote host doesn't support Kerberos"); 28438728Skfall if (errno == ENOENT) 28540858Sbostic warning("can't provide Kerberos auth data"); 28636512Skfall goto try_connect; 28736512Skfall } 28836511Skfall } else { 28953033Sleres #ifdef CRYPT 29053033Sleres if (doencrypt) { 29153033Sleres (void)fprintf(stderr, 29253033Sleres "rlogin: the -x flag requires Kerberos authentication.\n"); 29353033Sleres exit(1); 29453033Sleres } 29553033Sleres #endif /* CRYPT */ 29640858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 29736511Skfall } 29836512Skfall #else 29940858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 30045256Smckusick #endif /* KERBEROS */ 30136511Skfall 30240858Sbostic if (rem < 0) 30336511Skfall exit(1); 30436511Skfall 30540858Sbostic if (dflag && 30640858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 30740858Sbostic (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 30840858Sbostic strerror(errno)); 30944346Skarels one = IPTOS_LOWDELAY; 31044346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 31144346Skarels perror("rlogin: setsockopt TOS (ignored)"); 31240858Sbostic 31340858Sbostic (void)setuid(uid); 31440858Sbostic doit(omask); 3159365Ssam /*NOTREACHED*/ 3166444Swnj } 3176444Swnj 31840858Sbostic int child, defflags, deflflags, tabflag; 31940858Sbostic char deferase, defkill; 32040858Sbostic struct tchars deftc; 32140858Sbostic struct ltchars defltc; 32240858Sbostic struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 32340858Sbostic struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3246444Swnj 325*58470Sbostic void 32640858Sbostic doit(omask) 32740858Sbostic long omask; 3286444Swnj { 32913075Ssam struct sgttyb sb; 3306444Swnj 33140858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 33213075Ssam defflags = sb.sg_flags; 33312155Ssam tabflag = defflags & TBDELAY; 3349962Ssam defflags &= ECHO | CRMOD; 33513075Ssam deferase = sb.sg_erase; 33613075Ssam defkill = sb.sg_kill; 337*58470Sbostic (void)ioctl(0, TIOCLGET, &deflflags); 338*58470Sbostic (void)ioctl(0, TIOCGETC, &deftc); 33913075Ssam notc.t_startc = deftc.t_startc; 34013075Ssam notc.t_stopc = deftc.t_stopc; 341*58470Sbostic (void)ioctl(0, TIOCGLTC, &defltc); 34240858Sbostic (void)signal(SIGINT, SIG_IGN); 343*58470Sbostic setsignal(SIGHUP); 344*58470Sbostic setsignal(SIGQUIT); 3459365Ssam child = fork(); 3469365Ssam if (child == -1) { 34740858Sbostic (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 34825424Skarels done(1); 3499365Ssam } 3509365Ssam if (child == 0) { 35124726Smckusick mode(1); 35240858Sbostic if (reader(omask) == 0) { 35340858Sbostic msg("connection closed."); 35425424Skarels exit(0); 35525424Skarels } 35612155Ssam sleep(1); 35740858Sbostic msg("\007connection closed."); 35840858Sbostic exit(1); 3596444Swnj } 36029729Smckusick 36129729Smckusick /* 36240858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 36358261Smckusick * receive one soon) that we really want to send to the reader. When 36458261Smckusick * one of these comes in, the trap copytochild simply copies such 36558261Smckusick * signals to the child. We can now unblock SIGURG and SIGUSR1 36658261Smckusick * that were set above. 36729729Smckusick */ 36840858Sbostic (void)sigsetmask(omask); 36940858Sbostic (void)signal(SIGCHLD, catch_child); 3709365Ssam writer(); 37140858Sbostic msg("closed connection."); 37225424Skarels done(0); 3736444Swnj } 3746444Swnj 37540858Sbostic /* trap a signal, unless it is being ignored. */ 376*58470Sbostic void 377*58470Sbostic setsignal(sig) 37840858Sbostic int sig; 37929729Smckusick { 38029729Smckusick int omask = sigblock(sigmask(sig)); 38129729Smckusick 382*58470Sbostic if (signal(sig, exit) == SIG_IGN) 38340858Sbostic (void)signal(sig, SIG_IGN); 38440858Sbostic (void)sigsetmask(omask); 38529729Smckusick } 38629729Smckusick 387*58470Sbostic __dead void 38825424Skarels done(status) 38925424Skarels int status; 3906444Swnj { 39146850Sbostic int w, wstatus; 3926444Swnj 3936444Swnj mode(0); 39429729Smckusick if (child > 0) { 39540858Sbostic /* make sure catch_child does not snap it up */ 39640858Sbostic (void)signal(SIGCHLD, SIG_DFL); 39729729Smckusick if (kill(child, SIGKILL) >= 0) 39846850Sbostic while ((w = wait(&wstatus)) > 0 && w != child); 39929729Smckusick } 40025424Skarels exit(status); 4016444Swnj } 4026444Swnj 40340858Sbostic int dosigwinch; 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 */ 40940858Sbostic void 410*58470Sbostic writeroob(signo) 411*58470Sbostic int signo; 41224726Smckusick { 41325341Smckusick if (dosigwinch == 0) { 41424919Smckusick sendwindow(); 41540858Sbostic (void)signal(SIGWINCH, sigwinch); 41625341Smckusick } 41724726Smckusick dosigwinch = 1; 41824726Smckusick } 41924726Smckusick 42040858Sbostic void 421*58470Sbostic catch_child(signo) 422*58470Sbostic int signo; 42311803Sedward { 42411803Sedward union wait status; 42511803Sedward int pid; 42611803Sedward 42740858Sbostic for (;;) { 42854125Sbostic pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 42940858Sbostic if (pid == 0) 43040858Sbostic return; 43140858Sbostic /* if the child (reader) dies, just quit */ 432*58470Sbostic if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 43340858Sbostic done((int)(status.w_termsig | status.w_retcode)); 43440858Sbostic } 43540858Sbostic /* NOTREACHED */ 43611803Sedward } 43711803Sedward 4386444Swnj /* 4399365Ssam * writer: write to remote: 0 -> line. 44045063Sbostic * ~. terminate 44145063Sbostic * ~^Z suspend rlogin process. 44245063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4436444Swnj */ 444*58470Sbostic void 4459365Ssam writer() 4466444Swnj { 44745063Sbostic register int bol, local, n; 44823530Sbloom char c; 4496444Swnj 45040858Sbostic bol = 1; /* beginning of line */ 45140858Sbostic local = 0; 45211803Sedward for (;;) { 45340858Sbostic n = read(STDIN_FILENO, &c, 1); 45418358Ssam if (n <= 0) { 45518358Ssam if (n < 0 && errno == EINTR) 45618358Ssam continue; 45711803Sedward break; 45818358Ssam } 4599365Ssam /* 46040858Sbostic * If we're at the beginning of the line and recognize a 46140858Sbostic * command character, then we echo locally. Otherwise, 46240858Sbostic * characters are echo'd remotely. If the command character 46340858Sbostic * is doubled, this acts as a force and local echo is 46440858Sbostic * suppressed. 4659365Ssam */ 46623530Sbloom if (bol) { 46723530Sbloom bol = 0; 46845063Sbostic if (!noescape && c == escapechar) { 46923530Sbloom local = 1; 47023530Sbloom continue; 4716444Swnj } 47223530Sbloom } else if (local) { 47323530Sbloom local = 0; 47423530Sbloom if (c == '.' || c == deftc.t_eofc) { 47523530Sbloom echo(c); 47623530Sbloom break; 4776444Swnj } 47823530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 47923530Sbloom bol = 1; 48023530Sbloom echo(c); 48123530Sbloom stop(c); 48223530Sbloom continue; 48323530Sbloom } 48445063Sbostic if (c != escapechar) 48553033Sleres #ifdef CRYPT 48653033Sleres #ifdef KERBEROS 48753033Sleres if (doencrypt) 488*58470Sbostic (void)des_write(rem, 489*58470Sbostic (char *)&escapechar, 1); 49053033Sleres else 49153033Sleres #endif 49253033Sleres #endif 49345063Sbostic (void)write(rem, &escapechar, 1); 4946444Swnj } 49536511Skfall 49653033Sleres #ifdef CRYPT 49753033Sleres #ifdef KERBEROS 49853033Sleres if (doencrypt) { 49953033Sleres if (des_write(rem, &c, 1) == 0) { 50053033Sleres msg("line gone"); 50153033Sleres break; 50253033Sleres } 50353033Sleres } else 50453033Sleres #endif 50553033Sleres #endif 50636511Skfall if (write(rem, &c, 1) == 0) { 50740858Sbostic msg("line gone"); 50836511Skfall break; 50936511Skfall } 51023530Sbloom bol = c == defkill || c == deftc.t_eofc || 51125424Skarels c == deftc.t_intrc || c == defltc.t_suspc || 51223530Sbloom c == '\r' || c == '\n'; 5136444Swnj } 5146444Swnj } 5156444Swnj 516*58470Sbostic void 517*58470Sbostic #if __STDC__ 518*58470Sbostic echo(register char c) 519*58470Sbostic #else 52023530Sbloom echo(c) 521*58470Sbostic register char c; 522*58470Sbostic #endif 52323530Sbloom { 52440858Sbostic register char *p; 52523530Sbloom char buf[8]; 52623530Sbloom 52740858Sbostic p = buf; 52823530Sbloom c &= 0177; 52945063Sbostic *p++ = escapechar; 53023530Sbloom if (c < ' ') { 53123530Sbloom *p++ = '^'; 53223530Sbloom *p++ = c + '@'; 53323530Sbloom } else if (c == 0177) { 53423530Sbloom *p++ = '^'; 53523530Sbloom *p++ = '?'; 53623530Sbloom } else 53723530Sbloom *p++ = c; 53823530Sbloom *p++ = '\r'; 53923530Sbloom *p++ = '\n'; 54045063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 54123530Sbloom } 54223530Sbloom 543*58470Sbostic void 544*58470Sbostic #if __STDC__ 545*58470Sbostic stop(char cmdc) 546*58470Sbostic #else 54718358Ssam stop(cmdc) 54818358Ssam char cmdc; 549*58470Sbostic #endif 55018358Ssam { 55118358Ssam mode(0); 55240858Sbostic (void)signal(SIGCHLD, SIG_IGN); 55340858Sbostic (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 55440858Sbostic (void)signal(SIGCHLD, catch_child); 55518358Ssam mode(1); 556*58470Sbostic sigwinch(0); /* check for size changes */ 55718358Ssam } 55818358Ssam 55940858Sbostic void 560*58470Sbostic sigwinch(signo) 561*58470Sbostic int signo; 56218358Ssam { 56318358Ssam struct winsize ws; 56418358Ssam 56529729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 56640858Sbostic bcmp(&ws, &winsize, sizeof(ws))) { 56718358Ssam winsize = ws; 56824726Smckusick sendwindow(); 56918358Ssam } 57018358Ssam } 57118358Ssam 57224726Smckusick /* 57324726Smckusick * Send the window size to the server via the magic escape 57424726Smckusick */ 575*58470Sbostic void 57624726Smckusick sendwindow() 57724726Smckusick { 57840858Sbostic struct winsize *wp; 57924726Smckusick char obuf[4 + sizeof (struct winsize)]; 58024726Smckusick 58140858Sbostic wp = (struct winsize *)(obuf+4); 58224726Smckusick obuf[0] = 0377; 58324726Smckusick obuf[1] = 0377; 58424726Smckusick obuf[2] = 's'; 58524726Smckusick obuf[3] = 's'; 58624726Smckusick wp->ws_row = htons(winsize.ws_row); 58724726Smckusick wp->ws_col = htons(winsize.ws_col); 58824726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 58924726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 59036511Skfall 59153033Sleres #ifdef CRYPT 59253033Sleres #ifdef KERBEROS 59353033Sleres if(doencrypt) 59453033Sleres (void)des_write(rem, obuf, sizeof(obuf)); 59553033Sleres else 59653033Sleres #endif 59753033Sleres #endif 59840858Sbostic (void)write(rem, obuf, sizeof(obuf)); 59924726Smckusick } 60024726Smckusick 60125424Skarels /* 60225424Skarels * reader: read from remote: line -> 1 60325424Skarels */ 60425424Skarels #define READING 1 60525424Skarels #define WRITING 2 60625424Skarels 60740858Sbostic jmp_buf rcvtop; 60840858Sbostic int ppid, rcvcnt, rcvstate; 60940858Sbostic char rcvbuf[8 * 1024]; 61025424Skarels 61140858Sbostic void 612*58470Sbostic oob(signo) 613*58470Sbostic int signo; 6146444Swnj { 61540858Sbostic struct sgttyb sb; 61640858Sbostic int atmark, n, out, rcvd; 6179365Ssam char waste[BUFSIZ], mark; 6186444Swnj 61942230Sbostic out = O_RDWR; 62040858Sbostic rcvd = 0; 62125424Skarels while (recv(rem, &mark, 1, MSG_OOB) < 0) 62225424Skarels switch (errno) { 62325424Skarels case EWOULDBLOCK: 62425424Skarels /* 62540858Sbostic * Urgent data not here yet. It may not be possible 62640858Sbostic * to send it yet if we are blocked for output and 62740858Sbostic * our input buffer is full. 62825424Skarels */ 62925424Skarels if (rcvcnt < sizeof(rcvbuf)) { 63025424Skarels n = read(rem, rcvbuf + rcvcnt, 63140858Sbostic sizeof(rcvbuf) - rcvcnt); 63225424Skarels if (n <= 0) 63325424Skarels return; 63425424Skarels rcvd += n; 63525424Skarels } else { 63625424Skarels n = read(rem, waste, sizeof(waste)); 63725424Skarels if (n <= 0) 63825424Skarels return; 63925424Skarels } 64025424Skarels continue; 64125424Skarels default: 64225424Skarels return; 6436444Swnj } 64425424Skarels if (mark & TIOCPKT_WINDOW) { 64540858Sbostic /* Let server know about window size changes */ 64640858Sbostic (void)kill(ppid, SIGUSR1); 64724726Smckusick } 64825424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 64940858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 65024726Smckusick sb.sg_flags &= ~CBREAK; 65124726Smckusick sb.sg_flags |= RAW; 65240858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 65313075Ssam notc.t_stopc = -1; 65413075Ssam notc.t_startc = -1; 65540858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6566444Swnj } 65725424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 65840858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 65924726Smckusick sb.sg_flags &= ~RAW; 66024726Smckusick sb.sg_flags |= CBREAK; 66140858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 66213075Ssam notc.t_stopc = deftc.t_stopc; 66313075Ssam notc.t_startc = deftc.t_startc; 66440858Sbostic (void)ioctl(0, TIOCSETC, (char *)¬c); 6656444Swnj } 66625424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 66740858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 66825424Skarels for (;;) { 66925424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 67040858Sbostic (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 67140858Sbostic strerror(errno)); 67225424Skarels break; 67325424Skarels } 67425424Skarels if (atmark) 67525424Skarels break; 67625424Skarels n = read(rem, waste, sizeof (waste)); 67725424Skarels if (n <= 0) 67825424Skarels break; 67925424Skarels } 68025424Skarels /* 68140858Sbostic * Don't want any pending data to be output, so clear the recv 68240858Sbostic * buffer. If we were hanging on a write when interrupted, 68340858Sbostic * don't want it to restart. If we were reading, restart 68440858Sbostic * anyway. 68525424Skarels */ 68625424Skarels rcvcnt = 0; 68725424Skarels longjmp(rcvtop, 1); 68825424Skarels } 68929729Smckusick 69040858Sbostic /* oob does not do FLUSHREAD (alas!) */ 69129729Smckusick 69229729Smckusick /* 69340858Sbostic * If we filled the receive buffer while a read was pending, longjmp 69440858Sbostic * to the top to restart appropriately. Don't abort a pending write, 69540858Sbostic * however, or we won't know how much was written. 69625424Skarels */ 69725424Skarels if (rcvd && rcvstate == READING) 69825424Skarels longjmp(rcvtop, 1); 6996444Swnj } 7006444Swnj 70140858Sbostic /* reader: read from remote: line -> 1 */ 702*58470Sbostic int 70340858Sbostic reader(omask) 70440858Sbostic int omask; 7056444Swnj { 70640858Sbostic 70726981Skarels #if !defined(BSD) || BSD < 43 70826981Skarels int pid = -getpid(); 70926981Skarels #else 71025424Skarels int pid = getpid(); 71126981Skarels #endif 71225424Skarels int n, remaining; 71325424Skarels char *bufp = rcvbuf; 7146444Swnj 71540858Sbostic (void)signal(SIGTTOU, SIG_IGN); 71640858Sbostic (void)signal(SIGURG, oob); 71726981Skarels ppid = getppid(); 71840858Sbostic (void)fcntl(rem, F_SETOWN, pid); 71940858Sbostic (void)setjmp(rcvtop); 72040858Sbostic (void)sigsetmask(omask); 7216444Swnj for (;;) { 72225424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 72325424Skarels rcvstate = WRITING; 72445063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 72525424Skarels if (n < 0) { 72625424Skarels if (errno != EINTR) 727*58470Sbostic return (-1); 72825424Skarels continue; 72925424Skarels } 73025424Skarels bufp += n; 73125424Skarels } 73225424Skarels bufp = rcvbuf; 73325424Skarels rcvcnt = 0; 73425424Skarels rcvstate = READING; 73536511Skfall 73653033Sleres #ifdef CRYPT 73753033Sleres #ifdef KERBEROS 73853033Sleres if (doencrypt) 73953033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 74053033Sleres else 74153033Sleres #endif 74253033Sleres #endif 74336511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 74425424Skarels if (rcvcnt == 0) 74525424Skarels return (0); 74625424Skarels if (rcvcnt < 0) { 7479365Ssam if (errno == EINTR) 7486444Swnj continue; 74940858Sbostic (void)fprintf(stderr, "rlogin: read: %s.\n", 75040858Sbostic strerror(errno)); 751*58470Sbostic return (-1); 7526444Swnj } 7536444Swnj } 7546444Swnj } 7556444Swnj 756*58470Sbostic void 7576444Swnj mode(f) 758*58470Sbostic int f; 7596444Swnj { 76013075Ssam struct ltchars *ltc; 76113075Ssam struct sgttyb sb; 76240858Sbostic struct tchars *tc; 76340858Sbostic int lflags; 7649365Ssam 76540858Sbostic (void)ioctl(0, TIOCGETP, (char *)&sb); 76640858Sbostic (void)ioctl(0, TIOCLGET, (char *)&lflags); 76740858Sbostic switch(f) { 7689962Ssam case 0: 76913075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 77013075Ssam sb.sg_flags |= defflags|tabflag; 7719962Ssam tc = &deftc; 77213075Ssam ltc = &defltc; 77313075Ssam sb.sg_kill = defkill; 77413075Ssam sb.sg_erase = deferase; 77521583Sbloom lflags = deflflags; 7769962Ssam break; 7779962Ssam case 1: 77813075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 77913075Ssam sb.sg_flags &= ~defflags; 78012155Ssam /* preserve tab delays, but turn off XTABS */ 78113075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 78213075Ssam sb.sg_flags &= ~TBDELAY; 7839962Ssam tc = ¬c; 78413075Ssam ltc = &noltc; 78513075Ssam sb.sg_kill = sb.sg_erase = -1; 78621583Sbloom if (litout) 78721583Sbloom lflags |= LLITOUT; 7889962Ssam break; 7899962Ssam default: 7909962Ssam return; 7916444Swnj } 79240858Sbostic (void)ioctl(0, TIOCSLTC, (char *)ltc); 79340858Sbostic (void)ioctl(0, TIOCSETC, (char *)tc); 79440858Sbostic (void)ioctl(0, TIOCSETN, (char *)&sb); 79540858Sbostic (void)ioctl(0, TIOCLSET, (char *)&lflags); 7966444Swnj } 7976444Swnj 79840858Sbostic void 799*58470Sbostic lostpeer(signo) 800*58470Sbostic int signo; 8016444Swnj { 80240858Sbostic (void)signal(SIGPIPE, SIG_IGN); 80340858Sbostic msg("\007connection closed."); 80440858Sbostic done(1); 80540858Sbostic } 80629729Smckusick 80740858Sbostic /* copy SIGURGs to the child process. */ 80840858Sbostic void 809*58470Sbostic copytochild(signo) 810*58470Sbostic int signo; 81140858Sbostic { 81240858Sbostic (void)kill(child, SIGURG); 8136444Swnj } 8146444Swnj 815*58470Sbostic void 81640858Sbostic msg(str) 81740858Sbostic char *str; 8186444Swnj { 81940858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 82040858Sbostic } 82129729Smckusick 82240858Sbostic #ifdef KERBEROS 82340858Sbostic /* VARARGS */ 824*58470Sbostic void 825*58470Sbostic #if __STDC__ 826*58470Sbostic warning(const char *fmt, ...) 827*58470Sbostic #else 828*58470Sbostic warning(fmt, va_alist) 829*58470Sbostic char *fmt; 830*58470Sbostic va_dcl 831*58470Sbostic #endif 83240858Sbostic { 83340858Sbostic va_list ap; 83440858Sbostic 83540858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 836*58470Sbostic #ifdef __STDC__ 837*58470Sbostic va_start(ap, fmt); 838*58470Sbostic #else 83940858Sbostic va_start(ap); 840*58470Sbostic #endif 84140858Sbostic fmt = va_arg(ap, char *); 84240858Sbostic vfprintf(stderr, fmt, ap); 84340858Sbostic va_end(ap); 84440858Sbostic (void)fprintf(stderr, ".\n"); 8456444Swnj } 84640858Sbostic #endif 84736512Skfall 848*58470Sbostic __dead void 84940858Sbostic usage() 85036512Skfall { 85140858Sbostic (void)fprintf(stderr, 85240858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 85340858Sbostic #ifdef KERBEROS 85453033Sleres #ifdef CRYPT 85554125Sbostic "8EKLx", " [-k realm] "); 85653033Sleres #else 85754125Sbostic "8EKL", " [-k realm] "); 85853033Sleres #endif 85945256Smckusick #else 86045063Sbostic "8EL", " "); 86140858Sbostic #endif 86240858Sbostic exit(1); 86336512Skfall } 86440858Sbostic 86540858Sbostic /* 86640858Sbostic * The following routine provides compatibility (such as it is) between 4.2BSD 86740858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 86840858Sbostic */ 869*58470Sbostic #ifdef SUNOS4 870*58470Sbostic int 87140858Sbostic get_window_size(fd, wp) 87240858Sbostic int fd; 87340858Sbostic struct winsize *wp; 87440858Sbostic { 87540858Sbostic struct ttysize ts; 87640858Sbostic int error; 87740858Sbostic 87840858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 879*58470Sbostic return (error); 88040858Sbostic wp->ws_row = ts.ts_lines; 88140858Sbostic wp->ws_col = ts.ts_cols; 88240858Sbostic wp->ws_xpixel = 0; 88340858Sbostic wp->ws_ypixel = 0; 884*58470Sbostic return (0); 88540858Sbostic } 88640858Sbostic #endif 88745063Sbostic 888*58470Sbostic u_int 88945063Sbostic getescape(p) 89045063Sbostic register char *p; 89145063Sbostic { 89245063Sbostic long val; 89345063Sbostic int len; 89445063Sbostic 89545063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 896*58470Sbostic return ((u_int)*p); 89745063Sbostic /* otherwise, \nnn */ 89845063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 899*58470Sbostic val = strtol(++p, NULL, 8); 90045063Sbostic for (;;) { 90145063Sbostic if (!*++p) 902*58470Sbostic return ((u_int)val); 90345063Sbostic if (*p < '0' || *p > '8') 90445063Sbostic break; 90545063Sbostic } 90645063Sbostic } 90745063Sbostic msg("illegal option value -- e"); 90845063Sbostic usage(); 90945063Sbostic /* NOTREACHED */ 91045063Sbostic } 911