rlogin.c revision 1590
1218792Snp/* 2218792Snp * Copyright (c) 1983, 1990, 1993 3218792Snp * The Regents of the University of California. All rights reserved. 4218792Snp * 5218792Snp * Redistribution and use in source and binary forms, with or without 6218792Snp * modification, are permitted provided that the following conditions 7218792Snp * are met: 8218792Snp * 1. Redistributions of source code must retain the above copyright 9218792Snp * notice, this list of conditions and the following disclaimer. 10218792Snp * 2. Redistributions in binary form must reproduce the above copyright 11218792Snp * notice, this list of conditions and the following disclaimer in the 12218792Snp * documentation and/or other materials provided with the distribution. 13218792Snp * 3. All advertising materials mentioning features or use of this software 14218792Snp * must display the following acknowledgement: 15218792Snp * This product includes software developed by the University of 16218792Snp * California, Berkeley and its contributors. 17218792Snp * 4. Neither the name of the University nor the names of its contributors 18218792Snp * may be used to endorse or promote products derived from this software 19218792Snp * without specific prior written permission. 20218792Snp * 21218792Snp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24218792Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31218792Snp * SUCH DAMAGE. 32218792Snp */ 33218792Snp 34228561Snp#ifndef lint 35218792Snpstatic char copyright[] = 36218792Snp"@(#) Copyright (c) 1983, 1990, 1993\n\ 37218792Snp The Regents of the University of California. All rights reserved.\n"; 38257176Sglebius#endif /* not lint */ 39218792Snp 40257176Sglebius#ifndef lint 41257176Sglebiusstatic char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; 42345664Sjhb#endif /* not lint */ 43257176Sglebius 44257176Sglebius/* 45218792Snp * rlogin - remote login 46218792Snp */ 47218792Snp#include <sys/param.h> 48218792Snp#include <sys/socket.h> 49218792Snp#include <sys/time.h> 50218792Snp#include <sys/resource.h> 51218792Snp#include <sys/wait.h> 52257176Sglebius 53218792Snp#include <netinet/in.h> 54235944Sbz#include <netinet/in_systm.h> 55218792Snp#include <netinet/ip.h> 56218792Snp 57218792Snp#include <errno.h> 58301535Snp#include <fcntl.h> 59266757Snp#include <netdb.h> 60228561Snp#include <pwd.h> 61218792Snp#include <setjmp.h> 62275733Snp#include <sgtty.h> 63218792Snp#include <signal.h> 64218792Snp#include <stdio.h> 65218792Snp#include <stdlib.h> 66218792Snp#include <string.h> 67218792Snp#include <unistd.h> 68218792Snp 69218792Snp#ifdef __STDC__ 70218792Snp#include <stdarg.h> 71218792Snp#else 72218792Snp#include <varargs.h> 73218792Snp#endif 74339396Snp 75218792Snp#ifdef KERBEROS 76218792Snp#include <kerberosIV/des.h> 77231115Snp#include <kerberosIV/krb.h> 78231115Snp 79231115Snp#include "krb.h" 80231115Snp 81231115SnpCREDENTIALS cred; 82231115SnpKey_schedule schedule; 83344858Sjhbint use_kerberos = 1, doencrypt; 84344858Sjhbchar dst_realm_buf[REALM_SZ], *dest_realm = NULL; 85218792Snp#endif 86218792Snp 87218792Snp#ifndef TIOCPKT_WINDOW 88218792Snp#define TIOCPKT_WINDOW 0x80 89269411Snp#endif 90269411Snp 91269411Snp/* concession to Sun */ 92269411Snp#ifndef SIGUSR1 93269411Snp#define SIGUSR1 30 94269411Snp#endif 95269411Snp 96269411Snpint eight, litout, rem; 97218792Snp 98218792Snpint noescape; 99218792Snpu_char escapechar = '~'; 100269411Snp 101269411Snpchar *speeds[] = { 102218792Snp "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 103269411Snp "1800", "2400", "4800", "9600", "19200", "38400" 104269411Snp}; 105269411Snp 106269411Snp#ifdef OLDSUN 107219392Snpstruct winsize { 108263317Snp unsigned short ws_row, ws_col; 109219392Snp unsigned short ws_xpixel, ws_ypixel; 110263317Snp}; 111219392Snp#else 112275554Snp#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 113218792Snp#endif 114269411Snpstruct winsize winsize; 115276485Snp 116276485Snpvoid catch_child __P((int)); 117218792Snpvoid copytochild __P((int)); 118218792Snp__dead void doit __P((long)); 119218792Snp__dead void done __P((int)); 120218792Snpvoid echo __P((char)); 121219944Snpu_int getescape __P((char *)); 122219944Snpvoid lostpeer __P((int)); 123219944Snpvoid mode __P((int)); 124219944Snpvoid msg __P((char *)); 125219944Snpvoid oob __P((int)); 126219944Snpint reader __P((int)); 127219944Snpvoid sendwindow __P((void)); 128266757Snpvoid setsignal __P((int)); 129266757Snpvoid sigwinch __P((int)); 130266757Snpvoid stop __P((char)); 131266757Snp__dead void usage __P((void)); 132266757Snpvoid writer __P((void)); 133266757Snpvoid writeroob __P((int)); 134266757Snp 135266757Snp#ifdef KERBEROS 136266757Snpvoid warning __P((const char *, ...)); 137266757Snp#endif 138266757Snp#ifdef OLDSUN 139245274Snpint get_window_size __P((int, struct winsize *)); 140245274Snp#endif 141245274Snp 142245274Snpint 143245274Snpmain(argc, argv) 144245274Snp int argc; 145245274Snp char *argv[]; 146245274Snp{ 147245274Snp extern char *optarg; 148245274Snp extern int optind; 149218792Snp struct passwd *pw; 150218792Snp struct servent *sp; 151218792Snp struct sgttyb ttyb; 152330307Snp long omask; 153228561Snp int argoff, ch, dflag, one, uid; 154228561Snp char *host, *p, *user, term[1024]; 155278374Snp 156255050Snp argoff = dflag = 0; 157306664Sjhb one = 1; 158218792Snp host = user = NULL; 159218792Snp 160218792Snp if (p = rindex(argv[0], '/')) 161218792Snp ++p; 162291665Sjhb else 163334562Snp p = argv[0]; 164291665Sjhb 165291665Sjhb if (strcmp(p, "rlogin")) 166218792Snp host = p; 167291665Sjhb 168291665Sjhb /* handle "rlogin host flags" */ 169284445Snp if (!host && argc > 2 && argv[1][0] != '-') { 170284445Snp host = argv[1]; 171330307Snp argoff = 1; 172330307Snp } 173330307Snp 174218792Snp#ifdef KERBEROS 175218792Snp#define OPTIONS "8EKLde:k:l:x" 176291665Sjhb#else 177291665Sjhb#define OPTIONS "8EKLde:l:" 178245274Snp#endif 179245274Snp while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) 180245274Snp switch(ch) { 181218792Snp case '8': 182291665Sjhb eight = 1; 183218792Snp break; 184291665Sjhb case 'E': 185218792Snp noescape = 1; 186218792Snp break; 187218792Snp case 'K': 188218792Snp#ifdef KERBEROS 189218792Snp use_kerberos = 0; 190218792Snp#endif 191302110Snp break; 192309560Sjhb case 'L': 193218792Snp litout = 1; 194218792Snp break; 195218792Snp case 'd': 196285648Snp dflag = 1; 197218792Snp break; 198291665Sjhb case 'e': 199291665Sjhb noescape = 0; 200291665Sjhb escapechar = getescape(optarg); 201291665Sjhb break; 202291665Sjhb#ifdef KERBEROS 203218792Snp case 'k': 204318854Snp dest_realm = dst_realm_buf; 205318854Snp (void)strncpy(dest_realm, optarg, REALM_SZ); 206318854Snp break; 207318854Snp#endif 208318854Snp case 'l': 209228561Snp user = optarg; 210228561Snp break; 211228561Snp#ifdef CRYPT 212228561Snp#ifdef KERBEROS 213302110Snp case 'x': 214302110Snp doencrypt = 1; 215302110Snp des_set_key(cred.session, schedule); 216302110Snp break; 217218792Snp#endif 218330307Snp#endif 219218792Snp case '?': 220330307Snp default: 221218792Snp usage(); 222218792Snp } 223218792Snp optind += argoff; 224291665Sjhb argc -= optind; 225291665Sjhb argv += optind; 226291665Sjhb 227291665Sjhb /* if haven't gotten a host yet, do so */ 228291665Sjhb if (!host && !(host = *argv++)) 229291665Sjhb usage(); 230291665Sjhb 231291665Sjhb if (*argv) 232291665Sjhb usage(); 233318850Snp 234318850Snp if (!(pw = getpwuid(uid = getuid()))) { 235318850Snp (void)fprintf(stderr, "rlogin: unknown user id.\n"); 236318850Snp exit(1); 237318850Snp } 238301535Snp if (!user) 239346871Snp user = pw->pw_name; 240346871Snp 241346871Snp sp = NULL; 242346871Snp#ifdef KERBEROS 243301535Snp if (use_kerberos) { 244301535Snp sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 245318850Snp if (sp == NULL) { 246301535Snp use_kerberos = 0; 247346871Snp warning("can't get entry for %s/tcp service", 248318850Snp doencrypt ? "eklogin" : "klogin"); 249318850Snp } 250318850Snp } 251318850Snp#endif 252318850Snp if (sp == NULL) 253346871Snp sp = getservbyname("login", "tcp"); 254301535Snp if (sp == NULL) { 255301535Snp (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); 256318850Snp exit(1); 257318850Snp } 258318850Snp 259318850Snp (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); 260318850Snp if (ioctl(0, TIOCGETP, &ttyb) == 0) { 261318850Snp (void)strcat(term, "/"); 262318850Snp (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 263318850Snp } 264346871Snp 265346871Snp (void)get_window_size(0, &winsize); 266346871Snp 267318850Snp (void)signal(SIGPIPE, lostpeer); 268318850Snp /* will use SIGUSR1 for window size hack, so hold it off */ 269318850Snp omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 270291665Sjhb /* 271291665Sjhb * We set SIGURG and SIGUSR1 below so that an 272291665Sjhb * incoming signal will be held pending rather than being 273291665Sjhb * discarded. Note that these routines will be ready to get 274291665Sjhb * a signal by the time that they are unblocked below. 275291665Sjhb */ 276291665Sjhb (void)signal(SIGURG, copytochild); 277291665Sjhb (void)signal(SIGUSR1, writeroob); 278291665Sjhb 279318850Snp#ifdef KERBEROS 280301535Snptry_connect: 281291665Sjhb if (use_kerberos) { 282291665Sjhb struct hostent *hp; 283291665Sjhb 284291665Sjhb /* Fully qualify hostname (needed for krb_realmofhost). */ 285291665Sjhb hp = gethostbyname(host); 286291665Sjhb if (hp != NULL && !(host = strdup(hp->h_name))) { 287291665Sjhb (void)fprintf(stderr, "rlogin: %s\n", 288291665Sjhb strerror(ENOMEM)); 289291665Sjhb exit(1); 290291665Sjhb } 291330307Snp 292330307Snp rem = KSUCCESS; 293291665Sjhb errno = 0; 294218792Snp if (dest_realm == NULL) 295330307Snp dest_realm = krb_realmofhost(host); 296218792Snp 297272200Snp#ifdef CRYPT 298272200Snp if (doencrypt) 299272200Snp rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 300276485Snp dest_realm, &cred, schedule); 301345664Sjhb else 302345664Sjhb#endif /* CRYPT */ 303345664Sjhb rem = krcmd(&host, sp->s_port, user, term, 0, 304345664Sjhb dest_realm); 305272200Snp if (rem < 0) { 306218792Snp use_kerberos = 0; 307218792Snp sp = getservbyname("login", "tcp"); 308218792Snp if (sp == NULL) { 309291665Sjhb (void)fprintf(stderr, 310291665Sjhb "rlogin: unknown service login/tcp.\n"); 311263317Snp exit(1); 312263317Snp } 313263317Snp if (errno == ECONNREFUSED) 314263317Snp warning("remote host doesn't support Kerberos"); 315263317Snp if (errno == ENOENT) 316263317Snp warning("can't provide Kerberos auth data"); 317263317Snp goto try_connect; 318263317Snp } 319263317Snp } else { 320263317Snp#ifdef CRYPT 321263317Snp if (doencrypt) { 322263317Snp (void)fprintf(stderr, 323218792Snp "rlogin: the -x flag requires Kerberos authentication.\n"); 324218792Snp exit(1); 325263317Snp } 326263317Snp#endif /* CRYPT */ 327268971Snp rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 328263317Snp } 329263317Snp#else 330263317Snp rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); 331218792Snp#endif /* KERBEROS */ 332218792Snp 333218792Snp if (rem < 0) 334218792Snp exit(1); 335218792Snp 336276485Snp if (dflag && 337218792Snp setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 338218792Snp (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", 339218792Snp strerror(errno)); 340269411Snp one = IPTOS_LOWDELAY; 341269411Snp if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 342269411Snp perror("rlogin: setsockopt TOS (ignored)"); 343269411Snp 344269411Snp (void)setuid(uid); 345269411Snp doit(omask); 346269411Snp /*NOTREACHED*/ 347269411Snp} 348269411Snp 349269411Snpint child, defflags, deflflags, tabflag; 350218792Snpchar deferase, defkill; 351218792Snpstruct tchars deftc; 352228561Snpstruct ltchars defltc; 353228561Snpstruct tchars notc = { -1, -1, -1, -1, -1, -1 }; 354330307Snpstruct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 355228561Snp 356318842Snpvoid 357220649Snpdoit(omask) 358220649Snp long omask; 359220649Snp{ 360220649Snp struct sgttyb sb; 361220649Snp 362302110Snp (void)ioctl(0, TIOCGETP, (char *)&sb); 363302110Snp defflags = sb.sg_flags; 364302110Snp tabflag = defflags & TBDELAY; 365302110Snp defflags &= ECHO | CRMOD; 366302110Snp deferase = sb.sg_erase; 367218792Snp defkill = sb.sg_kill; 368218792Snp (void)ioctl(0, TIOCLGET, &deflflags); 369346852Snp (void)ioctl(0, TIOCGETC, &deftc); 370346852Snp notc.t_startc = deftc.t_startc; 371346852Snp notc.t_stopc = deftc.t_stopc; 372346852Snp (void)ioctl(0, TIOCGLTC, &defltc); 373346852Snp (void)signal(SIGINT, SIG_IGN); 374346852Snp setsignal(SIGHUP); 375346855Snp setsignal(SIGQUIT); 376346863Snp child = fork(); 377346852Snp if (child == -1) { 378346852Snp (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); 379346852Snp done(1); 380346852Snp } 381346852Snp if (child == 0) { 382302339Snp mode(1); 383302339Snp if (reader(omask) == 0) { 384302339Snp msg("connection closed."); 385302339Snp exit(0); 386302339Snp } 387302339Snp sleep(1); 388302339Snp msg("\007connection closed."); 389218792Snp exit(1); 390218792Snp } 391218792Snp 392218792Snp /* 393219290Snp * We may still own the socket, and may have a pending SIGURG (or might 394228561Snp * receive one soon) that we really want to send to the reader. When 395218792Snp * one of these comes in, the trap copytochild simply copies such 396269411Snp * signals to the child. We can now unblock SIGURG and SIGUSR1 397269411Snp * that were set above. 398218792Snp */ 399218792Snp (void)sigsetmask(omask); 400228561Snp (void)signal(SIGCHLD, catch_child); 401218792Snp writer(); 402269411Snp msg("closed connection."); 403218792Snp done(0); 404228561Snp} 405269411Snp 406228561Snp/* trap a signal, unless it is being ignored. */ 407228561Snpvoid 408269411Snpsetsignal(sig) 409269411Snp int sig; 410269411Snp{ 411269411Snp int omask = sigblock(sigmask(sig)); 412218792Snp 413218792Snp if (signal(sig, exit) == SIG_IGN) 414218792Snp (void)signal(sig, SIG_IGN); 415228561Snp (void)sigsetmask(omask); 416228561Snp} 417228561Snp 418228561Snp__dead void 419218792Snpdone(status) 420276485Snp int status; 421276485Snp{ 422276485Snp int w, wstatus; 423318854Snp 424218792Snp mode(0); 425218792Snp if (child > 0) { 426248925Snp /* make sure catch_child does not snap it up */ 427249392Snp (void)signal(SIGCHLD, SIG_DFL); 428248925Snp if (kill(child, SIGKILL) >= 0) 429218792Snp while ((w = wait(&wstatus)) > 0 && w != child); 430218792Snp } 431218792Snp exit(status); 432218792Snp} 433218792Snp 434218792Snpint dosigwinch; 435218792Snp 436228561Snp/* 437228561Snp * This is called when the reader process gets the out-of-band (urgent) 438306664Sjhb * request to turn on the window-changing protocol. 439218792Snp */ 440218792Snpvoid 441218792Snpwriteroob(signo) 442339396Snp int signo; 443248925Snp{ 444248925Snp if (dosigwinch == 0) { 445276485Snp sendwindow(); 446218792Snp (void)signal(SIGWINCH, sigwinch); 447218792Snp } 448276485Snp dosigwinch = 1; 449276485Snp} 450219288Snp 451228561Snpvoid 452276485Snpcatch_child(signo) 453228561Snp int signo; 454276485Snp{ 455276485Snp union wait status; 456276485Snp int pid; 457276485Snp 458220873Snp for (;;) { 459218792Snp pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 460263317Snp if (pid == 0) 461263317Snp return; 462263317Snp /* if the child (reader) dies, just quit */ 463263317Snp if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 464263317Snp done((int)(status.w_termsig | status.w_retcode)); 465263317Snp } 466255050Snp /* NOTREACHED */ 467255050Snp} 468263317Snp 469263317Snp/* 470263317Snp * writer: write to remote: 0 -> line. 471263317Snp * ~. terminate 472263317Snp * ~^Z suspend rlogin process. 473263317Snp * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 474228561Snp */ 475296603Snpvoid 476296603Snpwriter() 477296603Snp{ 478296603Snp register int bol, local, n; 479296603Snp char c; 480296603Snp 481296603Snp bol = 1; /* beginning of line */ 482296603Snp local = 0; 483296603Snp for (;;) { 484296603Snp n = read(STDIN_FILENO, &c, 1); 485296603Snp if (n <= 0) { 486296603Snp if (n < 0 && errno == EINTR) 487296603Snp continue; 488296603Snp break; 489296603Snp } 490296603Snp /* 491296603Snp * If we're at the beginning of the line and recognize a 492296603Snp * command character, then we echo locally. Otherwise, 493296603Snp * characters are echo'd remotely. If the command character 494296603Snp * is doubled, this acts as a force and local echo is 495296603Snp * suppressed. 496296603Snp */ 497296603Snp if (bol) { 498228561Snp bol = 0; 499228561Snp if (!noescape && c == escapechar) { 500255050Snp local = 1; 501269428Snp continue; 502228561Snp } 503228561Snp } else if (local) { 504269428Snp local = 0; 505269428Snp if (c == '.' || c == deftc.t_eofc) { 506269428Snp echo(c); 507269428Snp break; 508228561Snp } 509218792Snp if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 510218792Snp bol = 1; 511218792Snp echo(c); 512218792Snp stop(c); 513269428Snp continue; 514269428Snp } 515269428Snp if (c != escapechar) 516269428Snp#ifdef CRYPT 517263317Snp#ifdef KERBEROS 518269428Snp if (doencrypt) 519269428Snp (void)des_write(rem, 520269428Snp (char *)&escapechar, 1); 521269428Snp else 522263317Snp#endif 523269428Snp#endif 524269428Snp (void)write(rem, &escapechar, 1); 525269428Snp } 526269428Snp 527269428Snp#ifdef CRYPT 528269428Snp#ifdef KERBEROS 529269428Snp if (doencrypt) { 530269428Snp if (des_write(rem, &c, 1) == 0) { 531263317Snp msg("line gone"); 532263317Snp break; 533263317Snp } 534263317Snp } else 535263317Snp#endif 536269428Snp#endif 537269428Snp if (write(rem, &c, 1) == 0) { 538269428Snp msg("line gone"); 539269428Snp break; 540269428Snp } 541269428Snp bol = c == defkill || c == deftc.t_eofc || 542269428Snp c == deftc.t_intrc || c == defltc.t_suspc || 543269428Snp c == '\r' || c == '\n'; 544269428Snp } 545269428Snp} 546269428Snp 547269428Snpvoid 548269428Snp#if __STDC__ 549269428Snpecho(register char c) 550218792Snp#else 551218792Snpecho(c) 552276485Snp register char c; 553276485Snp#endif 554220873Snp{ 555218792Snp register char *p; 556218792Snp char buf[8]; 557220873Snp 558220873Snp p = buf; 559276485Snp c &= 0177; 560220873Snp *p++ = escapechar; 561276485Snp if (c < ' ') { 562276485Snp *p++ = '^'; 563301628Snp *p++ = c + '@'; 564218792Snp } else if (c == 0177) { 565276485Snp *p++ = '^'; 566218792Snp *p++ = '?'; 567218792Snp } else 568218792Snp *p++ = c; 569237819Snp *p++ = '\r'; 570218792Snp *p++ = '\n'; 571218792Snp (void)write(STDOUT_FILENO, buf, p - buf); 572218792Snp} 573218792Snp 574276485Snpvoid 575276485Snp#if __STDC__ 576276485Snpstop(char cmdc) 577276485Snp#else 578218792Snpstop(cmdc) 579218792Snp char cmdc; 580220873Snp#endif 581218792Snp{ 582218792Snp mode(0); 583218792Snp (void)signal(SIGCHLD, SIG_IGN); 584218792Snp (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 585228561Snp (void)signal(SIGCHLD, catch_child); 586218792Snp mode(1); 587219290Snp sigwinch(0); /* check for size changes */ 588237819Snp} 589218792Snp 590219290Snpvoid 591218792Snpsigwinch(signo) 592218792Snp int signo; 593218792Snp{ 594218792Snp struct winsize ws; 595218792Snp 596218792Snp if (dosigwinch && get_window_size(0, &ws) == 0 && 597218792Snp bcmp(&ws, &winsize, sizeof(ws))) { 598218792Snp winsize = ws; 599218792Snp sendwindow(); 600218792Snp } 601237263Snp} 602237263Snp 603237263Snp/* 604237263Snp * Send the window size to the server via the magic escape 605241733Sed */ 606237263Snpvoid 607237263Snpsendwindow() 608237263Snp{ 609228561Snp struct winsize *wp; 610228561Snp char obuf[4 + sizeof (struct winsize)]; 611228561Snp 612228561Snp wp = (struct winsize *)(obuf+4); 613228561Snp obuf[0] = 0377; 614237263Snp obuf[1] = 0377; 615237263Snp obuf[2] = 's'; 616237263Snp obuf[3] = 's'; 617237263Snp wp->ws_row = htons(winsize.ws_row); 618237263Snp wp->ws_col = htons(winsize.ws_col); 619241733Sed wp->ws_xpixel = htons(winsize.ws_xpixel); 620237263Snp wp->ws_ypixel = htons(winsize.ws_ypixel); 621228561Snp 622237263Snp#ifdef CRYPT 623237263Snp#ifdef KERBEROS 624237263Snp if(doencrypt) 625237263Snp (void)des_write(rem, obuf, sizeof(obuf)); 626276485Snp else 627237263Snp#endif 628237263Snp#endif 629276485Snp (void)write(rem, obuf, sizeof(obuf)); 630276485Snp} 631276485Snp 632276485Snp/* 633276485Snp * reader: read from remote: line -> 1 634276485Snp */ 635228561Snp#define READING 1 636228561Snp#define WRITING 2 637228561Snp 638228561Snpjmp_buf rcvtop; 639228561Snpint ppid, rcvcnt, rcvstate; 640220873Snpchar rcvbuf[8 * 1024]; 641220873Snp 642228561Snpvoid 643276485Snpoob(signo) 644228561Snp int signo; 645276485Snp{ 646276485Snp struct sgttyb sb; 647276485Snp int atmark, n, out, rcvd; 648276485Snp char waste[BUFSIZ], mark; 649237263Snp 650276485Snp out = O_RDWR; 651276485Snp rcvd = 0; 652237263Snp while (recv(rem, &mark, 1, MSG_OOB) < 0) { 653220873Snp switch (errno) { 654220873Snp case EWOULDBLOCK: 655276485Snp /* 656276485Snp * Urgent data not here yet. It may not be possible 657276485Snp * to send it yet if we are blocked for output and 658220873Snp * our input buffer is full. 659220873Snp */ 660220873Snp if (rcvcnt < sizeof(rcvbuf)) { 661276485Snp n = read(rem, rcvbuf + rcvcnt, 662276485Snp sizeof(rcvbuf) - rcvcnt); 663298955Spfg if (n <= 0) 664276485Snp return; 665276485Snp rcvd += n; 666276485Snp } else { 667276485Snp n = read(rem, waste, sizeof(waste)); 668276485Snp if (n <= 0) 669220873Snp return; 670220873Snp } 671266757Snp continue; 672266757Snp default: 673346875Snp return; 674291665Sjhb } 675266757Snp } 676269411Snp if (mark & TIOCPKT_WINDOW) { 677266757Snp /* Let server know about window size changes */ 678266757Snp (void)kill(ppid, SIGUSR1); 679266757Snp } 680266757Snp if (!eight && (mark & TIOCPKT_NOSTOP)) { 681266757Snp (void)ioctl(0, TIOCGETP, (char *)&sb); 682266757Snp sb.sg_flags &= ~CBREAK; 683266757Snp sb.sg_flags |= RAW; 684266757Snp (void)ioctl(0, TIOCSETN, (char *)&sb); 685266757Snp notc.t_stopc = -1; 686266757Snp notc.t_startc = -1; 687266757Snp (void)ioctl(0, TIOCSETC, (char *)¬c); 688266757Snp } 689266757Snp if (!eight && (mark & TIOCPKT_DOSTOP)) { 690266757Snp (void)ioctl(0, TIOCGETP, (char *)&sb); 691266757Snp sb.sg_flags &= ~RAW; 692266757Snp sb.sg_flags |= CBREAK; 693266757Snp (void)ioctl(0, TIOCSETN, (char *)&sb); 694266757Snp notc.t_stopc = deftc.t_stopc; 695266757Snp notc.t_startc = deftc.t_startc; 696266757Snp (void)ioctl(0, TIOCSETC, (char *)¬c); 697266757Snp } 698266757Snp if (mark & TIOCPKT_FLUSHWRITE) { 699266757Snp (void)ioctl(1, TIOCFLUSH, (char *)&out); 700266757Snp for (;;) { 701266757Snp if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 702266757Snp (void)fprintf(stderr, "rlogin: ioctl: %s.\n", 703266757Snp strerror(errno)); 704266757Snp break; 705266757Snp } 706266757Snp if (atmark) 707266757Snp break; 708266757Snp n = read(rem, waste, sizeof (waste)); 709266757Snp if (n <= 0) 710266757Snp break; 711266757Snp } 712266757Snp /* 713339396Snp * Don't want any pending data to be output, so clear the recv 714266757Snp * buffer. If we were hanging on a write when interrupted, 715266757Snp * don't want it to restart. If we were reading, restart 716266757Snp * anyway. 717266757Snp */ 718266757Snp rcvcnt = 0; 719266757Snp longjmp(rcvtop, 1); 720266757Snp } 721266757Snp 722266757Snp /* oob does not do FLUSHREAD (alas!) */ 723266757Snp 724266757Snp /* 725266757Snp * If we filled the receive buffer while a read was pending, longjmp 726266757Snp * to the top to restart appropriately. Don't abort a pending write, 727266757Snp * however, or we won't know how much was written. 728218792Snp */ 729228561Snp if (rcvd && rcvstate == READING) 730318854Snp longjmp(rcvtop, 1); 731228561Snp} 732228561Snp 733266757Snp/* reader: read from remote: line -> 1 */ 734266757Snpint 735228561Snpreader(omask) 736228561Snp int omask; 737218792Snp{ 738218792Snp int pid, n, remaining; 739228561Snp char *bufp; 740228561Snp 741218792Snp#if BSD >= 43 || defined(SUNOS4) 742218792Snp pid = getpid(); /* modern systems use positives for pid */ 743228561Snp#else 744228561Snp pid = -getpid(); /* old broken systems use negatives */ 745266757Snp#endif 746266757Snp (void)signal(SIGTTOU, SIG_IGN); 747218792Snp (void)signal(SIGURG, oob); 748306664Sjhb ppid = getppid(); 749306664Sjhb (void)fcntl(rem, F_SETOWN, pid); 750306664Sjhb (void)setjmp(rcvtop); 751306664Sjhb (void)sigsetmask(omask); 752218792Snp bufp = rcvbuf; 753218792Snp for (;;) { 754255050Snp while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 755263317Snp rcvstate = WRITING; 756263317Snp n = write(STDOUT_FILENO, bufp, remaining); 757263317Snp if (n < 0) { 758263317Snp if (errno != EINTR) 759218792Snp return (-1); 760218792Snp continue; 761309560Sjhb } 762309560Sjhb bufp += n; 763309560Sjhb } 764309560Sjhb bufp = rcvbuf; 765309560Sjhb rcvcnt = 0; 766309560Sjhb rcvstate = READING; 767309560Sjhb 768309560Sjhb#ifdef CRYPT 769309560Sjhb#ifdef KERBEROS 770218792Snp if (doencrypt) 771228561Snp rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); 772218792Snp else 773218792Snp#endif 774309560Sjhb#endif 775218792Snp rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 776218792Snp if (rcvcnt == 0) 777218792Snp return (0); 778218792Snp if (rcvcnt < 0) { 779218792Snp if (errno == EINTR) 780218792Snp continue; 781218792Snp (void)fprintf(stderr, "rlogin: read: %s.\n", 782218792Snp strerror(errno)); 783218792Snp return (-1); 784248925Snp } 785248925Snp } 786248925Snp} 787218792Snp 788218792Snpvoid 789218792Snpmode(f) 790296489Snp int f; 791296489Snp{ 792218792Snp struct ltchars *ltc; 793218792Snp struct sgttyb sb; 794218792Snp struct tchars *tc; 795218792Snp int lflags; 796218792Snp 797218792Snp (void)ioctl(0, TIOCGETP, (char *)&sb); 798218792Snp (void)ioctl(0, TIOCLGET, (char *)&lflags); 799218792Snp switch(f) { 800302110Snp case 0: 801302110Snp sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 802302110Snp sb.sg_flags |= defflags|tabflag; 803306664Sjhb tc = &deftc; 804306664Sjhb ltc = &defltc; 805218792Snp sb.sg_kill = defkill; 806218792Snp sb.sg_erase = deferase; 807218792Snp lflags = deflflags; 808218792Snp break; 809255015Snp case 1: 810302339Snp sb.sg_flags |= (eight ? RAW : CBREAK); 811218792Snp sb.sg_flags &= ~defflags; 812296383Snp /* preserve tab delays, but turn off XTABS */ 813218792Snp if ((sb.sg_flags & TBDELAY) == XTABS) 814330307Snp sb.sg_flags &= ~TBDELAY; 815218792Snp tc = ¬c; 816237263Snp ltc = &noltc; 817228561Snp sb.sg_kill = sb.sg_erase = -1; 818346805Snp if (litout) 819346805Snp lflags |= LLITOUT; 820346805Snp break; 821346805Snp default: 822331769Shselasky return; 823292736Snp } 824345040Sjhb (void)ioctl(0, TIOCSLTC, (char *)ltc); 825222509Snp (void)ioctl(0, TIOCSETC, (char *)tc); 826346855Snp (void)ioctl(0, TIOCSETN, (char *)&sb); 827218792Snp (void)ioctl(0, TIOCLSET, (char *)&lflags); 828345664Sjhb} 829218792Snp 830339396Snpvoid 831278374Snplostpeer(signo) 832278374Snp int signo; 833218792Snp{ 834284445Snp (void)signal(SIGPIPE, SIG_IGN); 835218792Snp msg("\007connection closed."); 836253691Snp done(1); 837253691Snp} 838253691Snp 839253691Snp/* copy SIGURGs to the child process. */ 840253691Snpvoid 841253691Snpcopytochild(signo) 842253691Snp int signo; 843253691Snp{ 844296641Snp (void)kill(child, SIGURG); 845296641Snp} 846309458Sjhb 847309458Sjhbvoid 848245936Snpmsg(str) 849245936Snp char *str; 850218792Snp{ 851296383Snp (void)fprintf(stderr, "rlogin: %s\r\n", str); 852218792Snp} 853218792Snp 854296710Snp#ifdef KERBEROS 855228561Snp/* VARARGS */ 856296710Snpvoid 857228561Snp#if __STDC__ 858228561Snpwarning(const char *fmt, ...) 859228561Snp#else 860309560Sjhbwarning(fmt, va_alist) 861228561Snp char *fmt; 862228561Snp va_dcl 863220873Snp#endif 864228561Snp{ 865228561Snp va_list ap; 866218792Snp 867218792Snp (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); 868228561Snp#ifdef __STDC__ 869228561Snp va_start(ap, fmt); 870228561Snp#else 871228561Snp va_start(ap); 872228561Snp#endif 873228561Snp vfprintf(stderr, fmt, ap); 874296552Snp va_end(ap); 875272200Snp (void)fprintf(stderr, ".\n"); 876296603Snp} 877296603Snp#endif 878318850Snp 879318850Snp__dead void 880318850Snpusage() 881245274Snp{ 882245274Snp (void)fprintf(stderr, 883286926Snp "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 884218792Snp#ifdef KERBEROS 885218792Snp#ifdef CRYPT 886218792Snp "8EKLx", " [-k realm] "); 887218792Snp#else 888218792Snp "8EKL", " [-k realm] "); 889218792Snp#endif 890218792Snp#else 891245274Snp "8EL", " "); 892245274Snp#endif 893245274Snp exit(1); 894245274Snp} 895245274Snp 896218792Snp/* 897218792Snp * The following routine provides compatibility (such as it is) between older 898218792Snp * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 899218792Snp */ 900218792Snp#ifdef OLDSUN 901218792Snpint 902218792Snpget_window_size(fd, wp) 903218792Snp int fd; 904218792Snp struct winsize *wp; 905218792Snp{ 906218792Snp struct ttysize ts; 907218792Snp int error; 908218792Snp 909218792Snp if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 910218792Snp return (error); 911218792Snp wp->ws_row = ts.ts_lines; 912218792Snp wp->ws_col = ts.ts_cols; 913218792Snp wp->ws_xpixel = 0; 914218792Snp wp->ws_ypixel = 0; 915218792Snp return (0); 916218792Snp} 917218792Snp#endif 918218792Snp 919218792Snpu_int 920218792Snpgetescape(p) 921218792Snp register char *p; 922218792Snp{ 923218792Snp long val; 924284445Snp int len; 925284445Snp 926284445Snp if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 927284445Snp return ((u_int)*p); 928284445Snp /* otherwise, \nnn */ 929284445Snp if (*p == '\\' && len >= 2 && len <= 4) { 930284445Snp val = strtol(++p, NULL, 8); 931284445Snp for (;;) { 932284445Snp if (!*++p) 933284445Snp return ((u_int)val); 934284445Snp if (*p < '0' || *p > '8') 935284445Snp break; 936284445Snp } 937284445Snp } 938284445Snp msg("illegal option value -- e"); 939284445Snp usage(); 940284445Snp /* NOTREACHED */ 941284445Snp} 942291665Sjhb