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