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