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