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