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