rlogin.c revision 91434
118334Speter/* 218334Speter * Copyright (c) 1983, 1990, 1993 318334Speter * The Regents of the University of California. All rights reserved. 418334Speter * 518334Speter * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 718334Speter * are met: 818334Speter * 1. Redistributions of source code must retain the above copyright 918334Speter * notice, this list of conditions and the following disclaimer. 1018334Speter * 2. Redistributions in binary form must reproduce the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer in the 1218334Speter * documentation and/or other materials provided with the distribution. 1318334Speter * 3. All advertising materials mentioning features or use of this software 1418334Speter * must display the following acknowledgement: 1518334Speter * This product includes software developed by the University of 1618334Speter * California, Berkeley and its contributors. 1718334Speter * 4. Neither the name of the University nor the names of its contributors 1818334Speter * may be used to endorse or promote products derived from this software 1918334Speter * without specific prior written permission. 2018334Speter * 2118334Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2218334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2318334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2418334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2518334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2618334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2718334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2818334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2918334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3018334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3118334Speter * SUCH DAMAGE. 3218334Speter */ 3318334Speter 3418334Speter#ifndef lint 3518334Speterstatic const char copyright[] = 3618334Speter"@(#) Copyright (c) 1983, 1990, 1993\n\ 3718334Speter The Regents of the University of California. All rights reserved.\n"; 3818334Speter#endif /* not lint */ 3918334Speter 4018334Speter#ifndef lint 4118334Speterstatic const char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; 4218334Speterstatic const char rcsid[] = 4318334Speter "$FreeBSD: head/usr.bin/rlogin/rlogin.c 91434 2002-02-27 22:45:10Z fenner $"; 4418334Speter#endif /* not lint */ 4518334Speter 4618334Speter/* 4718334Speter * rlogin - remote login 4818334Speter */ 4918334Speter#include <sys/param.h> 5018334Speter#include <sys/socket.h> 5118334Speter#include <sys/time.h> 5218334Speter#include <sys/resource.h> 5318334Speter#include <sys/wait.h> 5418334Speter 5518334Speter#include <netinet/in.h> 5618334Speter#include <netinet/in_systm.h> 5718334Speter#include <netinet/ip.h> 5818334Speter#include <netinet/tcp.h> 5918334Speter 6018334Speter#include <err.h> 6118334Speter#include <errno.h> 6218334Speter#include <fcntl.h> 6318334Speter#include <libutil.h> 6418334Speter#include <netdb.h> 6518334Speter#include <pwd.h> 6618334Speter#include <setjmp.h> 6718334Speter#include <sgtty.h> 6818334Speter#include <signal.h> 6918334Speter#include <stdio.h> 7018334Speter#include <stdlib.h> 7118334Speter#include <string.h> 7218334Speter#include <unistd.h> 7318334Speter#include <err.h> 7418334Speter 7518334Speter#ifdef KERBEROS 7618334Speter#include <openssl/des.h> 7718334Speter#include <krb.h> 7818334Speter 7918334Speter#include "../../bin/rcp/pathnames.h" 8018334Speter#include "krb.h" 8118334Speter 8218334SpeterCREDENTIALS cred; 8318334SpeterKey_schedule schedule; 8418334Speterint use_kerberos = 1, doencrypt; 8518334Speterchar dst_realm_buf[REALM_SZ], *dest_realm = NULL; 8618334Speter#endif 8718334Speter 8818334Speter#ifndef TIOCPKT_WINDOW 8918334Speter#define TIOCPKT_WINDOW 0x80 9018334Speter#endif 9118334Speter 9218334Speter/* concession to Sun */ 9318334Speter#ifndef SIGUSR1 9418334Speter#define SIGUSR1 30 9518334Speter#endif 9618334Speter 9718334Speterint eight, litout, rem; 9818334Speterint family = PF_UNSPEC; 9918334Speter 10018334Speterint noescape; 10118334Speteru_char escapechar = '~'; 10218334Speter 10318334Speterchar *speeds[] = { 10418334Speter "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 10518334Speter "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" 10618334Speter#define MAX_SPEED_LENGTH (sizeof("115200") - 1) 10718334Speter}; 10818334Speter 10918334Speter#ifdef OLDSUN 11018334Speterstruct winsize { 11118334Speter unsigned short ws_row, ws_col; 11218334Speter unsigned short ws_xpixel, ws_ypixel; 11318334Speter}; 11418334Speter#else 11518334Speter#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 11618334Speter#endif 11718334Speterstruct winsize winsize; 11818334Speter 11918334Spetervoid catch_child __P((int)); 12018334Spetervoid copytochild __P((int)); 12118334Spetervoid doit __P((long)) __dead2; 12218334Spetervoid done __P((int)) __dead2; 12318334Spetervoid echo __P((char)); 12418334Speteru_int getescape __P((char *)); 12518334Spetervoid lostpeer __P((int)); 12618334Spetervoid mode __P((int)); 12718334Spetervoid msg __P((char *)); 12818334Spetervoid oob __P((int)); 12918334Speterint reader __P((int)); 13018334Spetervoid sendwindow __P((void)); 13118334Spetervoid setsignal __P((int)); 13218334Spetervoid sigwinch __P((int)); 13318334Spetervoid stop __P((char)); 13418334Spetervoid usage __P((void)) __dead2; 13518334Spetervoid writer __P((void)); 13618334Spetervoid writeroob __P((int)); 13718334Speter 13818334Speter#ifdef OLDSUN 13918334Speterint get_window_size __P((int, struct winsize *)); 14018334Speter#endif 14118334Speter 14218334Speterint 14318334Spetermain(argc, argv) 14418334Speter int argc; 14518334Speter char *argv[]; 14618334Speter{ 14718334Speter struct passwd *pw; 14818334Speter struct servent *sp; 14918334Speter struct sgttyb ttyb; 15018334Speter long omask; 15118334Speter int argoff, ch, dflag, Dflag, one, uid; 15218334Speter char *host, *localname, *p, *user, term[1024]; 15318334Speter#ifdef KERBEROS 15418334Speter char *k; 15518334Speter#endif 15618334Speter struct sockaddr_storage ss; 15718334Speter int sslen; 15818334Speter 15918334Speter argoff = dflag = Dflag = 0; 16018334Speter one = 1; 16118334Speter host = localname = user = NULL; 16218334Speter 16318334Speter if ((p = rindex(argv[0], '/'))) 16418334Speter ++p; 16518334Speter else 16618334Speter p = argv[0]; 16718334Speter 16818334Speter if (strcmp(p, "rlogin")) 16918334Speter host = p; 17018334Speter 17118334Speter /* handle "rlogin host flags" */ 17218334Speter if (!host && argc > 2 && argv[1][0] != '-') { 17318334Speter host = argv[1]; 17418334Speter argoff = 1; 17518334Speter } 17618334Speter 17718334Speter#ifdef KERBEROS 17818334Speter#define OPTIONS "468DEKLde:i:k:l:x" 17918334Speter#else 18018334Speter#define OPTIONS "468DEKLde:i:l:" 18118334Speter#endif 18218334Speter while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 18318334Speter switch(ch) { 18418334Speter case '4': 18518334Speter family = PF_INET; 18618334Speter break; 18718334Speter 18818334Speter case '6': 18918334Speter family = PF_INET6; 19018334Speter break; 19118334Speter 19218334Speter case '8': 19318334Speter eight = 1; 19418334Speter break; 19518334Speter case 'D': 19618334Speter Dflag = 1; 19718334Speter break; 19818334Speter case 'E': 19918334Speter noescape = 1; 20018334Speter break; 20118334Speter case 'K': 20218334Speter#ifdef KERBEROS 20318334Speter use_kerberos = 0; 20418334Speter#endif 20518334Speter break; 20618334Speter case 'L': 20718334Speter litout = 1; 20818334Speter break; 20918334Speter case 'd': 21018334Speter dflag = 1; 21118334Speter break; 21218334Speter case 'e': 21318334Speter noescape = 0; 21418334Speter escapechar = getescape(optarg); 21518334Speter break; 21618334Speter case 'i': 21718334Speter if (getuid() != 0) 21818334Speter errx(1, "-i user: permission denied"); 21918334Speter localname = optarg; 22018334Speter break; 22118334Speter#ifdef KERBEROS 22218334Speter case 'k': 22318334Speter dest_realm = dst_realm_buf; 22418334Speter (void)strncpy(dest_realm, optarg, REALM_SZ); 22518334Speter break; 22618334Speter#endif 22718334Speter case 'l': 22818334Speter user = optarg; 22918334Speter break; 23018334Speter#ifdef CRYPT 23118334Speter#ifdef KERBEROS 23218334Speter case 'x': 23318334Speter doencrypt = 1; 23418334Speter break; 23518334Speter#endif 23618334Speter#endif 23718334Speter case '?': 23818334Speter default: 23918334Speter usage(); 24018334Speter } 24118334Speter optind += argoff; 24218334Speter 24318334Speter /* if haven't gotten a host yet, do so */ 24418334Speter if (!host && !(host = argv[optind++])) 24518334Speter usage(); 24618334Speter 24718334Speter if (argv[optind]) 24818334Speter usage(); 24918334Speter 25018334Speter if (!(pw = getpwuid(uid = getuid()))) 25118334Speter errx(1, "unknown user id"); 25218334Speter if (!user) 25318334Speter user = pw->pw_name; 25418334Speter if (!localname) 25518334Speter localname = pw->pw_name; 25618334Speter 25718334Speter sp = NULL; 25818334Speter#ifdef KERBEROS 25918334Speter k = auth_getval("auth_list"); 26018334Speter if (k && !strstr(k, "kerberos")) 26118334Speter use_kerberos = 0; 26218334Speter if (use_kerberos) { 26318334Speter sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 26418334Speter if (sp == NULL) { 26518334Speter use_kerberos = 0; 26618334Speter warn("can't get entry for %s/tcp service", 26718334Speter doencrypt ? "eklogin" : "klogin"); 26818334Speter } 26918334Speter } 27018334Speter#endif 27118334Speter if (sp == NULL) 27218334Speter sp = getservbyname("login", "tcp"); 27318334Speter if (sp == NULL) 27418334Speter errx(1, "login/tcp: unknown service"); 27518334Speter 27618334Speter#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) 27718334Speter 27818334Speter (void)strncpy(term, (p = getenv("TERM")) ? p : "network", 27918334Speter MAX_TERM_LENGTH); 28018334Speter term[MAX_TERM_LENGTH] = '\0'; 28118334Speter if (ioctl(0, TIOCGETP, &ttyb) == 0) { 28218334Speter (void)strcat(term, "/"); 28318334Speter (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 28418334Speter } 28518334Speter 28618334Speter (void)get_window_size(0, &winsize); 28718334Speter 28818334Speter (void)signal(SIGPIPE, lostpeer); 28918334Speter /* will use SIGUSR1 for window size hack, so hold it off */ 29018334Speter omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 29118334Speter /* 29218334Speter * We set SIGURG and SIGUSR1 below so that an 29318334Speter * incoming signal will be held pending rather than being 29418334Speter * discarded. Note that these routines will be ready to get 29518334Speter * a signal by the time that they are unblocked below. 29618334Speter */ 29718334Speter (void)signal(SIGURG, copytochild); 29818334Speter (void)signal(SIGUSR1, writeroob); 29918334Speter 30018334Speter#ifdef KERBEROS 30118334Speter if (use_kerberos) { 30218334Speter setuid(getuid()); 30318334Speter rem = KSUCCESS; 30418334Speter errno = 0; 30518334Speter if (dest_realm == NULL) 30618334Speter dest_realm = krb_realmofhost(host); 30718334Speter 30818334Speter#ifdef CRYPT 30918334Speter if (doencrypt) { 31018334Speter rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 31118334Speter dest_realm, &cred, schedule); 31218334Speter des_set_key(&cred.session, schedule); 31318334Speter } else 31418334Speter#endif /* CRYPT */ 31518334Speter rem = krcmd(&host, sp->s_port, user, term, 0, 31618334Speter dest_realm); 31718334Speter if (rem < 0) { 31818334Speter int i; 31918334Speter char **newargv; 32018334Speter 32118334Speter sp = getservbyname("login", "tcp"); 32218334Speter if (sp == NULL) 32318334Speter errx(1, "unknown service login/tcp"); 32418334Speter if (errno == ECONNREFUSED) 32518334Speter warn("remote host doesn't support Kerberos"); 32618334Speter if (errno == ENOENT) 32718334Speter warn("can't provide Kerberos auth data"); 32818334Speter newargv = malloc((argc + 2) * sizeof(*newargv)); 32918334Speter if (newargv == NULL) 33018334Speter err(1, "malloc"); 33118334Speter newargv[0] = argv[0]; 33218334Speter newargv[1] = "-K"; 33318334Speter for(i = 1; i < argc; ++i) 33418334Speter newargv[i + 1] = argv[i]; 33518334Speter newargv[argc + 1] = NULL; 33618334Speter execv(_PATH_RLOGIN, newargv); 33718334Speter } 33818334Speter } else { 33918334Speter#ifdef CRYPT 34018334Speter if (doencrypt) 34118334Speter errx(1, "the -x flag requires Kerberos authentication"); 34218334Speter#endif /* CRYPT */ 34318334Speter rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, 34418334Speter family); 34518334Speter } 34618334Speter#else 34718334Speter rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); 34818334Speter#endif /* KERBEROS */ 34918334Speter 35018334Speter if (rem < 0) 35118334Speter exit(1); 35218334Speter 35318334Speter if (dflag && 35418334Speter setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 35518334Speter warn("setsockopt"); 35618334Speter if (Dflag && 35718334Speter setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 35818334Speter warn("setsockopt NODELAY (ignored)"); 35918334Speter 36018334Speter sslen = sizeof(ss); 36118334Speter one = IPTOS_LOWDELAY; 36218334Speter if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 && 36318334Speter ss.ss_family == AF_INET) { 36418334Speter if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, 36518334Speter sizeof(int)) < 0) 36618334Speter warn("setsockopt TOS (ignored)"); 36718334Speter } else 36818334Speter if (ss.ss_family == AF_INET) 36918334Speter warn("setsockopt getsockname failed"); 37018334Speter 37118334Speter (void)setuid(uid); 37218334Speter doit(omask); 37318334Speter /*NOTREACHED*/ 37418334Speter} 37518334Speter 37618334Speterint child, defflags, deflflags, tabflag; 37718334Speterchar deferase, defkill; 37818334Speterstruct tchars deftc; 37918334Speterstruct ltchars defltc; 38018334Speterstruct tchars notc = { -1, -1, -1, -1, -1, -1 }; 38118334Speterstruct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 38218334Speter 38318334Spetervoid 38418334Speterdoit(omask) 38518334Speter long omask; 38618334Speter{ 38718334Speter struct sgttyb sb; 38818334Speter 38918334Speter (void)ioctl(0, TIOCGETP, (char *)&sb); 39018334Speter defflags = sb.sg_flags; 39118334Speter tabflag = defflags & TBDELAY; 39218334Speter defflags &= ECHO | CRMOD; 39318334Speter deferase = sb.sg_erase; 39418334Speter defkill = sb.sg_kill; 39518334Speter (void)ioctl(0, TIOCLGET, &deflflags); 39618334Speter (void)ioctl(0, TIOCGETC, &deftc); 39718334Speter notc.t_startc = deftc.t_startc; 39818334Speter notc.t_stopc = deftc.t_stopc; 39918334Speter (void)ioctl(0, TIOCGLTC, &defltc); 40018334Speter (void)signal(SIGINT, SIG_IGN); 40118334Speter setsignal(SIGHUP); 40218334Speter setsignal(SIGQUIT); 40318334Speter child = fork(); 40418334Speter if (child == -1) { 40518334Speter warn("fork"); 40618334Speter done(1); 40718334Speter } 40818334Speter if (child == 0) { 40918334Speter mode(1); 41018334Speter if (reader(omask) == 0) { 41118334Speter msg("connection closed."); 41218334Speter exit(0); 41318334Speter } 41418334Speter sleep(1); 41518334Speter msg("\007connection closed."); 41618334Speter exit(1); 41718334Speter } 41818334Speter 41918334Speter /* 42018334Speter * We may still own the socket, and may have a pending SIGURG (or might 42118334Speter * receive one soon) that we really want to send to the reader. When 42218334Speter * one of these comes in, the trap copytochild simply copies such 42318334Speter * signals to the child. We can now unblock SIGURG and SIGUSR1 42418334Speter * that were set above. 42518334Speter */ 42618334Speter (void)sigsetmask(omask); 42718334Speter (void)signal(SIGCHLD, catch_child); 42818334Speter writer(); 42918334Speter msg("closed connection."); 43018334Speter done(0); 43118334Speter} 43218334Speter 43318334Speter/* trap a signal, unless it is being ignored. */ 43418334Spetervoid 43518334Spetersetsignal(sig) 43618334Speter int sig; 43718334Speter{ 43818334Speter int omask = sigblock(sigmask(sig)); 43918334Speter 44018334Speter if (signal(sig, exit) == SIG_IGN) 44118334Speter (void)signal(sig, SIG_IGN); 44218334Speter (void)sigsetmask(omask); 44318334Speter} 44418334Speter 44518334Spetervoid 44618334Speterdone(status) 44718334Speter int status; 44818334Speter{ 44918334Speter int w, wstatus; 45018334Speter 45118334Speter mode(0); 45218334Speter if (child > 0) { 45318334Speter /* make sure catch_child does not snap it up */ 45418334Speter (void)signal(SIGCHLD, SIG_DFL); 45518334Speter if (kill(child, SIGKILL) >= 0) 45618334Speter while ((w = wait(&wstatus)) > 0 && w != child); 45718334Speter } 45818334Speter exit(status); 45918334Speter} 46018334Speter 46118334Speterint dosigwinch; 46218334Speter 46318334Speter/* 46418334Speter * This is called when the reader process gets the out-of-band (urgent) 46518334Speter * request to turn on the window-changing protocol. 46618334Speter */ 46718334Spetervoid 46818334Speterwriteroob(signo) 46918334Speter int signo; 47018334Speter{ 47118334Speter if (dosigwinch == 0) { 47218334Speter sendwindow(); 47318334Speter (void)signal(SIGWINCH, sigwinch); 47418334Speter } 47518334Speter dosigwinch = 1; 47618334Speter} 47718334Speter 47818334Spetervoid 47918334Spetercatch_child(signo) 48018334Speter int signo; 48118334Speter{ 48218334Speter union wait status; 48318334Speter int pid; 48418334Speter 48518334Speter for (;;) { 48618334Speter pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 48718334Speter if (pid == 0) 48818334Speter return; 48918334Speter /* if the child (reader) dies, just quit */ 49018334Speter if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 49118334Speter done((int)(status.w_termsig | status.w_retcode)); 49218334Speter } 49318334Speter /* NOTREACHED */ 49418334Speter} 49518334Speter 49618334Speter/* 49718334Speter * writer: write to remote: 0 -> line. 49818334Speter * ~. terminate 49918334Speter * ~^Z suspend rlogin process. 50018334Speter * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 50118334Speter */ 50218334Spetervoid 50318334Speterwriter() 50418334Speter{ 50518334Speter register int bol, local, n; 50618334Speter char c; 50718334Speter 50818334Speter bol = 1; /* beginning of line */ 50918334Speter local = 0; 51018334Speter for (;;) { 51118334Speter n = read(STDIN_FILENO, &c, 1); 51218334Speter if (n <= 0) { 51318334Speter if (n < 0 && errno == EINTR) 51418334Speter continue; 51518334Speter break; 51618334Speter } 51718334Speter /* 51818334Speter * If we're at the beginning of the line and recognize a 51918334Speter * command character, then we echo locally. Otherwise, 52018334Speter * characters are echo'd remotely. If the command character 52118334Speter * is doubled, this acts as a force and local echo is 52218334Speter * suppressed. 52318334Speter */ 52418334Speter if (bol) { 52518334Speter bol = 0; 52618334Speter if (!noescape && c == escapechar) { 52718334Speter local = 1; 52818334Speter continue; 52918334Speter } 53018334Speter } else if (local) { 53118334Speter local = 0; 53218334Speter if (c == '.' || c == deftc.t_eofc) { 53318334Speter echo(c); 53418334Speter break; 53518334Speter } 53618334Speter if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 53718334Speter bol = 1; 53818334Speter echo(c); 53918334Speter stop(c); 54018334Speter continue; 54118334Speter } 54218334Speter if (c != escapechar) 54318334Speter#ifdef CRYPT 54418334Speter#ifdef KERBEROS 54518334Speter if (doencrypt) 54618334Speter (void)des_enc_write(rem, 54718334Speter (char *)&escapechar, 1, 54818334Speter schedule, &cred.session); 54918334Speter else 55018334Speter#endif 55118334Speter#endif 55218334Speter (void)write(rem, &escapechar, 1); 55318334Speter } 55418334Speter 55518334Speter#ifdef CRYPT 55618334Speter#ifdef KERBEROS 55718334Speter if (doencrypt) { 55818334Speter if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 55918334Speter msg("line gone"); 56018334Speter break; 56118334Speter } 56218334Speter } else 56318334Speter#endif 56418334Speter#endif 56518334Speter if (write(rem, &c, 1) == 0) { 56618334Speter msg("line gone"); 56718334Speter break; 56818334Speter } 56918334Speter bol = c == defkill || c == deftc.t_eofc || 57018334Speter c == deftc.t_intrc || c == defltc.t_suspc || 57118334Speter c == '\r' || c == '\n'; 57218334Speter } 57318334Speter} 57418334Speter 57518334Spetervoid 57618334Speter#if __STDC__ 57718334Speterecho(register char c) 57818334Speter#else 57918334Speterecho(c) 58018334Speter register char c; 58118334Speter#endif 58218334Speter{ 58318334Speter register char *p; 58418334Speter char buf[8]; 58518334Speter 58618334Speter p = buf; 58718334Speter c &= 0177; 58818334Speter *p++ = escapechar; 58918334Speter if (c < ' ') { 59018334Speter *p++ = '^'; 59118334Speter *p++ = c + '@'; 59218334Speter } else if (c == 0177) { 59318334Speter *p++ = '^'; 59418334Speter *p++ = '?'; 59518334Speter } else 59618334Speter *p++ = c; 59718334Speter *p++ = '\r'; 59818334Speter *p++ = '\n'; 59918334Speter (void)write(STDOUT_FILENO, buf, p - buf); 60018334Speter} 60118334Speter 60218334Spetervoid 60318334Speter#if __STDC__ 60418334Speterstop(char cmdc) 60518334Speter#else 60618334Speterstop(cmdc) 60718334Speter char cmdc; 60818334Speter#endif 60918334Speter{ 61018334Speter mode(0); 61118334Speter (void)signal(SIGCHLD, SIG_IGN); 61218334Speter (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 61318334Speter (void)signal(SIGCHLD, catch_child); 61418334Speter mode(1); 61518334Speter sigwinch(0); /* check for size changes */ 61618334Speter} 61718334Speter 61818334Spetervoid 61918334Spetersigwinch(signo) 62018334Speter int signo; 62118334Speter{ 62218334Speter struct winsize ws; 62318334Speter 62418334Speter if (dosigwinch && get_window_size(0, &ws) == 0 && 62518334Speter bcmp(&ws, &winsize, sizeof(ws))) { 62618334Speter winsize = ws; 62718334Speter sendwindow(); 62818334Speter } 62918334Speter} 63018334Speter 63118334Speter/* 63218334Speter * Send the window size to the server via the magic escape 63318334Speter */ 63418334Spetervoid 63518334Spetersendwindow() 63618334Speter{ 63718334Speter struct winsize *wp; 63818334Speter char obuf[4 + sizeof (struct winsize)]; 63918334Speter 64018334Speter wp = (struct winsize *)(obuf+4); 64118334Speter obuf[0] = 0377; 64218334Speter obuf[1] = 0377; 64318334Speter obuf[2] = 's'; 64418334Speter obuf[3] = 's'; 64518334Speter wp->ws_row = htons(winsize.ws_row); 64618334Speter wp->ws_col = htons(winsize.ws_col); 64718334Speter wp->ws_xpixel = htons(winsize.ws_xpixel); 64818334Speter wp->ws_ypixel = htons(winsize.ws_ypixel); 64918334Speter 65018334Speter#ifdef CRYPT 65118334Speter#ifdef KERBEROS 65218334Speter if(doencrypt) 65318334Speter (void)des_enc_write(rem, obuf, sizeof(obuf), 65418334Speter schedule, &cred.session); 65518334Speter else 65618334Speter#endif 65718334Speter#endif 65818334Speter (void)write(rem, obuf, sizeof(obuf)); 65918334Speter} 66018334Speter 66118334Speter/* 66218334Speter * reader: read from remote: line -> 1 66318334Speter */ 66418334Speter#define READING 1 66518334Speter#define WRITING 2 66618334Speter 66718334Speterjmp_buf rcvtop; 66818334Speterint ppid, rcvcnt, rcvstate; 66918334Speterchar rcvbuf[8 * 1024]; 67018334Speter 67118334Spetervoid 67218334Speteroob(signo) 67318334Speter int signo; 67418334Speter{ 67518334Speter struct sgttyb sb; 67618334Speter int atmark, n, out, rcvd; 67718334Speter char waste[BUFSIZ], mark; 67818334Speter 67918334Speter out = O_RDWR; 68018334Speter rcvd = 0; 68118334Speter while (recv(rem, &mark, 1, MSG_OOB) < 0) { 68218334Speter switch (errno) { 68318334Speter case EWOULDBLOCK: 68418334Speter /* 68518334Speter * Urgent data not here yet. It may not be possible 68618334Speter * to send it yet if we are blocked for output and 68718334Speter * our input buffer is full. 68818334Speter */ 68918334Speter if (rcvcnt < sizeof(rcvbuf)) { 69018334Speter n = read(rem, rcvbuf + rcvcnt, 69118334Speter sizeof(rcvbuf) - rcvcnt); 69218334Speter if (n <= 0) 69318334Speter return; 69418334Speter rcvd += n; 69518334Speter } else { 69618334Speter n = read(rem, waste, sizeof(waste)); 69718334Speter if (n <= 0) 69818334Speter return; 69918334Speter } 70018334Speter continue; 70118334Speter default: 70218334Speter return; 70318334Speter } 70418334Speter } 70518334Speter if (mark & TIOCPKT_WINDOW) { 70618334Speter /* Let server know about window size changes */ 70718334Speter (void)kill(ppid, SIGUSR1); 70818334Speter } 70918334Speter if (!eight && (mark & TIOCPKT_NOSTOP)) { 71018334Speter (void)ioctl(0, TIOCGETP, (char *)&sb); 71118334Speter sb.sg_flags &= ~CBREAK; 71218334Speter sb.sg_flags |= RAW; 71318334Speter (void)ioctl(0, TIOCSETN, (char *)&sb); 71418334Speter notc.t_stopc = -1; 71518334Speter notc.t_startc = -1; 71618334Speter (void)ioctl(0, TIOCSETC, (char *)¬c); 71718334Speter } 71818334Speter if (!eight && (mark & TIOCPKT_DOSTOP)) { 71918334Speter (void)ioctl(0, TIOCGETP, (char *)&sb); 72018334Speter sb.sg_flags &= ~RAW; 72118334Speter sb.sg_flags |= CBREAK; 72218334Speter (void)ioctl(0, TIOCSETN, (char *)&sb); 72318334Speter notc.t_stopc = deftc.t_stopc; 72418334Speter notc.t_startc = deftc.t_startc; 72518334Speter (void)ioctl(0, TIOCSETC, (char *)¬c); 72618334Speter } 72718334Speter if (mark & TIOCPKT_FLUSHWRITE) { 72818334Speter (void)ioctl(1, TIOCFLUSH, (char *)&out); 72918334Speter for (;;) { 73018334Speter if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 73118334Speter warn("ioctl"); 73218334Speter break; 73318334Speter } 73418334Speter if (atmark) 73518334Speter break; 73618334Speter n = read(rem, waste, sizeof (waste)); 73718334Speter if (n <= 0) 73818334Speter break; 73918334Speter } 74018334Speter /* 74118334Speter * Don't want any pending data to be output, so clear the recv 74218334Speter * buffer. If we were hanging on a write when interrupted, 74318334Speter * don't want it to restart. If we were reading, restart 74418334Speter * anyway. 74518334Speter */ 74618334Speter rcvcnt = 0; 74718334Speter longjmp(rcvtop, 1); 74818334Speter } 74918334Speter 75018334Speter /* oob does not do FLUSHREAD (alas!) */ 75118334Speter 75218334Speter /* 75318334Speter * If we filled the receive buffer while a read was pending, longjmp 75418334Speter * to the top to restart appropriately. Don't abort a pending write, 75518334Speter * however, or we won't know how much was written. 75618334Speter */ 75718334Speter if (rcvd && rcvstate == READING) 75818334Speter longjmp(rcvtop, 1); 75918334Speter} 76018334Speter 76118334Speter/* reader: read from remote: line -> 1 */ 76218334Speterint 76318334Speterreader(omask) 76418334Speter int omask; 76518334Speter{ 76618334Speter int pid, n, remaining; 76718334Speter char *bufp; 76818334Speter 76918334Speter#if BSD >= 43 || defined(SUNOS4) 77018334Speter pid = getpid(); /* modern systems use positives for pid */ 77118334Speter#else 77218334Speter pid = -getpid(); /* old broken systems use negatives */ 77318334Speter#endif 77418334Speter (void)signal(SIGTTOU, SIG_IGN); 77518334Speter (void)signal(SIGURG, oob); 77618334Speter (void)signal(SIGUSR1, oob); /* When propogating SIGURG from parent */ 77718334Speter ppid = getppid(); 77818334Speter (void)fcntl(rem, F_SETOWN, pid); 77918334Speter (void)setjmp(rcvtop); 78018334Speter (void)sigsetmask(omask); 78118334Speter bufp = rcvbuf; 78218334Speter for (;;) { 78318334Speter while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 78418334Speter rcvstate = WRITING; 78518334Speter n = write(STDOUT_FILENO, bufp, remaining); 78618334Speter if (n < 0) { 78718334Speter if (errno != EINTR) 78818334Speter return (-1); 78918334Speter continue; 79018334Speter } 79118334Speter bufp += n; 79218334Speter } 79318334Speter bufp = rcvbuf; 79418334Speter rcvcnt = 0; 79518334Speter rcvstate = READING; 79618334Speter 79718334Speter#ifdef CRYPT 79818334Speter#ifdef KERBEROS 79918334Speter if (doencrypt) 80018334Speter rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf), 80118334Speter schedule, &cred.session); 80218334Speter else 80318334Speter#endif 80418334Speter#endif 80518334Speter rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 80618334Speter if (rcvcnt == 0) 80718334Speter return (0); 80818334Speter if (rcvcnt < 0) { 80918334Speter if (errno == EINTR) 81018334Speter continue; 81118334Speter warn("read"); 81218334Speter return (-1); 81318334Speter } 81418334Speter } 81518334Speter} 81618334Speter 81718334Spetervoid 81818334Spetermode(f) 81918334Speter int f; 82018334Speter{ 82118334Speter struct ltchars *ltc; 82218334Speter struct sgttyb sb; 82318334Speter struct tchars *tc; 82418334Speter int lflags; 82518334Speter 82618334Speter (void)ioctl(0, TIOCGETP, (char *)&sb); 82718334Speter (void)ioctl(0, TIOCLGET, (char *)&lflags); 82818334Speter switch(f) { 82918334Speter case 0: 83018334Speter sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 83118334Speter sb.sg_flags |= defflags|tabflag; 83218334Speter tc = &deftc; 83318334Speter ltc = &defltc; 83418334Speter sb.sg_kill = defkill; 83518334Speter sb.sg_erase = deferase; 83618334Speter lflags = deflflags; 83718334Speter break; 83818334Speter case 1: 83918334Speter sb.sg_flags |= (eight ? RAW : CBREAK); 84018334Speter sb.sg_flags &= ~defflags; 84118334Speter /* preserve tab delays, but turn off XTABS */ 84218334Speter if ((sb.sg_flags & TBDELAY) == XTABS) 84318334Speter sb.sg_flags &= ~TBDELAY; 84418334Speter tc = ¬c; 84518334Speter ltc = &noltc; 84618334Speter sb.sg_kill = sb.sg_erase = -1; 84718334Speter if (litout) 84818334Speter lflags |= LLITOUT; 84918334Speter break; 85018334Speter default: 85118334Speter return; 85218334Speter } 85318334Speter (void)ioctl(0, TIOCSLTC, (char *)ltc); 85418334Speter (void)ioctl(0, TIOCSETC, (char *)tc); 85518334Speter (void)ioctl(0, TIOCSETN, (char *)&sb); 85618334Speter (void)ioctl(0, TIOCLSET, (char *)&lflags); 85718334Speter} 85818334Speter 85918334Spetervoid 86018334Speterlostpeer(signo) 86118334Speter int signo; 86218334Speter{ 86318334Speter (void)signal(SIGPIPE, SIG_IGN); 86418334Speter msg("\007connection closed."); 86518334Speter done(1); 86618334Speter} 86718334Speter 86818334Speter/* copy SIGURGs to the child process via SIGUSR1. */ 86918334Spetervoid 87018334Spetercopytochild(signo) 87118334Speter int signo; 87218334Speter{ 87318334Speter (void)kill(child, SIGUSR1); 87418334Speter} 87518334Speter 87618334Spetervoid 87718334Spetermsg(str) 87818334Speter char *str; 87918334Speter{ 88018334Speter (void)fprintf(stderr, "rlogin: %s\r\n", str); 88118334Speter} 88218334Speter 88318334Spetervoid 88418334Speterusage() 88518334Speter{ 88618334Speter (void)fprintf(stderr, 88718334Speter "usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] host\n", 88818334Speter#ifdef KERBEROS 88918334Speter#ifdef CRYPT 89018334Speter "8DEKLdx", " [-k realm] "); 89118334Speter#else 89218334Speter "8DEKLd", " [-k realm] "); 89318334Speter#endif 89418334Speter#else 89518334Speter "8DEKLd", " "); 89618334Speter#endif 89718334Speter exit(1); 89818334Speter} 89918334Speter 90018334Speter/* 90118334Speter * The following routine provides compatibility (such as it is) between older 90218334Speter * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 90318334Speter */ 90418334Speter#ifdef OLDSUN 90518334Speterint 90618334Speterget_window_size(fd, wp) 90718334Speter int fd; 90818334Speter struct winsize *wp; 90918334Speter{ 91018334Speter struct ttysize ts; 91118334Speter int error; 91218334Speter 91318334Speter if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 91418334Speter return (error); 91518334Speter wp->ws_row = ts.ts_lines; 91618334Speter wp->ws_col = ts.ts_cols; 91718334Speter wp->ws_xpixel = 0; 91818334Speter wp->ws_ypixel = 0; 91918334Speter return (0); 92018334Speter} 92118334Speter#endif 92218334Speter 92318334Speteru_int 92418334Spetergetescape(p) 92518334Speter register char *p; 92618334Speter{ 92718334Speter long val; 92818334Speter int len; 92918334Speter 93018334Speter if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 93118334Speter return ((u_int)*p); 93218334Speter /* otherwise, \nnn */ 93318334Speter if (*p == '\\' && len >= 2 && len <= 4) { 93418334Speter val = strtol(++p, NULL, 8); 93518334Speter for (;;) { 93618334Speter if (!*++p) 93718334Speter return ((u_int)val); 93818334Speter if (*p < '0' || *p > '8') 93918334Speter break; 94018334Speter } 94118334Speter } 94218334Speter msg("illegal option value -- e"); 94318334Speter usage(); 94418334Speter /* NOTREACHED */ 94518334Speter} 94618334Speter