6 * Copyright (c) 1983 The Regents of the University of California.
9 * Redistribution and use in source and binary forms are permitted
10 * provided that the above copyright notice and this paragraph are
11 * duplicated in all such forms and that any documentation,
12 * advertising materials, and other materials related to such
13 * distribution and use acknowledge that the software was developed
14 * by the University of California, Berkeley. The name of the
15 * University may not be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * Copyright (C) 1998 by the FundsXpress, INC.
25 * All rights reserved.
27 * Export of this software from the United States of America may require
28 * a specific license from the United States Government. It is the
29 * responsibility of any person or organization contemplating export to
30 * obtain such a license before exporting.
32 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
33 * distribute this software and its documentation for any purpose and
34 * without fee is hereby granted, provided that the above copyright
35 * notice appear in all copies and that both that copyright notice and
36 * this permission notice appear in supporting documentation, and that
37 * the name of FundsXpress. not be used in advertising or publicity pertaining
38 * to distribution of the software without specific, written prior
39 * permission. FundsXpress makes no representations about the suitability of
40 * this software for any purpose. It is provided "as is" without express
41 * or implied warranty.
43 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
51 All rights reserved.\n";
54 /* based on @(#)rlogin.c 5.12 (Berkeley) 9/19/88 */
58 * rlogin - remote login
69 #include <sys/types.h>
70 #include <sys/param.h>
71 #include <sys/ioctl.h>
72 #include <sys/errno.h>
74 #include <sys/socket.h>
76 #include <sys/resource.h>
80 #include <netinet/in.h>
90 #ifdef HAVE_SYS_FILIO_H
91 /* Solaris needs <sys/filio.h> for FIONREAD */
92 #include <sys/filio.h>
98 #ifdef HAVE_SYS_SELECT_H
99 #include <sys/select.h>
102 #include <sys/time.h>
108 #define CNUL (char) 0
111 #else /* POSIX_TERMIOS */
113 #endif /* POSIX_TERMIOS */
115 #ifdef HAVE_SYS_SOCKIO_H
117 #include <sys/sockio.h>
121 #include <sys/stream.h>
122 #include <sys/stropts.h>
128 /* for struct winsize */
129 #include <sys/ptem.h>
133 #ifdef HAVE_SYS_PTYVAR_H
135 #include <sys/ttold.h>
136 /* solaris actually uses packet mode, so the real macros are needed too */
137 #include <sys/ptyvar.h>
141 #ifndef TIOCPKT_NOSTOP
142 /* These values are over-the-wire protocol, *not* local values */
143 #define TIOCPKT_NOSTOP 0x10
144 #define TIOCPKT_DOSTOP 0x20
145 #define TIOCPKT_FLUSHWRITE 0x02
148 #ifdef HAVE_SYS_IOCTL_COMPAT_H
149 #include <sys/ioctl_compat.h>
153 #include <sys/ttold.h>
160 #ifdef KRB5_KRB4_COMPAT
161 #include <kerberosIV/krb.h>
165 #define RLOGIN_BUFSIZ 5120
168 char *krb_realm = (char *)0;
169 int encrypt_flag = 0;
170 int fflag = 0, Fflag = 0;
172 struct sockaddr_in local, foreign;
173 krb5_context bsd_context;
174 krb5_auth_context auth_context;
176 #ifdef KRB5_KRB4_COMPAT
177 Key_schedule v4_schedule;
182 #define UCB_RLOGIN "/usr/ucb/rlogin"
186 #endif /* KERBEROS */
188 # ifndef TIOCPKT_WINDOW
189 # define TIOCPKT_WINDOW 0x80
190 # endif /* TIOCPKT_WINDOW */
197 struct termios deftty;
203 int rem = -1; /* Remote socket fd */
206 int eight = 1; /* Default to 8 bit transmission */
207 int no_local_escape = 0;
208 int null_local_username = 0;
209 int flow = 1; /* Default is to allow flow
210 control at the local terminal */
211 int flowcontrol; /* Since emacs can alter the
212 flow control characteristics
213 of a session we need a
214 variable to keep track of
215 the original characteristics */
216 int confirm = 0; /* ask if ~. is given before dying. */
218 #if defined(hpux) || defined(__hpux)
220 { "0", "50", "75", "110", "134", "150", "200", "300", "600",
221 "900", "1200", "1800", "2400", "3600", "4800", "7200", "9600",
222 "19200", "38400", "EXTA", "EXTB" };
224 /* Solaris note: There are higher values we could use. But Casper Dik
225 <Casper.Dik@Holland.Sun.Com> mentions in article
226 <casper.938167062@uk-usenet.uk.sun.com> in comp.protocols.kerberos
227 on 1999-09-24 some problems in sending higher values to remote
228 systems (for non-Kerberos rlogind?). So let's stick with this
229 list. Even if our current klogind doesn't have the problems, older
230 versions are likely to.
232 Daniel S. Riley <dsr@mail.lns.cornell.edu> gives 57600, 76800,
233 115200, 153600, 230400, 307200, 460800 as the higher values.
234 (article <sh6711s713.fsf@lnscu4.lns.cornell.edu> in
235 comp.protocols.kerberos, 1999-09-23) */
237 { "0", "50", "75", "110", "134", "150", "200", "300",
238 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
240 char term[256] = "network";
242 #ifndef POSIX_SIGNALS
244 #define sigmask(m) (1 << ((m)-1))
246 #endif /* POSIX_SIGNALS */
250 unsigned short ws_row, ws_col;
251 unsigned short ws_xpixel, ws_ypixel;
253 #endif /* NO_WINSIZE */
255 struct winsize winsize;
257 char *host=0; /* external, so it can be
258 reached from confirm_death() */
260 krb5_sigtype sigwinch (int);
261 int server_message (int);
263 krb5_sigtype lostpeer (int);
264 void setsignal (int sig, krb5_sigtype (*act)());
265 static int read_wrapper(int fd, char *buf, int size, int *got_esc);
266 static void prf(char *f);
267 void try_normal(char **);
268 static void mode(int);
270 static int reader(sigset_t *);
271 static void doit(sigset_t *);
273 static int reader(int);
274 static void doit(int);
276 static int control(char *, unsigned int);
277 static void sendwindow(void);
278 static void stop(int), echo(int);
279 static void writer(void), done(int);
280 static int confirm_death (void);
283 /* to allow exits from signal handlers, without conflicting declarations */
284 static krb5_sigtype exit_handler() {
290 * The following routine provides compatibility (such as it is)
291 * between 4.2BSD Suns and others. Suns have only a `ttysize',
292 * so we convert it to a winsize.
295 #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
299 #define SIGWINCH SIGWINDOW
305 #define DEFAULT_LINES 24
306 #define DEFAULT_COLS 80
312 get_window_size(fd, wp)
320 ts.ts_lines = DEFAULT_LINES;
321 ts.ts_cols = DEFAULT_COLS;
322 if (( envbuf = getenv("LINES")) != (char *) 0)
323 ts.ts_lines = atoi(envbuf);
324 if (( envbuf = getenv("COLUMNS")) != (char *) 0)
325 ts.ts_cols = atoi(envbuf);
327 if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
331 wp->ws_row = ts.ts_lines;
332 wp->ws_col = ts.ts_cols;
337 #endif /* TIOCGWINSZ */
341 /* Globals for terminal modes and flow control */
342 struct termios defmodes;
343 struct termios ixon_state;
346 /* Globals for terminal modes and flow control */
347 struct termio defmodes;
348 struct termio ixon_state;
358 char *cp = (char *) NULL;
370 struct servent defaultservent;
371 int uid, options = 0;
374 sigset_t *oldmask, omask, urgmask;
380 char **orig_argv = argv;
383 krb5_error_code status;
384 #ifdef KRB5_KRB4_COMPAT
390 int port, debug_port = 0;
391 enum kcmd_proto kcmd_proto = KCMD_PROTOCOL_COMPAT_HACK;
393 memset(&defaultservent, 0, sizeof(struct servent));
394 if (strrchr(argv[0], '/'))
395 argv[0] = strrchr(argv[0], '/')+1;
397 if ( argc < 2 ) goto usage;
402 if (argc > 0 && host == 0 && strncmp(*argv, "-", 1)) {
408 if (argc > 0 && !strcmp(*argv, "-D")) {
412 "rlogin: -D flag must be followed by the debug port.\n");
415 debug_port = htons(atoi(*argv));
419 if (argc > 0 && !strcmp(*argv, "-d")) {
424 if (argc > 0 && !strcmp(*argv, "-c")) {
429 if (argc > 0 && !strcmp(*argv, "-a")) { /* ask -- make remote */
430 argv++; argc--; /* machine ask for password */
431 null_local_username = 1; /* by giving null local user */
432 goto another; /* id */
434 if (argc > 0 && !strcmp(*argv, "-t")) {
436 if (argc == 0) goto usage;
437 cp = *argv++; argc--;
440 if (argc > 0 && !strcmp(*argv, "-n")) {
445 if (argc > 0 && !strcmp(*argv, "-7")) { /* Pass only 7 bits */
450 if (argc > 0 && !strcmp(*argv, "-noflow")) {
451 flow = 0; /* Turn off local flow control so
452 that ^S can be passed to emacs. */
456 if (argc > 0 && !strcmp(*argv, "-l")) {
460 name = *argv++; argc--;
463 if (argc > 0 && !strncmp(*argv, "-e", 2)) {
464 cmdchar = argv[0][2];
468 if (argc > 0 && !strcmp(*argv, "-8")) {
473 if (argc > 0 && !strcmp(*argv, "-L")) {
479 if (argc > 0 && !strcmp(*argv, "-k")) {
483 "rlogin: -k flag must be followed with a realm name.\n");
486 if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
487 fprintf(stderr, "rlogin: Cannot malloc.\n");
490 strcpy(krb_realm, *argv);
494 if (argc > 0 && !strcmp(*argv, "-x")) {
499 if (argc > 0 && !strcmp(*argv, "-f")) {
501 fprintf(stderr, "rlogin: Only one of -f and -F allowed\n");
508 if (argc > 0 && !strcmp(*argv, "-F")) {
510 fprintf(stderr, "rlogin: Only one of -f and -F allowed\n");
517 if (argc > 0 && !strcmp(*argv, "-PO")) {
518 kcmd_proto = KCMD_OLD_PROTOCOL;
522 if (argc > 0 && !strcmp(*argv, "-PN")) {
523 kcmd_proto = KCMD_NEW_PROTOCOL;
527 #ifdef KRB5_KRB4_COMPAT
528 if (argc > 0 && !strcmp(*argv, "-4")) {
534 #endif /* KERBEROS */
539 #ifdef KRB5_KRB4_COMPAT
540 if (kcmd_proto != KCMD_PROTOCOL_COMPAT_HACK && v4only) {
542 "-4 is incompatible with -PO/-PN");
546 pwd = getpwuid(getuid());
548 fprintf(stderr, "Who are you?\n");
552 status = krb5_init_context(&bsd_context);
554 com_err(argv[0], status, "while initializing krb5");
565 * if there is an entry in /etc/services for Kerberos login,
566 * attempt to login with Kerberos.
567 * If we fail at any step, use the standard rlogin
570 sp = getservbyname("eklogin","tcp");
572 sp = getservbyname("klogin","tcp");
574 sp = &defaultservent; /* ANL */
575 sp->s_port = encrypt_flag ? htons(2105) : htons(543);
578 sp = getservbyname("login", "tcp");
580 fprintf(stderr, "rlogin: login/tcp: unknown service\n");
583 #endif /* KERBEROS */
589 if (cp == (char *) NULL) cp = getenv("TERM");
591 (void) strncpy(term, cp, sizeof (term));
592 term[sizeof (term) - 1] = '\0';
595 if (tcgetattr(0, &ttyb) == 0) {
596 int ospeed = cfgetospeed (&ttyb);
598 term[sizeof(term) - 1] = '\0';
599 (void) strncat(term, "/", sizeof(term) - 1 - strlen(term));
601 /* On some systems, ospeed is the baud rate itself,
602 not a table index. */
603 sprintf (term + strlen (term), "%d", ospeed);
604 else if (ospeed >= sizeof(speeds)/sizeof(char*))
605 /* Past end of table, but not high enough to
606 look like a real speed. */
607 (void) strncat (term, speeds[sizeof(speeds)/sizeof(char*) - 1], sizeof(term) - 1 - strlen(term));
609 (void) strncat(term, speeds[ospeed], sizeof(term) - 1 - strlen(term));
611 term[sizeof (term) - 1] = '\0';
614 if (ioctl(0, TIOCGETP, &ttyb) == 0) {
615 (void) strncat(term, "/", sizeof(term) - 1 - strlen(term));
616 (void) strncat(term, speeds[ttyb.sg_ospeed], sizeof(term) - 1 - strlen(term));
619 (void) get_window_size(0, &winsize);
622 tcgetattr(0, &defmodes);
623 tcgetattr(0, &ixon_state);
626 /**** moved before rcmd call so that if get a SIGPIPE in rcmd **/
627 /**** we will have the defmodes set already. ***/
628 (void)ioctl(fileno(stdin), TIOCGETP, &defmodes);
629 (void)ioctl(fileno(stdin), TIOCGETP, &ixon_state);
633 /* Catch SIGPIPE, as that means we lost the connection */
634 /* will use SIGUSR1 for window size hack, so hold it off */
636 (void) sigemptyset(&sa.sa_mask);
638 sa.sa_handler = lostpeer;
639 (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
641 (void) sigemptyset(&urgmask);
642 (void) sigaddset(&urgmask, SIGUSR1);
644 (void) sigprocmask(SIG_BLOCK, &urgmask, oldmask);
646 (void) signal(SIGPIPE, lostpeer);
648 oldmask = sigignore( sigmask(SIGUSR1));
650 oldmask = sigblock( sigmask(SIGUSR1));
652 #endif /* POSIX_SIGNALS */
655 authopts = AP_OPTS_MUTUAL_REQUIRED;
657 /* Piggy-back forwarding flags on top of authopts; */
658 /* they will be reset in kcmd */
660 authopts |= OPTS_FORWARD_CREDS;
662 authopts |= OPTS_FORWARDABLE_CREDS;
664 #ifdef KRB5_KRB4_COMPAT
668 status = kcmd(&sock, &host, port,
669 null_local_username ? "" : pwd->pw_name,
670 name ? name : pwd->pw_name, term,
671 0, "host", krb_realm,
673 0, /* No need for sequence number */
674 0, /* No need for server seq # */
676 &auth_context, authopts,
677 0, /* Not any port # */
681 if (kcmd_proto == KCMD_NEW_PROTOCOL && encrypt_flag)
682 /* Don't fall back to something less secure. */
684 #ifdef KRB5_KRB4_COMPAT
685 fprintf(stderr, "Trying krb4 rlogin...\n");
687 status = k4cmd(&sock, &host, port,
688 null_local_username ? "" : pwd->pw_name,
689 name ? name : pwd->pw_name, term,
690 0, &v4_ticket, "rcmd", krb_realm,
691 &v4_cred, v4_schedule, &v4_msg_data, &local, &foreign,
692 (encrypt_flag) ? KOPT_DO_MUTUAL : 0L, 0);
694 try_normal(orig_argv);
695 rcmd_stream_init_krb4(v4_cred.session, encrypt_flag, 1, 1);
697 try_normal(orig_argv);
700 krb5_keyblock *key = 0;
702 if (kcmd_proto == KCMD_NEW_PROTOCOL) {
705 status = krb5_auth_con_getsendsubkey (bsd_context, auth_context,
707 if ((status || !key) && encrypt_flag)
708 try_normal(orig_argv);
711 key = &cred->keyblock;
713 rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, kcmd_proto);
719 rem = rcmd(&host, port,
720 null_local_username ? "" : pwd->pw_name,
721 name ? name : pwd->pw_name, term, 0);
722 #endif /* KERBEROS */
727 if (options & SO_DEBUG &&
728 setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char*)&on, sizeof (on)) < 0)
729 perror("rlogin: setsockopt (SO_DEBUG)");
731 if (setuid(uid) < 0) {
732 perror("rlogin: setuid");
735 flowcontrol = flow; /* Set up really correct non-volatile variable */
741 "usage: rlogin host [-option] [-option...] [-k realm ] [-t ttytype] [-l username]\n");
742 #ifdef KRB5_KRB4_COMPAT
743 fprintf (stderr, " where option is e, 7, 8, noflow, n, a, x, f, F, c, 4, PO, or PN\n");
745 fprintf (stderr, " where option is e, 7, 8, noflow, n, a, x, f, F, c, PO, or PN\n");
747 #else /* !KERBEROS */
749 "usage: rlogin host [-option] [-option...] [-t ttytype] [-l username]\n");
750 fprintf (stderr, " where option is e, 7, 8, noflow, n, a, or c\n");
751 #endif /* KERBEROS */
757 static int confirm_death ()
762 if (!confirm) return (1); /* no confirm, just die */
764 if (gethostname (hostname, sizeof(hostname)-1) != 0)
765 strcpy (hostname, "???");
767 hostname[sizeof(hostname)-1] = '\0';
769 fprintf (stderr, "\r\nKill session on %s from %s (y/n)? ",
772 if (read(0, &input, 1) != 1)
773 answer = EOF; /* read from stdin */
775 answer = (int) input;
776 fprintf (stderr, "%c\r\n", answer);
778 return (answer == 'y' || answer == 'Y' || answer == EOF ||
779 answer == 4); /* control-D */
787 krb5_sigtype catchild (int);
788 krb5_sigtype writeroob (int);
790 int defflags, tabflag;
792 char deferase, defkill;
795 char defvtim, defvmin;
796 #if defined(hpux) || defined(__hpux)
797 #include <sys/bsdtty.h>
798 #include <sys/ptyio.h>
801 char t_intrc; /* interrupt */
802 char t_quitc; /* quit */
803 char t_startc; /* start output */
804 char t_stopc; /* stop output */
805 char t_eofc; /* end-of-file */
806 char t_brkc; /* input delimiter (like nl) */
811 #ifndef POSIX_TERMIOS
814 * POSIX 1003.1-1988 does not define a 'suspend' character.
815 * POSIX 1003.1-1990 does define an optional VSUSP but not a VDSUSP character.
816 * Some termio implementations (A/UX, Ultrix 4.2) include both.
818 * However, since this is all derived from the BSD ioctl() and ltchars
819 * concept, all these implementations generally also allow for the BSD-style
820 * ioctl(). So we'll simplify the problem by only testing for the ioctl().
822 struct ltchars defltc;
823 struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
826 struct tchars notc = { -1, -1, -1, -1, -1, -1 };
829 static void doit(oldmask)
841 (void) tcgetattr(0, &deftty);
843 /* there's a POSIX way of doing this, but do we need it general? */
844 deftty.c_cc[VLNEXT] = 0;
853 (void) ioctl(0, TIOCGETP, (char *)&sb);
854 defflags = sb.sg_flags;
856 tabflag = sb.c_oflag & TABDLY;
858 deferase = sb.c_cc[VERASE];
859 defkill = sb.c_cc[VKILL];
862 defvtim = sb.c_cc[VTIME];
863 defvmin = sb.c_cc[VMIN];
864 deftc.t_quitc = CQUIT;
865 deftc.t_startc = CSTART;
866 deftc.t_stopc = CSTOP ;
870 tabflag = defflags & TBDELAY;
871 defflags &= ECHO | CRMOD;
872 deferase = sb.sg_erase;
873 defkill = sb.sg_kill;
874 (void) ioctl(0, TIOCLGET, (char *)&deflflags);
875 (void) ioctl(0, TIOCGETC, (char *)&deftc);
878 notc.t_startc = deftc.t_startc;
879 notc.t_stopc = deftc.t_stopc;
880 (void) ioctl(0, TIOCGLTC, (char *)&defltc);
883 (void) sigemptyset(&sa.sa_mask);
885 sa.sa_handler = SIG_IGN;
886 (void) sigaction(SIGINT, &sa, (struct sigaction *)0);
888 (void) signal(SIGINT, SIG_IGN);
891 setsignal(SIGHUP, exit_handler);
892 setsignal(SIGQUIT, exit_handler);
896 perror("rlogin: fork");
901 if (reader(oldmask) == 0) {
902 prf("Connection closed.");
906 prf("\007Connection closed.");
911 /* "sa" has already been initialized above. */
913 sa.sa_handler = writeroob;
914 (void) sigaction(SIGUSR1, &sa, (struct sigaction *)0);
916 sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
918 sa.sa_handler = catchild;
919 (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
921 (void) signal(SIGUSR1, writeroob);
923 (void) sigsetmask(oldmask);
925 (void) signal(SIGCHLD, catchild);
926 #endif /* POSIX_SIGNALS */
928 prf("Closed connection.");
935 * Trap a signal, unless it is being ignored.
940 krb5_sigtype (*act)();
943 sigset_t omask, igmask;
946 sigemptyset(&igmask);
947 sigaddset(&igmask, sig);
948 sigprocmask(SIG_BLOCK, &igmask, &omask);
951 int omask = sigignore(sigmask(sig));
953 int omask = sigblock(sigmask(sig));
955 #endif /* POSIX_SIGNALS */
958 (void) sigaction(sig, (struct sigaction *)0, &sa);
959 if (sa.sa_handler != SIG_IGN) {
960 (void) sigemptyset(&sa.sa_mask);
963 (void) sigaction(sig, &sa, (struct sigaction *)0);
965 sigprocmask(SIG_SETMASK, &omask, (sigset_t*)0);
967 if (signal(sig, act) == SIG_IGN)
968 (void) signal(sig, SIG_IGN);
970 (void) sigsetmask(omask);
990 /* make sure catchild does not snap it up */
992 (void) sigemptyset(&sa.sa_mask);
994 sa.sa_handler = SIG_DFL;
995 (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
997 (void) signal(SIGCHLD, SIG_DFL);
1000 if (kill(child, SIGKILL) >= 0) {
1002 (void) waitpid(child, 0, 0);
1004 while ((w = wait(0)) > 0 && w != child)
1018 * This is called when the reader process gets the out-of-band (urgent)
1019 * request to turn on the window-changing protocol.
1025 #ifdef POSIX_SIGNALS
1026 struct sigaction sa;
1029 if (dosigwinch == 0) {
1031 #ifdef POSIX_SIGNALS
1032 (void) sigemptyset(&sa.sa_mask);
1034 sa.sa_handler = sigwinch;
1035 (void) sigaction(SIGWINCH, &sa, (struct sigaction *)0);
1037 (void) signal(SIGWINCH, sigwinch);
1049 #ifdef WAIT_USES_INT
1058 pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
1060 pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
1065 * if the child (reader) dies, just quit
1067 #ifdef WAIT_USES_INT
1068 if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
1071 if ((pid < 0) || ((pid == child) && (!WIFSTOPPED(status))))
1072 done((int)(status.w_termsig | status.w_retcode));
1080 * writer: write to remote: 0 -> line.
1082 * ~^Z suspend rlogin process.
1083 * ~^Y suspend rlogin process, but leave reader alone.
1085 static void writer()
1089 int got_esc; /* set to true by read_wrapper if an escape char
1097 /* we need to wait until the reader() has set up the terminal, else
1098 the read() below may block and not unblock when the terminal
1103 FD_SET(0, &waitread);
1104 n = select(8*sizeof(waitread), &waitread, 0, 0, 0, 0);
1105 if (n < 0 && errno == EINTR)
1117 /* This loop works as follows. Call read_wrapper to get data until
1118 we would block or until we read a cmdchar at the beginning of a line.
1119 If got_esc is false, we just send everything we got back. If got_esc
1120 is true, we send everything except the cmdchar at the end and look at
1121 the next char. If its a "." we break out of the loop and terminate.
1122 If its ^Z or ^Y we call stop with the value of the char and continue.
1123 If its none of those, we send the cmdchar and then send the char we
1124 just read, unless that char is also the cmdchar (in which case we are
1125 only supposed to send one of them). When this loop ends, so does the
1131 /* read until we would block or we get a cmdchar */
1132 n_read = read_wrapper(0,buf,sizeof(buf),&got_esc);
1134 /* if read returns an error or 0 bytes, just quit */
1140 if (rcmd_stream_write(rem, buf, (unsigned) n_read, 0) == 0) {
1147 /* This next test is necessary to avoid sending 0 bytes of data
1148 in the event that we got just a cmdchar */
1150 if (rcmd_stream_write(rem, buf, (unsigned) (n_read-1), 0) == 0) {
1155 if (read_wrapper(0,&c,1,&got_esc) <= 0) {
1159 #ifdef POSIX_TERMIOS
1160 if (c == '.' || c == deftty.c_cc[VEOF])
1162 if (c == '.' || c == deftc.t_eofc)
1165 if (confirm_death()) {
1171 #ifdef POSIX_TERMIOS
1173 (c == deftty.c_cc[VSUSP])
1175 || (c == deftty.c_cc[VDSUSP])
1178 && !no_local_escape) {
1183 #else /*POSIX_TERMIOS*/
1185 if ((c == defltc.t_suspc || c == defltc.t_dsuspc)
1186 && !no_local_escape) {
1196 rcmd_stream_write(rem, &cmdchar, 1, 0);
1199 if (rcmd_stream_write(rem,&c,1,0) == 0) {
1207 /* This function reads up to size bytes from file desciptor fd into buf.
1208 It will copy as much data as it can without blocking, but will never
1209 copy more than size bytes. In addition, if it encounters a cmdchar
1210 at the beginning of a line, it will copy everything up to and including
1211 the cmdchar, but nothing after that. In this instance *esc_char is set
1212 to true and any remaining data is buffered and copied on a subsequent
1213 call. Otherwise, *esc_char will be set to false and the minimum of size,
1214 1024, and the number of bytes that can be read without blocking will
1215 be copied. In all cases, a non-negative return value indicates the number
1216 of bytes actually copied and a return value of -1 indicates that there
1217 was a read error (other than EINTR) and errno is set appropriately.
1220 static int read_wrapper(fd,buf,size,got_esc)
1226 static char tbuf[1024];
1227 static char *data_start = tbuf;
1228 static char *data_end = tbuf;
1230 unsigned int return_length = 0;
1233 /* if we have no data buffered, get more */
1234 if (data_start == data_end) {
1236 while ((n_read = read(fd, tbuf, sizeof(tbuf))) <= 0) {
1237 if (n_read < 0 && errno == EINTR)
1242 data_end = tbuf+n_read;
1247 /* We stop when we've fully checked the buffer or have checked size
1248 bytes. We break out and set *got_esc if we encounter a cmdchar
1249 at the beginning of a line.
1252 while (data_start+return_length < data_end && return_length < size) {
1254 c = *(data_start+return_length);
1257 if (bol == 1 && c == cmdchar) {
1263 #ifdef POSIX_TERMIOS
1264 bol = (c == deftty.c_cc[VKILL] ||
1265 c == deftty.c_cc[VINTR] ||
1266 c == '\r' || c == '\n');
1268 #else /* !POSIX_TERMIOS */
1269 bol = c == defkill || c == deftc.t_eofc ||
1270 c == deftc.t_intrc || c == defltc.t_suspc ||
1271 c == '\r' || c == '\n';
1275 memcpy(buf, data_start, return_length);
1276 data_start = data_start + return_length;
1277 return return_length;
1284 register char *p = buf;
1291 } else if (c == 0177) {
1298 (void) write(1, buf, (unsigned) (p - buf));
1303 static void stop(cmdc)
1306 #ifdef POSIX_SIGNALS
1307 struct sigaction sa;
1312 #ifdef POSIX_SIGNALS
1313 (void) sigemptyset(&sa.sa_mask);
1315 sa.sa_handler = SIG_IGN;
1316 (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
1318 (void) signal(SIGCHLD, SIG_IGN);
1321 #ifdef POSIX_TERMIOS
1322 (void) kill(cmdc == deftty.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
1325 (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
1328 #ifdef POSIX_SIGNALS
1329 sa.sa_handler = catchild;
1330 (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
1332 (void) signal(SIGCHLD, catchild);
1336 sigwinch(SIGWINCH); /* check for size changes */
1347 if (dosigwinch && get_window_size(0, &ws) == 0 &&
1348 memcmp(&winsize, &ws, sizeof (ws))) {
1357 * Send the window size to the server via the magic escape
1359 static void sendwindow()
1361 char obuf[4 + sizeof (struct winsize)];
1362 struct winsize *wp = (struct winsize *)(void *)(obuf+4);
1368 wp->ws_row = htons(winsize.ws_row);
1369 wp->ws_col = htons(winsize.ws_col);
1370 wp->ws_xpixel = htons(winsize.ws_xpixel);
1371 wp->ws_ypixel = htons(winsize.ws_ypixel);
1372 (void) rcmd_stream_write(rem, obuf, sizeof(obuf), 0);
1378 * reader: read from remote: line -> 1
1383 char rcvbuf[8 * 1024];
1388 /* returns 1 if flush, 0 otherwise */
1390 int server_message(mark)
1393 #ifndef POSIX_TERMIOS
1396 #ifdef POSIX_TERMIOS
1406 if (mark & TIOCPKT_WINDOW) {
1408 * Let server know about window size changes
1410 (void) kill(ppid, SIGUSR1);
1412 #ifdef POSIX_TERMIOS
1413 if (!eight && (mark & TIOCPKT_NOSTOP)) {
1414 (void) tcgetattr(0, &tty);
1415 tty.c_iflag &= ~IXON;
1416 (void) tcsetattr(0, TCSADRAIN, &tty);
1418 if (!eight && (mark & TIOCPKT_DOSTOP)) {
1419 (void) tcgetattr(0, &tty);
1420 tty.c_iflag |= IXON;
1421 (void) tcsetattr(0, TCSADRAIN, &tty);
1424 if (!eight && (mark & TIOCPKT_NOSTOP)) {
1425 (void) ioctl(0, TIOCGETP, (char *)&sb);
1427 sb.c_iflag |= IXOFF;
1428 sb.sg_flags &= ~ICANON;
1430 sb.sg_flags &= ~CBREAK;
1434 (void) ioctl(0, TIOCSETC, (char *)¬c);
1436 (void) ioctl(0, TIOCSETN, (char *)&sb);
1438 if (!eight && (mark & TIOCPKT_DOSTOP)) {
1439 (void) ioctl(0, TIOCGETP, (char *)&sb);
1441 sb.sg_flags |= ICANON;
1444 sb.sg_flags &= ~RAW;
1445 sb.sg_flags |= CBREAK;
1446 notc.t_stopc = deftc.t_stopc;
1447 notc.t_startc = deftc.t_startc;
1448 (void) ioctl(0, TIOCSETC, (char *)¬c);
1450 (void) ioctl(0, TIOCSETN, (char *)&sb);
1453 if (mark & TIOCPKT_FLUSHWRITE) {
1454 #ifdef POSIX_TERMIOS
1455 (void) tcflush(1, TCOFLUSH);
1458 (void) ioctl(1, TIOCFLUSH, (char *)&out);
1460 (void) ioctl(1, TCFLSH, 1);
1472 static char waste[RLOGIN_BUFSIZ];
1477 recv(rem, &mark, 1, MSG_OOB);
1479 if (server_message(mark)) {
1481 if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
1487 n = read(rem, waste, sizeof (waste));
1494 /* two control messages are defined:
1496 a double flag byte of 'o' indicates a one-byte message which is
1497 identical to what was once carried out of band.
1499 a double flag byte of 'q' indicates a zero-byte message. This
1500 message is interpreted as two \377 data bytes. This is just a
1501 quote rule so that binary data from the server does not confuse the
1504 static int control(cp, n)
1508 if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
1509 if (server_message(cp[4]))
1512 } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
1513 /* this is somewhat of a hack */
1523 * reader: read from remote: line -> 1
1527 #ifdef POSIX_SIGNALS
1533 fd_set readset, excset, writeset;
1536 char *bufp = rcvbuf;
1539 #ifdef POSIX_SIGNALS
1540 struct sigaction sa;
1542 (void) sigemptyset(&sa.sa_mask);
1544 sa.sa_handler = SIG_IGN;
1545 (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
1548 (void) signal(SIGTTOU, SIG_IGN);
1555 #ifdef POSIX_SIGNALS
1556 sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
1559 (void) sigsetmask(oldmask);
1561 #endif /* POSIX_SIGNALS */
1564 if ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
1565 FD_SET(1,&writeset);
1567 FD_CLR(rem, &readset);
1572 FD_SET(rem,&readset);
1573 FD_CLR(1,&writeset);
1576 FD_SET(rem,&excset);
1577 if (select(rem+1, &readset, &writeset, &excset, 0) > 0 ) {
1579 if (FD_ISSET(rem, &excset))
1581 if (FD_ISSET(1,&writeset)) {
1582 n = write(1, bufp, remaining);
1590 if (FD_ISSET(rem, &readset)) {
1591 rcvcnt = rcmd_stream_read(rem, rcvbuf, sizeof (rcvbuf), 0);
1598 for (cp = rcvbuf; cp < rcvbuf+rcvcnt-1; cp++) {
1599 if (cp[0] == '\377' &&
1601 left = (rcvbuf+rcvcnt) - cp;
1602 n = control(cp, left);
1607 /* flush before, and (-n) bytes */
1609 memmove(rcvbuf, cp+(-n), left);
1615 memmove(cp, cp+n, left);
1638 #ifdef POSIX_TERMIOS
1639 struct termios newtty;
1641 #define IEXTEN 0 /* No effect*/
1643 #ifndef _POSIX_VDISABLE
1644 #define _POSIX_VDISABLE 0 /*A good guess at the disable-this-character character*/
1649 (void) tcsetattr(0, TCSADRAIN, &deftty);
1652 (void) tcgetattr(0, &newtty);
1655 /* there's a POSIX way of doing this, but do we need it general? */
1656 newtty.c_cc[VLNEXT] = _POSIX_VDISABLE;
1659 newtty.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
1660 newtty.c_iflag &= ~(ISTRIP|INLCR|ICRNL);
1663 newtty.c_iflag &= ~(BRKINT|IXON|IXANY);
1664 newtty.c_oflag &= ~(OPOST);
1666 /* XXX - should we set ixon ? */
1667 newtty.c_iflag &= ~(IXON|IXANY);
1668 newtty.c_iflag |= (BRKINT);
1669 newtty.c_oflag &= ~(ONLCR|ONOCR);
1670 newtty.c_oflag |= (OPOST);
1673 /* preserve tab delays, but turn off XTABS */
1674 if ((newtty.c_oflag & TABDLY) == TAB3)
1675 newtty.c_oflag &= ~TABDLY;
1678 newtty.c_iflag |= ISTRIP;
1680 newtty.c_oflag &= ~OPOST;
1682 newtty.c_cc[VMIN] = 1;
1683 newtty.c_cc[VTIME] = 0;
1684 (void) tcsetattr(0, TCSADRAIN, &newtty);
1691 struct ltchars *ltc;
1698 (void) ioctl(0, TIOCLGET, (char *)&lflags);
1701 (void) ioctl(0, TIOCGETP, (char *)&sb);
1707 ** remember whether IXON was set, so it can be restored
1708 ** when mode(1) is next done
1710 (void) ioctl(fileno(stdin), TIOCGETP, &ixon_state);
1712 ** copy the initial modes we saved into sb; this is
1713 ** for restoring to the initial state
1715 (void)memcpy(&sb, &defmodes, sizeof(defmodes));
1718 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
1719 sb.sg_flags |= defflags|tabflag;
1720 sb.sg_kill = defkill;
1721 sb.sg_erase = deferase;
1731 ** turn off output mappings
1733 sb.c_oflag &= ~(ONLCR|OCRNL);
1735 ** turn off canonical processing and character echo;
1736 ** also turn off signal checking -- ICANON might be
1737 ** enough to do this, but we're being careful
1739 sb.c_lflag &= ~(ECHO|ICANON|ISIG);
1743 sb.c_iflag &= ~(ISTRIP);
1745 /* preserve tab delays, but turn off tab-to-space expansion */
1746 if ((sb.c_oflag & TABDLY) == TAB3)
1747 sb.c_oflag &= ~TAB3;
1750 ** restore current flow control state
1752 if ((ixon_state.c_iflag & IXON) && flow ) {
1755 sb.c_iflag &= ~IXON;
1757 #else /* ! USE_TERMIO */
1758 sb.sg_flags &= ~(CBREAK|RAW);
1759 sb.sg_flags |= (!flow ? RAW : CBREAK);
1760 /* preserve tab delays, but turn off XTABS */
1761 if ((sb.sg_flags & TBDELAY) == XTABS)
1762 sb.sg_flags &= ~TBDELAY;
1763 sb.sg_kill = sb.sg_erase = -1;
1773 sb.sg_flags &= ~defflags;
1774 #endif /* USE_TERMIO */
1782 (void) ioctl(0, TIOCSLTC, (char *)ltc);
1784 (void) ioctl(0, TIOCSETC, (char *)tc);
1785 (void) ioctl(0, TIOCLSET, (char *)&lflags);
1787 (void) ioctl(0, TIOCSETN, (char *)&sb);
1788 #endif /* !POSIX_TERMIOS */
1798 fprintf(stderr, CRLF);
1804 void try_normal(argv)
1807 register char *nhost;
1808 #ifdef POSIX_SIGNALS
1812 #ifndef KRB5_ATHENA_COMPAT
1816 fprintf(stderr,"trying normal rlogin (%s)\n",
1820 nhost = strrchr(argv[0], '/');
1825 if (!strcmp(nhost, "rlogin") || !strcmp(nhost, "rsh"))
1826 argv[0] = UCB_RLOGIN;
1828 #ifdef POSIX_SIGNALS
1830 sigprocmask(SIG_SETMASK, &mask, NULL);
1833 execv(UCB_RLOGIN, argv);
1841 krb5_sigtype lostpeer(signo)
1844 #ifdef POSIX_SIGNALS
1845 struct sigaction sa;
1847 (void) sigemptyset(&sa.sa_mask);
1849 sa.sa_handler = SIG_IGN;
1850 (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
1852 (void) signal(SIGPIPE, SIG_IGN);
1855 prf("\007Connection closed.");