rlogin.c revision 91434
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[] = 4350477Speter "$FreeBSD: head/usr.bin/rlogin/rlogin.c 91434 2002-02-27 22:45:10Z fenner $"; 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 7657450Smarkm#include <openssl/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; 9857232Sshinint family = PF_UNSPEC; 991590Srgrimes 1001590Srgrimesint noescape; 1011590Srgrimesu_char escapechar = '~'; 1021590Srgrimes 1031590Srgrimeschar *speeds[] = { 1041590Srgrimes "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 1059881Sache "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" 10617284Spst#define MAX_SPEED_LENGTH (sizeof("115200") - 1) 1071590Srgrimes}; 1081590Srgrimes 1091590Srgrimes#ifdef OLDSUN 1101590Srgrimesstruct winsize { 1111590Srgrimes unsigned short ws_row, ws_col; 1121590Srgrimes unsigned short ws_xpixel, ws_ypixel; 1131590Srgrimes}; 1141590Srgrimes#else 1151590Srgrimes#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 1161590Srgrimes#endif 1171590Srgrimesstruct winsize winsize; 1181590Srgrimes 1191590Srgrimesvoid catch_child __P((int)); 1201590Srgrimesvoid copytochild __P((int)); 12118286Sbdevoid doit __P((long)) __dead2; 12218286Sbdevoid done __P((int)) __dead2; 1231590Srgrimesvoid echo __P((char)); 1241590Srgrimesu_int getescape __P((char *)); 1251590Srgrimesvoid lostpeer __P((int)); 1261590Srgrimesvoid mode __P((int)); 1271590Srgrimesvoid msg __P((char *)); 1281590Srgrimesvoid oob __P((int)); 1291590Srgrimesint reader __P((int)); 1301590Srgrimesvoid sendwindow __P((void)); 1311590Srgrimesvoid setsignal __P((int)); 1321590Srgrimesvoid sigwinch __P((int)); 1331590Srgrimesvoid stop __P((char)); 13418286Sbdevoid usage __P((void)) __dead2; 1351590Srgrimesvoid writer __P((void)); 1361590Srgrimesvoid writeroob __P((int)); 1371590Srgrimes 1381590Srgrimes#ifdef OLDSUN 1391590Srgrimesint get_window_size __P((int, struct winsize *)); 1401590Srgrimes#endif 1411590Srgrimes 1421590Srgrimesint 1431590Srgrimesmain(argc, argv) 1441590Srgrimes int argc; 1451590Srgrimes char *argv[]; 1461590Srgrimes{ 1471590Srgrimes struct passwd *pw; 1481590Srgrimes struct servent *sp; 1491590Srgrimes struct sgttyb ttyb; 1501590Srgrimes long omask; 1518232Sdg int argoff, ch, dflag, Dflag, one, uid; 15247549Sbde char *host, *localname, *p, *user, term[1024]; 15340103Smarkm#ifdef KERBEROS 15440103Smarkm char *k; 15540103Smarkm#endif 15656590Sshin struct sockaddr_storage ss; 15756590Sshin int sslen; 1581590Srgrimes 1598232Sdg argoff = dflag = Dflag = 0; 1601590Srgrimes one = 1; 16147549Sbde host = localname = user = NULL; 1621590Srgrimes 16329922Smarkm if ((p = rindex(argv[0], '/'))) 1641590Srgrimes ++p; 1651590Srgrimes else 1661590Srgrimes p = argv[0]; 1671590Srgrimes 1681590Srgrimes if (strcmp(p, "rlogin")) 1691590Srgrimes host = p; 1701590Srgrimes 1711590Srgrimes /* handle "rlogin host flags" */ 1721590Srgrimes if (!host && argc > 2 && argv[1][0] != '-') { 1731590Srgrimes host = argv[1]; 1741590Srgrimes argoff = 1; 1751590Srgrimes } 1761590Srgrimes 1771590Srgrimes#ifdef KERBEROS 17857232Sshin#define OPTIONS "468DEKLde:i:k:l:x" 1791590Srgrimes#else 18057232Sshin#define OPTIONS "468DEKLde:i:l:" 1811590Srgrimes#endif 18224360Simp while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 1831590Srgrimes switch(ch) { 18457232Sshin case '4': 18557232Sshin family = PF_INET; 18657232Sshin break; 18757232Sshin 18857232Sshin case '6': 18957232Sshin family = PF_INET6; 19057232Sshin break; 19157232Sshin 1921590Srgrimes case '8': 1931590Srgrimes eight = 1; 1941590Srgrimes break; 1958232Sdg case 'D': 1968232Sdg Dflag = 1; 1978232Sdg break; 1981590Srgrimes case 'E': 1991590Srgrimes noescape = 1; 2001590Srgrimes break; 2011590Srgrimes case 'K': 2021590Srgrimes#ifdef KERBEROS 2031590Srgrimes use_kerberos = 0; 2041590Srgrimes#endif 2051590Srgrimes break; 2061590Srgrimes case 'L': 2071590Srgrimes litout = 1; 2081590Srgrimes break; 2091590Srgrimes case 'd': 2101590Srgrimes dflag = 1; 2111590Srgrimes break; 2121590Srgrimes case 'e': 2131590Srgrimes noescape = 0; 2141590Srgrimes escapechar = getescape(optarg); 2151590Srgrimes break; 21647488Speter case 'i': 21747549Sbde if (getuid() != 0) 21847549Sbde errx(1, "-i user: permission denied"); 21947488Speter localname = optarg; 22047488Speter break; 2211590Srgrimes#ifdef KERBEROS 2221590Srgrimes case 'k': 2231590Srgrimes dest_realm = dst_realm_buf; 2241590Srgrimes (void)strncpy(dest_realm, optarg, REALM_SZ); 2251590Srgrimes break; 2261590Srgrimes#endif 2271590Srgrimes case 'l': 2281590Srgrimes user = optarg; 2291590Srgrimes break; 2301590Srgrimes#ifdef CRYPT 2311590Srgrimes#ifdef KERBEROS 2321590Srgrimes case 'x': 2331590Srgrimes doencrypt = 1; 2341590Srgrimes break; 2351590Srgrimes#endif 2361590Srgrimes#endif 2371590Srgrimes case '?': 2381590Srgrimes default: 2391590Srgrimes usage(); 2401590Srgrimes } 2411590Srgrimes optind += argoff; 2421590Srgrimes 2431590Srgrimes /* if haven't gotten a host yet, do so */ 24434897Smarkm if (!host && !(host = argv[optind++])) 2451590Srgrimes usage(); 2461590Srgrimes 24734897Smarkm if (argv[optind]) 2481590Srgrimes usage(); 2491590Srgrimes 25027919Scharnier if (!(pw = getpwuid(uid = getuid()))) 25127919Scharnier errx(1, "unknown user id"); 2521590Srgrimes if (!user) 2531590Srgrimes user = pw->pw_name; 25447488Speter if (!localname) 25547488Speter localname = pw->pw_name; 2561590Srgrimes 2571590Srgrimes sp = NULL; 2581590Srgrimes#ifdef KERBEROS 25940103Smarkm k = auth_getval("auth_list"); 26040103Smarkm if (k && !strstr(k, "kerberos")) 26140103Smarkm use_kerberos = 0; 2621590Srgrimes if (use_kerberos) { 2631590Srgrimes sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 2641590Srgrimes if (sp == NULL) { 2651590Srgrimes use_kerberos = 0; 26629922Smarkm warn("can't get entry for %s/tcp service", 2671590Srgrimes doencrypt ? "eklogin" : "klogin"); 2681590Srgrimes } 2691590Srgrimes } 2701590Srgrimes#endif 2711590Srgrimes if (sp == NULL) 2721590Srgrimes sp = getservbyname("login", "tcp"); 27327919Scharnier if (sp == NULL) 27427919Scharnier errx(1, "login/tcp: unknown service"); 2751590Srgrimes 27617284Spst#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) 27717284Spst 27817284Spst (void)strncpy(term, (p = getenv("TERM")) ? p : "network", 27917284Spst MAX_TERM_LENGTH); 28017284Spst term[MAX_TERM_LENGTH] = '\0'; 2811590Srgrimes if (ioctl(0, TIOCGETP, &ttyb) == 0) { 2821590Srgrimes (void)strcat(term, "/"); 2831590Srgrimes (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 2841590Srgrimes } 2851590Srgrimes 2861590Srgrimes (void)get_window_size(0, &winsize); 2871590Srgrimes 2881590Srgrimes (void)signal(SIGPIPE, lostpeer); 2891590Srgrimes /* will use SIGUSR1 for window size hack, so hold it off */ 2901590Srgrimes omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 2911590Srgrimes /* 2921590Srgrimes * We set SIGURG and SIGUSR1 below so that an 2931590Srgrimes * incoming signal will be held pending rather than being 2941590Srgrimes * discarded. Note that these routines will be ready to get 2951590Srgrimes * a signal by the time that they are unblocked below. 2961590Srgrimes */ 2971590Srgrimes (void)signal(SIGURG, copytochild); 2981590Srgrimes (void)signal(SIGUSR1, writeroob); 2991590Srgrimes 3001590Srgrimes#ifdef KERBEROS 3011590Srgrimes if (use_kerberos) { 30234897Smarkm setuid(getuid()); 3031590Srgrimes rem = KSUCCESS; 3041590Srgrimes errno = 0; 3051590Srgrimes if (dest_realm == NULL) 3061590Srgrimes dest_realm = krb_realmofhost(host); 3071590Srgrimes 3081590Srgrimes#ifdef CRYPT 3093113Sdfr if (doencrypt) { 3101590Srgrimes rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 3111590Srgrimes dest_realm, &cred, schedule); 31229922Smarkm des_set_key(&cred.session, schedule); 3133113Sdfr } else 3141590Srgrimes#endif /* CRYPT */ 3151590Srgrimes rem = krcmd(&host, sp->s_port, user, term, 0, 3161590Srgrimes dest_realm); 3171590Srgrimes if (rem < 0) { 31834897Smarkm int i; 31934897Smarkm char **newargv; 32034897Smarkm 3211590Srgrimes sp = getservbyname("login", "tcp"); 32227919Scharnier if (sp == NULL) 32327919Scharnier errx(1, "unknown service login/tcp"); 3241590Srgrimes if (errno == ECONNREFUSED) 32529922Smarkm warn("remote host doesn't support Kerberos"); 3261590Srgrimes if (errno == ENOENT) 32729922Smarkm warn("can't provide Kerberos auth data"); 32834897Smarkm newargv = malloc((argc + 2) * sizeof(*newargv)); 32934897Smarkm if (newargv == NULL) 33034897Smarkm err(1, "malloc"); 33134897Smarkm newargv[0] = argv[0]; 33234897Smarkm newargv[1] = "-K"; 33334897Smarkm for(i = 1; i < argc; ++i) 33434897Smarkm newargv[i + 1] = argv[i]; 33534897Smarkm newargv[argc + 1] = NULL; 33634897Smarkm execv(_PATH_RLOGIN, newargv); 3371590Srgrimes } 3381590Srgrimes } else { 3391590Srgrimes#ifdef CRYPT 34027919Scharnier if (doencrypt) 34127919Scharnier errx(1, "the -x flag requires Kerberos authentication"); 3421590Srgrimes#endif /* CRYPT */ 34356590Sshin rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, 34457232Sshin family); 3451590Srgrimes } 3461590Srgrimes#else 34757232Sshin rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); 3481590Srgrimes#endif /* KERBEROS */ 3491590Srgrimes 3501590Srgrimes if (rem < 0) 3511590Srgrimes exit(1); 3521590Srgrimes 3531590Srgrimes if (dflag && 3541590Srgrimes setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 35527919Scharnier warn("setsockopt"); 3568232Sdg if (Dflag && 3578232Sdg setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 35827919Scharnier warn("setsockopt NODELAY (ignored)"); 3598232Sdg 36056590Sshin sslen = sizeof(ss); 3611590Srgrimes one = IPTOS_LOWDELAY; 36256590Sshin if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 && 36356590Sshin ss.ss_family == AF_INET) { 36456590Sshin if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, 36556590Sshin sizeof(int)) < 0) 36656590Sshin warn("setsockopt TOS (ignored)"); 36756590Sshin } else 36856590Sshin if (ss.ss_family == AF_INET) 36956590Sshin warn("setsockopt getsockname failed"); 3701590Srgrimes 3711590Srgrimes (void)setuid(uid); 3721590Srgrimes doit(omask); 3731590Srgrimes /*NOTREACHED*/ 3741590Srgrimes} 3751590Srgrimes 3761590Srgrimesint child, defflags, deflflags, tabflag; 3771590Srgrimeschar deferase, defkill; 3781590Srgrimesstruct tchars deftc; 3791590Srgrimesstruct ltchars defltc; 3801590Srgrimesstruct tchars notc = { -1, -1, -1, -1, -1, -1 }; 3811590Srgrimesstruct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3821590Srgrimes 3831590Srgrimesvoid 3841590Srgrimesdoit(omask) 3851590Srgrimes long omask; 3861590Srgrimes{ 3871590Srgrimes struct sgttyb sb; 3881590Srgrimes 3891590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 3901590Srgrimes defflags = sb.sg_flags; 3911590Srgrimes tabflag = defflags & TBDELAY; 3921590Srgrimes defflags &= ECHO | CRMOD; 3931590Srgrimes deferase = sb.sg_erase; 3941590Srgrimes defkill = sb.sg_kill; 3951590Srgrimes (void)ioctl(0, TIOCLGET, &deflflags); 3961590Srgrimes (void)ioctl(0, TIOCGETC, &deftc); 3971590Srgrimes notc.t_startc = deftc.t_startc; 3981590Srgrimes notc.t_stopc = deftc.t_stopc; 3991590Srgrimes (void)ioctl(0, TIOCGLTC, &defltc); 4001590Srgrimes (void)signal(SIGINT, SIG_IGN); 4011590Srgrimes setsignal(SIGHUP); 4021590Srgrimes setsignal(SIGQUIT); 4031590Srgrimes child = fork(); 4041590Srgrimes if (child == -1) { 40527919Scharnier warn("fork"); 4061590Srgrimes done(1); 4071590Srgrimes } 4081590Srgrimes if (child == 0) { 4091590Srgrimes mode(1); 4101590Srgrimes if (reader(omask) == 0) { 4111590Srgrimes msg("connection closed."); 4121590Srgrimes exit(0); 4131590Srgrimes } 4141590Srgrimes sleep(1); 4151590Srgrimes msg("\007connection closed."); 4161590Srgrimes exit(1); 4171590Srgrimes } 4181590Srgrimes 4191590Srgrimes /* 4201590Srgrimes * We may still own the socket, and may have a pending SIGURG (or might 4211590Srgrimes * receive one soon) that we really want to send to the reader. When 4221590Srgrimes * one of these comes in, the trap copytochild simply copies such 4231590Srgrimes * signals to the child. We can now unblock SIGURG and SIGUSR1 4241590Srgrimes * that were set above. 4251590Srgrimes */ 4261590Srgrimes (void)sigsetmask(omask); 4271590Srgrimes (void)signal(SIGCHLD, catch_child); 4281590Srgrimes writer(); 4291590Srgrimes msg("closed connection."); 4301590Srgrimes done(0); 4311590Srgrimes} 4321590Srgrimes 4331590Srgrimes/* trap a signal, unless it is being ignored. */ 4341590Srgrimesvoid 4351590Srgrimessetsignal(sig) 4361590Srgrimes int sig; 4371590Srgrimes{ 4381590Srgrimes int omask = sigblock(sigmask(sig)); 4391590Srgrimes 4401590Srgrimes if (signal(sig, exit) == SIG_IGN) 4411590Srgrimes (void)signal(sig, SIG_IGN); 4421590Srgrimes (void)sigsetmask(omask); 4431590Srgrimes} 4441590Srgrimes 44518286Sbdevoid 4461590Srgrimesdone(status) 4471590Srgrimes int status; 4481590Srgrimes{ 4491590Srgrimes int w, wstatus; 4501590Srgrimes 4511590Srgrimes mode(0); 4521590Srgrimes if (child > 0) { 4531590Srgrimes /* make sure catch_child does not snap it up */ 4541590Srgrimes (void)signal(SIGCHLD, SIG_DFL); 4551590Srgrimes if (kill(child, SIGKILL) >= 0) 4561590Srgrimes while ((w = wait(&wstatus)) > 0 && w != child); 4571590Srgrimes } 4581590Srgrimes exit(status); 4591590Srgrimes} 4601590Srgrimes 4611590Srgrimesint dosigwinch; 4621590Srgrimes 4631590Srgrimes/* 4641590Srgrimes * This is called when the reader process gets the out-of-band (urgent) 4651590Srgrimes * request to turn on the window-changing protocol. 4661590Srgrimes */ 4671590Srgrimesvoid 4681590Srgrimeswriteroob(signo) 4691590Srgrimes int signo; 4701590Srgrimes{ 4711590Srgrimes if (dosigwinch == 0) { 4721590Srgrimes sendwindow(); 4731590Srgrimes (void)signal(SIGWINCH, sigwinch); 4741590Srgrimes } 4751590Srgrimes dosigwinch = 1; 4761590Srgrimes} 4771590Srgrimes 4781590Srgrimesvoid 4791590Srgrimescatch_child(signo) 4801590Srgrimes int signo; 4811590Srgrimes{ 4821590Srgrimes union wait status; 4831590Srgrimes int pid; 4841590Srgrimes 4851590Srgrimes for (;;) { 4861590Srgrimes pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 4871590Srgrimes if (pid == 0) 4881590Srgrimes return; 4891590Srgrimes /* if the child (reader) dies, just quit */ 4901590Srgrimes if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 4911590Srgrimes done((int)(status.w_termsig | status.w_retcode)); 4921590Srgrimes } 4931590Srgrimes /* NOTREACHED */ 4941590Srgrimes} 4951590Srgrimes 4961590Srgrimes/* 4971590Srgrimes * writer: write to remote: 0 -> line. 4981590Srgrimes * ~. terminate 4991590Srgrimes * ~^Z suspend rlogin process. 5001590Srgrimes * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 5011590Srgrimes */ 5021590Srgrimesvoid 5031590Srgrimeswriter() 5041590Srgrimes{ 5051590Srgrimes register int bol, local, n; 5061590Srgrimes char c; 5071590Srgrimes 5081590Srgrimes bol = 1; /* beginning of line */ 5091590Srgrimes local = 0; 5101590Srgrimes for (;;) { 5111590Srgrimes n = read(STDIN_FILENO, &c, 1); 5121590Srgrimes if (n <= 0) { 5131590Srgrimes if (n < 0 && errno == EINTR) 5141590Srgrimes continue; 5151590Srgrimes break; 5161590Srgrimes } 5171590Srgrimes /* 5181590Srgrimes * If we're at the beginning of the line and recognize a 5191590Srgrimes * command character, then we echo locally. Otherwise, 5201590Srgrimes * characters are echo'd remotely. If the command character 5211590Srgrimes * is doubled, this acts as a force and local echo is 5221590Srgrimes * suppressed. 5231590Srgrimes */ 5241590Srgrimes if (bol) { 5251590Srgrimes bol = 0; 5261590Srgrimes if (!noescape && c == escapechar) { 5271590Srgrimes local = 1; 5281590Srgrimes continue; 5291590Srgrimes } 5301590Srgrimes } else if (local) { 5311590Srgrimes local = 0; 5321590Srgrimes if (c == '.' || c == deftc.t_eofc) { 5331590Srgrimes echo(c); 5341590Srgrimes break; 5351590Srgrimes } 5361590Srgrimes if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 5371590Srgrimes bol = 1; 5381590Srgrimes echo(c); 5391590Srgrimes stop(c); 5401590Srgrimes continue; 5411590Srgrimes } 5421590Srgrimes if (c != escapechar) 5431590Srgrimes#ifdef CRYPT 5441590Srgrimes#ifdef KERBEROS 5451590Srgrimes if (doencrypt) 54629922Smarkm (void)des_enc_write(rem, 54729922Smarkm (char *)&escapechar, 1, 54829922Smarkm schedule, &cred.session); 5491590Srgrimes else 5501590Srgrimes#endif 5511590Srgrimes#endif 5521590Srgrimes (void)write(rem, &escapechar, 1); 5531590Srgrimes } 5541590Srgrimes 5551590Srgrimes#ifdef CRYPT 5561590Srgrimes#ifdef KERBEROS 5571590Srgrimes if (doencrypt) { 55829922Smarkm if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 5591590Srgrimes msg("line gone"); 5601590Srgrimes break; 5611590Srgrimes } 5621590Srgrimes } else 5631590Srgrimes#endif 5641590Srgrimes#endif 5651590Srgrimes if (write(rem, &c, 1) == 0) { 5661590Srgrimes msg("line gone"); 5671590Srgrimes break; 5681590Srgrimes } 5691590Srgrimes bol = c == defkill || c == deftc.t_eofc || 5701590Srgrimes c == deftc.t_intrc || c == defltc.t_suspc || 5711590Srgrimes c == '\r' || c == '\n'; 5721590Srgrimes } 5731590Srgrimes} 5741590Srgrimes 5751590Srgrimesvoid 5761590Srgrimes#if __STDC__ 5771590Srgrimesecho(register char c) 5781590Srgrimes#else 5791590Srgrimesecho(c) 5801590Srgrimes register char c; 5811590Srgrimes#endif 5821590Srgrimes{ 5831590Srgrimes register char *p; 5841590Srgrimes char buf[8]; 5851590Srgrimes 5861590Srgrimes p = buf; 5871590Srgrimes c &= 0177; 5881590Srgrimes *p++ = escapechar; 5891590Srgrimes if (c < ' ') { 5901590Srgrimes *p++ = '^'; 5911590Srgrimes *p++ = c + '@'; 5921590Srgrimes } else if (c == 0177) { 5931590Srgrimes *p++ = '^'; 5941590Srgrimes *p++ = '?'; 5951590Srgrimes } else 5961590Srgrimes *p++ = c; 5971590Srgrimes *p++ = '\r'; 5981590Srgrimes *p++ = '\n'; 5991590Srgrimes (void)write(STDOUT_FILENO, buf, p - buf); 6001590Srgrimes} 6011590Srgrimes 6021590Srgrimesvoid 6031590Srgrimes#if __STDC__ 6041590Srgrimesstop(char cmdc) 6051590Srgrimes#else 6061590Srgrimesstop(cmdc) 6071590Srgrimes char cmdc; 6081590Srgrimes#endif 6091590Srgrimes{ 6101590Srgrimes mode(0); 6111590Srgrimes (void)signal(SIGCHLD, SIG_IGN); 6121590Srgrimes (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 6131590Srgrimes (void)signal(SIGCHLD, catch_child); 6141590Srgrimes mode(1); 6151590Srgrimes sigwinch(0); /* check for size changes */ 6161590Srgrimes} 6171590Srgrimes 6181590Srgrimesvoid 6191590Srgrimessigwinch(signo) 6201590Srgrimes int signo; 6211590Srgrimes{ 6221590Srgrimes struct winsize ws; 6231590Srgrimes 6241590Srgrimes if (dosigwinch && get_window_size(0, &ws) == 0 && 6251590Srgrimes bcmp(&ws, &winsize, sizeof(ws))) { 6261590Srgrimes winsize = ws; 6271590Srgrimes sendwindow(); 6281590Srgrimes } 6291590Srgrimes} 6301590Srgrimes 6311590Srgrimes/* 6321590Srgrimes * Send the window size to the server via the magic escape 6331590Srgrimes */ 6341590Srgrimesvoid 6351590Srgrimessendwindow() 6361590Srgrimes{ 6371590Srgrimes struct winsize *wp; 6381590Srgrimes char obuf[4 + sizeof (struct winsize)]; 6391590Srgrimes 6401590Srgrimes wp = (struct winsize *)(obuf+4); 6411590Srgrimes obuf[0] = 0377; 6421590Srgrimes obuf[1] = 0377; 6431590Srgrimes obuf[2] = 's'; 6441590Srgrimes obuf[3] = 's'; 6451590Srgrimes wp->ws_row = htons(winsize.ws_row); 6461590Srgrimes wp->ws_col = htons(winsize.ws_col); 6471590Srgrimes wp->ws_xpixel = htons(winsize.ws_xpixel); 6481590Srgrimes wp->ws_ypixel = htons(winsize.ws_ypixel); 6491590Srgrimes 6501590Srgrimes#ifdef CRYPT 6511590Srgrimes#ifdef KERBEROS 6521590Srgrimes if(doencrypt) 65329922Smarkm (void)des_enc_write(rem, obuf, sizeof(obuf), 65429922Smarkm schedule, &cred.session); 6551590Srgrimes else 6561590Srgrimes#endif 6571590Srgrimes#endif 6581590Srgrimes (void)write(rem, obuf, sizeof(obuf)); 6591590Srgrimes} 6601590Srgrimes 6611590Srgrimes/* 6621590Srgrimes * reader: read from remote: line -> 1 6631590Srgrimes */ 6641590Srgrimes#define READING 1 6651590Srgrimes#define WRITING 2 6661590Srgrimes 6671590Srgrimesjmp_buf rcvtop; 6681590Srgrimesint ppid, rcvcnt, rcvstate; 6691590Srgrimeschar rcvbuf[8 * 1024]; 6701590Srgrimes 6711590Srgrimesvoid 6721590Srgrimesoob(signo) 6731590Srgrimes int signo; 6741590Srgrimes{ 6751590Srgrimes struct sgttyb sb; 6761590Srgrimes int atmark, n, out, rcvd; 6771590Srgrimes char waste[BUFSIZ], mark; 6781590Srgrimes 6791590Srgrimes out = O_RDWR; 6801590Srgrimes rcvd = 0; 6811590Srgrimes while (recv(rem, &mark, 1, MSG_OOB) < 0) { 6821590Srgrimes switch (errno) { 6831590Srgrimes case EWOULDBLOCK: 6841590Srgrimes /* 6851590Srgrimes * Urgent data not here yet. It may not be possible 6861590Srgrimes * to send it yet if we are blocked for output and 6871590Srgrimes * our input buffer is full. 6881590Srgrimes */ 6891590Srgrimes if (rcvcnt < sizeof(rcvbuf)) { 6901590Srgrimes n = read(rem, rcvbuf + rcvcnt, 6911590Srgrimes sizeof(rcvbuf) - rcvcnt); 6921590Srgrimes if (n <= 0) 6931590Srgrimes return; 6941590Srgrimes rcvd += n; 6951590Srgrimes } else { 6961590Srgrimes n = read(rem, waste, sizeof(waste)); 6971590Srgrimes if (n <= 0) 6981590Srgrimes return; 6991590Srgrimes } 7001590Srgrimes continue; 7011590Srgrimes default: 7021590Srgrimes return; 7031590Srgrimes } 7041590Srgrimes } 7051590Srgrimes if (mark & TIOCPKT_WINDOW) { 7061590Srgrimes /* Let server know about window size changes */ 7071590Srgrimes (void)kill(ppid, SIGUSR1); 7081590Srgrimes } 7091590Srgrimes if (!eight && (mark & TIOCPKT_NOSTOP)) { 7101590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 7111590Srgrimes sb.sg_flags &= ~CBREAK; 7121590Srgrimes sb.sg_flags |= RAW; 7131590Srgrimes (void)ioctl(0, TIOCSETN, (char *)&sb); 7141590Srgrimes notc.t_stopc = -1; 7151590Srgrimes notc.t_startc = -1; 7161590Srgrimes (void)ioctl(0, TIOCSETC, (char *)¬c); 7171590Srgrimes } 7181590Srgrimes if (!eight && (mark & TIOCPKT_DOSTOP)) { 7191590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 7201590Srgrimes sb.sg_flags &= ~RAW; 7211590Srgrimes sb.sg_flags |= CBREAK; 7221590Srgrimes (void)ioctl(0, TIOCSETN, (char *)&sb); 7231590Srgrimes notc.t_stopc = deftc.t_stopc; 7241590Srgrimes notc.t_startc = deftc.t_startc; 7251590Srgrimes (void)ioctl(0, TIOCSETC, (char *)¬c); 7261590Srgrimes } 7271590Srgrimes if (mark & TIOCPKT_FLUSHWRITE) { 7281590Srgrimes (void)ioctl(1, TIOCFLUSH, (char *)&out); 7291590Srgrimes for (;;) { 7301590Srgrimes if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 73127919Scharnier warn("ioctl"); 7321590Srgrimes break; 7331590Srgrimes } 7341590Srgrimes if (atmark) 7351590Srgrimes break; 7361590Srgrimes n = read(rem, waste, sizeof (waste)); 7371590Srgrimes if (n <= 0) 7381590Srgrimes break; 7391590Srgrimes } 7401590Srgrimes /* 7411590Srgrimes * Don't want any pending data to be output, so clear the recv 7421590Srgrimes * buffer. If we were hanging on a write when interrupted, 7431590Srgrimes * don't want it to restart. If we were reading, restart 7441590Srgrimes * anyway. 7451590Srgrimes */ 7461590Srgrimes rcvcnt = 0; 7471590Srgrimes longjmp(rcvtop, 1); 7481590Srgrimes } 7491590Srgrimes 7501590Srgrimes /* oob does not do FLUSHREAD (alas!) */ 7511590Srgrimes 7521590Srgrimes /* 7531590Srgrimes * If we filled the receive buffer while a read was pending, longjmp 7541590Srgrimes * to the top to restart appropriately. Don't abort a pending write, 7551590Srgrimes * however, or we won't know how much was written. 7561590Srgrimes */ 7571590Srgrimes if (rcvd && rcvstate == READING) 7581590Srgrimes longjmp(rcvtop, 1); 7591590Srgrimes} 7601590Srgrimes 7611590Srgrimes/* reader: read from remote: line -> 1 */ 7621590Srgrimesint 7631590Srgrimesreader(omask) 7641590Srgrimes int omask; 7651590Srgrimes{ 7661590Srgrimes int pid, n, remaining; 7671590Srgrimes char *bufp; 7681590Srgrimes 7691590Srgrimes#if BSD >= 43 || defined(SUNOS4) 7701590Srgrimes pid = getpid(); /* modern systems use positives for pid */ 7711590Srgrimes#else 7721590Srgrimes pid = -getpid(); /* old broken systems use negatives */ 7731590Srgrimes#endif 7741590Srgrimes (void)signal(SIGTTOU, SIG_IGN); 7751590Srgrimes (void)signal(SIGURG, oob); 77691434Sfenner (void)signal(SIGUSR1, oob); /* When propogating SIGURG from parent */ 7771590Srgrimes ppid = getppid(); 7781590Srgrimes (void)fcntl(rem, F_SETOWN, pid); 7791590Srgrimes (void)setjmp(rcvtop); 7801590Srgrimes (void)sigsetmask(omask); 7811590Srgrimes bufp = rcvbuf; 7821590Srgrimes for (;;) { 7831590Srgrimes while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 7841590Srgrimes rcvstate = WRITING; 7851590Srgrimes n = write(STDOUT_FILENO, bufp, remaining); 7861590Srgrimes if (n < 0) { 7871590Srgrimes if (errno != EINTR) 7881590Srgrimes return (-1); 7891590Srgrimes continue; 7901590Srgrimes } 7911590Srgrimes bufp += n; 7921590Srgrimes } 7931590Srgrimes bufp = rcvbuf; 7941590Srgrimes rcvcnt = 0; 7951590Srgrimes rcvstate = READING; 7961590Srgrimes 7971590Srgrimes#ifdef CRYPT 7981590Srgrimes#ifdef KERBEROS 7991590Srgrimes if (doencrypt) 80029922Smarkm rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf), 80129922Smarkm schedule, &cred.session); 8021590Srgrimes else 8031590Srgrimes#endif 8041590Srgrimes#endif 8051590Srgrimes rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 8061590Srgrimes if (rcvcnt == 0) 8071590Srgrimes return (0); 8081590Srgrimes if (rcvcnt < 0) { 8091590Srgrimes if (errno == EINTR) 8101590Srgrimes continue; 81127919Scharnier warn("read"); 8121590Srgrimes return (-1); 8131590Srgrimes } 8141590Srgrimes } 8151590Srgrimes} 8161590Srgrimes 8171590Srgrimesvoid 8181590Srgrimesmode(f) 8191590Srgrimes int f; 8201590Srgrimes{ 8211590Srgrimes struct ltchars *ltc; 8221590Srgrimes struct sgttyb sb; 8231590Srgrimes struct tchars *tc; 8241590Srgrimes int lflags; 8251590Srgrimes 8261590Srgrimes (void)ioctl(0, TIOCGETP, (char *)&sb); 8271590Srgrimes (void)ioctl(0, TIOCLGET, (char *)&lflags); 8281590Srgrimes switch(f) { 8291590Srgrimes case 0: 8301590Srgrimes sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 8311590Srgrimes sb.sg_flags |= defflags|tabflag; 8321590Srgrimes tc = &deftc; 8331590Srgrimes ltc = &defltc; 8341590Srgrimes sb.sg_kill = defkill; 8351590Srgrimes sb.sg_erase = deferase; 8361590Srgrimes lflags = deflflags; 8371590Srgrimes break; 8381590Srgrimes case 1: 8391590Srgrimes sb.sg_flags |= (eight ? RAW : CBREAK); 8401590Srgrimes sb.sg_flags &= ~defflags; 8411590Srgrimes /* preserve tab delays, but turn off XTABS */ 8421590Srgrimes if ((sb.sg_flags & TBDELAY) == XTABS) 8431590Srgrimes sb.sg_flags &= ~TBDELAY; 8441590Srgrimes tc = ¬c; 8451590Srgrimes ltc = &noltc; 8461590Srgrimes sb.sg_kill = sb.sg_erase = -1; 8471590Srgrimes if (litout) 8481590Srgrimes lflags |= LLITOUT; 8491590Srgrimes break; 8501590Srgrimes default: 8511590Srgrimes return; 8521590Srgrimes } 8531590Srgrimes (void)ioctl(0, TIOCSLTC, (char *)ltc); 8541590Srgrimes (void)ioctl(0, TIOCSETC, (char *)tc); 8551590Srgrimes (void)ioctl(0, TIOCSETN, (char *)&sb); 8561590Srgrimes (void)ioctl(0, TIOCLSET, (char *)&lflags); 8571590Srgrimes} 8581590Srgrimes 8591590Srgrimesvoid 8601590Srgrimeslostpeer(signo) 8611590Srgrimes int signo; 8621590Srgrimes{ 8631590Srgrimes (void)signal(SIGPIPE, SIG_IGN); 8641590Srgrimes msg("\007connection closed."); 8651590Srgrimes done(1); 8661590Srgrimes} 8671590Srgrimes 86891434Sfenner/* copy SIGURGs to the child process via SIGUSR1. */ 8691590Srgrimesvoid 8701590Srgrimescopytochild(signo) 8711590Srgrimes int signo; 8721590Srgrimes{ 87391434Sfenner (void)kill(child, SIGUSR1); 8741590Srgrimes} 8751590Srgrimes 8761590Srgrimesvoid 8771590Srgrimesmsg(str) 8781590Srgrimes char *str; 8791590Srgrimes{ 8801590Srgrimes (void)fprintf(stderr, "rlogin: %s\r\n", str); 8811590Srgrimes} 8821590Srgrimes 8831590Srgrimesvoid 8841590Srgrimesusage() 8851590Srgrimes{ 8861590Srgrimes (void)fprintf(stderr, 88757232Sshin "usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] host\n", 8881590Srgrimes#ifdef KERBEROS 8891590Srgrimes#ifdef CRYPT 89047549Sbde "8DEKLdx", " [-k realm] "); 8911590Srgrimes#else 89247549Sbde "8DEKLd", " [-k realm] "); 8931590Srgrimes#endif 8941590Srgrimes#else 89569102Sjkoshy "8DEKLd", " "); 8961590Srgrimes#endif 8971590Srgrimes exit(1); 8981590Srgrimes} 8991590Srgrimes 9001590Srgrimes/* 9011590Srgrimes * The following routine provides compatibility (such as it is) between older 9021590Srgrimes * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 9031590Srgrimes */ 9041590Srgrimes#ifdef OLDSUN 9051590Srgrimesint 9061590Srgrimesget_window_size(fd, wp) 9071590Srgrimes int fd; 9081590Srgrimes struct winsize *wp; 9091590Srgrimes{ 9101590Srgrimes struct ttysize ts; 9111590Srgrimes int error; 9121590Srgrimes 9131590Srgrimes if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 9141590Srgrimes return (error); 9151590Srgrimes wp->ws_row = ts.ts_lines; 9161590Srgrimes wp->ws_col = ts.ts_cols; 9171590Srgrimes wp->ws_xpixel = 0; 9181590Srgrimes wp->ws_ypixel = 0; 9191590Srgrimes return (0); 9201590Srgrimes} 9211590Srgrimes#endif 9221590Srgrimes 9231590Srgrimesu_int 9241590Srgrimesgetescape(p) 9251590Srgrimes register char *p; 9261590Srgrimes{ 9271590Srgrimes long val; 9281590Srgrimes int len; 9291590Srgrimes 9301590Srgrimes if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 9311590Srgrimes return ((u_int)*p); 9321590Srgrimes /* otherwise, \nnn */ 9331590Srgrimes if (*p == '\\' && len >= 2 && len <= 4) { 9341590Srgrimes val = strtol(++p, NULL, 8); 9351590Srgrimes for (;;) { 9361590Srgrimes if (!*++p) 9371590Srgrimes return ((u_int)val); 9381590Srgrimes if (*p < '0' || *p > '8') 9391590Srgrimes break; 9401590Srgrimes } 9411590Srgrimes } 9421590Srgrimes msg("illegal option value -- e"); 9431590Srgrimes usage(); 9441590Srgrimes /* NOTREACHED */ 9451590Srgrimes} 946