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