Annotation of src/usr.bin/rlogin/rlogin.c, Revision 1.30
1.30 ! millert 1: /* $OpenBSD: rlogin.c,v 1.29 2002/02/17 19:42:31 millert Exp $ */
1.1 deraadt 2: /* $NetBSD: rlogin.c,v 1.8 1995/10/05 09:07:22 mycroft Exp $ */
3:
4: /*
5: * Copyright (c) 1983, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
38: static char copyright[] =
39: "@(#) Copyright (c) 1983, 1990, 1993\n\
40: The Regents of the University of California. All rights reserved.\n";
41: #endif /* not lint */
42:
43: #ifndef lint
44: #if 0
45: static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
46: #else
1.30 ! millert 47: static char rcsid[] = "$OpenBSD: rlogin.c,v 1.29 2002/02/17 19:42:31 millert Exp $";
1.1 deraadt 48: #endif
49: #endif /* not lint */
50:
51: /*
52: * rlogin - remote login
53: */
54: #include <sys/param.h>
55: #include <sys/ioctl.h>
56: #include <sys/socket.h>
57: #include <sys/time.h>
58: #include <sys/resource.h>
59: #include <sys/wait.h>
60:
61: #include <netinet/in.h>
62: #include <netinet/in_systm.h>
63: #include <netinet/ip.h>
64:
65: #include <errno.h>
66: #include <fcntl.h>
67: #include <netdb.h>
68: #include <pwd.h>
69: #include <setjmp.h>
70: #include <termios.h>
71: #include <signal.h>
72: #include <stdio.h>
73: #include <stdlib.h>
74: #include <string.h>
75: #include <unistd.h>
76: #include <stdarg.h>
77:
78: #ifdef KERBEROS
1.14 provos 79: #include <des.h>
1.1 deraadt 80: #include <kerberosIV/krb.h>
81:
82: CREDENTIALS cred;
1.9 mickey 83: des_key_schedule schedule;
1.1 deraadt 84: int use_kerberos = 1, doencrypt;
85: char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
1.19 art 86:
1.28 millert 87: int des_read(int, char *, int);
88: int des_write(int, char *, int);
1.19 art 89:
1.28 millert 90: int krcmd(char **, u_short, char *, char *, int *, char *);
1.29 millert 91: int krcmd_mutual(char **, u_short, char *, char *, int *, char *,
92: CREDENTIALS *, Key_schedule);
1.1 deraadt 93: #endif
94:
95: #ifndef TIOCPKT_WINDOW
96: #define TIOCPKT_WINDOW 0x80
97: #endif
98:
99: /* concession to Sun */
100: #ifndef SIGUSR1
101: #define SIGUSR1 30
102: #endif
103:
104: #ifndef CCEQ
105: #define CCEQ(val, c) (c == val ? val != _POSIX_VDISABLE : 0)
106: #endif
107:
108: int eight, rem;
109: struct termios deftty;
110:
111: int noescape;
112: u_char escapechar = '~';
113:
114: #ifdef OLDSUN
115: struct winsize {
116: unsigned short ws_row, ws_col;
117: unsigned short ws_xpixel, ws_ypixel;
118: };
119: #else
120: #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
121: #endif
122: struct winsize winsize;
123:
1.28 millert 124: void catch_child(int);
125: void copytochild(int);
126: __dead void doit(sigset_t *);
127: __dead void done(int);
128: __dead void sig_done(int);
129: void echo(char);
130: u_int getescape(char *);
131: void lostpeer(int);
132: void mode(int);
133: void msg(char *);
134: void oob(int);
135: int reader(sigset_t *);
136: void sendwindow(void);
137: void setsignal(int);
138: void sigwinch(int);
139: void stop(int);
140: __dead void usage(void) __attribute__((__noreturn__));
141: void writer(void);
142: void writeroob(int);
1.1 deraadt 143:
144: #ifdef KERBEROS
1.28 millert 145: void warning(const char *, ...);
146: void desrw_set_key(des_cblock *, des_key_schedule *);
1.1 deraadt 147: #endif
148: #ifdef OLDSUN
1.28 millert 149: int get_window_size(int, struct winsize *);
1.1 deraadt 150: #endif
151:
152: int
153: main(argc, argv)
154: int argc;
155: char *argv[];
156: {
157: extern char *optarg;
158: extern int optind;
159: struct passwd *pw;
160: struct servent *sp;
161: struct termios tty;
1.24 millert 162: sigset_t mask, omask;
1.1 deraadt 163: int argoff, ch, dflag, one, uid;
1.5 deraadt 164: char *host, *p, *user, term[64];
1.22 itojun 165: struct sockaddr_storage ss;
166: socklen_t sslen;
1.1 deraadt 167:
168: argoff = dflag = 0;
169: one = 1;
170: host = user = NULL;
171:
1.17 deraadt 172: if ((p = strrchr(argv[0], '/')))
1.1 deraadt 173: ++p;
174: else
175: p = argv[0];
176:
177: if (strcmp(p, "rlogin"))
178: host = p;
179:
180: /* handle "rlogin host flags" */
181: if (!host && argc > 2 && argv[1][0] != '-') {
182: host = argv[1];
183: argoff = 1;
184: }
185:
186: #ifdef KERBEROS
187: #define OPTIONS "8EKLde:k:l:x"
188: #else
189: #define OPTIONS "8EKLde:l:"
190: #endif
1.11 millert 191: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 192: switch(ch) {
193: case '8':
194: eight = 1;
195: break;
196: case 'E':
197: noescape = 1;
198: break;
199: case 'K':
200: #ifdef KERBEROS
201: use_kerberos = 0;
202: #endif
203: break;
204: case 'd':
205: dflag = 1;
206: break;
207: case 'e':
208: noescape = 0;
209: escapechar = getescape(optarg);
210: break;
211: #ifdef KERBEROS
212: case 'k':
1.23 jasoni 213: (void)strlcpy(dst_realm_buf, optarg,
214: sizeof(dst_realm_buf));
1.1 deraadt 215: dest_realm = dst_realm_buf;
216: break;
217: #endif
218: case 'l':
219: user = optarg;
220: break;
221: #ifdef KERBEROS
222: case 'x':
223: doencrypt = 1;
1.9 mickey 224: desrw_set_key(&cred.session, &schedule);
1.1 deraadt 225: break;
226: #endif
227: case '?':
228: default:
229: usage();
230: }
231: optind += argoff;
232: argc -= optind;
233: argv += optind;
234:
235: /* if haven't gotten a host yet, do so */
236: if (!host && !(host = *argv++))
237: usage();
238:
239: if (*argv)
240: usage();
241:
242: if (!(pw = getpwuid(uid = getuid()))) {
243: (void)fprintf(stderr, "rlogin: unknown user id.\n");
244: exit(1);
245: }
246: if (!user)
247: user = pw->pw_name;
248:
249: sp = NULL;
250: #ifdef KERBEROS
251: if (use_kerberos) {
252: sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
253: if (sp == NULL) {
254: use_kerberos = 0;
255: warning("can't get entry for %s/tcp service",
256: doencrypt ? "eklogin" : "klogin");
257: }
258: }
259: #endif
260: if (sp == NULL)
261: sp = getservbyname("login", "tcp");
262: if (sp == NULL) {
263: (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
264: exit(1);
265: }
266:
1.23 jasoni 267: (void)strlcpy(term, (p = getenv("TERM")) ? p : "network",
268: sizeof(term));
1.4 deraadt 269:
270: /*
271: * Add "/baud" only if there is room left; ie. do not send "/19"
272: * for 19200 baud with a particularily long $TERM
273: */
1.1 deraadt 274: if (tcgetattr(0, &tty) == 0) {
1.4 deraadt 275: char baud[20]; /* more than enough.. */
276:
277: (void)sprintf(baud, "/%d", cfgetospeed(&tty));
278: if (strlen(term) + strlen(baud) < sizeof(term) - 1)
279: (void)strcat(term, baud);
1.1 deraadt 280: }
281:
282: (void)get_window_size(0, &winsize);
283:
284: (void)signal(SIGPIPE, lostpeer);
285: /* will use SIGUSR1 for window size hack, so hold it off */
1.24 millert 286: sigemptyset(&mask);
287: sigaddset(&mask, SIGURG);
288: sigaddset(&mask, SIGUSR1);
289: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 290: /*
291: * We set SIGURG and SIGUSR1 below so that an
292: * incoming signal will be held pending rather than being
293: * discarded. Note that these routines will be ready to get
294: * a signal by the time that they are unblocked below.
295: */
296: (void)signal(SIGURG, copytochild);
297: (void)signal(SIGUSR1, writeroob);
298:
299: #ifdef KERBEROS
300: try_connect:
301: if (use_kerberos) {
302: struct hostent *hp;
303:
304: /* Fully qualify hostname (needed for krb_realmofhost). */
305: hp = gethostbyname(host);
306: if (hp != NULL && !(host = strdup(hp->h_name))) {
307: (void)fprintf(stderr, "rlogin: %s\n",
308: strerror(ENOMEM));
309: exit(1);
310: }
311:
312: rem = KSUCCESS;
313: errno = 0;
314: if (dest_realm == NULL)
315: dest_realm = krb_realmofhost(host);
316:
317: if (doencrypt)
318: rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
319: dest_realm, &cred, schedule);
320: else
321: rem = krcmd(&host, sp->s_port, user, term, 0,
322: dest_realm);
323: if (rem < 0) {
324: use_kerberos = 0;
325: sp = getservbyname("login", "tcp");
326: if (sp == NULL) {
327: (void)fprintf(stderr,
328: "rlogin: unknown service login/tcp.\n");
329: exit(1);
330: }
331: if (errno == ECONNREFUSED)
332: warning("remote host doesn't support Kerberos");
333: if (errno == ENOENT)
334: warning("can't provide Kerberos auth data");
335: goto try_connect;
336: }
337: } else {
338: if (doencrypt) {
339: (void)fprintf(stderr,
340: "rlogin: the -x flag requires Kerberos authentication.\n");
341: exit(1);
342: }
1.22 itojun 343: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, term, 0,
344: PF_UNSPEC);
1.1 deraadt 345: }
346: #else
1.22 itojun 347: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, term, 0, PF_UNSPEC);
1.1 deraadt 348: #endif /* KERBEROS */
349:
350: if (rem < 0)
351: exit(1);
352:
353: if (dflag &&
354: setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
355: (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
356: strerror(errno));
1.22 itojun 357:
358: sslen = sizeof(ss);
359: if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 &&
360: ss.ss_family == AF_INET) {
361: one = IPTOS_LOWDELAY;
362: if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one,
363: sizeof(int)) < 0)
364: perror("rlogin: setsockopt TOS (ignored)");
365: }
1.1 deraadt 366:
1.10 tholo 367: (void)seteuid(uid);
1.1 deraadt 368: (void)setuid(uid);
1.24 millert 369: doit(&omask);
1.1 deraadt 370: /*NOTREACHED*/
1.19 art 371:
372: return 0;
1.1 deraadt 373: }
374:
1.17 deraadt 375: pid_t child;
1.1 deraadt 376:
377: void
378: doit(omask)
1.24 millert 379: sigset_t *omask;
1.1 deraadt 380: {
1.17 deraadt 381: struct sigaction sa;
1.1 deraadt 382:
383: (void)signal(SIGINT, SIG_IGN);
384: setsignal(SIGHUP);
385: setsignal(SIGQUIT);
386: mode(1);
387: child = fork();
388: if (child == -1) {
389: (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
390: done(1);
391: }
392: if (child == 0) {
1.17 deraadt 393: (void)signal(SIGCHLD, SIG_DFL);
1.1 deraadt 394: if (reader(omask) == 0) {
395: msg("connection closed.");
396: exit(0);
397: }
398: sleep(1);
1.17 deraadt 399:
1.18 kstailey 400: msg("\aconnection closed.");
401: exit(1);
402: }
403:
1.17 deraadt 404: /*
405: * Use sigaction() instead of signal() to avoid getting SIGCHLDs
406: * for stopped children.
407: */
1.20 deraadt 408: memset(&sa, 0, sizeof sa);
1.17 deraadt 409: sigemptyset(&sa.sa_mask);
410: sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
411: sa.sa_handler = catch_child;
412: (void)sigaction(SIGCHLD, &sa, NULL);
1.1 deraadt 413:
414: /*
415: * We may still own the socket, and may have a pending SIGURG (or might
416: * receive one soon) that we really want to send to the reader. When
417: * one of these comes in, the trap copytochild simply copies such
418: * signals to the child. We can now unblock SIGURG and SIGUSR1
419: * that were set above.
420: */
1.24 millert 421: (void)sigprocmask(SIG_SETMASK, omask, NULL);
1.1 deraadt 422: writer();
423: msg("closed connection.");
424: done(0);
425: }
426:
427: /* trap a signal, unless it is being ignored. */
428: void
429: setsignal(sig)
430: int sig;
431: {
1.24 millert 432: sigset_t mask, omask;
433:
434: sigemptyset(&mask);
435: sigaddset(&mask, sig);
436: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 437:
438: if (signal(sig, exit) == SIG_IGN)
439: (void)signal(sig, SIG_IGN);
1.24 millert 440:
441: sigprocmask(SIG_SETMASK, &omask, NULL);
1.1 deraadt 442: }
443:
444: __dead void
445: done(status)
446: int status;
447: {
448: int w, wstatus;
449:
450: mode(0);
451: if (child > 0) {
452: /* make sure catch_child does not snap it up */
453: (void)signal(SIGCHLD, SIG_DFL);
454: if (kill(child, SIGKILL) >= 0)
1.17 deraadt 455: while ((w = wait(&wstatus)) > 0 && w != child)
456: ;
1.1 deraadt 457: }
458: exit(status);
459: }
460:
1.26 deraadt 461: __dead void
462: sig_done(status)
463: int status;
464: {
465: int w, wstatus;
466:
467: mode(0);
468: if (child > 0) {
469: /* make sure catch_child does not snap it up */
470: (void)signal(SIGCHLD, SIG_DFL);
471: if (kill(child, SIGKILL) >= 0)
472: while ((w = wait(&wstatus)) > 0 && w != child)
473: ;
474: }
475: _exit(status);
476: }
477:
1.1 deraadt 478: int dosigwinch;
479:
480: /*
481: * This is called when the reader process gets the out-of-band (urgent)
482: * request to turn on the window-changing protocol.
483: */
484: void
485: writeroob(signo)
486: int signo;
487: {
488: if (dosigwinch == 0) {
489: sendwindow();
490: (void)signal(SIGWINCH, sigwinch);
491: }
492: dosigwinch = 1;
493: }
494:
495: void
496: catch_child(signo)
497: int signo;
498: {
1.16 deraadt 499: int save_errno = errno;
1.17 deraadt 500: int status;
501: pid_t pid;
1.1 deraadt 502:
503: for (;;) {
1.17 deraadt 504: pid = wait3(&status, WNOHANG, NULL);
1.1 deraadt 505: if (pid == 0)
1.16 deraadt 506: break;
1.1 deraadt 507: /* if the child (reader) dies, just quit */
1.17 deraadt 508: if (pid == child && !WIFSTOPPED(status)) {
509: child = -1;
510: if (WIFEXITED(status))
1.26 deraadt 511: sig_done(WEXITSTATUS(status));
512: sig_done(WTERMSIG(status));
1.17 deraadt 513: }
1.1 deraadt 514: }
1.16 deraadt 515: errno = save_errno;
1.1 deraadt 516: }
517:
518: /*
519: * writer: write to remote: 0 -> line.
520: * ~. terminate
521: * ~^Z suspend rlogin process.
522: * ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
523: */
524: void
525: writer()
526: {
1.27 mpech 527: int bol, local, n;
1.1 deraadt 528: char c;
529:
530: bol = 1; /* beginning of line */
531: local = 0;
532: for (;;) {
533: n = read(STDIN_FILENO, &c, 1);
534: if (n <= 0) {
535: if (n < 0 && errno == EINTR)
536: continue;
537: break;
538: }
539: /*
540: * If we're at the beginning of the line and recognize a
541: * command character, then we echo locally. Otherwise,
542: * characters are echo'd remotely. If the command character
543: * is doubled, this acts as a force and local echo is
544: * suppressed.
545: */
546: if (bol) {
547: bol = 0;
548: if (!noescape && c == escapechar) {
549: local = 1;
550: continue;
551: }
552: } else if (local) {
553: local = 0;
554: if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) {
555: echo(c);
556: break;
557: }
558: if (CCEQ(deftty.c_cc[VSUSP], c)) {
559: bol = 1;
560: echo(c);
561: stop(1);
562: continue;
563: }
564: if (CCEQ(deftty.c_cc[VDSUSP], c)) {
565: bol = 1;
566: echo(c);
567: stop(0);
568: continue;
569: }
1.19 art 570: if (c != escapechar) {
1.1 deraadt 571: #ifdef KERBEROS
572: if (doencrypt)
573: (void)des_write(rem,
574: (char *)&escapechar, 1);
575: else
576: #endif
577: (void)write(rem, &escapechar, 1);
1.19 art 578: }
1.1 deraadt 579: }
580:
581: #ifdef KERBEROS
582: if (doencrypt) {
583: if (des_write(rem, &c, 1) == 0) {
584: msg("line gone");
585: break;
586: }
587: } else
588: #endif
589: if (write(rem, &c, 1) == 0) {
590: msg("line gone");
591: break;
592: }
593: bol = CCEQ(deftty.c_cc[VKILL], c) ||
594: CCEQ(deftty.c_cc[VEOF], c) ||
595: CCEQ(deftty.c_cc[VINTR], c) ||
596: CCEQ(deftty.c_cc[VSUSP], c) ||
597: c == '\r' || c == '\n';
598: }
599: }
600:
601: void
1.27 mpech 602: echo(char c)
1.1 deraadt 603: {
1.27 mpech 604: char *p;
1.1 deraadt 605: char buf[8];
606:
607: p = buf;
608: c &= 0177;
609: *p++ = escapechar;
610: if (c < ' ') {
611: *p++ = '^';
612: *p++ = c + '@';
613: } else if (c == 0177) {
614: *p++ = '^';
615: *p++ = '?';
616: } else
617: *p++ = c;
618: *p++ = '\r';
619: *p++ = '\n';
620: (void)write(STDOUT_FILENO, buf, p - buf);
621: }
622:
623: void
624: stop(all)
625: int all;
626: {
627: mode(0);
628: (void)kill(all ? 0 : getpid(), SIGTSTP);
629: mode(1);
630: sigwinch(0); /* check for size changes */
631: }
632:
633: void
634: sigwinch(signo)
635: int signo;
636: {
637: struct winsize ws;
638:
639: if (dosigwinch && get_window_size(0, &ws) == 0 &&
640: bcmp(&ws, &winsize, sizeof(ws))) {
641: winsize = ws;
642: sendwindow();
643: }
644: }
645:
646: /*
647: * Send the window size to the server via the magic escape
648: */
649: void
650: sendwindow()
651: {
652: struct winsize *wp;
653: char obuf[4 + sizeof (struct winsize)];
654:
655: wp = (struct winsize *)(obuf+4);
656: obuf[0] = 0377;
657: obuf[1] = 0377;
658: obuf[2] = 's';
659: obuf[3] = 's';
660: wp->ws_row = htons(winsize.ws_row);
661: wp->ws_col = htons(winsize.ws_col);
662: wp->ws_xpixel = htons(winsize.ws_xpixel);
663: wp->ws_ypixel = htons(winsize.ws_ypixel);
664:
665: #ifdef KERBEROS
666: if(doencrypt)
667: (void)des_write(rem, obuf, sizeof(obuf));
668: else
669: #endif
670: (void)write(rem, obuf, sizeof(obuf));
671: }
672:
673: /*
674: * reader: read from remote: line -> 1
675: */
676: #define READING 1
677: #define WRITING 2
678:
679: jmp_buf rcvtop;
1.17 deraadt 680: pid_t ppid;
681: int rcvcnt, rcvstate;
1.1 deraadt 682: char rcvbuf[8 * 1024];
683:
684: void
685: oob(signo)
686: int signo;
687: {
688: struct termios tty;
689: int atmark, n, rcvd;
1.16 deraadt 690: int save_errno = errno;
1.1 deraadt 691: char waste[BUFSIZ], mark;
692:
693: rcvd = 0;
694: while (recv(rem, &mark, 1, MSG_OOB) < 0) {
695: switch (errno) {
696: case EWOULDBLOCK:
697: /*
698: * Urgent data not here yet. It may not be possible
699: * to send it yet if we are blocked for output and
700: * our input buffer is full.
701: */
702: if (rcvcnt < sizeof(rcvbuf)) {
703: n = read(rem, rcvbuf + rcvcnt,
704: sizeof(rcvbuf) - rcvcnt);
1.16 deraadt 705: if (n <= 0) {
706: errno = save_errno;
1.1 deraadt 707: return;
1.16 deraadt 708: }
1.1 deraadt 709: rcvd += n;
710: } else {
711: n = read(rem, waste, sizeof(waste));
1.16 deraadt 712: if (n <= 0) {
713: errno = save_errno;
1.1 deraadt 714: return;
1.16 deraadt 715: }
1.1 deraadt 716: }
717: continue;
718: default:
1.16 deraadt 719: errno = save_errno;
1.1 deraadt 720: return;
721: }
722: }
1.25 art 723: if (mark & TIOCPKT_WINDOW && ppid > 1) {
1.1 deraadt 724: /* Let server know about window size changes */
725: (void)kill(ppid, SIGUSR1);
726: }
727: if (!eight && (mark & TIOCPKT_NOSTOP)) {
728: (void)tcgetattr(0, &tty);
729: tty.c_iflag &= ~IXON;
730: (void)tcsetattr(0, TCSANOW, &tty);
731: }
732: if (!eight && (mark & TIOCPKT_DOSTOP)) {
733: (void)tcgetattr(0, &tty);
734: tty.c_iflag |= (deftty.c_iflag & IXON);
735: (void)tcsetattr(0, TCSANOW, &tty);
736: }
737: if (mark & TIOCPKT_FLUSHWRITE) {
738: (void)tcflush(1, TCIOFLUSH);
739: for (;;) {
740: if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
741: (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
742: strerror(errno));
743: break;
744: }
745: if (atmark)
746: break;
747: n = read(rem, waste, sizeof (waste));
748: if (n <= 0)
749: break;
750: }
751: /*
752: * Don't want any pending data to be output, so clear the recv
753: * buffer. If we were hanging on a write when interrupted,
754: * don't want it to restart. If we were reading, restart
755: * anyway.
756: */
757: rcvcnt = 0;
758: longjmp(rcvtop, 1);
759: }
760:
761: /* oob does not do FLUSHREAD (alas!) */
762:
763: /*
764: * If we filled the receive buffer while a read was pending, longjmp
765: * to the top to restart appropriately. Don't abort a pending write,
766: * however, or we won't know how much was written.
767: */
768: if (rcvd && rcvstate == READING)
769: longjmp(rcvtop, 1);
1.16 deraadt 770: errno = save_errno;
1.1 deraadt 771: }
772:
773: /* reader: read from remote: line -> 1 */
774: int
775: reader(omask)
1.24 millert 776: sigset_t *omask;
1.1 deraadt 777: {
1.17 deraadt 778: pid_t pid;
779: int n, remaining;
1.1 deraadt 780: char *bufp;
781:
782: pid = getpid(); /* modern systems use positives for pid */
783: (void)signal(SIGTTOU, SIG_IGN);
784: (void)signal(SIGURG, oob);
785: ppid = getppid();
786: (void)fcntl(rem, F_SETOWN, pid);
787: (void)setjmp(rcvtop);
1.24 millert 788: (void)sigprocmask(SIG_SETMASK, omask, NULL);
1.1 deraadt 789: bufp = rcvbuf;
790: for (;;) {
791: while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
792: rcvstate = WRITING;
793: n = write(STDOUT_FILENO, bufp, remaining);
794: if (n < 0) {
795: if (errno != EINTR)
796: return (-1);
797: continue;
798: }
799: bufp += n;
800: }
801: bufp = rcvbuf;
802: rcvcnt = 0;
803: rcvstate = READING;
804:
805: #ifdef KERBEROS
806: if (doencrypt)
807: rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
808: else
809: #endif
810: rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
811: if (rcvcnt == 0)
812: return (0);
813: if (rcvcnt < 0) {
814: if (errno == EINTR)
815: continue;
816: (void)fprintf(stderr, "rlogin: read: %s.\n",
817: strerror(errno));
818: return (-1);
819: }
820: }
821: }
822:
823: void
824: mode(f)
825: int f;
826: {
827: struct termios tty;
828:
829: switch (f) {
830: case 0:
831: (void)tcsetattr(0, TCSANOW, &deftty);
832: break;
833: case 1:
834: (void)tcgetattr(0, &deftty);
835: tty = deftty;
836: /* This is loosely derived from sys/compat/tty_compat.c. */
837: tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
838: tty.c_iflag &= ~ICRNL;
839: tty.c_oflag &= ~OPOST;
1.7 deraadt 840: tty.c_cc[VMIN] = 1;
841: tty.c_cc[VTIME] = 0;
1.1 deraadt 842: if (eight) {
843: tty.c_iflag &= IXOFF;
844: tty.c_cflag &= ~(CSIZE|PARENB);
845: tty.c_cflag |= CS8;
846: }
847: (void)tcsetattr(0, TCSANOW, &tty);
848: break;
849: default:
850: return;
851: }
852: }
853:
854: void
855: lostpeer(signo)
856: int signo;
857: {
858: (void)signal(SIGPIPE, SIG_IGN);
859: msg("\aconnection closed.");
860: done(1);
861: }
862:
863: /* copy SIGURGs to the child process. */
864: void
865: copytochild(signo)
866: int signo;
867: {
1.16 deraadt 868: int save_errno = errno;
1.1 deraadt 869: (void)kill(child, SIGURG);
1.16 deraadt 870: errno = save_errno;
1.1 deraadt 871: }
872:
873: void
874: msg(str)
875: char *str;
876: {
877: (void)fprintf(stderr, "rlogin: %s\r\n", str);
878: }
879:
880: #ifdef KERBEROS
881: /* VARARGS */
882: void
883: warning(const char *fmt, ...)
884: {
1.8 tholo 885: char myrealm[REALM_SZ];
1.1 deraadt 886: va_list ap;
887:
1.8 tholo 888: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
889: return;
1.1 deraadt 890: (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
891: va_start(ap, fmt);
892: vfprintf(stderr, fmt, ap);
893: va_end(ap);
894: (void)fprintf(stderr, ".\n");
895: }
896: #endif
897:
898: __dead void
899: usage()
900: {
901: (void)fprintf(stderr,
902: "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
903: #ifdef KERBEROS
904: "8EKLx", " [-k realm] ");
905: #else
906: "8EL", " ");
907: #endif
908: exit(1);
909: }
910:
911: /*
912: * The following routine provides compatibility (such as it is) between older
913: * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
914: */
915: #ifdef OLDSUN
916: int
917: get_window_size(fd, wp)
918: int fd;
919: struct winsize *wp;
920: {
921: struct ttysize ts;
922: int error;
923:
924: if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
925: return (error);
926: wp->ws_row = ts.ts_lines;
927: wp->ws_col = ts.ts_cols;
928: wp->ws_xpixel = 0;
929: wp->ws_ypixel = 0;
930: return (0);
931: }
932: #endif
933:
934: u_int
935: getescape(p)
1.27 mpech 936: char *p;
1.1 deraadt 937: {
938: long val;
939: int len;
940:
941: if ((len = strlen(p)) == 1) /* use any single char, including '\' */
942: return ((u_int)*p);
943: /* otherwise, \nnn */
944: if (*p == '\\' && len >= 2 && len <= 4) {
945: val = strtol(++p, NULL, 8);
946: for (;;) {
947: if (!*++p)
948: return ((u_int)val);
949: if (*p < '0' || *p > '8')
950: break;
951: }
952: }
953: msg("illegal option value -- e");
954: usage();
955: /* NOTREACHED */
956: }