X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/86a16a64d0810c15bf0ee41b0a102f1657850e5a..9bccbd7c566bbf4900f2bd91d2b2c3d4506740a2:/usr/src/usr.bin/rlogin/rlogin.c diff --git a/usr/src/usr.bin/rlogin/rlogin.c b/usr/src/usr.bin/rlogin/rlogin.c index 70e5174ff2..db583603d8 100644 --- a/usr/src/usr.bin/rlogin/rlogin.c +++ b/usr/src/usr.bin/rlogin/rlogin.c @@ -1,343 +1,803 @@ +/* + * Copyright (c) 1983, 1990 The Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + */ + #ifndef lint -static char sccsid[] = "@(#)rlogin.c 4.5 82/11/27"; -#endif +char copyright[] = +"@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ -#include +#ifndef lint +static char sccsid[] = "@(#)rlogin.c 5.37 (Berkeley) %G%"; +#endif /* not lint */ + +/* + * $Source: mit/rlogin/RCS/rlogin.c,v $ + * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall + * Exp Locker: kfall $ + */ + +/* + * rlogin - remote login + */ +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include -#include #include +#include +#include #include #include -#include -#include +#include +#include +#include -/* - * rlogin - remote login - */ -char *index(), *rindex(), *malloc(), *getenv(); -struct passwd *getpwuid(); -char *name; -int rem; -char cmdchar = '~'; -int rcmdoptions = 0; -int eight; -char *speeds[] = - { "0", "50", "75", "110", "134", "150", "200", "300", - "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; -char term[64] = "network"; -extern int errno; -int lostpeer(); - -#define CTRL(c) ('c' & 037) +#ifdef KERBEROS +#include +#include + +CREDENTIALS cred; +Key_schedule schedule; +int use_kerberos = 1, doencrypt; +char dst_realm_buf[REALM_SZ], *dest_realm = NULL; +extern char *krb_realmofhost(); +#endif + +#ifndef TIOCPKT_WINDOW +#define TIOCPKT_WINDOW 0x80 +#endif + +/* concession to Sun */ +#ifndef SIGUSR1 +#define SIGUSR1 30 +#endif + +int eight, litout, rem; + +int noescape; +u_char escapechar = '~'; + +char *speeds[] = { + "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", + "1800", "2400", "4800", "9600", "19200", "38400" +}; + +#ifdef sun +struct winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; +#endif +struct winsize winsize; + +#ifndef sun +#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) +#endif + +void exit(); main(argc, argv) int argc; char **argv; { - char *host, *cp; - struct sgttyb ttyb; - struct passwd *pwd; + extern char *optarg; + extern int optind; + struct passwd *pw; struct servent *sp; - int uid; + struct hostent *hp; + struct sgttyb ttyb; + long omask; + int argoff, ch, dflag, one, uid; + char *host, *p, *user, term[1024]; + void lostpeer(), copytochild(), writeroob(); + u_char getescape(); + char *getenv(); - host = rindex(argv[0], '/'); - if (host) - host++; + argoff = dflag = 0; + one = 1; + host = user = NULL; + + if (p = rindex(argv[0], '/')) + ++p; else - host = argv[0]; - argv++, --argc; - if (!strcmp(host, "rlogin")) - host = *argv++, --argc; -another: - if (!strcmp(*argv, "-d")) { - argv++, argc--; - rcmdoptions |= SO_DEBUG; - goto another; - } - if (!strcmp(*argv, "-l")) { - argv++, argc--; - if (argc == 0) - goto usage; - name = *argv++; argc--; - goto another; + p = argv[0]; + + if (strcmp(p, "rlogin")) + host = p; + + /* handle "rlogin host flags" */ + if (!host && argc > 2 && argv[1][0] != '-') { + host = argv[1]; + argoff = 1; } - if (!strncmp(*argv, "-e", 2)) { - cmdchar = argv[0][2]; - argv++, argc--; - goto another; + +#ifdef KERBEROS +#define OPTIONS "8EKLde:k:l:x" +#else +#define OPTIONS "8EKLde:l:" +#endif + while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) + switch(ch) { + case '8': + eight = 1; + break; + case 'E': + noescape = 1; + break; + case 'K': +#ifdef KERBEROS + use_kerberos = 0; +#endif + break; + case 'L': + litout = 1; + break; + case 'd': + dflag = 1; + break; + case 'e': + noescape = 0; + escapechar = getescape(optarg); + break; +#ifdef KERBEROS + case 'k': + dest_realm = dst_realm_buf; + (void)strncpy(dest_realm, optarg, REALM_SZ); + break; +#endif + case 'l': + user = optarg; + break; + case '?': + default: + usage(); + } + optind += argoff; + argc -= optind; + argv += optind; + + /* if haven't gotten a host yet, do so */ + if (!host && !(host = *argv++)) + usage(); + + if (*argv) + usage(); + + if (!(pw = getpwuid(uid = getuid()))) { + (void)fprintf(stderr, "rlogin: unknown user id.\n"); + exit(1); } - if (!strcmp(*argv, "-8")) { - eight = 1; - argv++, argc--; - goto another; + if (!user) + user = pw->pw_name; + + sp = NULL; +#ifdef KERBEROS + if (use_kerberos) { + sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); + if (sp == NULL) { + use_kerberos = 0; + warning("can't get entry for %s/tcp service", + doencrypt ? "eklogin" : "klogin"); + } } - if (host == 0) - goto usage; - if (argc > 0) - goto usage; - pwd = getpwuid(getuid()); - if (pwd == 0) { - fprintf(stderr, "Who are you?\n"); +#endif + if (sp == NULL) + sp = getservbyname("login", "tcp"); + if (sp == NULL) { + (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); exit(1); } - sp = getservbyname("login", "tcp"); - if (sp == 0) { - fprintf(stderr, "rlogin: login/tcp: unknown service\n"); - exit(2); - } - cp = getenv("TERM"); - if (cp) - strcpy(term, cp); - if (gtty(0, &ttyb)==0) { - strcat(term, "/"); - strcat(term, speeds[ttyb.sg_ospeed]); + + (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); + if (ioctl(0, TIOCGETP, &ttyb) == 0) { + (void)strcat(term, "/"); + (void)strcat(term, speeds[ttyb.sg_ospeed]); } - signal(SIGPIPE, lostpeer); - rem = rcmd(&host, sp->s_port, pwd->pw_name, - name ? name : pwd->pw_name, term, 0); - if (rem < 0) - exit(1); - uid = getuid(); - if (setuid(uid) < 0) { - perror("rlogin: setuid"); - exit(1); + + (void)get_window_size(0, &winsize); + + (void)signal(SIGPIPE, lostpeer); + /* will use SIGUSR1 for window size hack, so hold it off */ + omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); + /* + * We set SIGURG and SIGUSR1 below so that an + * incoming signal will be held pending rather than being + * discarded. Note that these routines will be ready to get + * a signal by the time that they are unblocked below. + */ + (void)signal(SIGURG, copytochild); + (void)signal(SIGUSR1, writeroob); + +#ifdef KERBEROS +try_connect: + if (use_kerberos) { + /* fully qualify hostname (needed for krb_realmofhost) */ + hp = gethostbyname(host); + if (hp != NULL && !(host = strdup(hp->h_name))) { + (void)fprintf(stderr, "rlogin: %s.\n", strerror(ENOMEM)); + exit(1); + } + + rem = KSUCCESS; + errno = 0; + if (dest_realm == NULL) + dest_realm = krb_realmofhost(host); + + rem = krcmd(&host, sp->s_port, user, term, 0, + dest_realm); + if (rem < 0) { + use_kerberos = 0; + sp = getservbyname("login", "tcp"); + if (sp == NULL) { + (void)fprintf(stderr, + "rlogin: unknown service login/tcp.\n"); + exit(1); + } + if (errno == ECONNREFUSED) + warning("remote host doesn't support Kerberos"); + if (errno == ENOENT) + warning("can't provide Kerberos auth data"); + goto try_connect; + } + } else { + rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); } - doit(); - /*NOTREACHED*/ -usage: - fprintf(stderr, - "usage: rlogin host [ -ex ] [ -l username ]\n"); - exit(1); -} +#else + rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); +#endif /* KERBEROS */ -#define CRLF "\r\n" + if (rem < 0) + exit(1); -int child; -int done(); + if (dflag && + setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) + (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", + strerror(errno)); + one = IPTOS_LOWDELAY; + if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) + perror("rlogin: setsockopt TOS (ignored)"); -char tkill, terase; /* current input kill & erase */ -char defkill, deferase, defflags; + (void)setuid(uid); + doit(omask); + /*NOTREACHED*/ +} -struct tchars deftchars; -struct tchars notchars = { -1, -1, CTRL(q), CTRL(s), -1, -1 }; -struct ltchars defltchars; -struct ltchars noltchars = { -1, -1, -1, -1, -1, -1 }; +int child, defflags, deflflags, tabflag; +char deferase, defkill; +struct tchars deftc; +struct ltchars defltc; +struct tchars notc = { -1, -1, -1, -1, -1, -1 }; +struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; -doit() +doit(omask) + long omask; { - struct sgttyb stbuf; - int exit(); - - ioctl(0, TIOCGETP, (char *)&stbuf); - defkill = stbuf.sg_kill; - deferase = stbuf.sg_erase; - defflags = stbuf.sg_flags & (ECHO | CRMOD); - ioctl(0, TIOCGETC, (char *)&deftchars); - ioctl(0, TIOCGLTC, (char *)&defltchars); - signal(SIGINT, exit); - signal(SIGHUP, exit); - signal(SIGQUIT, exit); + struct sgttyb sb; + void catch_child(), exit(); + + (void)ioctl(0, TIOCGETP, (char *)&sb); + defflags = sb.sg_flags; + tabflag = defflags & TBDELAY; + defflags &= ECHO | CRMOD; + deferase = sb.sg_erase; + defkill = sb.sg_kill; + (void)ioctl(0, TIOCLGET, (char *)&deflflags); + (void)ioctl(0, TIOCGETC, (char *)&deftc); + notc.t_startc = deftc.t_startc; + notc.t_stopc = deftc.t_stopc; + (void)ioctl(0, TIOCGLTC, (char *)&defltc); + (void)signal(SIGINT, SIG_IGN); + setsignal(SIGHUP, exit); + setsignal(SIGQUIT, exit); child = fork(); if (child == -1) { - perror("rlogin: fork"); - done(); + (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); + done(1); } - signal(SIGINT, SIG_IGN); if (child == 0) { - signal(SIGPIPE, SIG_IGN); - reader(); - prf("\007Lost connection."); - exit(3); + mode(1); + if (reader(omask) == 0) { + msg("connection closed."); + exit(0); + } + sleep(1); + msg("\007connection closed."); + exit(1); } - signal(SIGCHLD, done); - mode(1); + + /* + * We may still own the socket, and may have a pending SIGURG (or might + * receive one soon) that we really want to send to the reader. When + * one of these comes in, the trap copytochild simply copies such + * signals to the child. We can now unblock SIGURG and SIGUSR1 + * that were set above. + */ + (void)sigsetmask(omask); + (void)signal(SIGCHLD, catch_child); writer(); - prf("Disconnected."); - done(); + msg("closed connection."); + done(0); } -done() +/* trap a signal, unless it is being ignored. */ +setsignal(sig, act) + int sig; + void (*act)(); { + int omask = sigblock(sigmask(sig)); + + if (signal(sig, act) == SIG_IGN) + (void)signal(sig, SIG_IGN); + (void)sigsetmask(omask); +} + +done(status) + int status; +{ + int w, wstatus; mode(0); - if (child > 0 && kill(child, SIGKILL) >= 0) - wait((int *)0); - exit(0); + if (child > 0) { + /* make sure catch_child does not snap it up */ + (void)signal(SIGCHLD, SIG_DFL); + if (kill(child, SIGKILL) >= 0) + while ((w = wait(&wstatus)) > 0 && w != child); + } + exit(status); +} + +int dosigwinch; +void sigwinch(); + +/* + * This is called when the reader process gets the out-of-band (urgent) + * request to turn on the window-changing protocol. + */ +void +writeroob() +{ + if (dosigwinch == 0) { + sendwindow(); + (void)signal(SIGWINCH, sigwinch); + } + dosigwinch = 1; +} + +void +catch_child() +{ + union wait status; + int pid; + + for (;;) { + pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); + if (pid == 0) + return; + /* if the child (reader) dies, just quit */ + if (pid < 0 || pid == child && !WIFSTOPPED(status)) + done((int)(status.w_termsig | status.w_retcode)); + } + /* NOTREACHED */ } /* * writer: write to remote: 0 -> line. - * ~. terminate - * ~^Z suspend rlogin process. + * ~. terminate + * ~^Z suspend rlogin process. + * ~ suspend rlogin process, but leave reader alone. */ writer() { - char b[600], c; - register char *p; - -top: - p = b; - while (read(0, &c, 1) > 0) { - int local; + register int bol, local, n; + char c; - if (eight == 0) - c &= 0177; + bol = 1; /* beginning of line */ + local = 0; + for (;;) { + n = read(STDIN_FILENO, &c, 1); + if (n <= 0) { + if (n < 0 && errno == EINTR) + continue; + break; + } /* - * If we're at the beginning of the line - * and recognize a command character, then - * we echo locally. Otherwise, characters - * are echo'd remotely. If the command - * character is doubled, this acts as a - * force and local echo is suppressed. + * If we're at the beginning of the line and recognize a + * command character, then we echo locally. Otherwise, + * characters are echo'd remotely. If the command character + * is doubled, this acts as a force and local echo is + * suppressed. */ - if (p == b) - local = (c == cmdchar); - if (p == b + 1 && *b == cmdchar) - local = (c != cmdchar); - if (!local) { - if (write(rem, &c, 1) == 0) { - prf("line gone"); - return; + if (bol) { + bol = 0; + if (!noescape && c == escapechar) { + local = 1; + continue; } - if (eight == 0) - c &= 0177; - } else { - if (c == 0177) - c = tkill; - if (c == '\r' || c == '\n') { - switch (b[1]) { - - case '.': - case CTRL(d): - write(0, CRLF, sizeof(CRLF)); - return; - - case CTRL(z): - write(0, CRLF, sizeof(CRLF)); - mode(0); - signal(SIGCHLD, SIG_IGN); - kill(0, SIGTSTP); - signal(SIGCHLD, done); - mode(1); - goto top; - } - *p++ = c; - write(rem, b, p - b); - goto top; + } else if (local) { + local = 0; + if (c == '.' || c == deftc.t_eofc) { + echo(c); + break; } - write(1, &c, 1); + if (c == defltc.t_suspc || c == defltc.t_dsuspc) { + bol = 1; + echo(c); + stop(c); + continue; + } + if (c != escapechar) + (void)write(rem, &escapechar, 1); } + + if (write(rem, &c, 1) == 0) { + msg("line gone"); + break; + } + bol = c == defkill || c == deftc.t_eofc || + c == deftc.t_intrc || c == defltc.t_suspc || + c == '\r' || c == '\n'; + } +} + +echo(c) +register char c; +{ + register char *p; + char buf[8]; + + p = buf; + c &= 0177; + *p++ = escapechar; + if (c < ' ') { + *p++ = '^'; + *p++ = c + '@'; + } else if (c == 0177) { + *p++ = '^'; + *p++ = '?'; + } else *p++ = c; - if (c == terase) { - p -= 2; - if (p < b) - goto top; - } - if (c == tkill || c == 0177 || c == CTRL(d) || - c == '\r' || c == '\n') - goto top; + *p++ = '\r'; + *p++ = '\n'; + (void)write(STDOUT_FILENO, buf, p - buf); +} + +stop(cmdc) + char cmdc; +{ + mode(0); + (void)signal(SIGCHLD, SIG_IGN); + (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); + (void)signal(SIGCHLD, catch_child); + mode(1); + sigwinch(); /* check for size changes */ +} + +void +sigwinch() +{ + struct winsize ws; + + if (dosigwinch && get_window_size(0, &ws) == 0 && + bcmp(&ws, &winsize, sizeof(ws))) { + winsize = ws; + sendwindow(); } } +/* + * Send the window size to the server via the magic escape + */ +sendwindow() +{ + struct winsize *wp; + char obuf[4 + sizeof (struct winsize)]; + + wp = (struct winsize *)(obuf+4); + obuf[0] = 0377; + obuf[1] = 0377; + obuf[2] = 's'; + obuf[3] = 's'; + wp->ws_row = htons(winsize.ws_row); + wp->ws_col = htons(winsize.ws_col); + wp->ws_xpixel = htons(winsize.ws_xpixel); + wp->ws_ypixel = htons(winsize.ws_ypixel); + + (void)write(rem, obuf, sizeof(obuf)); +} + +/* + * reader: read from remote: line -> 1 + */ +#define READING 1 +#define WRITING 2 + +jmp_buf rcvtop; +int ppid, rcvcnt, rcvstate; +char rcvbuf[8 * 1024]; + +void oob() { - int out = 1+1; + struct sgttyb sb; + int atmark, n, out, rcvd; char waste[BUFSIZ], mark; - signal(SIGURG, oob); - ioctl(1, TIOCFLUSH, (char *)&out); - for (;;) { - if (ioctl(rem, SIOCATMARK, &mark) < 0) { - perror("ioctl"); - break; - } - if (mark) - break; - (void) read(rem, waste, sizeof (waste)); + out = O_RDWR; + rcvd = 0; + while (recv(rem, &mark, 1, MSG_OOB) < 0) + switch (errno) { + case EWOULDBLOCK: + /* + * Urgent data not here yet. It may not be possible + * to send it yet if we are blocked for output and + * our input buffer is full. + */ + if (rcvcnt < sizeof(rcvbuf)) { + n = read(rem, rcvbuf + rcvcnt, + sizeof(rcvbuf) - rcvcnt); + if (n <= 0) + return; + rcvd += n; + } else { + n = read(rem, waste, sizeof(waste)); + if (n <= 0) + return; + } + continue; + default: + return; } - recv(rem, &mark, 1, SOF_OOB); - if (mark & TIOCPKT_NOSTOP) { - notchars.t_stopc = -1; - notchars.t_startc = -1; - ioctl(0, TIOCSETC, (char *)¬chars); + if (mark & TIOCPKT_WINDOW) { + /* Let server know about window size changes */ + (void)kill(ppid, SIGUSR1); } - if (mark & TIOCPKT_DOSTOP) { - notchars.t_stopc = CTRL(s); - notchars.t_startc = CTRL(q); - ioctl(0, TIOCSETC, (char *)¬chars); + if (!eight && (mark & TIOCPKT_NOSTOP)) { + (void)ioctl(0, TIOCGETP, (char *)&sb); + sb.sg_flags &= ~CBREAK; + sb.sg_flags |= RAW; + (void)ioctl(0, TIOCSETN, (char *)&sb); + notc.t_stopc = -1; + notc.t_startc = -1; + (void)ioctl(0, TIOCSETC, (char *)¬c); } + if (!eight && (mark & TIOCPKT_DOSTOP)) { + (void)ioctl(0, TIOCGETP, (char *)&sb); + sb.sg_flags &= ~RAW; + sb.sg_flags |= CBREAK; + (void)ioctl(0, TIOCSETN, (char *)&sb); + notc.t_stopc = deftc.t_stopc; + notc.t_startc = deftc.t_startc; + (void)ioctl(0, TIOCSETC, (char *)¬c); + } + if (mark & TIOCPKT_FLUSHWRITE) { + (void)ioctl(1, TIOCFLUSH, (char *)&out); + for (;;) { + if (ioctl(rem, SIOCATMARK, &atmark) < 0) { + (void)fprintf(stderr, "rlogin: ioctl: %s.\n", + strerror(errno)); + break; + } + if (atmark) + break; + n = read(rem, waste, sizeof (waste)); + if (n <= 0) + break; + } + /* + * Don't want any pending data to be output, so clear the recv + * buffer. If we were hanging on a write when interrupted, + * don't want it to restart. If we were reading, restart + * anyway. + */ + rcvcnt = 0; + longjmp(rcvtop, 1); + } + + /* oob does not do FLUSHREAD (alas!) */ + + /* + * If we filled the receive buffer while a read was pending, longjmp + * to the top to restart appropriately. Don't abort a pending write, + * however, or we won't know how much was written. + */ + if (rcvd && rcvstate == READING) + longjmp(rcvtop, 1); } -/* - * reader: read from remote: line -> 1 - */ -reader() +/* reader: read from remote: line -> 1 */ +reader(omask) + int omask; { - char rb[BUFSIZ]; - register int cnt; + void oob(); - signal(SIGURG, oob); -#ifdef notdef - { int pid = -getpid(); - ioctl(rem, SIOCSPGRP, (char *)&pid); } +#if !defined(BSD) || BSD < 43 + int pid = -getpid(); +#else + int pid = getpid(); #endif + int n, remaining; + char *bufp = rcvbuf; + + (void)signal(SIGTTOU, SIG_IGN); + (void)signal(SIGURG, oob); + ppid = getppid(); + (void)fcntl(rem, F_SETOWN, pid); + (void)setjmp(rcvtop); + (void)sigsetmask(omask); for (;;) { - cnt = read(rem, rb, sizeof (rb)); - if (cnt <= 0) { + while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { + rcvstate = WRITING; + n = write(STDOUT_FILENO, bufp, remaining); + if (n < 0) { + if (errno != EINTR) + return(-1); + continue; + } + bufp += n; + } + bufp = rcvbuf; + rcvcnt = 0; + rcvstate = READING; + + rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); + if (rcvcnt == 0) + return (0); + if (rcvcnt < 0) { if (errno == EINTR) continue; - break; + (void)fprintf(stderr, "rlogin: read: %s.\n", + strerror(errno)); + return(-1); } - write(1, rb, cnt); } } mode(f) { - struct sgttyb stbuf; - - ioctl(0, TIOCGETP, (char *)&stbuf); - if (f == 0) { - stbuf.sg_flags &= ~CBREAK; - stbuf.sg_flags |= defflags; - ioctl(0, TIOCSETC, (char *)&deftchars); - ioctl(0, TIOCSLTC, (char *)&defltchars); - stbuf.sg_kill = defkill; - stbuf.sg_erase = deferase; - } - if (f == 1) { - stbuf.sg_flags |= CBREAK; - stbuf.sg_flags &= ~(ECHO|CRMOD); - ioctl(0, TIOCSETC, (char *)¬chars); - ioctl(0, TIOCSLTC, (char *)&noltchars); - stbuf.sg_kill = -1; - stbuf.sg_erase = -1; - } - if (f == 2) { - stbuf.sg_flags &= ~CBREAK; - stbuf.sg_flags &= ~(ECHO|CRMOD); - ioctl(0, TIOCSETC, (char *)&deftchars); - ioctl(0, TIOCSLTC, (char *)&defltchars); - stbuf.sg_kill = -1; - stbuf.sg_erase = -1; + struct ltchars *ltc; + struct sgttyb sb; + struct tchars *tc; + int lflags; + + (void)ioctl(0, TIOCGETP, (char *)&sb); + (void)ioctl(0, TIOCLGET, (char *)&lflags); + switch(f) { + case 0: + sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); + sb.sg_flags |= defflags|tabflag; + tc = &deftc; + ltc = &defltc; + sb.sg_kill = defkill; + sb.sg_erase = deferase; + lflags = deflflags; + break; + case 1: + sb.sg_flags |= (eight ? RAW : CBREAK); + sb.sg_flags &= ~defflags; + /* preserve tab delays, but turn off XTABS */ + if ((sb.sg_flags & TBDELAY) == XTABS) + sb.sg_flags &= ~TBDELAY; + tc = ¬c; + ltc = &noltc; + sb.sg_kill = sb.sg_erase = -1; + if (litout) + lflags |= LLITOUT; + break; + default: + return; } - ioctl(0, TIOCSETN, (char *)&stbuf); + (void)ioctl(0, TIOCSLTC, (char *)ltc); + (void)ioctl(0, TIOCSETC, (char *)tc); + (void)ioctl(0, TIOCSETN, (char *)&sb); + (void)ioctl(0, TIOCLSET, (char *)&lflags); } -/*VARARGS*/ -prf(f, a1, a2, a3) - char *f; +void +lostpeer() { - fprintf(stderr, f, a1, a2, a3); - fprintf(stderr, CRLF); + (void)signal(SIGPIPE, SIG_IGN); + msg("\007connection closed."); + done(1); } -lostpeer() +/* copy SIGURGs to the child process. */ +void +copytochild() +{ + (void)kill(child, SIGURG); +} + +msg(str) + char *str; { - signal(SIGPIPE, SIG_IGN); - prf("\007Lost connection"); - done(); + (void)fprintf(stderr, "rlogin: %s\r\n", str); +} + +#ifdef KERBEROS +/* VARARGS */ +warning(va_alist) +va_dcl +{ + va_list ap; + char *fmt; + + (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); + va_start(ap); + fmt = va_arg(ap, char *); + vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, ".\n"); +} +#endif + +usage() +{ + (void)fprintf(stderr, + "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", +#ifdef KERBEROS + "8EKL", " [-k realm] "); +#else + "8EL", " "); +#endif + exit(1); +} + +/* + * The following routine provides compatibility (such as it is) between 4.2BSD + * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. + */ +#ifdef sun +get_window_size(fd, wp) + int fd; + struct winsize *wp; +{ + struct ttysize ts; + int error; + + if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) + return(error); + wp->ws_row = ts.ts_lines; + wp->ws_col = ts.ts_cols; + wp->ws_xpixel = 0; + wp->ws_ypixel = 0; + return(0); +} +#endif + +u_char +getescape(p) + register char *p; +{ + long val; + int len; + + if ((len = strlen(p)) == 1) /* use any single char, including '\' */ + return((u_char)*p); + /* otherwise, \nnn */ + if (*p == '\\' && len >= 2 && len <= 4) { + val = strtol(++p, (char **)NULL, 8); + for (;;) { + if (!*++p) + return((u_char)val); + if (*p < '0' || *p > '8') + break; + } + } + msg("illegal option value -- e"); + usage(); + /* NOTREACHED */ }