rlogin.c revision 47488
1148456Spjd/* 2213072Spjd * Copyright (c) 1983, 1990, 1993 3148456Spjd * The Regents of the University of California. All rights reserved. 4148456Spjd * 5148456Spjd * Redistribution and use in source and binary forms, with or without 6148456Spjd * modification, are permitted provided that the following conditions 7148456Spjd * are met: 8148456Spjd * 1. Redistributions of source code must retain the above copyright 9148456Spjd * notice, this list of conditions and the following disclaimer. 10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright 11148456Spjd * notice, this list of conditions and the following disclaimer in the 12148456Spjd * documentation and/or other materials provided with the distribution. 13155174Spjd * 3. All advertising materials mentioning features or use of this software 14148456Spjd * must display the following acknowledgement: 15148456Spjd * This product includes software developed by the University of 16148456Spjd * California, Berkeley and its contributors. 17148456Spjd * 4. Neither the name of the University nor the names of its contributors 18148456Spjd * may be used to endorse or promote products derived from this software 19148456Spjd * without specific prior written permission. 20148456Spjd * 21148456Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24148456Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31148456Spjd * SUCH DAMAGE. 32148456Spjd */ 33148456Spjd 34148456Spjd#ifndef lint 35148456Spjdstatic const char copyright[] = 36148456Spjd"@(#) Copyright (c) 1983, 1990, 1993\n\ 37148456Spjd The Regents of the University of California. All rights reserved.\n"; 38148456Spjd#endif /* not lint */ 39148456Spjd 40148456Spjd#ifndef lint 41148456Spjdstatic const char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; 42148456Spjdstatic const char rcsid[] = 43148456Spjd "$Id: rlogin.c,v 1.18 1998/10/09 06:45:28 markm Exp $"; 44148456Spjd#endif /* not lint */ 45148456Spjd 46148456Spjd/* 47148456Spjd * rlogin - remote login 48148456Spjd */ 49148456Spjd#include <sys/param.h> 50148456Spjd#include <sys/socket.h> 51148456Spjd#include <sys/time.h> 52148456Spjd#include <sys/resource.h> 53148456Spjd#include <sys/wait.h> 54148456Spjd 55148456Spjd#include <netinet/in.h> 56148456Spjd#include <netinet/in_systm.h> 57148456Spjd#include <netinet/ip.h> 58148456Spjd#include <netinet/tcp.h> 59148456Spjd 60148456Spjd#include <err.h> 61148456Spjd#include <errno.h> 62148456Spjd#include <fcntl.h> 63148456Spjd#include <libutil.h> 64148456Spjd#include <netdb.h> 65148456Spjd#include <pwd.h> 66148456Spjd#include <setjmp.h> 67148456Spjd#include <sgtty.h> 68148456Spjd#include <signal.h> 69213070Spjd#include <stdio.h> 70213070Spjd#include <stdlib.h> 71213070Spjd#include <string.h> 72148456Spjd#include <unistd.h> 73148456Spjd#include <err.h> 74148456Spjd 75148456Spjd#ifdef KERBEROS 76167755Ssam#include <des.h> 77148456Spjd#include <krb.h> 78148456Spjd 79271148Sjmg#include "../../bin/rcp/pathnames.h" 80148456Spjd#include "krb.h" 81148456Spjd 82148456SpjdCREDENTIALS cred; 83148456SpjdKey_schedule schedule; 84148456Spjdint use_kerberos = 1, doencrypt; 85148456Spjdchar dst_realm_buf[REALM_SZ], *dest_realm = NULL; 86148456Spjd#endif 87148456Spjd 88148456Spjd#ifndef TIOCPKT_WINDOW 89157900Spjd#define TIOCPKT_WINDOW 0x80 90148456Spjd#endif 91148456Spjd 92148456Spjd/* concession to Sun */ 93148456Spjd#ifndef SIGUSR1 94148456Spjd#define SIGUSR1 30 95148456Spjd#endif 96148456Spjd 97148456Spjdint eight, litout, rem; 98148456Spjd 99148456Spjdint noescape; 100148456Spjdu_char escapechar = '~'; 101148456Spjd 102148456Spjdchar *speeds[] = { 103271148Sjmg "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", 104275732Sjmg "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" 105148456Spjd#define MAX_SPEED_LENGTH (sizeof("115200") - 1) 106148456Spjd}; 107148456Spjd 108148456Spjd#ifdef OLDSUN 109148456Spjdstruct winsize { 110148456Spjd unsigned short ws_row, ws_col; 111148456Spjd unsigned short ws_xpixel, ws_ypixel; 112148456Spjd}; 113148456Spjd#else 114148456Spjd#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) 115148456Spjd#endif 116148456Spjdstruct winsize winsize; 117148456Spjd 118148456Spjdvoid catch_child __P((int)); 119148456Spjdvoid copytochild __P((int)); 120148456Spjdvoid doit __P((long)) __dead2; 121148456Spjdvoid done __P((int)) __dead2; 122148456Spjdvoid echo __P((char)); 123148456Spjdu_int getescape __P((char *)); 124148456Spjdvoid lostpeer __P((int)); 125148456Spjdvoid mode __P((int)); 126148456Spjdvoid msg __P((char *)); 127148456Spjdvoid oob __P((int)); 128213070Spjdint reader __P((int)); 129213070Spjdvoid sendwindow __P((void)); 130148456Spjdvoid setsignal __P((int)); 131148456Spjdvoid sigwinch __P((int)); 132148456Spjdvoid stop __P((char)); 133148456Spjdvoid usage __P((void)) __dead2; 134148456Spjdvoid writer __P((void)); 135148456Spjdvoid writeroob __P((int)); 136148456Spjd 137148456Spjd#ifdef OLDSUN 138148456Spjdint get_window_size __P((int, struct winsize *)); 139148456Spjd#endif 140148456Spjd 141148456Spjdint 142148456Spjdmain(argc, argv) 143148456Spjd int argc; 144148456Spjd char *argv[]; 145148456Spjd{ 146148456Spjd extern char *optarg; 147148456Spjd extern int optind; 148148456Spjd struct passwd *pw; 149148456Spjd struct servent *sp; 150148456Spjd struct sgttyb ttyb; 151148456Spjd long omask; 152173746Sjb int argoff, ch, dflag, Dflag, one, uid; 153172031Spjd char *host, *p, *user, term[1024]; 154172031Spjd#ifdef KERBEROS 155172031Spjd char *k; 156172031Spjd#endif 157172031Spjd char *localname = NULL; 158172031Spjd 159172031Spjd argoff = dflag = Dflag = 0; 160172031Spjd one = 1; 161172031Spjd host = user = NULL; 162172031Spjd 163172031Spjd if ((p = rindex(argv[0], '/'))) 164172031Spjd ++p; 165172031Spjd else 166172031Spjd p = argv[0]; 167172031Spjd 168173746Sjb if (strcmp(p, "rlogin")) 169148456Spjd host = p; 170148456Spjd 171148456Spjd /* handle "rlogin host flags" */ 172148456Spjd if (!host && argc > 2 && argv[1][0] != '-') { 173148456Spjd host = argv[1]; 174148456Spjd argoff = 1; 175148456Spjd } 176148456Spjd 177148456Spjd#ifdef KERBEROS 178148456Spjd#define OPTIONS "8DEKLde:i:k:l:x" 179148456Spjd#else 180148456Spjd#define OPTIONS "8DEKLde:i:l:" 181148456Spjd#endif 182148456Spjd while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 183148456Spjd switch(ch) { 184148456Spjd case '8': 185148456Spjd eight = 1; 186148456Spjd break; 187148456Spjd case 'D': 188148456Spjd Dflag = 1; 189148456Spjd break; 190148456Spjd case 'E': 191148456Spjd noescape = 1; 192148456Spjd break; 193148456Spjd case 'K': 194148456Spjd#ifdef KERBEROS 195148456Spjd use_kerberos = 0; 196148456Spjd#endif 197148456Spjd break; 198148456Spjd case 'L': 199148456Spjd litout = 1; 200148456Spjd break; 201148456Spjd case 'd': 202148456Spjd dflag = 1; 203148456Spjd break; 204148456Spjd case 'e': 205148456Spjd noescape = 0; 206213070Spjd escapechar = getescape(optarg); 207213070Spjd break; 208213070Spjd case 'i': 209213070Spjd if (getuid() != 0) { 210148456Spjd fprintf(stderr, "rlogin: -i user: permission denied\n"); 211148456Spjd exit(1); 212148456Spjd } 213148456Spjd localname = optarg; 214148456Spjd break; 215148456Spjd#ifdef KERBEROS 216148456Spjd case 'k': 217148456Spjd dest_realm = dst_realm_buf; 218213070Spjd (void)strncpy(dest_realm, optarg, REALM_SZ); 219213070Spjd break; 220213070Spjd#endif 221213070Spjd case 'l': 222148456Spjd user = optarg; 223148456Spjd break; 224#ifdef CRYPT 225#ifdef KERBEROS 226 case 'x': 227 doencrypt = 1; 228 break; 229#endif 230#endif 231 case '?': 232 default: 233 usage(); 234 } 235 optind += argoff; 236 237 /* if haven't gotten a host yet, do so */ 238 if (!host && !(host = argv[optind++])) 239 usage(); 240 241 if (argv[optind]) 242 usage(); 243 244 if (!(pw = getpwuid(uid = getuid()))) 245 errx(1, "unknown user id"); 246 if (!user) 247 user = pw->pw_name; 248 if (!localname) 249 localname = pw->pw_name; 250 251 sp = NULL; 252#ifdef KERBEROS 253 k = auth_getval("auth_list"); 254 if (k && !strstr(k, "kerberos")) 255 use_kerberos = 0; 256 if (use_kerberos) { 257 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); 258 if (sp == NULL) { 259 use_kerberos = 0; 260 warn("can't get entry for %s/tcp service", 261 doencrypt ? "eklogin" : "klogin"); 262 } 263 } 264#endif 265 if (sp == NULL) 266 sp = getservbyname("login", "tcp"); 267 if (sp == NULL) 268 errx(1, "login/tcp: unknown service"); 269 270#define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) 271 272 (void)strncpy(term, (p = getenv("TERM")) ? p : "network", 273 MAX_TERM_LENGTH); 274 term[MAX_TERM_LENGTH] = '\0'; 275 if (ioctl(0, TIOCGETP, &ttyb) == 0) { 276 (void)strcat(term, "/"); 277 (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); 278 } 279 280 (void)get_window_size(0, &winsize); 281 282 (void)signal(SIGPIPE, lostpeer); 283 /* will use SIGUSR1 for window size hack, so hold it off */ 284 omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 285 /* 286 * We set SIGURG and SIGUSR1 below so that an 287 * incoming signal will be held pending rather than being 288 * discarded. Note that these routines will be ready to get 289 * a signal by the time that they are unblocked below. 290 */ 291 (void)signal(SIGURG, copytochild); 292 (void)signal(SIGUSR1, writeroob); 293 294#ifdef KERBEROS 295 if (use_kerberos) { 296 setuid(getuid()); 297 rem = KSUCCESS; 298 errno = 0; 299 if (dest_realm == NULL) 300 dest_realm = krb_realmofhost(host); 301 302#ifdef CRYPT 303 if (doencrypt) { 304 rem = krcmd_mutual(&host, sp->s_port, user, term, 0, 305 dest_realm, &cred, schedule); 306 des_set_key(&cred.session, schedule); 307 } else 308#endif /* CRYPT */ 309 rem = krcmd(&host, sp->s_port, user, term, 0, 310 dest_realm); 311 if (rem < 0) { 312 int i; 313 char **newargv; 314 315 sp = getservbyname("login", "tcp"); 316 if (sp == NULL) 317 errx(1, "unknown service login/tcp"); 318 if (errno == ECONNREFUSED) 319 warn("remote host doesn't support Kerberos"); 320 if (errno == ENOENT) 321 warn("can't provide Kerberos auth data"); 322 newargv = malloc((argc + 2) * sizeof(*newargv)); 323 if (newargv == NULL) 324 err(1, "malloc"); 325 newargv[0] = argv[0]; 326 newargv[1] = "-K"; 327 for(i = 1; i < argc; ++i) 328 newargv[i + 1] = argv[i]; 329 newargv[argc + 1] = NULL; 330 execv(_PATH_RLOGIN, newargv); 331 } 332 } else { 333#ifdef CRYPT 334 if (doencrypt) 335 errx(1, "the -x flag requires Kerberos authentication"); 336#endif /* CRYPT */ 337 rem = rcmd(&host, sp->s_port, localname, user, term, 0); 338 } 339#else 340 rem = rcmd(&host, sp->s_port, localname, user, term, 0); 341#endif /* KERBEROS */ 342 343 if (rem < 0) 344 exit(1); 345 346 if (dflag && 347 setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) 348 warn("setsockopt"); 349 if (Dflag && 350 setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) 351 warn("setsockopt NODELAY (ignored)"); 352 353 one = IPTOS_LOWDELAY; 354 if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) 355 warn("setsockopt TOS (ignored)"); 356 357 (void)setuid(uid); 358 doit(omask); 359 /*NOTREACHED*/ 360} 361 362int child, defflags, deflflags, tabflag; 363char deferase, defkill; 364struct tchars deftc; 365struct ltchars defltc; 366struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 367struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 368 369void 370doit(omask) 371 long omask; 372{ 373 struct sgttyb sb; 374 375 (void)ioctl(0, TIOCGETP, (char *)&sb); 376 defflags = sb.sg_flags; 377 tabflag = defflags & TBDELAY; 378 defflags &= ECHO | CRMOD; 379 deferase = sb.sg_erase; 380 defkill = sb.sg_kill; 381 (void)ioctl(0, TIOCLGET, &deflflags); 382 (void)ioctl(0, TIOCGETC, &deftc); 383 notc.t_startc = deftc.t_startc; 384 notc.t_stopc = deftc.t_stopc; 385 (void)ioctl(0, TIOCGLTC, &defltc); 386 (void)signal(SIGINT, SIG_IGN); 387 setsignal(SIGHUP); 388 setsignal(SIGQUIT); 389 child = fork(); 390 if (child == -1) { 391 warn("fork"); 392 done(1); 393 } 394 if (child == 0) { 395 mode(1); 396 if (reader(omask) == 0) { 397 msg("connection closed."); 398 exit(0); 399 } 400 sleep(1); 401 msg("\007connection closed."); 402 exit(1); 403 } 404 405 /* 406 * We may still own the socket, and may have a pending SIGURG (or might 407 * receive one soon) that we really want to send to the reader. When 408 * one of these comes in, the trap copytochild simply copies such 409 * signals to the child. We can now unblock SIGURG and SIGUSR1 410 * that were set above. 411 */ 412 (void)sigsetmask(omask); 413 (void)signal(SIGCHLD, catch_child); 414 writer(); 415 msg("closed connection."); 416 done(0); 417} 418 419/* trap a signal, unless it is being ignored. */ 420void 421setsignal(sig) 422 int sig; 423{ 424 int omask = sigblock(sigmask(sig)); 425 426 if (signal(sig, exit) == SIG_IGN) 427 (void)signal(sig, SIG_IGN); 428 (void)sigsetmask(omask); 429} 430 431void 432done(status) 433 int status; 434{ 435 int w, wstatus; 436 437 mode(0); 438 if (child > 0) { 439 /* make sure catch_child does not snap it up */ 440 (void)signal(SIGCHLD, SIG_DFL); 441 if (kill(child, SIGKILL) >= 0) 442 while ((w = wait(&wstatus)) > 0 && w != child); 443 } 444 exit(status); 445} 446 447int dosigwinch; 448 449/* 450 * This is called when the reader process gets the out-of-band (urgent) 451 * request to turn on the window-changing protocol. 452 */ 453void 454writeroob(signo) 455 int signo; 456{ 457 if (dosigwinch == 0) { 458 sendwindow(); 459 (void)signal(SIGWINCH, sigwinch); 460 } 461 dosigwinch = 1; 462} 463 464void 465catch_child(signo) 466 int signo; 467{ 468 union wait status; 469 int pid; 470 471 for (;;) { 472 pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); 473 if (pid == 0) 474 return; 475 /* if the child (reader) dies, just quit */ 476 if (pid < 0 || (pid == child && !WIFSTOPPED(status))) 477 done((int)(status.w_termsig | status.w_retcode)); 478 } 479 /* NOTREACHED */ 480} 481 482/* 483 * writer: write to remote: 0 -> line. 484 * ~. terminate 485 * ~^Z suspend rlogin process. 486 * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. 487 */ 488void 489writer() 490{ 491 register int bol, local, n; 492 char c; 493 494 bol = 1; /* beginning of line */ 495 local = 0; 496 for (;;) { 497 n = read(STDIN_FILENO, &c, 1); 498 if (n <= 0) { 499 if (n < 0 && errno == EINTR) 500 continue; 501 break; 502 } 503 /* 504 * If we're at the beginning of the line and recognize a 505 * command character, then we echo locally. Otherwise, 506 * characters are echo'd remotely. If the command character 507 * is doubled, this acts as a force and local echo is 508 * suppressed. 509 */ 510 if (bol) { 511 bol = 0; 512 if (!noescape && c == escapechar) { 513 local = 1; 514 continue; 515 } 516 } else if (local) { 517 local = 0; 518 if (c == '.' || c == deftc.t_eofc) { 519 echo(c); 520 break; 521 } 522 if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 523 bol = 1; 524 echo(c); 525 stop(c); 526 continue; 527 } 528 if (c != escapechar) 529#ifdef CRYPT 530#ifdef KERBEROS 531 if (doencrypt) 532 (void)des_enc_write(rem, 533 (char *)&escapechar, 1, 534 schedule, &cred.session); 535 else 536#endif 537#endif 538 (void)write(rem, &escapechar, 1); 539 } 540 541#ifdef CRYPT 542#ifdef KERBEROS 543 if (doencrypt) { 544 if (des_enc_write(rem, &c, 1, schedule, &cred.session) == 0) { 545 msg("line gone"); 546 break; 547 } 548 } else 549#endif 550#endif 551 if (write(rem, &c, 1) == 0) { 552 msg("line gone"); 553 break; 554 } 555 bol = c == defkill || c == deftc.t_eofc || 556 c == deftc.t_intrc || c == defltc.t_suspc || 557 c == '\r' || c == '\n'; 558 } 559} 560 561void 562#if __STDC__ 563echo(register char c) 564#else 565echo(c) 566 register char c; 567#endif 568{ 569 register char *p; 570 char buf[8]; 571 572 p = buf; 573 c &= 0177; 574 *p++ = escapechar; 575 if (c < ' ') { 576 *p++ = '^'; 577 *p++ = c + '@'; 578 } else if (c == 0177) { 579 *p++ = '^'; 580 *p++ = '?'; 581 } else 582 *p++ = c; 583 *p++ = '\r'; 584 *p++ = '\n'; 585 (void)write(STDOUT_FILENO, buf, p - buf); 586} 587 588void 589#if __STDC__ 590stop(char cmdc) 591#else 592stop(cmdc) 593 char cmdc; 594#endif 595{ 596 mode(0); 597 (void)signal(SIGCHLD, SIG_IGN); 598 (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 599 (void)signal(SIGCHLD, catch_child); 600 mode(1); 601 sigwinch(0); /* check for size changes */ 602} 603 604void 605sigwinch(signo) 606 int signo; 607{ 608 struct winsize ws; 609 610 if (dosigwinch && get_window_size(0, &ws) == 0 && 611 bcmp(&ws, &winsize, sizeof(ws))) { 612 winsize = ws; 613 sendwindow(); 614 } 615} 616 617/* 618 * Send the window size to the server via the magic escape 619 */ 620void 621sendwindow() 622{ 623 struct winsize *wp; 624 char obuf[4 + sizeof (struct winsize)]; 625 626 wp = (struct winsize *)(obuf+4); 627 obuf[0] = 0377; 628 obuf[1] = 0377; 629 obuf[2] = 's'; 630 obuf[3] = 's'; 631 wp->ws_row = htons(winsize.ws_row); 632 wp->ws_col = htons(winsize.ws_col); 633 wp->ws_xpixel = htons(winsize.ws_xpixel); 634 wp->ws_ypixel = htons(winsize.ws_ypixel); 635 636#ifdef CRYPT 637#ifdef KERBEROS 638 if(doencrypt) 639 (void)des_enc_write(rem, obuf, sizeof(obuf), 640 schedule, &cred.session); 641 else 642#endif 643#endif 644 (void)write(rem, obuf, sizeof(obuf)); 645} 646 647/* 648 * reader: read from remote: line -> 1 649 */ 650#define READING 1 651#define WRITING 2 652 653jmp_buf rcvtop; 654int ppid, rcvcnt, rcvstate; 655char rcvbuf[8 * 1024]; 656 657void 658oob(signo) 659 int signo; 660{ 661 struct sgttyb sb; 662 int atmark, n, out, rcvd; 663 char waste[BUFSIZ], mark; 664 665 out = O_RDWR; 666 rcvd = 0; 667 while (recv(rem, &mark, 1, MSG_OOB) < 0) { 668 switch (errno) { 669 case EWOULDBLOCK: 670 /* 671 * Urgent data not here yet. It may not be possible 672 * to send it yet if we are blocked for output and 673 * our input buffer is full. 674 */ 675 if (rcvcnt < sizeof(rcvbuf)) { 676 n = read(rem, rcvbuf + rcvcnt, 677 sizeof(rcvbuf) - rcvcnt); 678 if (n <= 0) 679 return; 680 rcvd += n; 681 } else { 682 n = read(rem, waste, sizeof(waste)); 683 if (n <= 0) 684 return; 685 } 686 continue; 687 default: 688 return; 689 } 690 } 691 if (mark & TIOCPKT_WINDOW) { 692 /* Let server know about window size changes */ 693 (void)kill(ppid, SIGUSR1); 694 } 695 if (!eight && (mark & TIOCPKT_NOSTOP)) { 696 (void)ioctl(0, TIOCGETP, (char *)&sb); 697 sb.sg_flags &= ~CBREAK; 698 sb.sg_flags |= RAW; 699 (void)ioctl(0, TIOCSETN, (char *)&sb); 700 notc.t_stopc = -1; 701 notc.t_startc = -1; 702 (void)ioctl(0, TIOCSETC, (char *)¬c); 703 } 704 if (!eight && (mark & TIOCPKT_DOSTOP)) { 705 (void)ioctl(0, TIOCGETP, (char *)&sb); 706 sb.sg_flags &= ~RAW; 707 sb.sg_flags |= CBREAK; 708 (void)ioctl(0, TIOCSETN, (char *)&sb); 709 notc.t_stopc = deftc.t_stopc; 710 notc.t_startc = deftc.t_startc; 711 (void)ioctl(0, TIOCSETC, (char *)¬c); 712 } 713 if (mark & TIOCPKT_FLUSHWRITE) { 714 (void)ioctl(1, TIOCFLUSH, (char *)&out); 715 for (;;) { 716 if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 717 warn("ioctl"); 718 break; 719 } 720 if (atmark) 721 break; 722 n = read(rem, waste, sizeof (waste)); 723 if (n <= 0) 724 break; 725 } 726 /* 727 * Don't want any pending data to be output, so clear the recv 728 * buffer. If we were hanging on a write when interrupted, 729 * don't want it to restart. If we were reading, restart 730 * anyway. 731 */ 732 rcvcnt = 0; 733 longjmp(rcvtop, 1); 734 } 735 736 /* oob does not do FLUSHREAD (alas!) */ 737 738 /* 739 * If we filled the receive buffer while a read was pending, longjmp 740 * to the top to restart appropriately. Don't abort a pending write, 741 * however, or we won't know how much was written. 742 */ 743 if (rcvd && rcvstate == READING) 744 longjmp(rcvtop, 1); 745} 746 747/* reader: read from remote: line -> 1 */ 748int 749reader(omask) 750 int omask; 751{ 752 int pid, n, remaining; 753 char *bufp; 754 755#if BSD >= 43 || defined(SUNOS4) 756 pid = getpid(); /* modern systems use positives for pid */ 757#else 758 pid = -getpid(); /* old broken systems use negatives */ 759#endif 760 (void)signal(SIGTTOU, SIG_IGN); 761 (void)signal(SIGURG, oob); 762 ppid = getppid(); 763 (void)fcntl(rem, F_SETOWN, pid); 764 (void)setjmp(rcvtop); 765 (void)sigsetmask(omask); 766 bufp = rcvbuf; 767 for (;;) { 768 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 769 rcvstate = WRITING; 770 n = write(STDOUT_FILENO, bufp, remaining); 771 if (n < 0) { 772 if (errno != EINTR) 773 return (-1); 774 continue; 775 } 776 bufp += n; 777 } 778 bufp = rcvbuf; 779 rcvcnt = 0; 780 rcvstate = READING; 781 782#ifdef CRYPT 783#ifdef KERBEROS 784 if (doencrypt) 785 rcvcnt = des_enc_read(rem, rcvbuf, sizeof(rcvbuf), 786 schedule, &cred.session); 787 else 788#endif 789#endif 790 rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); 791 if (rcvcnt == 0) 792 return (0); 793 if (rcvcnt < 0) { 794 if (errno == EINTR) 795 continue; 796 warn("read"); 797 return (-1); 798 } 799 } 800} 801 802void 803mode(f) 804 int f; 805{ 806 struct ltchars *ltc; 807 struct sgttyb sb; 808 struct tchars *tc; 809 int lflags; 810 811 (void)ioctl(0, TIOCGETP, (char *)&sb); 812 (void)ioctl(0, TIOCLGET, (char *)&lflags); 813 switch(f) { 814 case 0: 815 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 816 sb.sg_flags |= defflags|tabflag; 817 tc = &deftc; 818 ltc = &defltc; 819 sb.sg_kill = defkill; 820 sb.sg_erase = deferase; 821 lflags = deflflags; 822 break; 823 case 1: 824 sb.sg_flags |= (eight ? RAW : CBREAK); 825 sb.sg_flags &= ~defflags; 826 /* preserve tab delays, but turn off XTABS */ 827 if ((sb.sg_flags & TBDELAY) == XTABS) 828 sb.sg_flags &= ~TBDELAY; 829 tc = ¬c; 830 ltc = &noltc; 831 sb.sg_kill = sb.sg_erase = -1; 832 if (litout) 833 lflags |= LLITOUT; 834 break; 835 default: 836 return; 837 } 838 (void)ioctl(0, TIOCSLTC, (char *)ltc); 839 (void)ioctl(0, TIOCSETC, (char *)tc); 840 (void)ioctl(0, TIOCSETN, (char *)&sb); 841 (void)ioctl(0, TIOCLSET, (char *)&lflags); 842} 843 844void 845lostpeer(signo) 846 int signo; 847{ 848 (void)signal(SIGPIPE, SIG_IGN); 849 msg("\007connection closed."); 850 done(1); 851} 852 853/* copy SIGURGs to the child process. */ 854void 855copytochild(signo) 856 int signo; 857{ 858 (void)kill(child, SIGURG); 859} 860 861void 862msg(str) 863 char *str; 864{ 865 (void)fprintf(stderr, "rlogin: %s\r\n", str); 866} 867 868void 869usage() 870{ 871 (void)fprintf(stderr, 872 "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", 873#ifdef KERBEROS 874#ifdef CRYPT 875 "8DEKLx", " [-k realm] "); 876#else 877 "8DEKL", " [-k realm] "); 878#endif 879#else 880 "8DEL", " "); 881#endif 882 exit(1); 883} 884 885/* 886 * The following routine provides compatibility (such as it is) between older 887 * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. 888 */ 889#ifdef OLDSUN 890int 891get_window_size(fd, wp) 892 int fd; 893 struct winsize *wp; 894{ 895 struct ttysize ts; 896 int error; 897 898 if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) 899 return (error); 900 wp->ws_row = ts.ts_lines; 901 wp->ws_col = ts.ts_cols; 902 wp->ws_xpixel = 0; 903 wp->ws_ypixel = 0; 904 return (0); 905} 906#endif 907 908u_int 909getescape(p) 910 register char *p; 911{ 912 long val; 913 int len; 914 915 if ((len = strlen(p)) == 1) /* use any single char, including '\' */ 916 return ((u_int)*p); 917 /* otherwise, \nnn */ 918 if (*p == '\\' && len >= 2 && len <= 4) { 919 val = strtol(++p, NULL, 8); 920 for (;;) { 921 if (!*++p) 922 return ((u_int)val); 923 if (*p < '0' || *p > '8') 924 break; 925 } 926 } 927 msg("illegal option value -- e"); 928 usage(); 929 /* NOTREACHED */ 930} 931