144346Skarels /* 262213Sbostic * Copyright (c) 1983, 1990, 1993 362213Sbostic * The Regents of the University of California. All rights reserved. 435539Sbostic * 542763Sbostic * %sccs.include.redist.c% 621595Sdist */ 721595Sdist 86444Swnj #ifndef lint 962213Sbostic static char copyright[] = 1062213Sbostic "@(#) Copyright (c) 1983, 1990, 1993\n\ 1162213Sbostic The Regents of the University of California. All rights reserved.\n"; 1235539Sbostic #endif /* not lint */ 136444Swnj 1421595Sdist #ifndef lint 15*67749Spendry static char sccsid[] = "@(#)rlogin.c 8.3 (Berkeley) 08/31/94"; 1635539Sbostic #endif /* not lint */ 1721595Sdist 1812990Ssam /* 1912990Ssam * rlogin - remote login 2012990Ssam */ 2126981Skarels #include <sys/param.h> 226444Swnj #include <sys/socket.h> 2329729Smckusick #include <sys/time.h> 2429729Smckusick #include <sys/resource.h> 2513620Ssam #include <sys/wait.h> 2667737Spendry #include <sys/ioctl.h> 279365Ssam 289207Ssam #include <netinet/in.h> 2944346Skarels #include <netinet/in_systm.h> 3044346Skarels #include <netinet/ip.h> 319365Ssam 326444Swnj #include <errno.h> 3358470Sbostic #include <fcntl.h> 3458470Sbostic #include <netdb.h> 356444Swnj #include <pwd.h> 3658470Sbostic #include <setjmp.h> 3767737Spendry #include <termios.h> 3858470Sbostic #include <signal.h> 3940858Sbostic #include <stdio.h> 4058470Sbostic #include <stdlib.h> 4158470Sbostic #include <string.h> 4240858Sbostic #include <unistd.h> 436444Swnj 4458766Sbostic #ifdef __STDC__ 4558766Sbostic #include <stdarg.h> 4658766Sbostic #else 4758766Sbostic #include <varargs.h> 4858766Sbostic #endif 4958766Sbostic 5040858Sbostic #ifdef KERBEROS 5141760Skfall #include <kerberosIV/des.h> 5240683Sbostic #include <kerberosIV/krb.h> 5336511Skfall 5458470Sbostic #include "krb.h" 5558470Sbostic 5640858Sbostic CREDENTIALS cred; 5740858Sbostic Key_schedule schedule; 5846850Sbostic int use_kerberos = 1, doencrypt; 5940858Sbostic char dst_realm_buf[REALM_SZ], *dest_realm = NULL; 6040858Sbostic #endif 6124726Smckusick 6240858Sbostic #ifndef TIOCPKT_WINDOW 6340858Sbostic #define TIOCPKT_WINDOW 0x80 6440858Sbostic #endif 6529729Smckusick 6640858Sbostic /* concession to Sun */ 6740858Sbostic #ifndef SIGUSR1 6840858Sbostic #define SIGUSR1 30 6926981Skarels #endif 7040858Sbostic 7140858Sbostic int eight, litout, rem; 7245063Sbostic 7345063Sbostic int noescape; 7445063Sbostic u_char escapechar = '~'; 7545063Sbostic 7659175Storek #ifdef OLDSUN 7726981Skarels struct winsize { 7826981Skarels unsigned short ws_row, ws_col; 7926981Skarels unsigned short ws_xpixel, ws_ypixel; 8026981Skarels }; 8158470Sbostic #else 8258470Sbostic #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 8340858Sbostic #endif 8418358Ssam struct winsize winsize; 856444Swnj 8658470Sbostic void catch_child __P((int)); 8758470Sbostic void copytochild __P((int)); 8867737Spendry __dead void doit __P((sigset_t *)); 8958470Sbostic __dead void done __P((int)); 9058470Sbostic void echo __P((char)); 9158470Sbostic u_int getescape __P((char *)); 9258470Sbostic void lostpeer __P((int)); 9358470Sbostic void mode __P((int)); 9458470Sbostic void msg __P((char *)); 9558470Sbostic void oob __P((int)); 9667737Spendry int reader __P((sigset_t *)); 9758470Sbostic void sendwindow __P((void)); 9858470Sbostic void setsignal __P((int)); 99*67749Spendry int speed __P((int)); 10058470Sbostic void sigwinch __P((int)); 10158470Sbostic void stop __P((char)); 10258470Sbostic __dead void usage __P((void)); 10358470Sbostic void writer __P((void)); 10458470Sbostic void writeroob __P((int)); 10558470Sbostic 10658470Sbostic #ifdef KERBEROS 10758470Sbostic void warning __P((const char *, ...)); 10840858Sbostic #endif 10959175Storek #ifdef OLDSUN 11058470Sbostic int get_window_size __P((int, struct winsize *)); 11158470Sbostic #endif 11229729Smckusick 11358470Sbostic int 1146444Swnj main(argc, argv) 1156444Swnj int argc; 11658470Sbostic char *argv[]; 1176444Swnj { 11840858Sbostic struct passwd *pw; 11940858Sbostic struct servent *sp; 12067737Spendry sigset_t smask; 12167737Spendry uid_t uid; 12267737Spendry int argoff, ch, dflag, one; 12340858Sbostic char *host, *p, *user, term[1024]; 12467737Spendry struct sigaction sa; 1256444Swnj 12640858Sbostic argoff = dflag = 0; 12740858Sbostic one = 1; 12840858Sbostic host = user = NULL; 12940858Sbostic 13067737Spendry if (p = strrchr(argv[0], '/')) 13140858Sbostic ++p; 1326444Swnj else 13340858Sbostic p = argv[0]; 13440858Sbostic 13567737Spendry if (strcmp(p, "rlogin") != 0) 13640858Sbostic host = p; 13740858Sbostic 13840858Sbostic /* handle "rlogin host flags" */ 13940858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 14040858Sbostic host = argv[1]; 14140858Sbostic argoff = 1; 1426444Swnj } 14336511Skfall 14440858Sbostic #ifdef KERBEROS 14545063Sbostic #define OPTIONS "8EKLde:k:l:x" 14640858Sbostic #else 14745063Sbostic #define OPTIONS "8EKLde:l:" 14840858Sbostic #endif 14940858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 15040858Sbostic switch(ch) { 15140858Sbostic case '8': 15240858Sbostic eight = 1; 15340858Sbostic break; 15445063Sbostic case 'E': 15545063Sbostic noescape = 1; 15645063Sbostic break; 15740868Sbostic case 'K': 15840868Sbostic #ifdef KERBEROS 15940868Sbostic use_kerberos = 0; 16040868Sbostic #endif 16140868Sbostic break; 16240858Sbostic case 'L': 16340858Sbostic litout = 1; 16440858Sbostic break; 16540858Sbostic case 'd': 16640858Sbostic dflag = 1; 16740858Sbostic break; 16840858Sbostic case 'e': 16953033Sleres noescape = 0; 17045063Sbostic escapechar = getescape(optarg); 17140858Sbostic break; 17240858Sbostic #ifdef KERBEROS 17340858Sbostic case 'k': 17440858Sbostic dest_realm = dst_realm_buf; 17540858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 17640858Sbostic break; 17740858Sbostic #endif 17840858Sbostic case 'l': 17940858Sbostic user = optarg; 18040858Sbostic break; 18153033Sleres #ifdef CRYPT 18253033Sleres #ifdef KERBEROS 18353033Sleres case 'x': 18453033Sleres doencrypt = 1; 18553033Sleres des_set_key(cred.session, schedule); 18653033Sleres break; 18753033Sleres #endif 18853033Sleres #endif 18940858Sbostic case '?': 19040858Sbostic default: 19140858Sbostic usage(); 19236524Skfall } 19340858Sbostic optind += argoff; 19440858Sbostic argc -= optind; 19540858Sbostic argv += optind; 19636524Skfall 19740858Sbostic /* if haven't gotten a host yet, do so */ 19840858Sbostic if (!host && !(host = *argv++)) 19940858Sbostic usage(); 20036511Skfall 20140858Sbostic if (*argv) 20240858Sbostic usage(); 20340858Sbostic 20467737Spendry if (!(pw = getpwuid(uid = getuid()))) 20567737Spendry errx(1, "unknown user id."); 20667737Spendry 20740858Sbostic if (!user) 20840858Sbostic user = pw->pw_name; 20940858Sbostic 21040868Sbostic sp = NULL; 21140858Sbostic #ifdef KERBEROS 21240868Sbostic if (use_kerberos) { 21346850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 21440868Sbostic if (sp == NULL) { 21540868Sbostic use_kerberos = 0; 21640868Sbostic warning("can't get entry for %s/tcp service", 21746850Sbostic doencrypt ? "eklogin" : "klogin"); 21840868Sbostic } 21936512Skfall } 22036512Skfall #endif 22140868Sbostic if (sp == NULL) 22240868Sbostic sp = getservbyname("login", "tcp"); 22367737Spendry if (sp == NULL) 22467737Spendry errx(1, "login/tcp: unknown service."); 22540858Sbostic 22667737Spendry (void)snprintf(term, sizeof(term), "%s/%d", 22767737Spendry ((p = getenv("TERM")) ? p : "network"), 228*67749Spendry speed(0)); 22940858Sbostic 23040858Sbostic (void)get_window_size(0, &winsize); 23140858Sbostic 23267737Spendry sigemptyset(&sa.sa_mask); 23367737Spendry sa.sa_flags = SA_RESTART; 23467737Spendry sa.sa_handler = lostpeer; 23567737Spendry (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); 23629729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 23767737Spendry sigemptyset(&smask); 23867737Spendry sigaddset(&smask, SIGURG); 23967737Spendry sigaddset(&smask, SIGUSR1); 24067737Spendry (void)sigprocmask(SIG_SETMASK, &smask, &smask); 24158261Smckusick /* 24258261Smckusick * We set SIGURG and SIGUSR1 below so that an 24358261Smckusick * incoming signal will be held pending rather than being 24458261Smckusick * discarded. Note that these routines will be ready to get 24558261Smckusick * a signal by the time that they are unblocked below. 24658261Smckusick */ 24767737Spendry sa.sa_handler = copytochild; 24867737Spendry (void)sigaction(SIGURG, &sa, (struct sigaction *) 0); 24967737Spendry sa.sa_handler = writeroob; 25067737Spendry (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0); 25136511Skfall 25240858Sbostic #ifdef KERBEROS 25336512Skfall try_connect: 25440858Sbostic if (use_kerberos) { 25558470Sbostic struct hostent *hp; 25658470Sbostic 25758470Sbostic /* Fully qualify hostname (needed for krb_realmofhost). */ 25856960Seric hp = gethostbyname(host); 25967737Spendry if (hp != NULL && !(host = strdup(hp->h_name))) 26067737Spendry errx(1, "%s", strerror(ENOMEM)); 26156960Seric 26236512Skfall rem = KSUCCESS; 26340858Sbostic errno = 0; 26438728Skfall if (dest_realm == NULL) 26538728Skfall dest_realm = krb_realmofhost(host); 26638728Skfall 26753033Sleres #ifdef CRYPT 26853033Sleres if (doencrypt) 26953033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 27053033Sleres dest_realm, &cred, schedule); 27153033Sleres else 27253033Sleres #endif /* CRYPT */ 27340858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 27440858Sbostic dest_realm); 27538728Skfall if (rem < 0) { 27636512Skfall use_kerberos = 0; 27736628Skfall sp = getservbyname("login", "tcp"); 27867737Spendry if (sp == NULL) 27967737Spendry errx(1, "unknown service login/tcp."); 28038728Skfall if (errno == ECONNREFUSED) 28140858Sbostic warning("remote host doesn't support Kerberos"); 28238728Skfall if (errno == ENOENT) 28340858Sbostic warning("can't provide Kerberos auth data"); 28436512Skfall goto try_connect; 28536512Skfall } 28636511Skfall } else { 28753033Sleres #ifdef CRYPT 28867737Spendry if (doencrypt) 28967737Spendry errx(1, "the -x flag requires Kerberos authentication."); 29053033Sleres #endif /* CRYPT */ 29140858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 29236511Skfall } 29336512Skfall #else 29440858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 29545256Smckusick #endif /* KERBEROS */ 29636511Skfall 29740858Sbostic if (rem < 0) 29836511Skfall exit(1); 29936511Skfall 30040858Sbostic if (dflag && 30140858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 30267737Spendry warn("setsockopt DEBUG (ignored)"); 30344346Skarels one = IPTOS_LOWDELAY; 30444346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 30567737Spendry warn("setsockopt TOS (ignored)"); 30640858Sbostic 30740858Sbostic (void)setuid(uid); 30867737Spendry doit(&smask); 3099365Ssam /*NOTREACHED*/ 3106444Swnj } 3116444Swnj 312*67749Spendry #if BSD >= 198810 313*67749Spendry int 314*67749Spendry speed(fd) 315*67749Spendry int fd; 316*67749Spendry { 317*67749Spendry struct termios tt; 318*67749Spendry 319*67749Spendry (void)tcgetattr(fd, &tt); 320*67749Spendry 321*67749Spendry return ((int) cfgetispeed(&tt)); 322*67749Spendry } 323*67749Spendry #else 324*67749Spendry int speeds[] = { /* for older systems, B0 .. EXTB */ 325*67749Spendry 0, 50, 75, 110, 326*67749Spendry 134, 150, 200, 300, 327*67749Spendry 600, 1200, 1800, 2400, 328*67749Spendry 4800, 9600, 19200, 38400 329*67749Spendry }; 330*67749Spendry 331*67749Spendry int 332*67749Spendry speed(fd) 333*67749Spendry int fd; 334*67749Spendry { 335*67749Spendry struct termios tt; 336*67749Spendry 337*67749Spendry (void)tcgetattr(fd, &tt); 338*67749Spendry 339*67749Spendry return (speeds[(int)cfgetispeed(&tt)]); 340*67749Spendry } 341*67749Spendry #endif 342*67749Spendry 34367737Spendry pid_t child; 34467737Spendry struct termios deftt; 34567737Spendry struct termios nott; 3466444Swnj 34758470Sbostic void 34867737Spendry doit(smask) 34967737Spendry sigset_t *smask; 3506444Swnj { 35167737Spendry int i; 35267737Spendry struct sigaction sa; 3536444Swnj 35467737Spendry for (i = 0; i < NCCS; i++) 35567737Spendry nott.c_cc[i] = _POSIX_VDISABLE; 35667737Spendry tcgetattr(0, &deftt); 35767737Spendry nott.c_cc[VSTART] = deftt.c_cc[VSTART]; 35867737Spendry nott.c_cc[VSTOP] = deftt.c_cc[VSTOP]; 35967737Spendry sigemptyset(&sa.sa_mask); 36067737Spendry sa.sa_flags = SA_RESTART; 36167737Spendry sa.sa_handler = SIG_IGN; 36267737Spendry (void)sigaction(SIGINT, &sa, (struct sigaction *) 0); 36358470Sbostic setsignal(SIGHUP); 36458470Sbostic setsignal(SIGQUIT); 3659365Ssam child = fork(); 3669365Ssam if (child == -1) { 36767737Spendry warn("fork"); 36825424Skarels done(1); 3699365Ssam } 3709365Ssam if (child == 0) { 37124726Smckusick mode(1); 37267737Spendry if (reader(smask) == 0) { 37340858Sbostic msg("connection closed."); 37425424Skarels exit(0); 37525424Skarels } 37612155Ssam sleep(1); 37740858Sbostic msg("\007connection closed."); 37840858Sbostic exit(1); 3796444Swnj } 38029729Smckusick 38129729Smckusick /* 38240858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 38358261Smckusick * receive one soon) that we really want to send to the reader. When 38458261Smckusick * one of these comes in, the trap copytochild simply copies such 38558261Smckusick * signals to the child. We can now unblock SIGURG and SIGUSR1 38658261Smckusick * that were set above. 38729729Smckusick */ 38867737Spendry (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); 38967737Spendry sa.sa_handler = catch_child; 39067737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 3919365Ssam writer(); 39240858Sbostic msg("closed connection."); 39325424Skarels done(0); 3946444Swnj } 3956444Swnj 39640858Sbostic /* trap a signal, unless it is being ignored. */ 39758470Sbostic void 39858470Sbostic setsignal(sig) 39940858Sbostic int sig; 40029729Smckusick { 40167737Spendry struct sigaction sa; 40267737Spendry sigset_t sigs; 40329729Smckusick 40467737Spendry sigemptyset(&sigs); 40567737Spendry sigaddset(&sigs, sig); 40667737Spendry sigprocmask(SIG_BLOCK, &sigs, &sigs); 40767737Spendry 40867737Spendry sigemptyset(&sa.sa_mask); 40967737Spendry sa.sa_handler = exit; 41067737Spendry sa.sa_flags = SA_RESTART; 41167737Spendry (void)sigaction(sig, &sa, &sa); 41267737Spendry if (sa.sa_handler == SIG_IGN) 41367737Spendry (void)sigaction(sig, &sa, (struct sigaction *) 0); 41467737Spendry 41567737Spendry (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0); 41629729Smckusick } 41729729Smckusick 41858470Sbostic __dead void 41925424Skarels done(status) 42025424Skarels int status; 4216444Swnj { 42267737Spendry pid_t w; 42367737Spendry int wstatus; 42467737Spendry struct sigaction sa; 4256444Swnj 4266444Swnj mode(0); 42729729Smckusick if (child > 0) { 42840858Sbostic /* make sure catch_child does not snap it up */ 42967737Spendry sigemptyset(&sa.sa_mask); 43067737Spendry sa.sa_handler = SIG_DFL; 43167737Spendry sa.sa_flags = 0; 43267737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 43329729Smckusick if (kill(child, SIGKILL) >= 0) 43467737Spendry while ((w = wait(&wstatus)) > 0 && w != child) 43567737Spendry continue; 43629729Smckusick } 43725424Skarels exit(status); 4386444Swnj } 4396444Swnj 44040858Sbostic int dosigwinch; 44129729Smckusick 44229729Smckusick /* 44324726Smckusick * This is called when the reader process gets the out-of-band (urgent) 44424726Smckusick * request to turn on the window-changing protocol. 44524726Smckusick */ 44640858Sbostic void 44758470Sbostic writeroob(signo) 44858470Sbostic int signo; 44924726Smckusick { 45067737Spendry struct sigaction sa; 45167737Spendry 45225341Smckusick if (dosigwinch == 0) { 45324919Smckusick sendwindow(); 45467737Spendry sigemptyset(&sa.sa_mask); 45567737Spendry sa.sa_handler = sigwinch; 45667737Spendry sa.sa_flags = SA_RESTART; 45767737Spendry (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0); 45825341Smckusick } 45924726Smckusick dosigwinch = 1; 46024726Smckusick } 46124726Smckusick 46240858Sbostic void 46358470Sbostic catch_child(signo) 46458470Sbostic int signo; 46511803Sedward { 46667737Spendry int status; 46767737Spendry pid_t pid; 46811803Sedward 46940858Sbostic for (;;) { 47067737Spendry pid = waitpid(-1, &status, WNOHANG|WUNTRACED); 47140858Sbostic if (pid == 0) 47240858Sbostic return; 47340858Sbostic /* if the child (reader) dies, just quit */ 47458470Sbostic if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 47567737Spendry done(WEXITSTATUS(status) | WTERMSIG(status)); 47640858Sbostic } 47740858Sbostic /* NOTREACHED */ 47811803Sedward } 47911803Sedward 4806444Swnj /* 4819365Ssam * writer: write to remote: 0 -> line. 48245063Sbostic * ~. terminate 48345063Sbostic * ~^Z suspend rlogin process. 48445063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4856444Swnj */ 48658470Sbostic void 4879365Ssam writer() 4886444Swnj { 48945063Sbostic register int bol, local, n; 49023530Sbloom char c; 4916444Swnj 49240858Sbostic bol = 1; /* beginning of line */ 49340858Sbostic local = 0; 49411803Sedward for (;;) { 49540858Sbostic n = read(STDIN_FILENO, &c, 1); 49618358Ssam if (n <= 0) { 49718358Ssam if (n < 0 && errno == EINTR) 49818358Ssam continue; 49911803Sedward break; 50018358Ssam } 5019365Ssam /* 50240858Sbostic * If we're at the beginning of the line and recognize a 50340858Sbostic * command character, then we echo locally. Otherwise, 50440858Sbostic * characters are echo'd remotely. If the command character 50540858Sbostic * is doubled, this acts as a force and local echo is 50640858Sbostic * suppressed. 5079365Ssam */ 50823530Sbloom if (bol) { 50923530Sbloom bol = 0; 51045063Sbostic if (!noescape && c == escapechar) { 51123530Sbloom local = 1; 51223530Sbloom continue; 5136444Swnj } 51423530Sbloom } else if (local) { 51523530Sbloom local = 0; 51667737Spendry if (c == '.' || c == deftt.c_cc[VEOF]) { 51723530Sbloom echo(c); 51823530Sbloom break; 5196444Swnj } 52067737Spendry if (c == deftt.c_cc[VSUSP] || c == deftt.c_cc[VDSUSP]) { 52123530Sbloom bol = 1; 52223530Sbloom echo(c); 52323530Sbloom stop(c); 52423530Sbloom continue; 52523530Sbloom } 52645063Sbostic if (c != escapechar) 52753033Sleres #ifdef CRYPT 52853033Sleres #ifdef KERBEROS 52953033Sleres if (doencrypt) 53058470Sbostic (void)des_write(rem, 53158470Sbostic (char *)&escapechar, 1); 53253033Sleres else 53353033Sleres #endif 53453033Sleres #endif 53545063Sbostic (void)write(rem, &escapechar, 1); 5366444Swnj } 53736511Skfall 53853033Sleres #ifdef CRYPT 53953033Sleres #ifdef KERBEROS 54053033Sleres if (doencrypt) { 54153033Sleres if (des_write(rem, &c, 1) == 0) { 54253033Sleres msg("line gone"); 54353033Sleres break; 54453033Sleres } 54553033Sleres } else 54653033Sleres #endif 54753033Sleres #endif 54836511Skfall if (write(rem, &c, 1) == 0) { 54940858Sbostic msg("line gone"); 55036511Skfall break; 55136511Skfall } 55267737Spendry bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] || 55367737Spendry c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] || 55423530Sbloom c == '\r' || c == '\n'; 5556444Swnj } 5566444Swnj } 5576444Swnj 55858470Sbostic void 55958470Sbostic #if __STDC__ 56058470Sbostic echo(register char c) 56158470Sbostic #else 56223530Sbloom echo(c) 56358470Sbostic register char c; 56458470Sbostic #endif 56523530Sbloom { 56640858Sbostic register char *p; 56723530Sbloom char buf[8]; 56823530Sbloom 56940858Sbostic p = buf; 57023530Sbloom c &= 0177; 57145063Sbostic *p++ = escapechar; 57223530Sbloom if (c < ' ') { 57323530Sbloom *p++ = '^'; 57423530Sbloom *p++ = c + '@'; 57523530Sbloom } else if (c == 0177) { 57623530Sbloom *p++ = '^'; 57723530Sbloom *p++ = '?'; 57823530Sbloom } else 57923530Sbloom *p++ = c; 58023530Sbloom *p++ = '\r'; 58123530Sbloom *p++ = '\n'; 58245063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 58323530Sbloom } 58423530Sbloom 58558470Sbostic void 58658470Sbostic #if __STDC__ 58758470Sbostic stop(char cmdc) 58858470Sbostic #else 58918358Ssam stop(cmdc) 59018358Ssam char cmdc; 59158470Sbostic #endif 59218358Ssam { 59367737Spendry struct sigaction sa; 59467737Spendry 59518358Ssam mode(0); 59667737Spendry sigemptyset(&sa.sa_mask); 59767737Spendry sa.sa_handler = SIG_IGN; 59867737Spendry sa.sa_flags = SA_RESTART; 59967737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 60067737Spendry (void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP); 60167737Spendry sa.sa_handler = catch_child; 60267737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 60318358Ssam mode(1); 60458470Sbostic sigwinch(0); /* check for size changes */ 60518358Ssam } 60618358Ssam 60740858Sbostic void 60858470Sbostic sigwinch(signo) 60958470Sbostic int signo; 61018358Ssam { 61118358Ssam struct winsize ws; 61218358Ssam 61329729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 61467737Spendry memcmp(&ws, &winsize, sizeof(ws))) { 61518358Ssam winsize = ws; 61624726Smckusick sendwindow(); 61718358Ssam } 61818358Ssam } 61918358Ssam 62024726Smckusick /* 62124726Smckusick * Send the window size to the server via the magic escape 62224726Smckusick */ 62358470Sbostic void 62424726Smckusick sendwindow() 62524726Smckusick { 62640858Sbostic struct winsize *wp; 62724726Smckusick char obuf[4 + sizeof (struct winsize)]; 62824726Smckusick 62940858Sbostic wp = (struct winsize *)(obuf+4); 63024726Smckusick obuf[0] = 0377; 63124726Smckusick obuf[1] = 0377; 63224726Smckusick obuf[2] = 's'; 63324726Smckusick obuf[3] = 's'; 63424726Smckusick wp->ws_row = htons(winsize.ws_row); 63524726Smckusick wp->ws_col = htons(winsize.ws_col); 63624726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 63724726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 63836511Skfall 63953033Sleres #ifdef CRYPT 64053033Sleres #ifdef KERBEROS 64153033Sleres if(doencrypt) 64253033Sleres (void)des_write(rem, obuf, sizeof(obuf)); 64353033Sleres else 64453033Sleres #endif 64553033Sleres #endif 64640858Sbostic (void)write(rem, obuf, sizeof(obuf)); 64724726Smckusick } 64824726Smckusick 64925424Skarels /* 65025424Skarels * reader: read from remote: line -> 1 65125424Skarels */ 65225424Skarels #define READING 1 65325424Skarels #define WRITING 2 65425424Skarels 65540858Sbostic jmp_buf rcvtop; 65667737Spendry pid_t ppid; 65767737Spendry int rcvcnt, rcvstate; 65840858Sbostic char rcvbuf[8 * 1024]; 65925424Skarels 66040858Sbostic void 66158470Sbostic oob(signo) 66258470Sbostic int signo; 6636444Swnj { 66467737Spendry struct termios tt; 66540858Sbostic int atmark, n, out, rcvd; 6669365Ssam char waste[BUFSIZ], mark; 6676444Swnj 66842230Sbostic out = O_RDWR; 66940858Sbostic rcvd = 0; 67059175Storek while (recv(rem, &mark, 1, MSG_OOB) < 0) { 67125424Skarels switch (errno) { 67225424Skarels case EWOULDBLOCK: 67325424Skarels /* 67440858Sbostic * Urgent data not here yet. It may not be possible 67540858Sbostic * to send it yet if we are blocked for output and 67640858Sbostic * our input buffer is full. 67725424Skarels */ 67825424Skarels if (rcvcnt < sizeof(rcvbuf)) { 67925424Skarels n = read(rem, rcvbuf + rcvcnt, 68040858Sbostic sizeof(rcvbuf) - rcvcnt); 68125424Skarels if (n <= 0) 68225424Skarels return; 68325424Skarels rcvd += n; 68425424Skarels } else { 68525424Skarels n = read(rem, waste, sizeof(waste)); 68625424Skarels if (n <= 0) 68725424Skarels return; 68825424Skarels } 68925424Skarels continue; 69025424Skarels default: 69125424Skarels return; 69259175Storek } 6936444Swnj } 69425424Skarels if (mark & TIOCPKT_WINDOW) { 69540858Sbostic /* Let server know about window size changes */ 69640858Sbostic (void)kill(ppid, SIGUSR1); 69724726Smckusick } 69825424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 69967737Spendry tcgetattr(0, &tt); 700*67749Spendry tt.c_iflag &= ~(IXON | IXOFF); 70167737Spendry tt.c_cc[VSTOP] = _POSIX_VDISABLE; 70267737Spendry tt.c_cc[VSTART] = _POSIX_VDISABLE; 70367737Spendry tcsetattr(0, TCSANOW, &tt); 7046444Swnj } 70525424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 70667737Spendry tcgetattr(0, &tt); 70767737Spendry tt.c_iflag |= (IXON|IXOFF); 70867737Spendry tt.c_cc[VSTOP] = deftt.c_cc[VSTOP]; 70967737Spendry tt.c_cc[VSTART] = deftt.c_cc[VSTART]; 71067737Spendry tcsetattr(0, TCSANOW, &tt); 7116444Swnj } 71225424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 71340858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 71425424Skarels for (;;) { 71525424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 71667737Spendry warn("ioctl SIOCATMARK (ignored)"); 71725424Skarels break; 71825424Skarels } 71925424Skarels if (atmark) 72025424Skarels break; 72125424Skarels n = read(rem, waste, sizeof (waste)); 72225424Skarels if (n <= 0) 72325424Skarels break; 72425424Skarels } 72525424Skarels /* 72640858Sbostic * Don't want any pending data to be output, so clear the recv 72740858Sbostic * buffer. If we were hanging on a write when interrupted, 72840858Sbostic * don't want it to restart. If we were reading, restart 72940858Sbostic * anyway. 73025424Skarels */ 73125424Skarels rcvcnt = 0; 73225424Skarels longjmp(rcvtop, 1); 73325424Skarels } 73429729Smckusick 73540858Sbostic /* oob does not do FLUSHREAD (alas!) */ 73629729Smckusick 73729729Smckusick /* 73840858Sbostic * If we filled the receive buffer while a read was pending, longjmp 73940858Sbostic * to the top to restart appropriately. Don't abort a pending write, 74040858Sbostic * however, or we won't know how much was written. 74125424Skarels */ 74225424Skarels if (rcvd && rcvstate == READING) 74325424Skarels longjmp(rcvtop, 1); 7446444Swnj } 7456444Swnj 74640858Sbostic /* reader: read from remote: line -> 1 */ 74758470Sbostic int 74867737Spendry reader(smask) 74967737Spendry sigset_t *smask; 7506444Swnj { 75167737Spendry pid_t pid; 75267737Spendry int n, remaining; 75359175Storek char *bufp; 75467737Spendry struct sigaction sa; 75540858Sbostic 75659175Storek #if BSD >= 43 || defined(SUNOS4) 75759175Storek pid = getpid(); /* modern systems use positives for pid */ 75826981Skarels #else 75959175Storek pid = -getpid(); /* old broken systems use negatives */ 76026981Skarels #endif 76167737Spendry sigemptyset(&sa.sa_mask); 76267737Spendry sa.sa_flags = SA_RESTART; 76367737Spendry sa.sa_handler = SIG_IGN; 76467737Spendry (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0); 76567737Spendry sa.sa_handler = oob; 76667737Spendry (void)sigaction(SIGURG, &sa, (struct sigaction *) 0); 76726981Skarels ppid = getppid(); 76840858Sbostic (void)fcntl(rem, F_SETOWN, pid); 76940858Sbostic (void)setjmp(rcvtop); 77067737Spendry (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); 77159175Storek bufp = rcvbuf; 7726444Swnj for (;;) { 77325424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 77425424Skarels rcvstate = WRITING; 77545063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 77625424Skarels if (n < 0) { 77725424Skarels if (errno != EINTR) 77858470Sbostic return (-1); 77925424Skarels continue; 78025424Skarels } 78125424Skarels bufp += n; 78225424Skarels } 78325424Skarels bufp = rcvbuf; 78425424Skarels rcvcnt = 0; 78525424Skarels rcvstate = READING; 78636511Skfall 78753033Sleres #ifdef CRYPT 78853033Sleres #ifdef KERBEROS 78953033Sleres if (doencrypt) 79053033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 79153033Sleres else 79253033Sleres #endif 79353033Sleres #endif 79436511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 79525424Skarels if (rcvcnt == 0) 79625424Skarels return (0); 79725424Skarels if (rcvcnt < 0) { 7989365Ssam if (errno == EINTR) 7996444Swnj continue; 80067737Spendry warn("read"); 80158470Sbostic return (-1); 8026444Swnj } 8036444Swnj } 8046444Swnj } 8056444Swnj 80658470Sbostic void 8076444Swnj mode(f) 80858470Sbostic int f; 8096444Swnj { 81067737Spendry struct termios tt; 8119365Ssam 81267737Spendry switch (f) { 8139962Ssam case 0: 81467737Spendry tcsetattr(0, TCSADRAIN, &deftt); 8159962Ssam break; 8169962Ssam case 1: 81767737Spendry tt = deftt; 818*67749Spendry tt.c_oflag &= ~(OPOST); 81967737Spendry tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 820*67749Spendry tt.c_iflag &= ~(ICRNL); 82167737Spendry tt.c_cc[VMIN] = 1; 82267737Spendry tt.c_cc[VTIME] = 0; 82367737Spendry if (eight) { 824*67749Spendry tt.c_iflag &= ~(IXON | IXOFF | ISTRIP); 82567737Spendry tt.c_cc[VSTOP] = _POSIX_VDISABLE; 82667737Spendry tt.c_cc[VSTART] = _POSIX_VDISABLE; 82767737Spendry } 82867737Spendry /*if (litout) 82967737Spendry lflags |= LLITOUT;*/ 83067737Spendry tcsetattr(0, TCSADRAIN, &tt); 8319962Ssam break; 83267737Spendry 8339962Ssam default: 8349962Ssam return; 8356444Swnj } 8366444Swnj } 8376444Swnj 83840858Sbostic void 83958470Sbostic lostpeer(signo) 84058470Sbostic int signo; 8416444Swnj { 84267737Spendry struct sigaction sa; 84367737Spendry 84467737Spendry sigemptyset(&sa.sa_mask); 84567737Spendry sa.sa_flags = SA_RESTART; 84667737Spendry sa.sa_handler = SIG_IGN; 84767737Spendry (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); 84840858Sbostic msg("\007connection closed."); 84940858Sbostic done(1); 85040858Sbostic } 85129729Smckusick 85240858Sbostic /* copy SIGURGs to the child process. */ 85340858Sbostic void 85458470Sbostic copytochild(signo) 85558470Sbostic int signo; 85640858Sbostic { 85767737Spendry 85840858Sbostic (void)kill(child, SIGURG); 8596444Swnj } 8606444Swnj 86158470Sbostic void 86240858Sbostic msg(str) 86340858Sbostic char *str; 8646444Swnj { 86567737Spendry 86640858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 86740858Sbostic } 86829729Smckusick 86940858Sbostic #ifdef KERBEROS 87040858Sbostic /* VARARGS */ 87158470Sbostic void 87258470Sbostic #if __STDC__ 87358470Sbostic warning(const char *fmt, ...) 87458470Sbostic #else 87558470Sbostic warning(fmt, va_alist) 87658470Sbostic char *fmt; 87758470Sbostic va_dcl 87858470Sbostic #endif 87940858Sbostic { 88040858Sbostic va_list ap; 88140858Sbostic 88240858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 88358470Sbostic #ifdef __STDC__ 88458470Sbostic va_start(ap, fmt); 88558470Sbostic #else 88640858Sbostic va_start(ap); 88758470Sbostic #endif 88840858Sbostic vfprintf(stderr, fmt, ap); 88940858Sbostic va_end(ap); 89040858Sbostic (void)fprintf(stderr, ".\n"); 8916444Swnj } 89240858Sbostic #endif 89336512Skfall 89458470Sbostic __dead void 89540858Sbostic usage() 89636512Skfall { 89740858Sbostic (void)fprintf(stderr, 89840858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 89940858Sbostic #ifdef KERBEROS 90053033Sleres #ifdef CRYPT 90154125Sbostic "8EKLx", " [-k realm] "); 90253033Sleres #else 90354125Sbostic "8EKL", " [-k realm] "); 90453033Sleres #endif 90545256Smckusick #else 90645063Sbostic "8EL", " "); 90740858Sbostic #endif 90840858Sbostic exit(1); 90936512Skfall } 91040858Sbostic 91140858Sbostic /* 91259175Storek * The following routine provides compatibility (such as it is) between older 91340858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 91440858Sbostic */ 91559175Storek #ifdef OLDSUN 91658470Sbostic int 91740858Sbostic get_window_size(fd, wp) 91840858Sbostic int fd; 91940858Sbostic struct winsize *wp; 92040858Sbostic { 92140858Sbostic struct ttysize ts; 92240858Sbostic int error; 92340858Sbostic 92440858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 92558470Sbostic return (error); 92640858Sbostic wp->ws_row = ts.ts_lines; 92740858Sbostic wp->ws_col = ts.ts_cols; 92840858Sbostic wp->ws_xpixel = 0; 92940858Sbostic wp->ws_ypixel = 0; 93058470Sbostic return (0); 93140858Sbostic } 93240858Sbostic #endif 93345063Sbostic 93458470Sbostic u_int 93545063Sbostic getescape(p) 93645063Sbostic register char *p; 93745063Sbostic { 93845063Sbostic long val; 93945063Sbostic int len; 94045063Sbostic 94145063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 94258470Sbostic return ((u_int)*p); 94345063Sbostic /* otherwise, \nnn */ 94445063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 94558470Sbostic val = strtol(++p, NULL, 8); 94645063Sbostic for (;;) { 94745063Sbostic if (!*++p) 94858470Sbostic return ((u_int)val); 94945063Sbostic if (*p < '0' || *p > '8') 95045063Sbostic break; 95145063Sbostic } 95245063Sbostic } 95345063Sbostic msg("illegal option value -- e"); 95445063Sbostic usage(); 95545063Sbostic /* NOTREACHED */ 95645063Sbostic } 957