Annotation of src/usr.bin/rlogin/rlogin.c, Revision 1.3
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:
259: (void)strcpy(term, (p = getenv("TERM")) ? p : "network");
260: if (tcgetattr(0, &tty) == 0) {
261: (void)strcat(term, "/");
262: (void)sprintf(term + strlen(term), "%d", cfgetospeed(&tty));
263: }
264:
265: (void)get_window_size(0, &winsize);
266:
267: (void)signal(SIGPIPE, lostpeer);
268: /* will use SIGUSR1 for window size hack, so hold it off */
269: omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
270: /*
271: * We set SIGURG and SIGUSR1 below so that an
272: * incoming signal will be held pending rather than being
273: * discarded. Note that these routines will be ready to get
274: * a signal by the time that they are unblocked below.
275: */
276: (void)signal(SIGURG, copytochild);
277: (void)signal(SIGUSR1, writeroob);
278:
279: #ifdef KERBEROS
280: try_connect:
281: if (use_kerberos) {
282: struct hostent *hp;
283:
284: /* Fully qualify hostname (needed for krb_realmofhost). */
285: hp = gethostbyname(host);
286: if (hp != NULL && !(host = strdup(hp->h_name))) {
287: (void)fprintf(stderr, "rlogin: %s\n",
288: strerror(ENOMEM));
289: exit(1);
290: }
291:
292: rem = KSUCCESS;
293: errno = 0;
294: if (dest_realm == NULL)
295: dest_realm = krb_realmofhost(host);
296:
297: if (doencrypt)
298: rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
299: dest_realm, &cred, schedule);
300: else
301: rem = krcmd(&host, sp->s_port, user, term, 0,
302: dest_realm);
303: if (rem < 0) {
304: use_kerberos = 0;
305: sp = getservbyname("login", "tcp");
306: if (sp == NULL) {
307: (void)fprintf(stderr,
308: "rlogin: unknown service login/tcp.\n");
309: exit(1);
310: }
311: if (errno == ECONNREFUSED)
312: warning("remote host doesn't support Kerberos");
313: if (errno == ENOENT)
314: warning("can't provide Kerberos auth data");
315: goto try_connect;
316: }
317: } else {
318: if (doencrypt) {
319: (void)fprintf(stderr,
320: "rlogin: the -x flag requires Kerberos authentication.\n");
321: exit(1);
322: }
323: rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
324: }
325: #else
326: rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
327: #endif /* KERBEROS */
328:
329: if (rem < 0)
330: exit(1);
331:
332: if (dflag &&
333: setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
334: (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
335: strerror(errno));
336: one = IPTOS_LOWDELAY;
337: if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
338: perror("rlogin: setsockopt TOS (ignored)");
339:
340: (void)setuid(uid);
341: doit(omask);
342: /*NOTREACHED*/
343: }
344:
345: int child;
346:
347: void
348: doit(omask)
349: long omask;
350: {
351:
352: (void)signal(SIGINT, SIG_IGN);
353: setsignal(SIGHUP);
354: setsignal(SIGQUIT);
355: mode(1);
356: child = fork();
357: if (child == -1) {
358: (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
359: done(1);
360: }
361: if (child == 0) {
362: if (reader(omask) == 0) {
363: msg("connection closed.");
364: exit(0);
365: }
366: sleep(1);
367: msg("\aconnection closed.");
368: exit(1);
369: }
370:
371: /*
372: * We may still own the socket, and may have a pending SIGURG (or might
373: * receive one soon) that we really want to send to the reader. When
374: * one of these comes in, the trap copytochild simply copies such
375: * signals to the child. We can now unblock SIGURG and SIGUSR1
376: * that were set above.
377: */
378: (void)sigsetmask(omask);
379: (void)signal(SIGCHLD, catch_child);
380: writer();
381: msg("closed connection.");
382: done(0);
383: }
384:
385: /* trap a signal, unless it is being ignored. */
386: void
387: setsignal(sig)
388: int sig;
389: {
390: int omask = sigblock(sigmask(sig));
391:
392: if (signal(sig, exit) == SIG_IGN)
393: (void)signal(sig, SIG_IGN);
394: (void)sigsetmask(omask);
395: }
396:
397: __dead void
398: done(status)
399: int status;
400: {
401: int w, wstatus;
402:
403: mode(0);
404: if (child > 0) {
405: /* make sure catch_child does not snap it up */
406: (void)signal(SIGCHLD, SIG_DFL);
407: if (kill(child, SIGKILL) >= 0)
408: while ((w = wait(&wstatus)) > 0 && w != child);
409: }
410: exit(status);
411: }
412:
413: int dosigwinch;
414:
415: /*
416: * This is called when the reader process gets the out-of-band (urgent)
417: * request to turn on the window-changing protocol.
418: */
419: void
420: writeroob(signo)
421: int signo;
422: {
423: if (dosigwinch == 0) {
424: sendwindow();
425: (void)signal(SIGWINCH, sigwinch);
426: }
427: dosigwinch = 1;
428: }
429:
430: void
431: catch_child(signo)
432: int signo;
433: {
434: union wait status;
435: int pid;
436:
437: for (;;) {
438: pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
439: if (pid == 0)
440: return;
441: /* if the child (reader) dies, just quit */
442: if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
443: done((int)(status.w_termsig | status.w_retcode));
444: }
445: /* NOTREACHED */
446: }
447:
448: /*
449: * writer: write to remote: 0 -> line.
450: * ~. terminate
451: * ~^Z suspend rlogin process.
452: * ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
453: */
454: void
455: writer()
456: {
457: register int bol, local, n;
458: char c;
459:
460: bol = 1; /* beginning of line */
461: local = 0;
462: for (;;) {
463: n = read(STDIN_FILENO, &c, 1);
464: if (n <= 0) {
465: if (n < 0 && errno == EINTR)
466: continue;
467: break;
468: }
469: /*
470: * If we're at the beginning of the line and recognize a
471: * command character, then we echo locally. Otherwise,
472: * characters are echo'd remotely. If the command character
473: * is doubled, this acts as a force and local echo is
474: * suppressed.
475: */
476: if (bol) {
477: bol = 0;
478: if (!noescape && c == escapechar) {
479: local = 1;
480: continue;
481: }
482: } else if (local) {
483: local = 0;
484: if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) {
485: echo(c);
486: break;
487: }
488: if (CCEQ(deftty.c_cc[VSUSP], c)) {
489: bol = 1;
490: echo(c);
491: stop(1);
492: continue;
493: }
494: if (CCEQ(deftty.c_cc[VDSUSP], c)) {
495: bol = 1;
496: echo(c);
497: stop(0);
498: continue;
499: }
500: if (c != escapechar)
501: #ifdef KERBEROS
502: if (doencrypt)
503: (void)des_write(rem,
504: (char *)&escapechar, 1);
505: else
506: #endif
507: (void)write(rem, &escapechar, 1);
508: }
509:
510: #ifdef KERBEROS
511: if (doencrypt) {
512: if (des_write(rem, &c, 1) == 0) {
513: msg("line gone");
514: break;
515: }
516: } else
517: #endif
518: if (write(rem, &c, 1) == 0) {
519: msg("line gone");
520: break;
521: }
522: bol = CCEQ(deftty.c_cc[VKILL], c) ||
523: CCEQ(deftty.c_cc[VEOF], c) ||
524: CCEQ(deftty.c_cc[VINTR], c) ||
525: CCEQ(deftty.c_cc[VSUSP], c) ||
526: c == '\r' || c == '\n';
527: }
528: }
529:
530: void
531: #if __STDC__
532: echo(register char c)
533: #else
534: echo(c)
535: register char c;
536: #endif
537: {
538: register char *p;
539: char buf[8];
540:
541: p = buf;
542: c &= 0177;
543: *p++ = escapechar;
544: if (c < ' ') {
545: *p++ = '^';
546: *p++ = c + '@';
547: } else if (c == 0177) {
548: *p++ = '^';
549: *p++ = '?';
550: } else
551: *p++ = c;
552: *p++ = '\r';
553: *p++ = '\n';
554: (void)write(STDOUT_FILENO, buf, p - buf);
555: }
556:
557: void
558: stop(all)
559: int all;
560: {
561: mode(0);
562: (void)signal(SIGCHLD, SIG_IGN);
563: (void)kill(all ? 0 : getpid(), SIGTSTP);
564: (void)signal(SIGCHLD, catch_child);
565: mode(1);
566: sigwinch(0); /* check for size changes */
567: }
568:
569: void
570: sigwinch(signo)
571: int signo;
572: {
573: struct winsize ws;
574:
575: if (dosigwinch && get_window_size(0, &ws) == 0 &&
576: bcmp(&ws, &winsize, sizeof(ws))) {
577: winsize = ws;
578: sendwindow();
579: }
580: }
581:
582: /*
583: * Send the window size to the server via the magic escape
584: */
585: void
586: sendwindow()
587: {
588: struct winsize *wp;
589: char obuf[4 + sizeof (struct winsize)];
590:
591: wp = (struct winsize *)(obuf+4);
592: obuf[0] = 0377;
593: obuf[1] = 0377;
594: obuf[2] = 's';
595: obuf[3] = 's';
596: wp->ws_row = htons(winsize.ws_row);
597: wp->ws_col = htons(winsize.ws_col);
598: wp->ws_xpixel = htons(winsize.ws_xpixel);
599: wp->ws_ypixel = htons(winsize.ws_ypixel);
600:
601: #ifdef KERBEROS
602: if(doencrypt)
603: (void)des_write(rem, obuf, sizeof(obuf));
604: else
605: #endif
606: (void)write(rem, obuf, sizeof(obuf));
607: }
608:
609: /*
610: * reader: read from remote: line -> 1
611: */
612: #define READING 1
613: #define WRITING 2
614:
615: jmp_buf rcvtop;
616: int ppid, rcvcnt, rcvstate;
617: char rcvbuf[8 * 1024];
618:
619: void
620: oob(signo)
621: int signo;
622: {
623: struct termios tty;
624: int atmark, n, rcvd;
625: char waste[BUFSIZ], mark;
626:
627: rcvd = 0;
628: while (recv(rem, &mark, 1, MSG_OOB) < 0) {
629: switch (errno) {
630: case EWOULDBLOCK:
631: /*
632: * Urgent data not here yet. It may not be possible
633: * to send it yet if we are blocked for output and
634: * our input buffer is full.
635: */
636: if (rcvcnt < sizeof(rcvbuf)) {
637: n = read(rem, rcvbuf + rcvcnt,
638: sizeof(rcvbuf) - rcvcnt);
639: if (n <= 0)
640: return;
641: rcvd += n;
642: } else {
643: n = read(rem, waste, sizeof(waste));
644: if (n <= 0)
645: return;
646: }
647: continue;
648: default:
649: return;
650: }
651: }
652: if (mark & TIOCPKT_WINDOW) {
653: /* Let server know about window size changes */
654: (void)kill(ppid, SIGUSR1);
655: }
656: if (!eight && (mark & TIOCPKT_NOSTOP)) {
657: (void)tcgetattr(0, &tty);
658: tty.c_iflag &= ~IXON;
659: (void)tcsetattr(0, TCSANOW, &tty);
660: }
661: if (!eight && (mark & TIOCPKT_DOSTOP)) {
662: (void)tcgetattr(0, &tty);
663: tty.c_iflag |= (deftty.c_iflag & IXON);
664: (void)tcsetattr(0, TCSANOW, &tty);
665: }
666: if (mark & TIOCPKT_FLUSHWRITE) {
667: (void)tcflush(1, TCIOFLUSH);
668: for (;;) {
669: if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
670: (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
671: strerror(errno));
672: break;
673: }
674: if (atmark)
675: break;
676: n = read(rem, waste, sizeof (waste));
677: if (n <= 0)
678: break;
679: }
680: /*
681: * Don't want any pending data to be output, so clear the recv
682: * buffer. If we were hanging on a write when interrupted,
683: * don't want it to restart. If we were reading, restart
684: * anyway.
685: */
686: rcvcnt = 0;
687: longjmp(rcvtop, 1);
688: }
689:
690: /* oob does not do FLUSHREAD (alas!) */
691:
692: /*
693: * If we filled the receive buffer while a read was pending, longjmp
694: * to the top to restart appropriately. Don't abort a pending write,
695: * however, or we won't know how much was written.
696: */
697: if (rcvd && rcvstate == READING)
698: longjmp(rcvtop, 1);
699: }
700:
701: /* reader: read from remote: line -> 1 */
702: int
703: reader(omask)
704: int omask;
705: {
706: int pid, n, remaining;
707: char *bufp;
708:
709: #if BSD >= 43 || defined(SUNOS4)
710: pid = getpid(); /* modern systems use positives for pid */
711: #else
712: pid = -getpid(); /* old broken systems use negatives */
713: #endif
714: (void)signal(SIGTTOU, SIG_IGN);
715: (void)signal(SIGURG, oob);
716: ppid = getppid();
717: (void)fcntl(rem, F_SETOWN, pid);
718: (void)setjmp(rcvtop);
719: (void)sigsetmask(omask);
720: bufp = rcvbuf;
721: for (;;) {
722: while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
723: rcvstate = WRITING;
724: n = write(STDOUT_FILENO, bufp, remaining);
725: if (n < 0) {
726: if (errno != EINTR)
727: return (-1);
728: continue;
729: }
730: bufp += n;
731: }
732: bufp = rcvbuf;
733: rcvcnt = 0;
734: rcvstate = READING;
735:
736: #ifdef KERBEROS
737: if (doencrypt)
738: rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
739: else
740: #endif
741: rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
742: if (rcvcnt == 0)
743: return (0);
744: if (rcvcnt < 0) {
745: if (errno == EINTR)
746: continue;
747: (void)fprintf(stderr, "rlogin: read: %s.\n",
748: strerror(errno));
749: return (-1);
750: }
751: }
752: }
753:
754: void
755: mode(f)
756: int f;
757: {
758: struct termios tty;
759:
760: switch (f) {
761: case 0:
762: (void)tcsetattr(0, TCSANOW, &deftty);
763: break;
764: case 1:
765: (void)tcgetattr(0, &deftty);
766: tty = deftty;
767: /* This is loosely derived from sys/compat/tty_compat.c. */
768: tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
769: tty.c_iflag &= ~ICRNL;
770: tty.c_oflag &= ~OPOST;
771: if (eight) {
772: tty.c_iflag &= IXOFF;
773: tty.c_cflag &= ~(CSIZE|PARENB);
774: tty.c_cflag |= CS8;
775: }
776: (void)tcsetattr(0, TCSANOW, &tty);
777: break;
778: default:
779: return;
780: }
781: }
782:
783: void
784: lostpeer(signo)
785: int signo;
786: {
787: (void)signal(SIGPIPE, SIG_IGN);
788: msg("\aconnection closed.");
789: done(1);
790: }
791:
792: /* copy SIGURGs to the child process. */
793: void
794: copytochild(signo)
795: int signo;
796: {
797: (void)kill(child, SIGURG);
798: }
799:
800: void
801: msg(str)
802: char *str;
803: {
804: (void)fprintf(stderr, "rlogin: %s\r\n", str);
805: }
806:
807: #ifdef KERBEROS
808: /* VARARGS */
809: void
810: #if __STDC__
811: warning(const char *fmt, ...)
812: #else
813: warning(fmt, va_alist)
814: char *fmt;
815: va_dcl
816: #endif
817: {
818: va_list ap;
819:
820: (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
821: #ifdef __STDC__
822: va_start(ap, fmt);
823: #else
824: va_start(ap);
825: #endif
826: vfprintf(stderr, fmt, ap);
827: va_end(ap);
828: (void)fprintf(stderr, ".\n");
829: }
830: #endif
831:
832: __dead void
833: usage()
834: {
835: (void)fprintf(stderr,
836: "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
837: #ifdef KERBEROS
838: "8EKLx", " [-k realm] ");
839: #else
840: "8EL", " ");
841: #endif
842: exit(1);
843: }
844:
845: /*
846: * The following routine provides compatibility (such as it is) between older
847: * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
848: */
849: #ifdef OLDSUN
850: int
851: get_window_size(fd, wp)
852: int fd;
853: struct winsize *wp;
854: {
855: struct ttysize ts;
856: int error;
857:
858: if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
859: return (error);
860: wp->ws_row = ts.ts_lines;
861: wp->ws_col = ts.ts_cols;
862: wp->ws_xpixel = 0;
863: wp->ws_ypixel = 0;
864: return (0);
865: }
866: #endif
867:
868: u_int
869: getescape(p)
870: register char *p;
871: {
872: long val;
873: int len;
874:
875: if ((len = strlen(p)) == 1) /* use any single char, including '\' */
876: return ((u_int)*p);
877: /* otherwise, \nnn */
878: if (*p == '\\' && len >= 2 && len <= 4) {
879: val = strtol(++p, NULL, 8);
880: for (;;) {
881: if (!*++p)
882: return ((u_int)val);
883: if (*p < '0' || *p > '8')
884: break;
885: }
886: }
887: msg("illegal option value -- e");
888: usage();
889: /* NOTREACHED */
890: }