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