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