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