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