rlogin.c revision 47549
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1983, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3527919Scharnierstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1983, 1990, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 4129922Smarkmstatic const char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; 4227919Scharnierstatic const char rcsid[] = 4347549Sbde "$Id: rlogin.c,v 1.19 1999/05/25 11:14:33 peter Exp $"; 441590Srgrimes#endif /* not lint */ 451590Srgrimes 461590Srgrimes/* 471590Srgrimes * rlogin - remote login 481590Srgrimes */ 491590Srgrimes#include <sys/param.h> 501590Srgrimes#include <sys/socket.h> 511590Srgrimes#include <sys/time.h> 521590Srgrimes#include <sys/resource.h> 531590Srgrimes#include <sys/wait.h> 541590Srgrimes 551590Srgrimes#include <netinet/in.h> 561590Srgrimes#include <netinet/in_systm.h> 571590Srgrimes#include <netinet/ip.h> 588232Sdg#include <netinet/tcp.h> 591590Srgrimes 6027919Scharnier#include <err.h> 611590Srgrimes#include <errno.h> 621590Srgrimes#include <fcntl.h> 6340103Smarkm#include <libutil.h> 641590Srgrimes#include <netdb.h> 651590Srgrimes#include <pwd.h> 661590Srgrimes#include <setjmp.h> 671590Srgrimes#include <sgtty.h> 681590Srgrimes#include <signal.h> 691590Srgrimes#include <stdio.h> 701590Srgrimes#include <stdlib.h> 711590Srgrimes#include <string.h> 721590Srgrimes#include <unistd.h> 7329922Smarkm#include <err.h> 741590Srgrimes 751590Srgrimes#ifdef KERBEROS 7614024Smarkm#include <des.h> 7729922Smarkm#include <krb.h> 781590Srgrimes 7934897Smarkm#include "../../bin/rcp/pathnames.h" 801590Srgrimes#include "krb.h" 811590Srgrimes 821590SrgrimesCREDENTIALS cred; 831590SrgrimesKey_schedule schedule; 841590Srgrimesint use_kerberos = 1, doencrypt; 851590Srgrimeschar dst_realm_buf[REALM_SZ], *dest_realm = NULL; 861590Srgrimes#endif 871590Srgrimes 881590Srgrimes#ifndef TIOCPKT_WINDOW 891590Srgrimes#define TIOCPKT_WINDOW 0x80 901590Srgrimes#endif 911590Srgrimes 921590Srgrimes/* concession to Sun */ 931590Srgrimes#ifndef SIGUSR1 941590Srgrimes#define SIGUSR1 30 951590Srgrimes#endif 961590Srgrimes 971590Srgrimesint eight, litout, rem; 981590Srgrimes 991590Srgrimesint noescape; 1001590Srgrimesu_char escapechar = '~'; 1011590Srgrimes 1021590Srgrimeschar *speeds[] = { 1031590Srgrimes "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 1049881Sache "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" 10517284Spst#define MAX_SPEED_LENGTH (sizeof("115200") - 1) 1061590Srgrimes}; 1071590Srgrimes 1081590Srgrimes#ifdef OLDSUN 1091590Srgrimesstruct winsize { 1101590Srgrimes unsigned short ws_row, ws_col; 1111590Srgrimes unsigned short ws_xpixel, ws_ypixel; 1121590Srgrimes}; 1131590Srgrimes#else 1141590Srgrimes#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 1151590Srgrimes#endif 1161590Srgrimesstruct winsize winsize; 1171590Srgrimes 1181590Srgrimesvoid catch_child __P((int)); 1191590Srgrimesvoid copytochild __P((int)); 12018286Sbdevoid doit __P((long)) __dead2; 12118286Sbdevoid done __P((int)) __dead2; 1221590Srgrimesvoid echo __P((char)); 1231590Srgrimesu_int getescape __P((char *)); 1241590Srgrimesvoid lostpeer __P((int)); 1251590Srgrimesvoid mode __P((int)); 1261590Srgrimesvoid msg __P((char *)); 1271590Srgrimesvoid oob __P((int)); 1281590Srgrimesint reader __P((int)); 1291590Srgrimesvoid sendwindow __P((void)); 1301590Srgrimesvoid setsignal __P((int)); 1311590Srgrimesvoid sigwinch __P((int)); 1321590Srgrimesvoid stop __P((char)); 13318286Sbdevoid usage __P((void)) __dead2; 1341590Srgrimesvoid writer __P((void)); 1351590Srgrimesvoid writeroob __P((int)); 1361590Srgrimes 1371590Srgrimes#ifdef OLDSUN 1381590Srgrimesint get_window_size __P((int, struct winsize *)); 1391590Srgrimes#endif 1401590Srgrimes 1411590Srgrimesint 1421590Srgrimesmain(argc, argv) 1431590Srgrimes int argc; 1441590Srgrimes char *argv[]; 1451590Srgrimes{ 1461590Srgrimes extern char *optarg; 1471590Srgrimes extern int optind; 1481590Srgrimes struct passwd *pw; 1491590Srgrimes struct servent *sp; 1501590Srgrimes struct sgttyb ttyb; 1511590Srgrimes long omask; 1528232Sdg int argoff, ch, dflag, Dflag, one, uid; 15347549Sbde char *host, *localname, *p, *user, term[1024]; 15440103Smarkm#ifdef KERBEROS 15540103Smarkm char *k; 15640103Smarkm#endif 1571590Srgrimes 1588232Sdg argoff = dflag = Dflag = 0; 1591590Srgrimes one = 1; 16047549Sbde host = localname = user = NULL; 1611590Srgrimes 16229922Smarkm if ((p = rindex(argv[0], '/'))) 1631590Srgrimes ++p; 1641590Srgrimes else 1651590Srgrimes p = argv[0]; 1661590Srgrimes 1671590Srgrimes if (strcmp(p, "rlogin")) 1681590Srgrimes host = p; 1691590Srgrimes 1701590Srgrimes /* handle "rlogin host flags" */ 1711590Srgrimes if (!host && argc > 2 && argv[1][0] != '-') { 1721590Srgrimes host = argv[1]; 1731590Srgrimes argoff = 1; 1741590Srgrimes } 1751590Srgrimes 1761590Srgrimes#ifdef KERBEROS 17747488Speter#define OPTIONS "8DEKLde:i:k:l:x" 1781590Srgrimes#else 17947488Speter#define OPTIONS "8DEKLde:i:l:" 1801590Srgrimes#endif 18124360Simp while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 1821590Srgrimes switch(ch) { 1831590Srgrimes case '8': 1841590Srgrimes eight = 1; 1851590Srgrimes break; 1868232Sdg case 'D': 1878232Sdg Dflag = 1; 1888232Sdg break; 1891590Srgrimes case 'E': 1901590Srgrimes noescape = 1; 1911590Srgrimes break; 1921590Srgrimes case 'K': 1931590Srgrimes#ifdef KERBEROS 1941590Srgrimes use_kerberos = 0; 1951590Srgrimes#endif 1961590Srgrimes break; 1971590Srgrimes case 'L': 1981590Srgrimes litout = 1; 1991590Srgrimes break; 2001590Srgrimes case 'd': 2011590Srgrimes dflag = 1; 2021590Srgrimes break; 2031590Srgrimes case 'e': 2041590Srgrimes noescape = 0; 2051590Srgrimes escapechar = getescape(optarg); 2061590Srgrimes break; 20747488Speter case 'i': 20847549Sbde if (getuid() != 0) 20947549Sbde errx(1, "-i user: permission denied"); 21047488Speter localname = optarg; 21147488Speter break; 2121590Srgrimes#ifdef KERBEROS 2131590Srgrimes case 'k': 2141590Srgrimes dest_realm = dst_realm_buf; 2151590Srgrimes (void)strncpy(dest_realm, optarg, REALM_SZ); 2161590Srgrimes break; 2171590Srgrimes#endif 2181590Srgrimes case 'l': 2191590Srgrimes user = optarg; 2201590Srgrimes break; 2211590Srgrimes#ifdef CRYPT 2221590Srgrimes#ifdef KERBEROS 2231590Srgrimes case 'x': 2241590Srgrimes doencrypt = 1; 2251590Srgrimes break; 2261590Srgrimes#endif 2271590Srgrimes#endif 2281590Srgrimes case '?': 2291590Srgrimes default: 2301590Srgrimes usage(); 2311590Srgrimes } 2321590Srgrimes optind += argoff; 2331590Srgrimes 2341590Srgrimes /* if haven't gotten a host yet, do so */ 23534897Smarkm if (!host && !(host = argv[optind++])) 2361590Srgrimes usage(); 2371590Srgrimes 23834897Smarkm if (argv[optind]) 2391590Srgrimes usage(); 2401590Srgrimes 24127919Scharnier if (!(pw = getpwuid(uid = getuid()))) 24227919Scharnier errx(1, "unknown user id"); 2431590Srgrimes if (!user) 2441590Srgrimes user = pw->pw_name; 24547488Speter if (!localname) 24647488Speter localname = pw->pw_name; 2471590Srgrimes 2481590Srgrimes sp = NULL; 2491590Srgrimes#ifdef KERBEROS 25040103Smarkm k = auth_getval("auth_list"); 25140103Smarkm if (k && !strstr(k, "kerberos")) 25240103Smarkm use_kerberos = 0; 2531590Srgrimes if (use_kerberos) { 2541590Srgrimes sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 2551590Srgrimes if (sp == NULL) { 2561590Srgrimes use_kerberos = 0; 25729922Smarkm warn("can't get entry for %s/tcp service", 2581590Srgrimes doencrypt ? "eklogin" : "klogin"); 2591590Srgrimes } 2601590Srgrimes } 2611590Srgrimes#endif 2621590Srgrimes if (sp == NULL) 2631590Srgrimes sp = getservbyname("login", "tcp"); 26427919Scharnier if (sp == NULL) 26527919Scharnier errx(1, "login/tcp: unknown service"); 2661590Srgrimes 26717284Spst#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) 26817284Spst 26917284Spst (void)strncpy(term, (p = getenv("TERM")) ? p : "network", 27017284Spst MAX_TERM_LENGTH); 27117284Spst term[MAX_TERM_LENGTH] = '\0'; 2721590Srgrimes if (ioctl(0, TIOCGETP, &ttyb) == 0) { 2731590Srgrimes (void)strcat(term, "/"); 2741590Srgrimes (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 2751590Srgrimes } 2761590Srgrimes 2771590Srgrimes (void)get_window_size(0, &winsize); 2781590Srgrimes 2791590Srgrimes (void)signal(SIGPIPE, lostpeer); 2801590Srgrimes /* will use SIGUSR1 for window size hack, so hold it off */ 2811590Srgrimes omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 2821590Srgrimes /* 2831590Srgrimes * We set SIGURG and SIGUSR1 below so that an 2841590Srgrimes * incoming signal will be held pending rather than being 2851590Srgrimes * discarded. Note that these routines will be ready to get 2861590Srgrimes * a signal by the time that they are unblocked below. 2871590Srgrimes */ 2881590Srgrimes (void)signal(SIGURG, copytochild); 2891590Srgrimes (void)signal(SIGUSR1, writeroob); 2901590Srgrimes 2911590Srgrimes#ifdef KERBEROS 2921590Srgrimes if (use_kerberos) { 29334897Smarkm setuid(getuid()); 2941590Srgrimes rem = KSUCCESS; 2951590Srgrimes errno = 0; 2961590Srgrimes if (dest_realm == NULL) 2971590Srgrimes dest_realm = krb_realmofhost(host); 2981590Srgrimes 2991590Srgrimes#ifdef CRYPT 3003113Sdfr if (doencrypt) { 3011590Srgrimes rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 3021590Srgrimes dest_realm, &cred, schedule); 30329922Smarkm des_set_key(&cred.session, schedule); 3043113Sdfr } else 3051590Srgrimes#endif /* CRYPT */ 3061590Srgrimes rem = krcmd(&host, sp->s_port, user, term, 0, 3071590Srgrimes dest_realm); 3081590Srgrimes if (rem < 0) { 30934897Smarkm int i; 31034897Smarkm char **newargv; 31134897Smarkm 3121590Srgrimes sp = getservbyname("login", "tcp"); 31327919Scharnier if (sp == NULL) 31427919Scharnier errx(1, "unknown service login/tcp"); 3151590Srgrimes if (errno == ECONNREFUSED) 31629922Smarkm warn("remote host doesn't support Kerberos"); 3171590Srgrimes if (errno == ENOENT) 31829922Smarkm warn("can't provide Kerberos auth data"); 31934897Smarkm newargv = malloc((argc + 2) * sizeof(*newargv)); 32034897Smarkm if (newargv == NULL) 32134897Smarkm err(1, "malloc"); 32234897Smarkm newargv[0] = argv[0]; 32334897Smarkm newargv[1] = "-K"; 32434897Smarkm for(i = 1; i < argc; ++i) 32534897Smarkm newargv[i + 1] = argv[i]; 32634897Smarkm newargv[argc + 1] = NULL; 32734897Smarkm execv(_PATH_RLOGIN, newargv); 3281590Srgrimes } 3291590Srgrimes } else { 3301590Srgrimes#ifdef CRYPT 33127919Scharnier if (doencrypt) 33227919Scharnier errx(1, "the -x flag requires Kerberos authentication"); 3331590Srgrimes#endif /* CRYPT */ 33447488Speter rem = rcmd(&host, sp->s_port, localname, user, term, 0); 3351590Srgrimes } 3361590Srgrimes#else 33747488Speter rem = rcmd(&host, sp->s_port, localname, user, term, 0); 3381590Srgrimes#endif /* KERBEROS */ 3391590Srgrimes 3401590Srgrimes if (rem < 0) 3411590Srgrimes exit(1); 3421590Srgrimes 3431590Srgrimes if (dflag && 3441590Srgrimes setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 34527919Scharnier warn("setsockopt"); 3468232Sdg if (Dflag && 3478232Sdg setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 34827919Scharnier warn("setsockopt NODELAY (ignored)"); 3498232Sdg 3501590Srgrimes one = IPTOS_LOWDELAY; 3511590Srgrimes if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 35227919Scharnier warn("setsockopt TOS (ignored)"); 3531590Srgrimes 3541590Srgrimes (void)setuid(uid); 3551590Srgrimes doit(omask); 3561590Srgrimes /*NOTREACHED*/ 3571590Srgrimes} 3581590Srgrimes 3591590Srgrimesint child, defflags, deflflags, tabflag; 3601590Srgrimeschar deferase, defkill; 3611590Srgrimesstruct tchars deftc; 3621590Srgrimesstruct ltchars defltc; 3631590Srgrimesstruct tchars notc = { -1, -1, -1, -1, -1, -1 }; 3641590Srgrimesstruct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3651590Srgrimes 3661590Srgrimesvoid 3671590Srgrimesdoit(omask) 3681590Srgrimes long omask; 3691590Srgrimes{ 3701590Srgrimes struct sgttyb sb; 3711590Srgrimes 3721590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 3731590Srgrimes defflags = sb.sg_flags; 3741590Srgrimes tabflag = defflags & TBDELAY; 3751590Srgrimes defflags &= ECHO | CRMOD; 3761590Srgrimes deferase = sb.sg_erase; 3771590Srgrimes defkill = sb.sg_kill; 3781590Srgrimes (void)ioctl(0, TIOCLGET, &deflflags); 3791590Srgrimes (void)ioctl(0, TIOCGETC, &deftc); 3801590Srgrimes notc.t_startc = deftc.t_startc; 3811590Srgrimes notc.t_stopc = deftc.t_stopc; 3821590Srgrimes (void)ioctl(0, TIOCGLTC, &defltc); 3831590Srgrimes (void)signal(SIGINT, SIG_IGN); 3841590Srgrimes setsignal(SIGHUP); 3851590Srgrimes setsignal(SIGQUIT); 3861590Srgrimes child = fork(); 3871590Srgrimes if (child == -1) { 38827919Scharnier warn("fork"); 3891590Srgrimes done(1); 3901590Srgrimes } 3911590Srgrimes if (child == 0) { 3921590Srgrimes mode(1); 3931590Srgrimes if (reader(omask) == 0) { 3941590Srgrimes msg("connection closed."); 3951590Srgrimes exit(0); 3961590Srgrimes } 3971590Srgrimes sleep(1); 3981590Srgrimes msg("\007connection closed."); 3991590Srgrimes exit(1); 4001590Srgrimes } 4011590Srgrimes 4021590Srgrimes /* 4031590Srgrimes * We may still own the socket, and may have a pending SIGURG (or might 4041590Srgrimes * receive one soon) that we really want to send to the reader. When 4051590Srgrimes * one of these comes in, the trap copytochild simply copies such 4061590Srgrimes * signals to the child. We can now unblock SIGURG and SIGUSR1 4071590Srgrimes * that were set above. 4081590Srgrimes */ 4091590Srgrimes (void)sigsetmask(omask); 4101590Srgrimes (void)signal(SIGCHLD, catch_child); 4111590Srgrimes writer(); 4121590Srgrimes msg("closed connection."); 4131590Srgrimes done(0); 4141590Srgrimes} 4151590Srgrimes 4161590Srgrimes/* trap a signal, unless it is being ignored. */ 4171590Srgrimesvoid 4181590Srgrimessetsignal(sig) 4191590Srgrimes int sig; 4201590Srgrimes{ 4211590Srgrimes int omask = sigblock(sigmask(sig)); 4221590Srgrimes 4231590Srgrimes if (signal(sig, exit) == SIG_IGN) 4241590Srgrimes (void)signal(sig, SIG_IGN); 4251590Srgrimes (void)sigsetmask(omask); 4261590Srgrimes} 4271590Srgrimes 42818286Sbdevoid 4291590Srgrimesdone(status) 4301590Srgrimes int status; 4311590Srgrimes{ 4321590Srgrimes int w, wstatus; 4331590Srgrimes 4341590Srgrimes mode(0); 4351590Srgrimes if (child > 0) { 4361590Srgrimes /* make sure catch_child does not snap it up */ 4371590Srgrimes (void)signal(SIGCHLD, SIG_DFL); 4381590Srgrimes if (kill(child, SIGKILL) >= 0) 4391590Srgrimes while ((w = wait(&wstatus)) > 0 && w != child); 4401590Srgrimes } 4411590Srgrimes exit(status); 4421590Srgrimes} 4431590Srgrimes 4441590Srgrimesint dosigwinch; 4451590Srgrimes 4461590Srgrimes/* 4471590Srgrimes * This is called when the reader process gets the out-of-band (urgent) 4481590Srgrimes * request to turn on the window-changing protocol. 4491590Srgrimes */ 4501590Srgrimesvoid 4511590Srgrimeswriteroob(signo) 4521590Srgrimes int signo; 4531590Srgrimes{ 4541590Srgrimes if (dosigwinch == 0) { 4551590Srgrimes sendwindow(); 4561590Srgrimes (void)signal(SIGWINCH, sigwinch); 4571590Srgrimes } 4581590Srgrimes dosigwinch = 1; 4591590Srgrimes} 4601590Srgrimes 4611590Srgrimesvoid 4621590Srgrimescatch_child(signo) 4631590Srgrimes int signo; 4641590Srgrimes{ 4651590Srgrimes union wait status; 4661590Srgrimes int pid; 4671590Srgrimes 4681590Srgrimes for (;;) { 4691590Srgrimes pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 4701590Srgrimes if (pid == 0) 4711590Srgrimes return; 4721590Srgrimes /* if the child (reader) dies, just quit */ 4731590Srgrimes if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 4741590Srgrimes done((int)(status.w_termsig | status.w_retcode)); 4751590Srgrimes } 4761590Srgrimes /* NOTREACHED */ 4771590Srgrimes} 4781590Srgrimes 4791590Srgrimes/* 4801590Srgrimes * writer: write to remote: 0 -> line. 4811590Srgrimes * ~. terminate 4821590Srgrimes * ~^Z suspend rlogin process. 4831590Srgrimes * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4841590Srgrimes */ 4851590Srgrimesvoid 4861590Srgrimeswriter() 4871590Srgrimes{ 4881590Srgrimes register int bol, local, n; 4891590Srgrimes char c; 4901590Srgrimes 4911590Srgrimes bol = 1; /* beginning of line */ 4921590Srgrimes local = 0; 4931590Srgrimes for (;;) { 4941590Srgrimes n = read(STDIN_FILENO, &c, 1); 4951590Srgrimes if (n <= 0) { 4961590Srgrimes if (n < 0 && errno == EINTR) 4971590Srgrimes continue; 4981590Srgrimes break; 4991590Srgrimes } 5001590Srgrimes /* 5011590Srgrimes * If we're at the beginning of the line and recognize a 5021590Srgrimes * command character, then we echo locally. Otherwise, 5031590Srgrimes * characters are echo'd remotely. If the command character 5041590Srgrimes * is doubled, this acts as a force and local echo is 5051590Srgrimes * suppressed. 5061590Srgrimes */ 5071590Srgrimes if (bol) { 5081590Srgrimes bol = 0; 5091590Srgrimes if (!noescape && c == escapechar) { 5101590Srgrimes local = 1; 5111590Srgrimes continue; 5121590Srgrimes } 5131590Srgrimes } else if (local) { 5141590Srgrimes local = 0; 5151590Srgrimes if (c == '.' || c == deftc.t_eofc) { 5161590Srgrimes echo(c); 5171590Srgrimes break; 5181590Srgrimes } 5191590Srgrimes if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 5201590Srgrimes bol = 1; 5211590Srgrimes echo(c); 5221590Srgrimes stop(c); 5231590Srgrimes continue; 5241590Srgrimes } 5251590Srgrimes if (c != escapechar) 5261590Srgrimes#ifdef CRYPT 5271590Srgrimes#ifdef KERBEROS 5281590Srgrimes if (doencrypt) 52929922Smarkm (void)des_enc_write(rem, 53029922Smarkm (char *)&escapechar, 1, 53129922Smarkm schedule, &cred.session); 5321590Srgrimes else 5331590Srgrimes#endif 5341590Srgrimes#endif 5351590Srgrimes (void)write(rem, &escapechar, 1); 5361590Srgrimes } 5371590Srgrimes 5381590Srgrimes#ifdef CRYPT 5391590Srgrimes#ifdef KERBEROS 5401590Srgrimes if (doencrypt) { 54129922Smarkm if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 5421590Srgrimes msg("line gone"); 5431590Srgrimes break; 5441590Srgrimes } 5451590Srgrimes } else 5461590Srgrimes#endif 5471590Srgrimes#endif 5481590Srgrimes if (write(rem, &c, 1) == 0) { 5491590Srgrimes msg("line gone"); 5501590Srgrimes break; 5511590Srgrimes } 5521590Srgrimes bol = c == defkill || c == deftc.t_eofc || 5531590Srgrimes c == deftc.t_intrc || c == defltc.t_suspc || 5541590Srgrimes c == '\r' || c == '\n'; 5551590Srgrimes } 5561590Srgrimes} 5571590Srgrimes 5581590Srgrimesvoid 5591590Srgrimes#if __STDC__ 5601590Srgrimesecho(register char c) 5611590Srgrimes#else 5621590Srgrimesecho(c) 5631590Srgrimes register char c; 5641590Srgrimes#endif 5651590Srgrimes{ 5661590Srgrimes register char *p; 5671590Srgrimes char buf[8]; 5681590Srgrimes 5691590Srgrimes p = buf; 5701590Srgrimes c &= 0177; 5711590Srgrimes *p++ = escapechar; 5721590Srgrimes if (c < ' ') { 5731590Srgrimes *p++ = '^'; 5741590Srgrimes *p++ = c + '@'; 5751590Srgrimes } else if (c == 0177) { 5761590Srgrimes *p++ = '^'; 5771590Srgrimes *p++ = '?'; 5781590Srgrimes } else 5791590Srgrimes *p++ = c; 5801590Srgrimes *p++ = '\r'; 5811590Srgrimes *p++ = '\n'; 5821590Srgrimes (void)write(STDOUT_FILENO, buf, p - buf); 5831590Srgrimes} 5841590Srgrimes 5851590Srgrimesvoid 5861590Srgrimes#if __STDC__ 5871590Srgrimesstop(char cmdc) 5881590Srgrimes#else 5891590Srgrimesstop(cmdc) 5901590Srgrimes char cmdc; 5911590Srgrimes#endif 5921590Srgrimes{ 5931590Srgrimes mode(0); 5941590Srgrimes (void)signal(SIGCHLD, SIG_IGN); 5951590Srgrimes (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 5961590Srgrimes (void)signal(SIGCHLD, catch_child); 5971590Srgrimes mode(1); 5981590Srgrimes sigwinch(0); /* check for size changes */ 5991590Srgrimes} 6001590Srgrimes 6011590Srgrimesvoid 6021590Srgrimessigwinch(signo) 6031590Srgrimes int signo; 6041590Srgrimes{ 6051590Srgrimes struct winsize ws; 6061590Srgrimes 6071590Srgrimes if (dosigwinch && get_window_size(0, &ws) == 0 && 6081590Srgrimes bcmp(&ws, &winsize, sizeof(ws))) { 6091590Srgrimes winsize = ws; 6101590Srgrimes sendwindow(); 6111590Srgrimes } 6121590Srgrimes} 6131590Srgrimes 6141590Srgrimes/* 6151590Srgrimes * Send the window size to the server via the magic escape 6161590Srgrimes */ 6171590Srgrimesvoid 6181590Srgrimessendwindow() 6191590Srgrimes{ 6201590Srgrimes struct winsize *wp; 6211590Srgrimes char obuf[4 + sizeof (struct winsize)]; 6221590Srgrimes 6231590Srgrimes wp = (struct winsize *)(obuf+4); 6241590Srgrimes obuf[0] = 0377; 6251590Srgrimes obuf[1] = 0377; 6261590Srgrimes obuf[2] = 's'; 6271590Srgrimes obuf[3] = 's'; 6281590Srgrimes wp->ws_row = htons(winsize.ws_row); 6291590Srgrimes wp->ws_col = htons(winsize.ws_col); 6301590Srgrimes wp->ws_xpixel = htons(winsize.ws_xpixel); 6311590Srgrimes wp->ws_ypixel = htons(winsize.ws_ypixel); 6321590Srgrimes 6331590Srgrimes#ifdef CRYPT 6341590Srgrimes#ifdef KERBEROS 6351590Srgrimes if(doencrypt) 63629922Smarkm (void)des_enc_write(rem, obuf, sizeof(obuf), 63729922Smarkm schedule, &cred.session); 6381590Srgrimes else 6391590Srgrimes#endif 6401590Srgrimes#endif 6411590Srgrimes (void)write(rem, obuf, sizeof(obuf)); 6421590Srgrimes} 6431590Srgrimes 6441590Srgrimes/* 6451590Srgrimes * reader: read from remote: line -> 1 6461590Srgrimes */ 6471590Srgrimes#define READING 1 6481590Srgrimes#define WRITING 2 6491590Srgrimes 6501590Srgrimesjmp_buf rcvtop; 6511590Srgrimesint ppid, rcvcnt, rcvstate; 6521590Srgrimeschar rcvbuf[8 * 1024]; 6531590Srgrimes 6541590Srgrimesvoid 6551590Srgrimesoob(signo) 6561590Srgrimes int signo; 6571590Srgrimes{ 6581590Srgrimes struct sgttyb sb; 6591590Srgrimes int atmark, n, out, rcvd; 6601590Srgrimes char waste[BUFSIZ], mark; 6611590Srgrimes 6621590Srgrimes out = O_RDWR; 6631590Srgrimes rcvd = 0; 6641590Srgrimes while (recv(rem, &mark, 1, MSG_OOB) < 0) { 6651590Srgrimes switch (errno) { 6661590Srgrimes case EWOULDBLOCK: 6671590Srgrimes /* 6681590Srgrimes * Urgent data not here yet. It may not be possible 6691590Srgrimes * to send it yet if we are blocked for output and 6701590Srgrimes * our input buffer is full. 6711590Srgrimes */ 6721590Srgrimes if (rcvcnt < sizeof(rcvbuf)) { 6731590Srgrimes n = read(rem, rcvbuf + rcvcnt, 6741590Srgrimes sizeof(rcvbuf) - rcvcnt); 6751590Srgrimes if (n <= 0) 6761590Srgrimes return; 6771590Srgrimes rcvd += n; 6781590Srgrimes } else { 6791590Srgrimes n = read(rem, waste, sizeof(waste)); 6801590Srgrimes if (n <= 0) 6811590Srgrimes return; 6821590Srgrimes } 6831590Srgrimes continue; 6841590Srgrimes default: 6851590Srgrimes return; 6861590Srgrimes } 6871590Srgrimes } 6881590Srgrimes if (mark & TIOCPKT_WINDOW) { 6891590Srgrimes /* Let server know about window size changes */ 6901590Srgrimes (void)kill(ppid, SIGUSR1); 6911590Srgrimes } 6921590Srgrimes if (!eight && (mark & TIOCPKT_NOSTOP)) { 6931590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 6941590Srgrimes sb.sg_flags &= ~CBREAK; 6951590Srgrimes sb.sg_flags |= RAW; 6961590Srgrimes (void)ioctl(0, TIOCSETN, (char *)&sb); 6971590Srgrimes notc.t_stopc = -1; 6981590Srgrimes notc.t_startc = -1; 6991590Srgrimes (void)ioctl(0, TIOCSETC, (char *)¬c); 7001590Srgrimes } 7011590Srgrimes if (!eight && (mark & TIOCPKT_DOSTOP)) { 7021590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 7031590Srgrimes sb.sg_flags &= ~RAW; 7041590Srgrimes sb.sg_flags |= CBREAK; 7051590Srgrimes (void)ioctl(0, TIOCSETN, (char *)&sb); 7061590Srgrimes notc.t_stopc = deftc.t_stopc; 7071590Srgrimes notc.t_startc = deftc.t_startc; 7081590Srgrimes (void)ioctl(0, TIOCSETC, (char *)¬c); 7091590Srgrimes } 7101590Srgrimes if (mark & TIOCPKT_FLUSHWRITE) { 7111590Srgrimes (void)ioctl(1, TIOCFLUSH, (char *)&out); 7121590Srgrimes for (;;) { 7131590Srgrimes if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 71427919Scharnier warn("ioctl"); 7151590Srgrimes break; 7161590Srgrimes } 7171590Srgrimes if (atmark) 7181590Srgrimes break; 7191590Srgrimes n = read(rem, waste, sizeof (waste)); 7201590Srgrimes if (n <= 0) 7211590Srgrimes break; 7221590Srgrimes } 7231590Srgrimes /* 7241590Srgrimes * Don't want any pending data to be output, so clear the recv 7251590Srgrimes * buffer. If we were hanging on a write when interrupted, 7261590Srgrimes * don't want it to restart. If we were reading, restart 7271590Srgrimes * anyway. 7281590Srgrimes */ 7291590Srgrimes rcvcnt = 0; 7301590Srgrimes longjmp(rcvtop, 1); 7311590Srgrimes } 7321590Srgrimes 7331590Srgrimes /* oob does not do FLUSHREAD (alas!) */ 7341590Srgrimes 7351590Srgrimes /* 7361590Srgrimes * If we filled the receive buffer while a read was pending, longjmp 7371590Srgrimes * to the top to restart appropriately. Don't abort a pending write, 7381590Srgrimes * however, or we won't know how much was written. 7391590Srgrimes */ 7401590Srgrimes if (rcvd && rcvstate == READING) 7411590Srgrimes longjmp(rcvtop, 1); 7421590Srgrimes} 7431590Srgrimes 7441590Srgrimes/* reader: read from remote: line -> 1 */ 7451590Srgrimesint 7461590Srgrimesreader(omask) 7471590Srgrimes int omask; 7481590Srgrimes{ 7491590Srgrimes int pid, n, remaining; 7501590Srgrimes char *bufp; 7511590Srgrimes 7521590Srgrimes#if BSD >= 43 || defined(SUNOS4) 7531590Srgrimes pid = getpid(); /* modern systems use positives for pid */ 7541590Srgrimes#else 7551590Srgrimes pid = -getpid(); /* old broken systems use negatives */ 7561590Srgrimes#endif 7571590Srgrimes (void)signal(SIGTTOU, SIG_IGN); 7581590Srgrimes (void)signal(SIGURG, oob); 7591590Srgrimes ppid = getppid(); 7601590Srgrimes (void)fcntl(rem, F_SETOWN, pid); 7611590Srgrimes (void)setjmp(rcvtop); 7621590Srgrimes (void)sigsetmask(omask); 7631590Srgrimes bufp = rcvbuf; 7641590Srgrimes for (;;) { 7651590Srgrimes while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 7661590Srgrimes rcvstate = WRITING; 7671590Srgrimes n = write(STDOUT_FILENO, bufp, remaining); 7681590Srgrimes if (n < 0) { 7691590Srgrimes if (errno != EINTR) 7701590Srgrimes return (-1); 7711590Srgrimes continue; 7721590Srgrimes } 7731590Srgrimes bufp += n; 7741590Srgrimes } 7751590Srgrimes bufp = rcvbuf; 7761590Srgrimes rcvcnt = 0; 7771590Srgrimes rcvstate = READING; 7781590Srgrimes 7791590Srgrimes#ifdef CRYPT 7801590Srgrimes#ifdef KERBEROS 7811590Srgrimes if (doencrypt) 78229922Smarkm rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf), 78329922Smarkm schedule, &cred.session); 7841590Srgrimes else 7851590Srgrimes#endif 7861590Srgrimes#endif 7871590Srgrimes rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 7881590Srgrimes if (rcvcnt == 0) 7891590Srgrimes return (0); 7901590Srgrimes if (rcvcnt < 0) { 7911590Srgrimes if (errno == EINTR) 7921590Srgrimes continue; 79327919Scharnier warn("read"); 7941590Srgrimes return (-1); 7951590Srgrimes } 7961590Srgrimes } 7971590Srgrimes} 7981590Srgrimes 7991590Srgrimesvoid 8001590Srgrimesmode(f) 8011590Srgrimes int f; 8021590Srgrimes{ 8031590Srgrimes struct ltchars *ltc; 8041590Srgrimes struct sgttyb sb; 8051590Srgrimes struct tchars *tc; 8061590Srgrimes int lflags; 8071590Srgrimes 8081590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 8091590Srgrimes (void)ioctl(0, TIOCLGET, (char *)&lflags); 8101590Srgrimes switch(f) { 8111590Srgrimes case 0: 8121590Srgrimes sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 8131590Srgrimes sb.sg_flags |= defflags|tabflag; 8141590Srgrimes tc = &deftc; 8151590Srgrimes ltc = &defltc; 8161590Srgrimes sb.sg_kill = defkill; 8171590Srgrimes sb.sg_erase = deferase; 8181590Srgrimes lflags = deflflags; 8191590Srgrimes break; 8201590Srgrimes case 1: 8211590Srgrimes sb.sg_flags |= (eight ? RAW : CBREAK); 8221590Srgrimes sb.sg_flags &= ~defflags; 8231590Srgrimes /* preserve tab delays, but turn off XTABS */ 8241590Srgrimes if ((sb.sg_flags & TBDELAY) == XTABS) 8251590Srgrimes sb.sg_flags &= ~TBDELAY; 8261590Srgrimes tc = ¬c; 8271590Srgrimes ltc = &noltc; 8281590Srgrimes sb.sg_kill = sb.sg_erase = -1; 8291590Srgrimes if (litout) 8301590Srgrimes lflags |= LLITOUT; 8311590Srgrimes break; 8321590Srgrimes default: 8331590Srgrimes return; 8341590Srgrimes } 8351590Srgrimes (void)ioctl(0, TIOCSLTC, (char *)ltc); 8361590Srgrimes (void)ioctl(0, TIOCSETC, (char *)tc); 8371590Srgrimes (void)ioctl(0, TIOCSETN, (char *)&sb); 8381590Srgrimes (void)ioctl(0, TIOCLSET, (char *)&lflags); 8391590Srgrimes} 8401590Srgrimes 8411590Srgrimesvoid 8421590Srgrimeslostpeer(signo) 8431590Srgrimes int signo; 8441590Srgrimes{ 8451590Srgrimes (void)signal(SIGPIPE, SIG_IGN); 8461590Srgrimes msg("\007connection closed."); 8471590Srgrimes done(1); 8481590Srgrimes} 8491590Srgrimes 8501590Srgrimes/* copy SIGURGs to the child process. */ 8511590Srgrimesvoid 8521590Srgrimescopytochild(signo) 8531590Srgrimes int signo; 8541590Srgrimes{ 8551590Srgrimes (void)kill(child, SIGURG); 8561590Srgrimes} 8571590Srgrimes 8581590Srgrimesvoid 8591590Srgrimesmsg(str) 8601590Srgrimes char *str; 8611590Srgrimes{ 8621590Srgrimes (void)fprintf(stderr, "rlogin: %s\r\n", str); 8631590Srgrimes} 8641590Srgrimes 8651590Srgrimesvoid 8661590Srgrimesusage() 8671590Srgrimes{ 8681590Srgrimes (void)fprintf(stderr, 86947549Sbde "usage: rlogin [-%s]%s[-e char] [-i localname] [-l username] host\n", 8701590Srgrimes#ifdef KERBEROS 8711590Srgrimes#ifdef CRYPT 87247549Sbde "8DEKLdx", " [-k realm] "); 8731590Srgrimes#else 87447549Sbde "8DEKLd", " [-k realm] "); 8751590Srgrimes#endif 8761590Srgrimes#else 87747549Sbde "8DELd", " "); 8781590Srgrimes#endif 8791590Srgrimes exit(1); 8801590Srgrimes} 8811590Srgrimes 8821590Srgrimes/* 8831590Srgrimes * The following routine provides compatibility (such as it is) between older 8841590Srgrimes * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 8851590Srgrimes */ 8861590Srgrimes#ifdef OLDSUN 8871590Srgrimesint 8881590Srgrimesget_window_size(fd, wp) 8891590Srgrimes int fd; 8901590Srgrimes struct winsize *wp; 8911590Srgrimes{ 8921590Srgrimes struct ttysize ts; 8931590Srgrimes int error; 8941590Srgrimes 8951590Srgrimes if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 8961590Srgrimes return (error); 8971590Srgrimes wp->ws_row = ts.ts_lines; 8981590Srgrimes wp->ws_col = ts.ts_cols; 8991590Srgrimes wp->ws_xpixel = 0; 9001590Srgrimes wp->ws_ypixel = 0; 9011590Srgrimes return (0); 9021590Srgrimes} 9031590Srgrimes#endif 9041590Srgrimes 9051590Srgrimesu_int 9061590Srgrimesgetescape(p) 9071590Srgrimes register char *p; 9081590Srgrimes{ 9091590Srgrimes long val; 9101590Srgrimes int len; 9111590Srgrimes 9121590Srgrimes if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 9131590Srgrimes return ((u_int)*p); 9141590Srgrimes /* otherwise, \nnn */ 9151590Srgrimes if (*p == '\\' && len >= 2 && len <= 4) { 9161590Srgrimes val = strtol(++p, NULL, 8); 9171590Srgrimes for (;;) { 9181590Srgrimes if (!*++p) 9191590Srgrimes return ((u_int)val); 9201590Srgrimes if (*p < '0' || *p > '8') 9211590Srgrimes break; 9221590Srgrimes } 9231590Srgrimes } 9241590Srgrimes msg("illegal option value -- e"); 9251590Srgrimes usage(); 9261590Srgrimes /* NOTREACHED */ 9271590Srgrimes} 928