Annotation of src/usr.bin/rlogin/rlogin.c, Revision 1.11
1.11 ! millert 1: /* $OpenBSD: rlogin.c,v 1.10 1996/12/22 03:26:01 tholo 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.11 ! millert 47: static char rcsid[] = "$OpenBSD: rlogin.c,v 1.10 1996/12/22 03:26:01 tholo 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
84: #include <kerberosIV/des.h>
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));
124: __dead void doit __P((long));
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;
159: long omask;
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:
167: if (p = rindex(argv[0], '/'))
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)
362: long omask;
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;
448: int pid;
449:
450: for (;;) {
451: pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
452: if (pid == 0)
453: return;
454: /* if the child (reader) dies, just quit */
455: if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
456: done((int)(status.w_termsig | status.w_retcode));
457: }
458: /* NOTREACHED */
459: }
460:
461: /*
462: * writer: write to remote: 0 -> line.
463: * ~. terminate
464: * ~^Z suspend rlogin process.
465: * ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
466: */
467: void
468: writer()
469: {
470: register int bol, local, n;
471: char c;
472:
473: bol = 1; /* beginning of line */
474: local = 0;
475: for (;;) {
476: n = read(STDIN_FILENO, &c, 1);
477: if (n <= 0) {
478: if (n < 0 && errno == EINTR)
479: continue;
480: break;
481: }
482: /*
483: * If we're at the beginning of the line and recognize a
484: * command character, then we echo locally. Otherwise,
485: * characters are echo'd remotely. If the command character
486: * is doubled, this acts as a force and local echo is
487: * suppressed.
488: */
489: if (bol) {
490: bol = 0;
491: if (!noescape && c == escapechar) {
492: local = 1;
493: continue;
494: }
495: } else if (local) {
496: local = 0;
497: if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) {
498: echo(c);
499: break;
500: }
501: if (CCEQ(deftty.c_cc[VSUSP], c)) {
502: bol = 1;
503: echo(c);
504: stop(1);
505: continue;
506: }
507: if (CCEQ(deftty.c_cc[VDSUSP], c)) {
508: bol = 1;
509: echo(c);
510: stop(0);
511: continue;
512: }
513: if (c != escapechar)
514: #ifdef KERBEROS
515: if (doencrypt)
516: (void)des_write(rem,
517: (char *)&escapechar, 1);
518: else
519: #endif
520: (void)write(rem, &escapechar, 1);
521: }
522:
523: #ifdef KERBEROS
524: if (doencrypt) {
525: if (des_write(rem, &c, 1) == 0) {
526: msg("line gone");
527: break;
528: }
529: } else
530: #endif
531: if (write(rem, &c, 1) == 0) {
532: msg("line gone");
533: break;
534: }
535: bol = CCEQ(deftty.c_cc[VKILL], c) ||
536: CCEQ(deftty.c_cc[VEOF], c) ||
537: CCEQ(deftty.c_cc[VINTR], c) ||
538: CCEQ(deftty.c_cc[VSUSP], c) ||
539: c == '\r' || c == '\n';
540: }
541: }
542:
543: void
544: #if __STDC__
545: echo(register char c)
546: #else
547: echo(c)
548: register char c;
549: #endif
550: {
551: register char *p;
552: char buf[8];
553:
554: p = buf;
555: c &= 0177;
556: *p++ = escapechar;
557: if (c < ' ') {
558: *p++ = '^';
559: *p++ = c + '@';
560: } else if (c == 0177) {
561: *p++ = '^';
562: *p++ = '?';
563: } else
564: *p++ = c;
565: *p++ = '\r';
566: *p++ = '\n';
567: (void)write(STDOUT_FILENO, buf, p - buf);
568: }
569:
570: void
571: stop(all)
572: int all;
573: {
574: mode(0);
575: (void)signal(SIGCHLD, SIG_IGN);
576: (void)kill(all ? 0 : getpid(), SIGTSTP);
577: (void)signal(SIGCHLD, catch_child);
578: mode(1);
579: sigwinch(0); /* check for size changes */
580: }
581:
582: void
583: sigwinch(signo)
584: int signo;
585: {
586: struct winsize ws;
587:
588: if (dosigwinch && get_window_size(0, &ws) == 0 &&
589: bcmp(&ws, &winsize, sizeof(ws))) {
590: winsize = ws;
591: sendwindow();
592: }
593: }
594:
595: /*
596: * Send the window size to the server via the magic escape
597: */
598: void
599: sendwindow()
600: {
601: struct winsize *wp;
602: char obuf[4 + sizeof (struct winsize)];
603:
604: wp = (struct winsize *)(obuf+4);
605: obuf[0] = 0377;
606: obuf[1] = 0377;
607: obuf[2] = 's';
608: obuf[3] = 's';
609: wp->ws_row = htons(winsize.ws_row);
610: wp->ws_col = htons(winsize.ws_col);
611: wp->ws_xpixel = htons(winsize.ws_xpixel);
612: wp->ws_ypixel = htons(winsize.ws_ypixel);
613:
614: #ifdef KERBEROS
615: if(doencrypt)
616: (void)des_write(rem, obuf, sizeof(obuf));
617: else
618: #endif
619: (void)write(rem, obuf, sizeof(obuf));
620: }
621:
622: /*
623: * reader: read from remote: line -> 1
624: */
625: #define READING 1
626: #define WRITING 2
627:
628: jmp_buf rcvtop;
629: int ppid, rcvcnt, rcvstate;
630: char rcvbuf[8 * 1024];
631:
632: void
633: oob(signo)
634: int signo;
635: {
636: struct termios tty;
637: int atmark, n, rcvd;
638: char waste[BUFSIZ], mark;
639:
640: rcvd = 0;
641: while (recv(rem, &mark, 1, MSG_OOB) < 0) {
642: switch (errno) {
643: case EWOULDBLOCK:
644: /*
645: * Urgent data not here yet. It may not be possible
646: * to send it yet if we are blocked for output and
647: * our input buffer is full.
648: */
649: if (rcvcnt < sizeof(rcvbuf)) {
650: n = read(rem, rcvbuf + rcvcnt,
651: sizeof(rcvbuf) - rcvcnt);
652: if (n <= 0)
653: return;
654: rcvd += n;
655: } else {
656: n = read(rem, waste, sizeof(waste));
657: if (n <= 0)
658: return;
659: }
660: continue;
661: default:
662: return;
663: }
664: }
665: if (mark & TIOCPKT_WINDOW) {
666: /* Let server know about window size changes */
667: (void)kill(ppid, SIGUSR1);
668: }
669: if (!eight && (mark & TIOCPKT_NOSTOP)) {
670: (void)tcgetattr(0, &tty);
671: tty.c_iflag &= ~IXON;
672: (void)tcsetattr(0, TCSANOW, &tty);
673: }
674: if (!eight && (mark & TIOCPKT_DOSTOP)) {
675: (void)tcgetattr(0, &tty);
676: tty.c_iflag |= (deftty.c_iflag & IXON);
677: (void)tcsetattr(0, TCSANOW, &tty);
678: }
679: if (mark & TIOCPKT_FLUSHWRITE) {
680: (void)tcflush(1, TCIOFLUSH);
681: for (;;) {
682: if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
683: (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
684: strerror(errno));
685: break;
686: }
687: if (atmark)
688: break;
689: n = read(rem, waste, sizeof (waste));
690: if (n <= 0)
691: break;
692: }
693: /*
694: * Don't want any pending data to be output, so clear the recv
695: * buffer. If we were hanging on a write when interrupted,
696: * don't want it to restart. If we were reading, restart
697: * anyway.
698: */
699: rcvcnt = 0;
700: longjmp(rcvtop, 1);
701: }
702:
703: /* oob does not do FLUSHREAD (alas!) */
704:
705: /*
706: * If we filled the receive buffer while a read was pending, longjmp
707: * to the top to restart appropriately. Don't abort a pending write,
708: * however, or we won't know how much was written.
709: */
710: if (rcvd && rcvstate == READING)
711: longjmp(rcvtop, 1);
712: }
713:
714: /* reader: read from remote: line -> 1 */
715: int
716: reader(omask)
717: int omask;
718: {
719: int pid, n, remaining;
720: char *bufp;
721:
722: #if BSD >= 43 || defined(SUNOS4)
723: pid = getpid(); /* modern systems use positives for pid */
724: #else
725: pid = -getpid(); /* old broken systems use negatives */
726: #endif
727: (void)signal(SIGTTOU, SIG_IGN);
728: (void)signal(SIGURG, oob);
729: ppid = getppid();
730: (void)fcntl(rem, F_SETOWN, pid);
731: (void)setjmp(rcvtop);
732: (void)sigsetmask(omask);
733: bufp = rcvbuf;
734: for (;;) {
735: while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
736: rcvstate = WRITING;
737: n = write(STDOUT_FILENO, bufp, remaining);
738: if (n < 0) {
739: if (errno != EINTR)
740: return (-1);
741: continue;
742: }
743: bufp += n;
744: }
745: bufp = rcvbuf;
746: rcvcnt = 0;
747: rcvstate = READING;
748:
749: #ifdef KERBEROS
750: if (doencrypt)
751: rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
752: else
753: #endif
754: rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
755: if (rcvcnt == 0)
756: return (0);
757: if (rcvcnt < 0) {
758: if (errno == EINTR)
759: continue;
760: (void)fprintf(stderr, "rlogin: read: %s.\n",
761: strerror(errno));
762: return (-1);
763: }
764: }
765: }
766:
767: void
768: mode(f)
769: int f;
770: {
771: struct termios tty;
772:
773: switch (f) {
774: case 0:
775: (void)tcsetattr(0, TCSANOW, &deftty);
776: break;
777: case 1:
778: (void)tcgetattr(0, &deftty);
779: tty = deftty;
780: /* This is loosely derived from sys/compat/tty_compat.c. */
781: tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
782: tty.c_iflag &= ~ICRNL;
783: tty.c_oflag &= ~OPOST;
1.7 deraadt 784: tty.c_cc[VMIN] = 1;
785: tty.c_cc[VTIME] = 0;
1.1 deraadt 786: if (eight) {
787: tty.c_iflag &= IXOFF;
788: tty.c_cflag &= ~(CSIZE|PARENB);
789: tty.c_cflag |= CS8;
790: }
791: (void)tcsetattr(0, TCSANOW, &tty);
792: break;
793: default:
794: return;
795: }
796: }
797:
798: void
799: lostpeer(signo)
800: int signo;
801: {
802: (void)signal(SIGPIPE, SIG_IGN);
803: msg("\aconnection closed.");
804: done(1);
805: }
806:
807: /* copy SIGURGs to the child process. */
808: void
809: copytochild(signo)
810: int signo;
811: {
812: (void)kill(child, SIGURG);
813: }
814:
815: void
816: msg(str)
817: char *str;
818: {
819: (void)fprintf(stderr, "rlogin: %s\r\n", str);
820: }
821:
822: #ifdef KERBEROS
823: /* VARARGS */
824: void
825: #if __STDC__
826: warning(const char *fmt, ...)
827: #else
828: warning(fmt, va_alist)
829: char *fmt;
830: va_dcl
831: #endif
832: {
1.8 tholo 833: char myrealm[REALM_SZ];
1.1 deraadt 834: va_list ap;
835:
1.8 tholo 836: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
837: return;
1.1 deraadt 838: (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
839: #ifdef __STDC__
840: va_start(ap, fmt);
841: #else
842: va_start(ap);
843: #endif
844: vfprintf(stderr, fmt, ap);
845: va_end(ap);
846: (void)fprintf(stderr, ".\n");
847: }
848: #endif
849:
850: __dead void
851: usage()
852: {
853: (void)fprintf(stderr,
854: "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
855: #ifdef KERBEROS
856: "8EKLx", " [-k realm] ");
857: #else
858: "8EL", " ");
859: #endif
860: exit(1);
861: }
862:
863: /*
864: * The following routine provides compatibility (such as it is) between older
865: * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
866: */
867: #ifdef OLDSUN
868: int
869: get_window_size(fd, wp)
870: int fd;
871: struct winsize *wp;
872: {
873: struct ttysize ts;
874: int error;
875:
876: if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
877: return (error);
878: wp->ws_row = ts.ts_lines;
879: wp->ws_col = ts.ts_cols;
880: wp->ws_xpixel = 0;
881: wp->ws_ypixel = 0;
882: return (0);
883: }
884: #endif
885:
886: u_int
887: getescape(p)
888: register char *p;
889: {
890: long val;
891: int len;
892:
893: if ((len = strlen(p)) == 1) /* use any single char, including '\' */
894: return ((u_int)*p);
895: /* otherwise, \nnn */
896: if (*p == '\\' && len >= 2 && len <= 4) {
897: val = strtol(++p, NULL, 8);
898: for (;;) {
899: if (!*++p)
900: return ((u_int)val);
901: if (*p < '0' || *p > '8')
902: break;
903: }
904: }
905: msg("illegal option value -- e");
906: usage();
907: /* NOTREACHED */
908: }