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