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*67737Spendry static char sccsid[] = "@(#)rlogin.c 8.2 (Berkeley) 08/23/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> 26*67737Spendry #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> 37*67737Spendry #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)); 88*67737Spendry __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)); 96*67737Spendry int reader __P((sigset_t *)); 9758470Sbostic void sendwindow __P((void)); 9858470Sbostic void setsignal __P((int)); 9958470Sbostic void sigwinch __P((int)); 10058470Sbostic void stop __P((char)); 10158470Sbostic __dead void usage __P((void)); 10258470Sbostic void writer __P((void)); 10358470Sbostic void writeroob __P((int)); 10458470Sbostic 10558470Sbostic #ifdef KERBEROS 10658470Sbostic void warning __P((const char *, ...)); 10740858Sbostic #endif 10859175Storek #ifdef OLDSUN 10958470Sbostic int get_window_size __P((int, struct winsize *)); 11058470Sbostic #endif 11129729Smckusick 11258470Sbostic int 1136444Swnj main(argc, argv) 1146444Swnj int argc; 11558470Sbostic char *argv[]; 1166444Swnj { 11740858Sbostic struct passwd *pw; 11840858Sbostic struct servent *sp; 119*67737Spendry sigset_t smask; 120*67737Spendry uid_t uid; 121*67737Spendry int argoff, ch, dflag, one; 12240858Sbostic char *host, *p, *user, term[1024]; 123*67737Spendry struct sigaction sa; 1246444Swnj 12540858Sbostic argoff = dflag = 0; 12640858Sbostic one = 1; 12740858Sbostic host = user = NULL; 12840858Sbostic 129*67737Spendry if (p = strrchr(argv[0], '/')) 13040858Sbostic ++p; 1316444Swnj else 13240858Sbostic p = argv[0]; 13340858Sbostic 134*67737Spendry if (strcmp(p, "rlogin") != 0) 13540858Sbostic host = p; 13640858Sbostic 13740858Sbostic /* handle "rlogin host flags" */ 13840858Sbostic if (!host && argc > 2 && argv[1][0] != '-') { 13940858Sbostic host = argv[1]; 14040858Sbostic argoff = 1; 1416444Swnj } 14236511Skfall 14340858Sbostic #ifdef KERBEROS 14445063Sbostic #define OPTIONS "8EKLde:k:l:x" 14540858Sbostic #else 14645063Sbostic #define OPTIONS "8EKLde:l:" 14740858Sbostic #endif 14840858Sbostic while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 14940858Sbostic switch(ch) { 15040858Sbostic case '8': 15140858Sbostic eight = 1; 15240858Sbostic break; 15345063Sbostic case 'E': 15445063Sbostic noescape = 1; 15545063Sbostic break; 15640868Sbostic case 'K': 15740868Sbostic #ifdef KERBEROS 15840868Sbostic use_kerberos = 0; 15940868Sbostic #endif 16040868Sbostic break; 16140858Sbostic case 'L': 16240858Sbostic litout = 1; 16340858Sbostic break; 16440858Sbostic case 'd': 16540858Sbostic dflag = 1; 16640858Sbostic break; 16740858Sbostic case 'e': 16853033Sleres noescape = 0; 16945063Sbostic escapechar = getescape(optarg); 17040858Sbostic break; 17140858Sbostic #ifdef KERBEROS 17240858Sbostic case 'k': 17340858Sbostic dest_realm = dst_realm_buf; 17440858Sbostic (void)strncpy(dest_realm, optarg, REALM_SZ); 17540858Sbostic break; 17640858Sbostic #endif 17740858Sbostic case 'l': 17840858Sbostic user = optarg; 17940858Sbostic break; 18053033Sleres #ifdef CRYPT 18153033Sleres #ifdef KERBEROS 18253033Sleres case 'x': 18353033Sleres doencrypt = 1; 18453033Sleres des_set_key(cred.session, schedule); 18553033Sleres break; 18653033Sleres #endif 18753033Sleres #endif 18840858Sbostic case '?': 18940858Sbostic default: 19040858Sbostic usage(); 19136524Skfall } 19240858Sbostic optind += argoff; 19340858Sbostic argc -= optind; 19440858Sbostic argv += optind; 19536524Skfall 19640858Sbostic /* if haven't gotten a host yet, do so */ 19740858Sbostic if (!host && !(host = *argv++)) 19840858Sbostic usage(); 19936511Skfall 20040858Sbostic if (*argv) 20140858Sbostic usage(); 20240858Sbostic 203*67737Spendry if (!(pw = getpwuid(uid = getuid()))) 204*67737Spendry errx(1, "unknown user id."); 205*67737Spendry 20640858Sbostic if (!user) 20740858Sbostic user = pw->pw_name; 20840858Sbostic 20940868Sbostic sp = NULL; 21040858Sbostic #ifdef KERBEROS 21140868Sbostic if (use_kerberos) { 21246850Sbostic sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 21340868Sbostic if (sp == NULL) { 21440868Sbostic use_kerberos = 0; 21540868Sbostic warning("can't get entry for %s/tcp service", 21646850Sbostic doencrypt ? "eklogin" : "klogin"); 21740868Sbostic } 21836512Skfall } 21936512Skfall #endif 22040868Sbostic if (sp == NULL) 22140868Sbostic sp = getservbyname("login", "tcp"); 222*67737Spendry if (sp == NULL) 223*67737Spendry errx(1, "login/tcp: unknown service."); 22440858Sbostic 225*67737Spendry (void)snprintf(term, sizeof(term), "%s/%d", 226*67737Spendry ((p = getenv("TERM")) ? p : "network"), 227*67737Spendry cfgetispeed(0)); 22840858Sbostic 22940858Sbostic (void)get_window_size(0, &winsize); 23040858Sbostic 231*67737Spendry sigemptyset(&sa.sa_mask); 232*67737Spendry sa.sa_flags = SA_RESTART; 233*67737Spendry sa.sa_handler = lostpeer; 234*67737Spendry (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); 23529729Smckusick /* will use SIGUSR1 for window size hack, so hold it off */ 236*67737Spendry sigemptyset(&smask); 237*67737Spendry sigaddset(&smask, SIGURG); 238*67737Spendry sigaddset(&smask, SIGUSR1); 239*67737Spendry (void)sigprocmask(SIG_SETMASK, &smask, &smask); 24058261Smckusick /* 24158261Smckusick * We set SIGURG and SIGUSR1 below so that an 24258261Smckusick * incoming signal will be held pending rather than being 24358261Smckusick * discarded. Note that these routines will be ready to get 24458261Smckusick * a signal by the time that they are unblocked below. 24558261Smckusick */ 246*67737Spendry sa.sa_handler = copytochild; 247*67737Spendry (void)sigaction(SIGURG, &sa, (struct sigaction *) 0); 248*67737Spendry sa.sa_handler = writeroob; 249*67737Spendry (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0); 25036511Skfall 25140858Sbostic #ifdef KERBEROS 25236512Skfall try_connect: 25340858Sbostic if (use_kerberos) { 25458470Sbostic struct hostent *hp; 25558470Sbostic 25658470Sbostic /* Fully qualify hostname (needed for krb_realmofhost). */ 25756960Seric hp = gethostbyname(host); 258*67737Spendry if (hp != NULL && !(host = strdup(hp->h_name))) 259*67737Spendry errx(1, "%s", strerror(ENOMEM)); 26056960Seric 26136512Skfall rem = KSUCCESS; 26240858Sbostic errno = 0; 26338728Skfall if (dest_realm == NULL) 26438728Skfall dest_realm = krb_realmofhost(host); 26538728Skfall 26653033Sleres #ifdef CRYPT 26753033Sleres if (doencrypt) 26853033Sleres rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 26953033Sleres dest_realm, &cred, schedule); 27053033Sleres else 27153033Sleres #endif /* CRYPT */ 27240858Sbostic rem = krcmd(&host, sp->s_port, user, term, 0, 27340858Sbostic dest_realm); 27438728Skfall if (rem < 0) { 27536512Skfall use_kerberos = 0; 27636628Skfall sp = getservbyname("login", "tcp"); 277*67737Spendry if (sp == NULL) 278*67737Spendry errx(1, "unknown service login/tcp."); 27938728Skfall if (errno == ECONNREFUSED) 28040858Sbostic warning("remote host doesn't support Kerberos"); 28138728Skfall if (errno == ENOENT) 28240858Sbostic warning("can't provide Kerberos auth data"); 28336512Skfall goto try_connect; 28436512Skfall } 28536511Skfall } else { 28653033Sleres #ifdef CRYPT 287*67737Spendry if (doencrypt) 288*67737Spendry errx(1, "the -x flag requires Kerberos authentication."); 28953033Sleres #endif /* CRYPT */ 29040858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 29136511Skfall } 29236512Skfall #else 29340858Sbostic rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 29445256Smckusick #endif /* KERBEROS */ 29536511Skfall 29640858Sbostic if (rem < 0) 29736511Skfall exit(1); 29836511Skfall 29940858Sbostic if (dflag && 30040858Sbostic setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 301*67737Spendry warn("setsockopt DEBUG (ignored)"); 30244346Skarels one = IPTOS_LOWDELAY; 30344346Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 304*67737Spendry warn("setsockopt TOS (ignored)"); 30540858Sbostic 30640858Sbostic (void)setuid(uid); 307*67737Spendry doit(&smask); 3089365Ssam /*NOTREACHED*/ 3096444Swnj } 3106444Swnj 311*67737Spendry pid_t child; 312*67737Spendry struct termios deftt; 313*67737Spendry struct termios nott; 3146444Swnj 31558470Sbostic void 316*67737Spendry doit(smask) 317*67737Spendry sigset_t *smask; 3186444Swnj { 319*67737Spendry int i; 320*67737Spendry struct sigaction sa; 3216444Swnj 322*67737Spendry for (i = 0; i < NCCS; i++) 323*67737Spendry nott.c_cc[i] = _POSIX_VDISABLE; 324*67737Spendry tcgetattr(0, &deftt); 325*67737Spendry nott.c_cc[VSTART] = deftt.c_cc[VSTART]; 326*67737Spendry nott.c_cc[VSTOP] = deftt.c_cc[VSTOP]; 327*67737Spendry sigemptyset(&sa.sa_mask); 328*67737Spendry sa.sa_flags = SA_RESTART; 329*67737Spendry sa.sa_handler = SIG_IGN; 330*67737Spendry (void)sigaction(SIGINT, &sa, (struct sigaction *) 0); 33158470Sbostic setsignal(SIGHUP); 33258470Sbostic setsignal(SIGQUIT); 3339365Ssam child = fork(); 3349365Ssam if (child == -1) { 335*67737Spendry warn("fork"); 33625424Skarels done(1); 3379365Ssam } 3389365Ssam if (child == 0) { 33924726Smckusick mode(1); 340*67737Spendry if (reader(smask) == 0) { 34140858Sbostic msg("connection closed."); 34225424Skarels exit(0); 34325424Skarels } 34412155Ssam sleep(1); 34540858Sbostic msg("\007connection closed."); 34640858Sbostic exit(1); 3476444Swnj } 34829729Smckusick 34929729Smckusick /* 35040858Sbostic * We may still own the socket, and may have a pending SIGURG (or might 35158261Smckusick * receive one soon) that we really want to send to the reader. When 35258261Smckusick * one of these comes in, the trap copytochild simply copies such 35358261Smckusick * signals to the child. We can now unblock SIGURG and SIGUSR1 35458261Smckusick * that were set above. 35529729Smckusick */ 356*67737Spendry (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); 357*67737Spendry sa.sa_handler = catch_child; 358*67737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 3599365Ssam writer(); 36040858Sbostic msg("closed connection."); 36125424Skarels done(0); 3626444Swnj } 3636444Swnj 36440858Sbostic /* trap a signal, unless it is being ignored. */ 36558470Sbostic void 36658470Sbostic setsignal(sig) 36740858Sbostic int sig; 36829729Smckusick { 369*67737Spendry struct sigaction sa; 370*67737Spendry sigset_t sigs; 37129729Smckusick 372*67737Spendry sigemptyset(&sigs); 373*67737Spendry sigaddset(&sigs, sig); 374*67737Spendry sigprocmask(SIG_BLOCK, &sigs, &sigs); 375*67737Spendry 376*67737Spendry sigemptyset(&sa.sa_mask); 377*67737Spendry sa.sa_handler = exit; 378*67737Spendry sa.sa_flags = SA_RESTART; 379*67737Spendry (void)sigaction(sig, &sa, &sa); 380*67737Spendry if (sa.sa_handler == SIG_IGN) 381*67737Spendry (void)sigaction(sig, &sa, (struct sigaction *) 0); 382*67737Spendry 383*67737Spendry (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0); 38429729Smckusick } 38529729Smckusick 38658470Sbostic __dead void 38725424Skarels done(status) 38825424Skarels int status; 3896444Swnj { 390*67737Spendry pid_t w; 391*67737Spendry int wstatus; 392*67737Spendry struct sigaction sa; 3936444Swnj 3946444Swnj mode(0); 39529729Smckusick if (child > 0) { 39640858Sbostic /* make sure catch_child does not snap it up */ 397*67737Spendry sigemptyset(&sa.sa_mask); 398*67737Spendry sa.sa_handler = SIG_DFL; 399*67737Spendry sa.sa_flags = 0; 400*67737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 40129729Smckusick if (kill(child, SIGKILL) >= 0) 402*67737Spendry while ((w = wait(&wstatus)) > 0 && w != child) 403*67737Spendry continue; 40429729Smckusick } 40525424Skarels exit(status); 4066444Swnj } 4076444Swnj 40840858Sbostic int dosigwinch; 40929729Smckusick 41029729Smckusick /* 41124726Smckusick * This is called when the reader process gets the out-of-band (urgent) 41224726Smckusick * request to turn on the window-changing protocol. 41324726Smckusick */ 41440858Sbostic void 41558470Sbostic writeroob(signo) 41658470Sbostic int signo; 41724726Smckusick { 418*67737Spendry struct sigaction sa; 419*67737Spendry 42025341Smckusick if (dosigwinch == 0) { 42124919Smckusick sendwindow(); 422*67737Spendry sigemptyset(&sa.sa_mask); 423*67737Spendry sa.sa_handler = sigwinch; 424*67737Spendry sa.sa_flags = SA_RESTART; 425*67737Spendry (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0); 42625341Smckusick } 42724726Smckusick dosigwinch = 1; 42824726Smckusick } 42924726Smckusick 43040858Sbostic void 43158470Sbostic catch_child(signo) 43258470Sbostic int signo; 43311803Sedward { 434*67737Spendry int status; 435*67737Spendry pid_t pid; 43611803Sedward 43740858Sbostic for (;;) { 438*67737Spendry pid = waitpid(-1, &status, WNOHANG|WUNTRACED); 43940858Sbostic if (pid == 0) 44040858Sbostic return; 44140858Sbostic /* if the child (reader) dies, just quit */ 44258470Sbostic if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 443*67737Spendry done(WEXITSTATUS(status) | WTERMSIG(status)); 44440858Sbostic } 44540858Sbostic /* NOTREACHED */ 44611803Sedward } 44711803Sedward 4486444Swnj /* 4499365Ssam * writer: write to remote: 0 -> line. 45045063Sbostic * ~. terminate 45145063Sbostic * ~^Z suspend rlogin process. 45245063Sbostic * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 4536444Swnj */ 45458470Sbostic void 4559365Ssam writer() 4566444Swnj { 45745063Sbostic register int bol, local, n; 45823530Sbloom char c; 4596444Swnj 46040858Sbostic bol = 1; /* beginning of line */ 46140858Sbostic local = 0; 46211803Sedward for (;;) { 46340858Sbostic n = read(STDIN_FILENO, &c, 1); 46418358Ssam if (n <= 0) { 46518358Ssam if (n < 0 && errno == EINTR) 46618358Ssam continue; 46711803Sedward break; 46818358Ssam } 4699365Ssam /* 47040858Sbostic * If we're at the beginning of the line and recognize a 47140858Sbostic * command character, then we echo locally. Otherwise, 47240858Sbostic * characters are echo'd remotely. If the command character 47340858Sbostic * is doubled, this acts as a force and local echo is 47440858Sbostic * suppressed. 4759365Ssam */ 47623530Sbloom if (bol) { 47723530Sbloom bol = 0; 47845063Sbostic if (!noescape && c == escapechar) { 47923530Sbloom local = 1; 48023530Sbloom continue; 4816444Swnj } 48223530Sbloom } else if (local) { 48323530Sbloom local = 0; 484*67737Spendry if (c == '.' || c == deftt.c_cc[VEOF]) { 48523530Sbloom echo(c); 48623530Sbloom break; 4876444Swnj } 488*67737Spendry if (c == deftt.c_cc[VSUSP] || c == deftt.c_cc[VDSUSP]) { 48923530Sbloom bol = 1; 49023530Sbloom echo(c); 49123530Sbloom stop(c); 49223530Sbloom continue; 49323530Sbloom } 49445063Sbostic if (c != escapechar) 49553033Sleres #ifdef CRYPT 49653033Sleres #ifdef KERBEROS 49753033Sleres if (doencrypt) 49858470Sbostic (void)des_write(rem, 49958470Sbostic (char *)&escapechar, 1); 50053033Sleres else 50153033Sleres #endif 50253033Sleres #endif 50345063Sbostic (void)write(rem, &escapechar, 1); 5046444Swnj } 50536511Skfall 50653033Sleres #ifdef CRYPT 50753033Sleres #ifdef KERBEROS 50853033Sleres if (doencrypt) { 50953033Sleres if (des_write(rem, &c, 1) == 0) { 51053033Sleres msg("line gone"); 51153033Sleres break; 51253033Sleres } 51353033Sleres } else 51453033Sleres #endif 51553033Sleres #endif 51636511Skfall if (write(rem, &c, 1) == 0) { 51740858Sbostic msg("line gone"); 51836511Skfall break; 51936511Skfall } 520*67737Spendry bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] || 521*67737Spendry c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] || 52223530Sbloom c == '\r' || c == '\n'; 5236444Swnj } 5246444Swnj } 5256444Swnj 52658470Sbostic void 52758470Sbostic #if __STDC__ 52858470Sbostic echo(register char c) 52958470Sbostic #else 53023530Sbloom echo(c) 53158470Sbostic register char c; 53258470Sbostic #endif 53323530Sbloom { 53440858Sbostic register char *p; 53523530Sbloom char buf[8]; 53623530Sbloom 53740858Sbostic p = buf; 53823530Sbloom c &= 0177; 53945063Sbostic *p++ = escapechar; 54023530Sbloom if (c < ' ') { 54123530Sbloom *p++ = '^'; 54223530Sbloom *p++ = c + '@'; 54323530Sbloom } else if (c == 0177) { 54423530Sbloom *p++ = '^'; 54523530Sbloom *p++ = '?'; 54623530Sbloom } else 54723530Sbloom *p++ = c; 54823530Sbloom *p++ = '\r'; 54923530Sbloom *p++ = '\n'; 55045063Sbostic (void)write(STDOUT_FILENO, buf, p - buf); 55123530Sbloom } 55223530Sbloom 55358470Sbostic void 55458470Sbostic #if __STDC__ 55558470Sbostic stop(char cmdc) 55658470Sbostic #else 55718358Ssam stop(cmdc) 55818358Ssam char cmdc; 55958470Sbostic #endif 56018358Ssam { 561*67737Spendry struct sigaction sa; 562*67737Spendry 56318358Ssam mode(0); 564*67737Spendry sigemptyset(&sa.sa_mask); 565*67737Spendry sa.sa_handler = SIG_IGN; 566*67737Spendry sa.sa_flags = SA_RESTART; 567*67737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 568*67737Spendry (void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP); 569*67737Spendry sa.sa_handler = catch_child; 570*67737Spendry (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0); 57118358Ssam mode(1); 57258470Sbostic sigwinch(0); /* check for size changes */ 57318358Ssam } 57418358Ssam 57540858Sbostic void 57658470Sbostic sigwinch(signo) 57758470Sbostic int signo; 57818358Ssam { 57918358Ssam struct winsize ws; 58018358Ssam 58129729Smckusick if (dosigwinch && get_window_size(0, &ws) == 0 && 582*67737Spendry memcmp(&ws, &winsize, sizeof(ws))) { 58318358Ssam winsize = ws; 58424726Smckusick sendwindow(); 58518358Ssam } 58618358Ssam } 58718358Ssam 58824726Smckusick /* 58924726Smckusick * Send the window size to the server via the magic escape 59024726Smckusick */ 59158470Sbostic void 59224726Smckusick sendwindow() 59324726Smckusick { 59440858Sbostic struct winsize *wp; 59524726Smckusick char obuf[4 + sizeof (struct winsize)]; 59624726Smckusick 59740858Sbostic wp = (struct winsize *)(obuf+4); 59824726Smckusick obuf[0] = 0377; 59924726Smckusick obuf[1] = 0377; 60024726Smckusick obuf[2] = 's'; 60124726Smckusick obuf[3] = 's'; 60224726Smckusick wp->ws_row = htons(winsize.ws_row); 60324726Smckusick wp->ws_col = htons(winsize.ws_col); 60424726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 60524726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 60636511Skfall 60753033Sleres #ifdef CRYPT 60853033Sleres #ifdef KERBEROS 60953033Sleres if(doencrypt) 61053033Sleres (void)des_write(rem, obuf, sizeof(obuf)); 61153033Sleres else 61253033Sleres #endif 61353033Sleres #endif 61440858Sbostic (void)write(rem, obuf, sizeof(obuf)); 61524726Smckusick } 61624726Smckusick 61725424Skarels /* 61825424Skarels * reader: read from remote: line -> 1 61925424Skarels */ 62025424Skarels #define READING 1 62125424Skarels #define WRITING 2 62225424Skarels 62340858Sbostic jmp_buf rcvtop; 624*67737Spendry pid_t ppid; 625*67737Spendry int rcvcnt, rcvstate; 62640858Sbostic char rcvbuf[8 * 1024]; 62725424Skarels 62840858Sbostic void 62958470Sbostic oob(signo) 63058470Sbostic int signo; 6316444Swnj { 632*67737Spendry struct termios tt; 63340858Sbostic int atmark, n, out, rcvd; 6349365Ssam char waste[BUFSIZ], mark; 6356444Swnj 63642230Sbostic out = O_RDWR; 63740858Sbostic rcvd = 0; 63859175Storek while (recv(rem, &mark, 1, MSG_OOB) < 0) { 63925424Skarels switch (errno) { 64025424Skarels case EWOULDBLOCK: 64125424Skarels /* 64240858Sbostic * Urgent data not here yet. It may not be possible 64340858Sbostic * to send it yet if we are blocked for output and 64440858Sbostic * our input buffer is full. 64525424Skarels */ 64625424Skarels if (rcvcnt < sizeof(rcvbuf)) { 64725424Skarels n = read(rem, rcvbuf + rcvcnt, 64840858Sbostic sizeof(rcvbuf) - rcvcnt); 64925424Skarels if (n <= 0) 65025424Skarels return; 65125424Skarels rcvd += n; 65225424Skarels } else { 65325424Skarels n = read(rem, waste, sizeof(waste)); 65425424Skarels if (n <= 0) 65525424Skarels return; 65625424Skarels } 65725424Skarels continue; 65825424Skarels default: 65925424Skarels return; 66059175Storek } 6616444Swnj } 66225424Skarels if (mark & TIOCPKT_WINDOW) { 66340858Sbostic /* Let server know about window size changes */ 66440858Sbostic (void)kill(ppid, SIGUSR1); 66524726Smckusick } 66625424Skarels if (!eight && (mark & TIOCPKT_NOSTOP)) { 667*67737Spendry tcgetattr(0, &tt); 668*67737Spendry tt.c_iflag &= ~(IXON|IXOFF); 669*67737Spendry tt.c_cc[VSTOP] = _POSIX_VDISABLE; 670*67737Spendry tt.c_cc[VSTART] = _POSIX_VDISABLE; 671*67737Spendry tcsetattr(0, TCSANOW, &tt); 6726444Swnj } 67325424Skarels if (!eight && (mark & TIOCPKT_DOSTOP)) { 674*67737Spendry tcgetattr(0, &tt); 675*67737Spendry tt.c_iflag |= (IXON|IXOFF); 676*67737Spendry tt.c_cc[VSTOP] = deftt.c_cc[VSTOP]; 677*67737Spendry tt.c_cc[VSTART] = deftt.c_cc[VSTART]; 678*67737Spendry tcsetattr(0, TCSANOW, &tt); 6796444Swnj } 68025424Skarels if (mark & TIOCPKT_FLUSHWRITE) { 68140858Sbostic (void)ioctl(1, TIOCFLUSH, (char *)&out); 68225424Skarels for (;;) { 68325424Skarels if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 684*67737Spendry warn("ioctl SIOCATMARK (ignored)"); 68525424Skarels break; 68625424Skarels } 68725424Skarels if (atmark) 68825424Skarels break; 68925424Skarels n = read(rem, waste, sizeof (waste)); 69025424Skarels if (n <= 0) 69125424Skarels break; 69225424Skarels } 69325424Skarels /* 69440858Sbostic * Don't want any pending data to be output, so clear the recv 69540858Sbostic * buffer. If we were hanging on a write when interrupted, 69640858Sbostic * don't want it to restart. If we were reading, restart 69740858Sbostic * anyway. 69825424Skarels */ 69925424Skarels rcvcnt = 0; 70025424Skarels longjmp(rcvtop, 1); 70125424Skarels } 70229729Smckusick 70340858Sbostic /* oob does not do FLUSHREAD (alas!) */ 70429729Smckusick 70529729Smckusick /* 70640858Sbostic * If we filled the receive buffer while a read was pending, longjmp 70740858Sbostic * to the top to restart appropriately. Don't abort a pending write, 70840858Sbostic * however, or we won't know how much was written. 70925424Skarels */ 71025424Skarels if (rcvd && rcvstate == READING) 71125424Skarels longjmp(rcvtop, 1); 7126444Swnj } 7136444Swnj 71440858Sbostic /* reader: read from remote: line -> 1 */ 71558470Sbostic int 716*67737Spendry reader(smask) 717*67737Spendry sigset_t *smask; 7186444Swnj { 719*67737Spendry pid_t pid; 720*67737Spendry int n, remaining; 72159175Storek char *bufp; 722*67737Spendry struct sigaction sa; 72340858Sbostic 72459175Storek #if BSD >= 43 || defined(SUNOS4) 72559175Storek pid = getpid(); /* modern systems use positives for pid */ 72626981Skarels #else 72759175Storek pid = -getpid(); /* old broken systems use negatives */ 72826981Skarels #endif 729*67737Spendry sigemptyset(&sa.sa_mask); 730*67737Spendry sa.sa_flags = SA_RESTART; 731*67737Spendry sa.sa_handler = SIG_IGN; 732*67737Spendry (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0); 733*67737Spendry sa.sa_handler = oob; 734*67737Spendry (void)sigaction(SIGURG, &sa, (struct sigaction *) 0); 73526981Skarels ppid = getppid(); 73640858Sbostic (void)fcntl(rem, F_SETOWN, pid); 73740858Sbostic (void)setjmp(rcvtop); 738*67737Spendry (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0); 73959175Storek bufp = rcvbuf; 7406444Swnj for (;;) { 74125424Skarels while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 74225424Skarels rcvstate = WRITING; 74345063Sbostic n = write(STDOUT_FILENO, bufp, remaining); 74425424Skarels if (n < 0) { 74525424Skarels if (errno != EINTR) 74658470Sbostic return (-1); 74725424Skarels continue; 74825424Skarels } 74925424Skarels bufp += n; 75025424Skarels } 75125424Skarels bufp = rcvbuf; 75225424Skarels rcvcnt = 0; 75325424Skarels rcvstate = READING; 75436511Skfall 75553033Sleres #ifdef CRYPT 75653033Sleres #ifdef KERBEROS 75753033Sleres if (doencrypt) 75853033Sleres rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 75953033Sleres else 76053033Sleres #endif 76153033Sleres #endif 76236511Skfall rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 76325424Skarels if (rcvcnt == 0) 76425424Skarels return (0); 76525424Skarels if (rcvcnt < 0) { 7669365Ssam if (errno == EINTR) 7676444Swnj continue; 768*67737Spendry warn("read"); 76958470Sbostic return (-1); 7706444Swnj } 7716444Swnj } 7726444Swnj } 7736444Swnj 77458470Sbostic void 7756444Swnj mode(f) 77658470Sbostic int f; 7776444Swnj { 778*67737Spendry struct termios tt; 7799365Ssam 780*67737Spendry switch (f) { 7819962Ssam case 0: 782*67737Spendry tcsetattr(0, TCSADRAIN, &deftt); 7839962Ssam break; 7849962Ssam case 1: 785*67737Spendry tt = deftt; 786*67737Spendry tt.c_oflag &= ~OPOST; 787*67737Spendry tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 788*67737Spendry tt.c_cc[VMIN] = 1; 789*67737Spendry tt.c_cc[VTIME] = 0; 790*67737Spendry if (eight) { 791*67737Spendry tt.c_iflag &= ~(IXON | IXOFF); 792*67737Spendry tt.c_cc[VSTOP] = _POSIX_VDISABLE; 793*67737Spendry tt.c_cc[VSTART] = _POSIX_VDISABLE; 794*67737Spendry } 795*67737Spendry /*if (litout) 796*67737Spendry lflags |= LLITOUT;*/ 797*67737Spendry tcsetattr(0, TCSADRAIN, &tt); 7989962Ssam break; 799*67737Spendry 8009962Ssam default: 8019962Ssam return; 8026444Swnj } 8036444Swnj } 8046444Swnj 80540858Sbostic void 80658470Sbostic lostpeer(signo) 80758470Sbostic int signo; 8086444Swnj { 809*67737Spendry struct sigaction sa; 810*67737Spendry 811*67737Spendry sigemptyset(&sa.sa_mask); 812*67737Spendry sa.sa_flags = SA_RESTART; 813*67737Spendry sa.sa_handler = SIG_IGN; 814*67737Spendry (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0); 81540858Sbostic msg("\007connection closed."); 81640858Sbostic done(1); 81740858Sbostic } 81829729Smckusick 81940858Sbostic /* copy SIGURGs to the child process. */ 82040858Sbostic void 82158470Sbostic copytochild(signo) 82258470Sbostic int signo; 82340858Sbostic { 824*67737Spendry 82540858Sbostic (void)kill(child, SIGURG); 8266444Swnj } 8276444Swnj 82858470Sbostic void 82940858Sbostic msg(str) 83040858Sbostic char *str; 8316444Swnj { 832*67737Spendry 83340858Sbostic (void)fprintf(stderr, "rlogin: %s\r\n", str); 83440858Sbostic } 83529729Smckusick 83640858Sbostic #ifdef KERBEROS 83740858Sbostic /* VARARGS */ 83858470Sbostic void 83958470Sbostic #if __STDC__ 84058470Sbostic warning(const char *fmt, ...) 84158470Sbostic #else 84258470Sbostic warning(fmt, va_alist) 84358470Sbostic char *fmt; 84458470Sbostic va_dcl 84558470Sbostic #endif 84640858Sbostic { 84740858Sbostic va_list ap; 84840858Sbostic 84940858Sbostic (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 85058470Sbostic #ifdef __STDC__ 85158470Sbostic va_start(ap, fmt); 85258470Sbostic #else 85340858Sbostic va_start(ap); 85458470Sbostic #endif 85540858Sbostic vfprintf(stderr, fmt, ap); 85640858Sbostic va_end(ap); 85740858Sbostic (void)fprintf(stderr, ".\n"); 8586444Swnj } 85940858Sbostic #endif 86036512Skfall 86158470Sbostic __dead void 86240858Sbostic usage() 86336512Skfall { 86440858Sbostic (void)fprintf(stderr, 86540858Sbostic "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 86640858Sbostic #ifdef KERBEROS 86753033Sleres #ifdef CRYPT 86854125Sbostic "8EKLx", " [-k realm] "); 86953033Sleres #else 87054125Sbostic "8EKL", " [-k realm] "); 87153033Sleres #endif 87245256Smckusick #else 87345063Sbostic "8EL", " "); 87440858Sbostic #endif 87540858Sbostic exit(1); 87636512Skfall } 87740858Sbostic 87840858Sbostic /* 87959175Storek * The following routine provides compatibility (such as it is) between older 88040858Sbostic * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 88140858Sbostic */ 88259175Storek #ifdef OLDSUN 88358470Sbostic int 88440858Sbostic get_window_size(fd, wp) 88540858Sbostic int fd; 88640858Sbostic struct winsize *wp; 88740858Sbostic { 88840858Sbostic struct ttysize ts; 88940858Sbostic int error; 89040858Sbostic 89140858Sbostic if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 89258470Sbostic return (error); 89340858Sbostic wp->ws_row = ts.ts_lines; 89440858Sbostic wp->ws_col = ts.ts_cols; 89540858Sbostic wp->ws_xpixel = 0; 89640858Sbostic wp->ws_ypixel = 0; 89758470Sbostic return (0); 89840858Sbostic } 89940858Sbostic #endif 90045063Sbostic 90158470Sbostic u_int 90245063Sbostic getescape(p) 90345063Sbostic register char *p; 90445063Sbostic { 90545063Sbostic long val; 90645063Sbostic int len; 90745063Sbostic 90845063Sbostic if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 90958470Sbostic return ((u_int)*p); 91045063Sbostic /* otherwise, \nnn */ 91145063Sbostic if (*p == '\\' && len >= 2 && len <= 4) { 91258470Sbostic val = strtol(++p, NULL, 8); 91345063Sbostic for (;;) { 91445063Sbostic if (!*++p) 91558470Sbostic return ((u_int)val); 91645063Sbostic if (*p < '0' || *p > '8') 91745063Sbostic break; 91845063Sbostic } 91945063Sbostic } 92045063Sbostic msg("illegal option value -- e"); 92145063Sbostic usage(); 92245063Sbostic /* NOTREACHED */ 92345063Sbostic } 924