This commit was manufactured by cvs2svn to create tag
[krb5.git] / src / appl / bsd / krlogin.c
1 /*
2  *    appl/bsd/krlogin.c
3  */
4
5 /*
6  * Copyright (c) 1983 The Regents of the University of California.
7  * All rights reserved.
8  *
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.
20  */
21
22 /*
23  * Copyright (C) 1998 by the FundsXpress, INC.
24  * 
25  * All rights reserved.
26  * 
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.
31  * 
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.
42  * 
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.
46  */
47
48 #ifndef lint
49 char copyright[] =
50   "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
51  All rights reserved.\n";
52 #endif /* not lint */
53
54 /* based on @(#)rlogin.c        5.12 (Berkeley) 9/19/88 */
55
56      
57      /*
58       * rlogin - remote login
59       */
60      
61 #ifdef HAVE_UNISTD_H
62 #include <unistd.h>
63 #endif
64 #ifdef HAVE_STDLIB_H
65 #include <stdlib.h>
66 #endif
67
68
69 #include <sys/types.h>
70 #include <sys/param.h>
71 #include <sys/ioctl.h>
72 #include <sys/errno.h>
73 #include <sys/file.h>
74 #include <sys/socket.h>
75 #include <sys/time.h>
76 #include <sys/resource.h>
77 #include <sys/wait.h>
78 #include <fcntl.h>
79
80 #include <netinet/in.h>
81
82 #include <stdio.h>
83 #include <string.h>
84 #include <errno.h>
85 #include <pwd.h>
86 #include <signal.h>
87 #include <setjmp.h>
88 #include <netdb.h>
89      
90 #ifdef HAVE_SYS_FILIO_H
91 /* Solaris needs <sys/filio.h> for FIONREAD */
92 #include <sys/filio.h>
93 #endif
94
95 #ifdef HAVE_STDLIB_H
96 #include <stdlib.h>
97 #endif
98 #ifdef HAVE_SYS_SELECT_H
99 #include <sys/select.h>
100 #endif
101 #if HAVE_SYS_TIME_H
102 #include <sys/time.h>
103 #endif
104
105 #ifdef POSIX_TERMIOS
106 #include <termios.h>
107 #ifndef CNUL
108 #define CNUL (char) 0
109 #endif
110
111 #else /* POSIX_TERMIOS */
112 #include <sgtty.h>
113 #endif /* POSIX_TERMIOS */
114
115 #ifdef HAVE_SYS_SOCKIO_H
116 /* for SIOCATMARK */
117 #include <sys/sockio.h>
118 #endif
119
120 #ifdef HAVE_STREAMS
121 #include <sys/stream.h>
122 #include <sys/stropts.h>
123 #endif
124
125 #ifdef __SCO__
126 /* for TIOCPKT_* */
127 #include <sys/spt.h>
128 /* for struct winsize */
129 #include <sys/ptem.h>
130 #endif
131
132 #ifdef HAVE_STREAMS
133 #ifdef HAVE_SYS_PTYVAR_H
134 #include <sys/tty.h>
135 #include <sys/ttold.h>
136 /* solaris actually uses packet mode, so the real macros are needed too */
137 #include <sys/ptyvar.h>
138 #endif
139 #endif
140
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
146 #endif
147
148 #ifdef HAVE_SYS_IOCTL_COMPAT_H
149 #include <sys/ioctl_compat.h>
150 #endif
151
152 #ifdef CRAY
153 #include <sys/ttold.h>
154 #endif
155
156
157 #ifdef KERBEROS
158 #include <krb5.h>
159 #include <com_err.h>
160 #ifdef KRB5_KRB4_COMPAT
161 #include <kerberosIV/krb.h>
162 #endif
163 #include "defines.h"
164      
165 #define RLOGIN_BUFSIZ 5120
166
167 void try_normal();
168 char *krb_realm = (char *)0;
169 int encrypt_flag = 0;
170 int fflag = 0, Fflag = 0;
171 krb5_creds *cred;
172 struct sockaddr_in local, foreign;
173 krb5_context bsd_context;
174 krb5_auth_context auth_context;
175
176 #ifdef KRB5_KRB4_COMPAT
177 Key_schedule v4_schedule;
178 CREDENTIALS v4_cred;
179 #endif
180
181 #ifndef UCB_RLOGIN
182 #define UCB_RLOGIN      "/usr/ucb/rlogin"
183 #endif
184
185 #include "rpaths.h"
186 #endif /* KERBEROS */
187
188 # ifndef TIOCPKT_WINDOW
189 # define TIOCPKT_WINDOW 0x80
190 # endif /* TIOCPKT_WINDOW */
191
192 #ifndef ONOCR
193 #define ONOCR 0
194 #endif
195
196 #ifdef POSIX_TERMIOS
197 struct termios deftty;
198 #endif
199
200 char    *getenv();
201
202 char    *name;
203 int     rem = -1;               /* Remote socket fd */
204 int     do_inband = 0;
205 char    cmdchar = '~';
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. */
217 int     litout;
218 #if defined(hpux) || defined(__hpux)
219 char    *speeds[] =
220 { "0", "50", "75", "110", "134", "150", "200", "300", "600",
221     "900", "1200", "1800", "2400", "3600", "4800", "7200", "9600",
222     "19200", "38400", "EXTA", "EXTB" };
223 #else
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.
231
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) */
236 char    *speeds[] =
237 { "0", "50", "75", "110", "134", "150", "200", "300",
238     "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
239 #endif
240 char    term[256] = "network";
241
242 #ifndef POSIX_SIGNALS
243 #ifndef sigmask
244 #define sigmask(m)    (1 << ((m)-1))
245 #endif
246 #endif /* POSIX_SIGNALS */
247
248 #ifdef NO_WINSIZE
249 struct winsize {
250     unsigned short ws_row, ws_col;
251     unsigned short ws_xpixel, ws_ypixel;
252 };
253 #endif /* NO_WINSIZE */
254 int     dosigwinch = 0;
255 struct  winsize winsize;
256
257 char    *host=0;                        /* external, so it can be
258                                            reached from confirm_death() */
259
260 krb5_sigtype    sigwinch (int);
261 int server_message (int);
262 void oob (void);
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);
269 #ifdef POSIX_SIGNALS
270 static int reader(sigset_t *);
271 static void doit(sigset_t *);
272 #else
273 static int reader(int);
274 static void doit(int);
275 #endif
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);
281
282
283 /* to allow exits from signal handlers, without conflicting declarations */
284 static krb5_sigtype exit_handler() {
285   exit(1);
286 }
287
288
289 /*
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.
293  */
294 #ifdef TIOCGWINSZ
295 #define get_window_size(fd, wp)       ioctl(fd, TIOCGWINSZ, wp)
296 #else
297 #ifdef SYSV
298 #ifndef SIGWINCH
299 #define SIGWINCH SIGWINDOW
300 #endif
301 struct ttysize {
302     int ts_lines;
303     int ts_cols;
304 };
305 #define DEFAULT_LINES 24
306 #define DEFAULT_COLS 80
307 #endif
308
309
310
311 int
312   get_window_size(fd, wp)
313 int fd;
314 struct winsize *wp;
315 {
316     struct ttysize ts;
317     int error;
318 #ifdef SYSV
319     char *envbuf;
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);
326 #else
327     if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
328       return (error);
329 #endif
330     
331     wp->ws_row = ts.ts_lines;
332     wp->ws_col = ts.ts_cols;
333     wp->ws_xpixel = 0;
334     wp->ws_ypixel = 0;
335     return (0);
336 }
337 #endif /* TIOCGWINSZ */
338
339
340 #ifdef POSIX_TERMIOS
341 /* Globals for terminal modes and flow control */
342 struct  termios defmodes;
343 struct  termios ixon_state;
344 #else
345 #ifdef USE_TERMIO
346 /* Globals for terminal modes and flow control */
347 struct  termio defmodes;
348 struct  termio ixon_state;
349 #endif
350 #endif
351
352
353 int
354 main(argc, argv)
355      int argc;
356      char **argv;
357 {
358     char *cp = (char *) NULL;
359 #ifdef POSIX_TERMIOS
360     struct termios ttyb;
361 #else
362 #ifdef USE_TERMIO
363     struct termio ttyb;
364 #else
365     struct sgttyb ttyb;
366 #endif
367 #endif
368     struct passwd *pwd;
369     struct servent *sp;
370     struct servent defaultservent;
371     int uid, options = 0;
372 #ifdef POSIX_SIGNALS
373     struct sigaction sa;
374     sigset_t *oldmask, omask, urgmask;
375 #else
376     int oldmask;
377 #endif
378     int on = 1;
379 #ifdef KERBEROS
380     char **orig_argv = argv;
381     int sock;
382     krb5_flags authopts;
383     krb5_error_code status;
384 #ifdef KRB5_KRB4_COMPAT
385     KTEXT_ST v4_ticket;
386     MSG_DAT v4_msg_data;
387     int v4only = 0;
388 #endif
389 #endif
390     int port, debug_port = 0;
391     enum kcmd_proto kcmd_proto = KCMD_PROTOCOL_COMPAT_HACK;
392
393     memset(&defaultservent, 0, sizeof(struct servent));
394     if (strrchr(argv[0], '/'))
395       argv[0] = strrchr(argv[0], '/')+1;
396
397     if ( argc < 2 ) goto usage;
398     argc--;
399     argv++;
400
401   another:
402     if (argc > 0 && host == 0 && strncmp(*argv, "-", 1)) {
403         host = *argv;
404         argv++, argc--;
405         goto another;
406     }
407
408     if (argc > 0 && !strcmp(*argv, "-D")) {
409         argv++; argc--;
410         if (*argv == NULL) {
411             fprintf (stderr,
412                      "rlogin: -D flag must be followed by the debug port.\n");
413             exit (1);
414         }
415         debug_port = htons(atoi(*argv));
416         argv++; argc--;
417         goto another;
418     }
419     if (argc > 0 && !strcmp(*argv, "-d")) {
420         argv++, argc--;
421         options |= SO_DEBUG;
422         goto another;
423     }
424     if (argc > 0 && !strcmp(*argv, "-c")) {
425         confirm = 1;
426         argv++; argc--;
427         goto another;
428     }
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 */
433     }
434     if (argc > 0 && !strcmp(*argv, "-t")) {
435         argv++; argc--;
436         if (argc == 0) goto usage;
437         cp = *argv++; argc--;
438         goto another;
439     }
440     if (argc > 0 && !strcmp(*argv, "-n")) {
441         no_local_escape = 1;
442         argv++, argc--;
443         goto another;
444     }
445     if (argc > 0 && !strcmp(*argv, "-7")) {  /* Pass only 7 bits */
446         eight = 0;
447         argv++, argc--;
448         goto another;
449     }
450     if (argc > 0 && !strcmp(*argv, "-noflow")) {
451         flow = 0;               /* Turn off local flow control so
452                                    that ^S can be passed to emacs. */
453         argv++, argc--;
454         goto another;
455     }
456     if (argc > 0 && !strcmp(*argv, "-l")) {
457         argv++, argc--;
458         if (argc == 0)
459           goto usage;
460         name = *argv++; argc--;
461         goto another;
462     }
463     if (argc > 0 && !strncmp(*argv, "-e", 2)) {
464         cmdchar = argv[0][2];
465         argv++, argc--;
466         goto another;
467     }
468     if (argc > 0 && !strcmp(*argv, "-8")) {
469         eight = 1;
470         argv++, argc--;
471         goto another;
472     }
473     if (argc > 0 && !strcmp(*argv, "-L")) {
474         litout = 1;
475         argv++, argc--;
476         goto another;
477     }
478 #ifdef KERBEROS
479     if (argc > 0 && !strcmp(*argv, "-k")) {
480         argv++, argc--;
481         if (argc == 0) {
482             fprintf(stderr,
483                     "rlogin: -k flag must be followed with a realm name.\n");
484             exit (1);
485         }
486         if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
487             fprintf(stderr, "rlogin: Cannot malloc.\n");
488             exit(1);
489         }
490         strcpy(krb_realm, *argv);
491         argv++, argc--;
492         goto another;
493     }
494     if (argc > 0 && !strcmp(*argv, "-x")) {
495         encrypt_flag++;
496         argv++, argc--;
497         goto another;
498     }
499     if (argc > 0 && !strcmp(*argv, "-f")) {
500         if (Fflag) {
501             fprintf(stderr, "rlogin: Only one of -f and -F allowed\n");
502             goto usage;
503         }
504         fflag++;
505         argv++, argc--;
506         goto another;
507     }
508     if (argc > 0 && !strcmp(*argv, "-F")) {
509         if (fflag) {
510             fprintf(stderr, "rlogin: Only one of -f and -F allowed\n");
511             goto usage;
512         }
513         Fflag++;
514         argv++, argc--;
515         goto another;
516     }
517     if (argc > 0 && !strcmp(*argv, "-PO")) {
518         kcmd_proto = KCMD_OLD_PROTOCOL;
519         argv++, argc--;
520         goto another;
521     }
522     if (argc > 0 && !strcmp(*argv, "-PN")) {
523         kcmd_proto = KCMD_NEW_PROTOCOL;
524         argv++, argc--;
525         goto another;
526     }
527 #ifdef KRB5_KRB4_COMPAT
528     if (argc > 0 && !strcmp(*argv, "-4")) {
529         v4only++;
530         argv++, argc--;
531         goto another;
532     }
533 #endif /* krb4 */
534 #endif /* KERBEROS */
535     if (host == 0)
536       goto usage;
537     if (argc > 0)
538       goto usage;
539 #ifdef KRB5_KRB4_COMPAT
540     if (kcmd_proto != KCMD_PROTOCOL_COMPAT_HACK && v4only) {
541         com_err (argv[0], 0,
542                  "-4 is incompatible with -PO/-PN");
543         exit(1);
544     }
545 #endif
546     pwd = getpwuid(getuid());
547     if (pwd == 0) {
548         fprintf(stderr, "Who are you?\n");
549         exit(1);
550     }
551 #ifdef KERBEROS
552     status = krb5_init_context(&bsd_context);
553     if (status) {
554             com_err(argv[0], status, "while initializing krb5");
555             exit(1);
556     }
557 #endif
558
559
560     if (debug_port)
561       port = debug_port;
562     else {
563 #ifdef KERBEROS
564     /*
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
568      */
569       if (encrypt_flag)
570         sp = getservbyname("eklogin","tcp");
571       else 
572         sp = getservbyname("klogin","tcp");
573       if (sp == 0) {
574                 sp = &defaultservent;   /* ANL */
575                 sp->s_port = encrypt_flag ? htons(2105) : htons(543);
576       }
577 #else
578       sp = getservbyname("login", "tcp");
579       if (sp == 0) {
580         fprintf(stderr, "rlogin: login/tcp: unknown service\n");
581         exit(2);
582       }
583 #endif /* KERBEROS */
584
585       port = sp->s_port;
586     }
587
588
589     if (cp == (char *) NULL) cp = getenv("TERM");
590     if (cp) {
591       (void) strncpy(term, cp, sizeof (term));
592       term[sizeof (term) - 1] = '\0';
593     }
594 #ifdef POSIX_TERMIOS
595         if (tcgetattr(0, &ttyb) == 0) {
596                 int ospeed = cfgetospeed (&ttyb);
597
598                 term[sizeof(term) - 1] = '\0';
599                 (void) strncat(term, "/", sizeof(term) - 1 - strlen(term));
600                 if (ospeed >= 50)
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));
608                 else {
609                         (void) strncat(term, speeds[ospeed], sizeof(term) - 1 - strlen(term));
610                 }
611                 term[sizeof (term) - 1] = '\0';
612         }
613 #else
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));
617     }
618 #endif
619     (void) get_window_size(0, &winsize);
620     
621 #ifdef POSIX_TERMIOS
622     tcgetattr(0, &defmodes);
623     tcgetattr(0, &ixon_state);
624 #else
625 #ifdef USE_TERMIO
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);
630 #endif
631 #endif
632
633     /* Catch SIGPIPE, as that means we lost the connection */
634     /* will use SIGUSR1 for window size hack, so hold it off */
635 #ifdef POSIX_SIGNALS
636     (void) sigemptyset(&sa.sa_mask);
637     sa.sa_flags = 0;
638     sa.sa_handler = lostpeer;
639     (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
640     
641     (void) sigemptyset(&urgmask);
642     (void) sigaddset(&urgmask, SIGUSR1);
643     oldmask = &omask;
644     (void) sigprocmask(SIG_BLOCK, &urgmask, oldmask);
645 #else
646     (void) signal(SIGPIPE, lostpeer);
647 #ifdef sgi
648     oldmask = sigignore( sigmask(SIGUSR1));
649 #else
650     oldmask = sigblock( sigmask(SIGUSR1));
651 #endif
652 #endif /* POSIX_SIGNALS */
653
654 #ifdef KERBEROS
655     authopts = AP_OPTS_MUTUAL_REQUIRED;
656
657     /* Piggy-back forwarding flags on top of authopts; */
658     /* they will be reset in kcmd */
659     if (fflag || Fflag)
660       authopts |= OPTS_FORWARD_CREDS;
661     if (Fflag)
662       authopts |= OPTS_FORWARDABLE_CREDS;
663
664 #ifdef KRB5_KRB4_COMPAT
665     if (v4only)
666         goto try_v4;
667 #endif
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,
672                   &cred,
673                   0,            /* No need for sequence number */
674                   0,            /* No need for server seq # */
675                   &local, &foreign,
676                   &auth_context, authopts,
677                   0,            /* Not any port # */
678                   0,
679                   &kcmd_proto);
680     if (status) {
681         if (kcmd_proto == KCMD_NEW_PROTOCOL && encrypt_flag)
682             /* Don't fall back to something less secure.  */
683             exit (1);
684 #ifdef KRB5_KRB4_COMPAT
685         fprintf(stderr, "Trying krb4 rlogin...\n");
686     try_v4:
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);
693         if (status)
694             try_normal(orig_argv);
695         rcmd_stream_init_krb4(v4_cred.session, encrypt_flag, 1, 1);
696 #else
697         try_normal(orig_argv);
698 #endif
699     } else {
700         krb5_keyblock *key = 0;
701
702         if (kcmd_proto == KCMD_NEW_PROTOCOL) {
703             do_inband = 1;
704
705             status = krb5_auth_con_getsendsubkey (bsd_context, auth_context,
706                                                   &key);
707             if ((status || !key) && encrypt_flag)
708                 try_normal(orig_argv);
709         }
710         if (key == 0)
711             key = &cred->keyblock;
712
713         rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, kcmd_proto);
714     }
715         
716     rem = sock;
717     
718 #else
719     rem = rcmd(&host, port,
720                null_local_username ? "" : pwd->pw_name,
721                name ? name : pwd->pw_name, term, 0);
722 #endif /* KERBEROS */
723
724     if (rem < 0)
725       exit(1);
726     
727     if (options & SO_DEBUG &&
728         setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char*)&on, sizeof (on)) < 0)
729       perror("rlogin: setsockopt (SO_DEBUG)");
730     uid = getuid();
731     if (setuid(uid) < 0) {
732         perror("rlogin: setuid");
733         exit(1);
734     }
735     flowcontrol = flow;  /* Set up really correct non-volatile variable */
736     doit(oldmask);
737     /*NOTREACHED*/
738   usage:
739 #ifdef KERBEROS
740     fprintf (stderr,
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");
744 #else
745     fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, x, f, F, c, PO, or PN\n");
746 #endif
747 #else /* !KERBEROS */
748     fprintf (stderr,
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 */
752     exit(1);
753 }
754
755
756
757 static int confirm_death ()
758 {
759     char hostname[33];
760     char input;
761     int answer;
762     if (!confirm) return (1);   /* no confirm, just die */
763     
764     if (gethostname (hostname, sizeof(hostname)-1) != 0)
765       strcpy (hostname, "???");
766     else
767       hostname[sizeof(hostname)-1] = '\0';
768     
769     fprintf (stderr, "\r\nKill session on %s from %s (y/n)?  ",
770              host, hostname);
771     fflush (stderr);
772     if (read(0, &input, 1) != 1)
773       answer = EOF;     /* read from stdin */
774     else
775       answer = (int) input;
776     fprintf (stderr, "%c\r\n", answer);
777     fflush (stderr);
778     return (answer == 'y' || answer == 'Y' || answer == EOF ||
779             answer == 4);       /* control-D */
780 }
781
782
783
784 #define CRLF "\r\n"
785
786 int     child;
787 krb5_sigtype    catchild (int);
788 krb5_sigtype    writeroob (int);
789
790 int     defflags, tabflag;
791 int     deflflags;
792 char    deferase, defkill;
793
794 #ifdef USE_TERMIO
795 char defvtim, defvmin;
796 #if defined(hpux) || defined(__hpux)
797 #include <sys/bsdtty.h>
798 #include <sys/ptyio.h>
799 #endif
800 struct tchars {
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) */
807 };
808 #endif
809
810
811 #ifndef POSIX_TERMIOS
812 #ifdef TIOCGLTC
813 /*
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.
817  *
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().
821  */
822 struct  ltchars defltc;
823 struct  ltchars noltc = { -1, -1, -1, -1, -1, -1 };
824 #endif
825 struct  tchars deftc;
826 struct  tchars notc =   { -1, -1, -1, -1, -1, -1 };
827 #endif
828
829 static void doit(oldmask)
830 #ifdef POSIX_SIGNALS
831     sigset_t *oldmask;
832 #else
833     int oldmask;
834 #endif
835 {
836 #ifdef POSIX_SIGNALS
837     struct sigaction sa;
838 #endif
839
840 #ifdef POSIX_TERMIOS
841     (void) tcgetattr(0, &deftty);
842 #ifdef VLNEXT
843     /* there's a POSIX way of doing this, but do we need it general? */
844     deftty.c_cc[VLNEXT] = 0;
845 #endif
846 #else
847 #ifdef USE_TERMIO
848     struct termio sb;
849 #else
850     struct sgttyb sb;
851 #endif
852     
853     (void) ioctl(0, TIOCGETP, (char *)&sb);
854     defflags = sb.sg_flags;
855 #ifdef USE_TERMIO
856     tabflag = sb.c_oflag & TABDLY;
857     defflags |= ECHO;
858     deferase = sb.c_cc[VERASE];
859     defkill = sb.c_cc[VKILL];
860     sb.c_cc[VMIN] = 1;
861     sb.c_cc[VTIME] = 1;
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 ;
867     deftc.t_eofc = CEOF;
868     deftc.t_brkc =  '\n';
869 #else
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);
876 #endif
877
878     notc.t_startc = deftc.t_startc;
879     notc.t_stopc = deftc.t_stopc;
880     (void) ioctl(0, TIOCGLTC, (char *)&defltc);
881 #endif
882 #ifdef POSIX_SIGNALS
883     (void) sigemptyset(&sa.sa_mask);
884     sa.sa_flags = 0;
885     sa.sa_handler = SIG_IGN;
886     (void) sigaction(SIGINT, &sa, (struct sigaction *)0);
887 #else
888     (void) signal(SIGINT, SIG_IGN);
889 #endif
890
891     setsignal(SIGHUP, exit_handler);
892     setsignal(SIGQUIT, exit_handler);
893
894     child = fork();
895     if (child == -1) {
896         perror("rlogin: fork");
897         done(1);
898     }
899     if (child == 0) {
900         mode(1);
901         if (reader(oldmask) == 0) {
902             prf("Connection closed.");
903             exit(0);
904         }
905         sleep(1);
906         prf("\007Connection closed.");
907         exit(3);
908     }
909     
910 #ifdef POSIX_SIGNALS
911     /* "sa" has already been initialized above. */
912
913     sa.sa_handler = writeroob;
914     (void) sigaction(SIGUSR1, &sa, (struct sigaction *)0);
915     
916     sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
917
918     sa.sa_handler = catchild;
919     (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
920 #else
921     (void) signal(SIGUSR1, writeroob);
922 #ifndef sgi
923     (void) sigsetmask(oldmask);
924 #endif
925     (void) signal(SIGCHLD, catchild);
926 #endif /* POSIX_SIGNALS */
927     writer();
928     prf("Closed connection.");
929     done(0);
930 }
931
932
933
934 /*
935  * Trap a signal, unless it is being ignored.
936  */
937 void
938 setsignal(sig, act)
939      int sig;
940      krb5_sigtype (*act)();
941 {
942 #ifdef POSIX_SIGNALS
943     sigset_t omask, igmask;
944     struct sigaction sa;
945     
946     sigemptyset(&igmask);
947     sigaddset(&igmask, sig);
948     sigprocmask(SIG_BLOCK, &igmask, &omask);
949 #else
950 #ifdef sgi
951     int omask = sigignore(sigmask(sig));
952 #else
953     int omask = sigblock(sigmask(sig));
954 #endif
955 #endif /* POSIX_SIGNALS */
956     
957 #ifdef POSIX_SIGNALS
958     (void) sigaction(sig, (struct sigaction *)0, &sa);
959     if (sa.sa_handler != SIG_IGN) {
960         (void) sigemptyset(&sa.sa_mask);
961         sa.sa_flags = 0;
962         sa.sa_handler = act;
963         (void) sigaction(sig, &sa, (struct sigaction *)0);
964     }
965     sigprocmask(SIG_SETMASK, &omask, (sigset_t*)0);
966 #else    
967     if (signal(sig, act) == SIG_IGN)
968         (void) signal(sig, SIG_IGN);
969 #ifndef sgi
970     (void) sigsetmask(omask);
971 #endif
972 #endif
973 }
974
975
976
977 static void
978 done(status)
979      int status;
980 {
981 #ifdef POSIX_SIGNALS
982     struct sigaction sa;
983 #endif
984 #ifndef HAVE_WAITPID
985     pid_t w;
986 #endif
987     
988     mode(0);
989     if (child > 0) {
990         /* make sure catchild does not snap it up */
991 #ifdef POSIX_SIGNALS
992         (void) sigemptyset(&sa.sa_mask);
993         sa.sa_flags = 0;
994         sa.sa_handler = SIG_DFL;
995         (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
996 #else
997         (void) signal(SIGCHLD, SIG_DFL);
998 #endif
999         
1000         if (kill(child, SIGKILL) >= 0) {
1001 #ifdef HAVE_WAITPID
1002             (void) waitpid(child, 0, 0);
1003 #else
1004             while ((w = wait(0)) > 0 && w != child)
1005                 /*void*/;
1006 #endif
1007         }
1008     }
1009     exit(status);
1010 }
1011
1012
1013
1014
1015
1016
1017 /*
1018  * This is called when the reader process gets the out-of-band (urgent)
1019  * request to turn on the window-changing protocol.
1020  */
1021 krb5_sigtype
1022   writeroob(signo)
1023 int signo;
1024 {
1025 #ifdef POSIX_SIGNALS
1026     struct sigaction sa;
1027 #endif
1028     
1029     if (dosigwinch == 0) {
1030         sendwindow();
1031 #ifdef POSIX_SIGNALS
1032         (void) sigemptyset(&sa.sa_mask);
1033         sa.sa_flags = 0;
1034         sa.sa_handler = sigwinch;
1035         (void) sigaction(SIGWINCH, &sa, (struct sigaction *)0);
1036 #else
1037         (void) signal(SIGWINCH, sigwinch);
1038 #endif
1039     }
1040     dosigwinch = 1;
1041 }
1042
1043
1044
1045 krb5_sigtype
1046   catchild(signo)
1047 int signo;
1048 {
1049 #ifdef WAIT_USES_INT
1050     int status;
1051 #else
1052     union wait status;
1053 #endif
1054     int pid;
1055     
1056   again:
1057 #ifdef HAVE_WAITPID
1058     pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
1059 #else
1060     pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
1061 #endif
1062     if (pid == 0)
1063       return;
1064     /*
1065      * if the child (reader) dies, just quit
1066      */
1067 #ifdef WAIT_USES_INT
1068     if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
1069       done(status);
1070 #else
1071     if ((pid < 0) || ((pid == child) && (!WIFSTOPPED(status))))
1072         done((int)(status.w_termsig | status.w_retcode));
1073 #endif
1074     goto again;
1075 }
1076
1077
1078
1079 /*
1080  * writer: write to remote: 0 -> line.
1081  * ~.   terminate
1082  * ~^Z  suspend rlogin process.
1083  * ~^Y  suspend rlogin process, but leave reader alone.
1084  */
1085 static void writer()
1086 {
1087     int n_read;
1088     char buf[1024];
1089     int got_esc; /* set to true by read_wrapper if an escape char
1090                     was encountered */
1091     char c;
1092
1093 #ifdef ultrix             
1094     fd_set waitread;
1095     register n;
1096     
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
1099        state is reset.
1100        */
1101     for (;;) {
1102         FD_ZERO(&waitread);
1103         FD_SET(0, &waitread);
1104         n = select(8*sizeof(waitread), &waitread, 0, 0, 0, 0);
1105         if (n < 0 && errno == EINTR)
1106           continue;
1107         if (n > 0)
1108           break;
1109         else
1110           if (n < 0) {
1111               perror("select");
1112               break;
1113           }
1114     }
1115 #endif /* ultrix */
1116
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
1126        program.
1127     */
1128
1129     for (;;) {
1130
1131       /* read until we would block or we get a cmdchar */
1132       n_read = read_wrapper(0,buf,sizeof(buf),&got_esc);
1133   
1134       /* if read returns an error or 0 bytes, just quit */
1135       if (n_read <= 0) {
1136         break;
1137       }
1138       
1139       if (!got_esc) {
1140         if (rcmd_stream_write(rem, buf, (unsigned) n_read, 0) == 0) {
1141           prf("line gone");
1142           break;
1143         }
1144         continue;
1145       }
1146       else {
1147         /* This next test is necessary to avoid sending 0 bytes of data
1148            in the event that we got just a cmdchar */
1149         if (n_read > 1) {
1150           if (rcmd_stream_write(rem, buf, (unsigned) (n_read-1), 0) == 0) {
1151             prf("line gone");
1152             break;
1153           }
1154         }
1155         if (read_wrapper(0,&c,1,&got_esc) <= 0) {
1156           break;
1157         }
1158
1159 #ifdef POSIX_TERMIOS
1160         if (c == '.' || c == deftty.c_cc[VEOF]) 
1161 #else
1162           if (c == '.' || c == deftc.t_eofc) 
1163 #endif
1164             {
1165               if (confirm_death()) {
1166                 echo(c);
1167                 break; 
1168               }
1169             }
1170
1171 #ifdef POSIX_TERMIOS
1172         if ( (
1173               (c == deftty.c_cc[VSUSP]) 
1174 #ifdef VDSUSP
1175               || (c == deftty.c_cc[VDSUSP]) 
1176 #endif
1177               )
1178              && !no_local_escape) {
1179           echo(c);
1180           stop(c);
1181           continue;
1182         }
1183 #else /*POSIX_TERMIOS*/
1184 #ifdef TIOCGLTC
1185         if ((c == defltc.t_suspc || c == defltc.t_dsuspc)
1186             && !no_local_escape) {
1187           echo(c);
1188           stop(c);
1189           continue;
1190         }
1191 #endif /*TIOCGLTC*/
1192 #endif
1193
1194       
1195         if (c != cmdchar) {
1196           rcmd_stream_write(rem, &cmdchar, 1, 0);
1197         }
1198
1199         if (rcmd_stream_write(rem,&c,1,0) == 0) {
1200           prf("line gone");
1201           break;
1202         }
1203       }
1204     }
1205 }
1206
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. 
1218 */
1219
1220 static int read_wrapper(fd,buf,size,got_esc) 
1221      int fd;
1222      char *buf;
1223      int size;
1224      int *got_esc;
1225 {
1226   static char tbuf[1024];
1227   static char *data_start = tbuf;
1228   static char *data_end = tbuf;
1229   static int bol = 1;
1230   unsigned int return_length = 0;
1231   char c;
1232
1233   /* if we have no data buffered, get more */
1234   if (data_start == data_end) {
1235     int n_read;
1236     while ((n_read = read(fd, tbuf, sizeof(tbuf))) <= 0) {
1237       if (n_read < 0 && errno == EINTR)
1238         continue;
1239       return n_read;
1240     }
1241     data_start = tbuf;
1242     data_end = tbuf+n_read;
1243   }
1244
1245   *got_esc = 0;
1246
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.
1250   */
1251
1252   while (data_start+return_length < data_end && return_length < size) {
1253     
1254     c = *(data_start+return_length);
1255     return_length++;
1256
1257     if (bol == 1 && c == cmdchar) {
1258       bol = 0;
1259       *got_esc = 1;
1260       break;
1261     }
1262
1263 #ifdef POSIX_TERMIOS
1264     bol = (c == deftty.c_cc[VKILL] ||
1265            c == deftty.c_cc[VINTR] ||
1266            c == '\r' || c == '\n');
1267         
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';
1272 #endif
1273   }
1274    
1275   memcpy(buf, data_start, return_length);
1276   data_start = data_start + return_length;
1277   return return_length;
1278 }
1279
1280 static void echo(c)
1281      register char c;
1282 {
1283     char buf[8];
1284     register char *p = buf;
1285     
1286     c &= 0177;
1287     *p++ = cmdchar;
1288     if (c < ' ') {
1289         *p++ = '^';
1290         *p++ = c + '@';
1291     } else if (c == 0177) {
1292         *p++ = '^';
1293         *p++ = '?';
1294     } else
1295       *p++ = c;
1296     *p++ = '\r';
1297     *p++ = '\n';
1298     (void) write(1, buf, (unsigned) (p - buf));
1299 }
1300
1301
1302
1303 static void stop(cmdc)
1304      char cmdc;
1305 {
1306 #ifdef POSIX_SIGNALS
1307     struct sigaction sa;
1308 #endif
1309     
1310     mode(0);
1311
1312 #ifdef POSIX_SIGNALS
1313     (void) sigemptyset(&sa.sa_mask);
1314     sa.sa_flags = 0;
1315     sa.sa_handler = SIG_IGN;
1316     (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
1317 #else
1318     (void) signal(SIGCHLD, SIG_IGN);
1319 #endif
1320     
1321 #ifdef POSIX_TERMIOS
1322     (void) kill(cmdc == deftty.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
1323 #else
1324 #ifdef TIOCGLTC
1325     (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
1326 #endif
1327 #endif
1328 #ifdef POSIX_SIGNALS
1329     sa.sa_handler = catchild;
1330     (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
1331 #else
1332     (void) signal(SIGCHLD, catchild);
1333 #endif
1334     
1335     mode(1);
1336     sigwinch(SIGWINCH);         /* check for size changes */
1337 }
1338
1339
1340
1341 krb5_sigtype
1342   sigwinch(signo)
1343 int signo;
1344 {
1345     struct winsize ws;
1346     
1347     if (dosigwinch && get_window_size(0, &ws) == 0 &&
1348         memcmp(&winsize, &ws, sizeof (ws))) {
1349         winsize = ws;
1350         sendwindow();
1351     }
1352 }
1353
1354
1355
1356 /*
1357  * Send the window size to the server via the magic escape
1358  */
1359 static void sendwindow()
1360 {
1361     char obuf[4 + sizeof (struct winsize)];
1362     struct winsize *wp = (struct winsize *)(void *)(obuf+4);
1363     
1364     obuf[0] = 0377;
1365     obuf[1] = 0377;
1366     obuf[2] = 's';
1367     obuf[3] = 's';
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);
1373 }
1374
1375
1376
1377 /*
1378  * reader: read from remote: line -> 1
1379  */
1380 #define READING 1
1381 #define WRITING 2
1382
1383 char    rcvbuf[8 * 1024];
1384 int     rcvcnt;
1385 int     rcvstate;
1386 int     ppid;
1387
1388 /* returns 1 if flush, 0 otherwise */
1389
1390 int server_message(mark)
1391      int mark;
1392 {
1393 #ifndef POSIX_TERMIOS
1394     int out = FWRITE;
1395 #endif
1396 #ifdef POSIX_TERMIOS
1397     struct termios tty;
1398 #else
1399 #ifdef USE_TERMIO
1400     struct termio sb;
1401 #else
1402     struct sgttyb sb;
1403 #endif
1404 #endif
1405
1406     if (mark & TIOCPKT_WINDOW) {
1407         /*
1408          * Let server know about window size changes
1409          */
1410         (void) kill(ppid, SIGUSR1);
1411     }
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);
1417     }
1418     if (!eight && (mark & TIOCPKT_DOSTOP)) {
1419       (void) tcgetattr(0, &tty);
1420       tty.c_iflag |= IXON;
1421       (void) tcsetattr(0, TCSADRAIN, &tty);
1422     }
1423 #else
1424     if (!eight && (mark & TIOCPKT_NOSTOP)) {
1425         (void) ioctl(0, TIOCGETP, (char *)&sb);
1426 #ifdef USE_TERMIO
1427         sb.c_iflag |= IXOFF;
1428         sb.sg_flags &= ~ICANON;
1429 #else
1430         sb.sg_flags &= ~CBREAK;
1431         sb.sg_flags |= RAW;
1432         notc.t_stopc = -1;
1433         notc.t_startc = -1;
1434         (void) ioctl(0, TIOCSETC, (char *)&notc);
1435 #endif
1436         (void) ioctl(0, TIOCSETN, (char *)&sb);
1437     }
1438     if (!eight && (mark & TIOCPKT_DOSTOP)) {
1439         (void) ioctl(0, TIOCGETP, (char *)&sb);
1440 #ifdef USE_TERMIO
1441         sb.sg_flags  |= ICANON;
1442         sb.c_iflag |= IXON;
1443 #else
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 *)&notc);
1449 #endif
1450         (void) ioctl(0, TIOCSETN, (char *)&sb);
1451     }
1452 #endif
1453     if (mark & TIOCPKT_FLUSHWRITE) {
1454 #ifdef POSIX_TERMIOS
1455         (void) tcflush(1, TCOFLUSH);
1456 #else
1457 #ifdef  TIOCFLUSH
1458         (void) ioctl(1, TIOCFLUSH, (char *)&out);
1459 #else
1460         (void) ioctl(1, TCFLSH, 1);
1461 #endif
1462 #endif
1463         return(1);
1464     }
1465
1466     return(0);
1467 }
1468
1469 void oob()
1470 {
1471     char mark;
1472     static char waste[RLOGIN_BUFSIZ];
1473     int atmark, n;
1474
1475     mark = 0;
1476     
1477     recv(rem, &mark, 1, MSG_OOB);
1478
1479     if (server_message(mark)) {
1480         for (;;) {
1481             if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
1482                 perror("ioctl");
1483                 return;
1484             }
1485             if (atmark)
1486                 break;
1487             n = read(rem, waste, sizeof (waste));
1488             if (n <= 0)
1489                 break;
1490         }
1491     }
1492 }
1493
1494 /* two control messages are defined:
1495
1496    a double flag byte of 'o' indicates a one-byte message which is
1497    identical to what was once carried out of band.  
1498
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
1502    client.  */
1503
1504 static int control(cp, n)
1505      char *cp;
1506      unsigned int n;
1507 {
1508     if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
1509         if (server_message(cp[4]))
1510             return(-5);
1511         return(5);
1512     } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
1513         /* this is somewhat of a hack */
1514         cp[2] = '\377';
1515         cp[3] = '\377';
1516         return(2);
1517     }
1518
1519     return(0);
1520 }
1521
1522 /*
1523  * reader: read from remote: line -> 1 
1524  */
1525 static int 
1526 reader(oldmask)
1527 #ifdef POSIX_SIGNALS
1528     sigset_t *oldmask;
1529 #else
1530      int oldmask;
1531 #endif
1532 {
1533     fd_set readset, excset, writeset;
1534     int n, remaining;
1535     unsigned int left;
1536     char *bufp = rcvbuf;
1537     char *cp;
1538
1539 #ifdef POSIX_SIGNALS
1540     struct sigaction sa;
1541
1542     (void) sigemptyset(&sa.sa_mask);
1543     sa.sa_flags = 0;
1544     sa.sa_handler = SIG_IGN;
1545     (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
1546
1547 #else    
1548     (void) signal(SIGTTOU, SIG_IGN);
1549 #endif
1550     
1551     ppid = getppid();
1552     FD_ZERO(&readset);
1553     FD_ZERO(&excset);
1554     FD_ZERO(&writeset);
1555 #ifdef POSIX_SIGNALS
1556     sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
1557 #else
1558 #ifndef sgi
1559     (void) sigsetmask(oldmask);
1560 #endif
1561 #endif /* POSIX_SIGNALS */
1562
1563     for (;;) {
1564         if ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
1565             FD_SET(1,&writeset);
1566             rcvstate = WRITING;
1567             FD_CLR(rem, &readset);
1568         } else {
1569             bufp = rcvbuf;
1570             rcvcnt = 0;
1571             rcvstate = READING;
1572             FD_SET(rem,&readset);
1573             FD_CLR(1,&writeset);
1574         }
1575         if (!do_inband)
1576             FD_SET(rem,&excset);
1577         if (select(rem+1, &readset, &writeset, &excset, 0) > 0 ) {
1578             if (!do_inband)
1579                 if (FD_ISSET(rem, &excset))
1580                     oob();
1581             if (FD_ISSET(1,&writeset)) {
1582                 n = write(1, bufp, remaining);
1583                 if (n < 0) {
1584                     if (errno != EINTR)
1585                         return (-1);
1586                     continue;
1587                 }
1588                 bufp += n;
1589             }
1590             if (FD_ISSET(rem, &readset)) {
1591                 rcvcnt = rcmd_stream_read(rem, rcvbuf, sizeof (rcvbuf), 0);
1592                 if (rcvcnt == 0)
1593                     return (0);
1594                 if (rcvcnt < 0)
1595                     goto error;
1596
1597                 if (do_inband) {
1598                     for (cp = rcvbuf; cp < rcvbuf+rcvcnt-1; cp++) {
1599                         if (cp[0] == '\377' &&
1600                             cp[1] == '\377') {
1601                             left = (rcvbuf+rcvcnt) - cp;
1602                             n = control(cp, left);
1603                             /* |n| <= left */
1604                             if (n < 0) {
1605                                 left -= (-n);
1606                                 rcvcnt = 0;
1607                                 /* flush before, and (-n) bytes */
1608                                 if (left > 0)
1609                                     memmove(rcvbuf, cp+(-n), left);
1610                                 cp = rcvbuf-1;
1611                             } else if (n) {
1612                                 left -= n;
1613                                 rcvcnt -= n;
1614                                 if (left > 0)
1615                                     memmove(cp, cp+n, left);
1616                                 cp--;
1617                             }
1618                         }
1619                     }
1620                 }
1621             }
1622         } else
1623 error:
1624         {
1625             if (errno == EINTR)
1626               continue;
1627             perror("read");
1628             return (-1);
1629         }
1630     }
1631 }
1632
1633
1634
1635 static void mode(f)
1636 int f;
1637 {
1638 #ifdef POSIX_TERMIOS
1639     struct termios newtty;
1640 #ifndef IEXTEN
1641 #define IEXTEN 0 /* No effect*/
1642 #endif
1643 #ifndef _POSIX_VDISABLE
1644 #define _POSIX_VDISABLE 0 /*A good guess at the disable-this-character character*/
1645 #endif
1646
1647     switch(f) {
1648     case 0:
1649         (void) tcsetattr(0, TCSADRAIN, &deftty);
1650         break;
1651     case 1:
1652         (void) tcgetattr(0, &newtty);
1653         /* was __svr4__ */
1654 #ifdef VLNEXT
1655         /* there's a POSIX way of doing this, but do we need it general? */
1656         newtty.c_cc[VLNEXT] = _POSIX_VDISABLE;
1657 #endif
1658                 
1659         newtty.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
1660         newtty.c_iflag &= ~(ISTRIP|INLCR|ICRNL);
1661
1662         if (!flow) {
1663             newtty.c_iflag &= ~(BRKINT|IXON|IXANY);
1664             newtty.c_oflag &= ~(OPOST);
1665         } else {
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);
1671         }
1672 #ifdef TABDLY
1673         /* preserve tab delays, but turn off XTABS */
1674         if ((newtty.c_oflag & TABDLY) == TAB3)
1675             newtty.c_oflag &= ~TABDLY;
1676 #endif
1677         if (!eight)
1678             newtty.c_iflag |= ISTRIP;
1679         if (litout)
1680             newtty.c_oflag &= ~OPOST;
1681
1682         newtty.c_cc[VMIN] = 1;
1683         newtty.c_cc[VTIME] = 0;
1684         (void) tcsetattr(0, TCSADRAIN, &newtty);
1685         break;
1686     default:
1687         return;
1688         /* NOTREACHED */
1689     }
1690 #else
1691     struct ltchars *ltc;
1692 #ifdef USE_TERMIO
1693     struct termio sb;
1694 #else
1695     struct tchars *tc;
1696     struct sgttyb sb;
1697     int lflags;
1698     (void) ioctl(0, TIOCLGET, (char *)&lflags);
1699 #endif
1700     
1701     (void) ioctl(0, TIOCGETP, (char *)&sb);
1702     switch (f) {
1703         
1704     case 0:
1705 #ifdef USE_TERMIO
1706         /*
1707         **      remember whether IXON was set, so it can be restored
1708         **      when mode(1) is next done
1709         */
1710         (void) ioctl(fileno(stdin), TIOCGETP, &ixon_state);
1711         /*
1712         **      copy the initial modes we saved into sb; this is
1713         **      for restoring to the initial state
1714         */
1715         (void)memcpy(&sb, &defmodes, sizeof(defmodes));
1716         
1717 #else
1718         sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
1719         sb.sg_flags |= defflags|tabflag;
1720         sb.sg_kill = defkill;
1721         sb.sg_erase = deferase;
1722         lflags = deflflags;
1723         tc = &deftc;
1724 #endif
1725         ltc = &defltc;
1726         break;
1727         
1728     case 1:
1729 #ifdef USE_TERMIO
1730         /*
1731         **      turn off output mappings
1732         */
1733         sb.c_oflag &= ~(ONLCR|OCRNL);
1734         /*
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
1738         */
1739         sb.c_lflag &= ~(ECHO|ICANON|ISIG);
1740         sb.c_cc[VTIME] = 1;
1741         sb.c_cc[VMIN] = 1;
1742         if (eight)
1743             sb.c_iflag &= ~(ISTRIP);
1744 #ifdef TABDLY
1745         /* preserve tab delays, but turn off tab-to-space expansion */
1746         if ((sb.c_oflag & TABDLY) == TAB3)
1747             sb.c_oflag &= ~TAB3;
1748 #endif
1749         /*
1750         **  restore current flow control state
1751         */
1752         if ((ixon_state.c_iflag & IXON) && flow ) {
1753             sb.c_iflag |= IXON;
1754         } else {
1755             sb.c_iflag &= ~IXON;
1756         }
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;
1764 #ifdef LLITOUT
1765         if (litout)
1766             lflags |= LLITOUT;
1767 #endif
1768 #ifdef LPASS8
1769         if (eight)
1770             lflags |= LPASS8;
1771 #endif /* LPASS8 */
1772         tc = &notc;
1773         sb.sg_flags &= ~defflags;
1774 #endif /* USE_TERMIO */
1775         
1776         ltc = &noltc;
1777         break;
1778         
1779     default:
1780         return;
1781     }
1782     (void) ioctl(0, TIOCSLTC, (char *)ltc);
1783 #ifndef USE_TERMIO
1784     (void) ioctl(0, TIOCSETC, (char *)tc);
1785     (void) ioctl(0, TIOCLSET, (char *)&lflags);
1786 #endif
1787     (void) ioctl(0, TIOCSETN, (char *)&sb);
1788 #endif /* !POSIX_TERMIOS */
1789 }
1790
1791
1792
1793 static void
1794 prf(f)
1795      char *f;
1796 {
1797     fprintf(stderr, f);
1798     fprintf(stderr, CRLF);
1799 }
1800
1801
1802
1803 #ifdef KERBEROS
1804 void try_normal(argv)
1805      char **argv;
1806 {
1807     register char *nhost;
1808 #ifdef POSIX_SIGNALS
1809     sigset_t mask;
1810 #endif
1811     
1812 #ifndef KRB5_ATHENA_COMPAT
1813     if (encrypt_flag)
1814       exit(1);
1815 #endif
1816     fprintf(stderr,"trying normal rlogin (%s)\n",
1817             UCB_RLOGIN);
1818     fflush(stderr);
1819     
1820     nhost = strrchr(argv[0], '/');
1821     if (nhost)
1822       nhost++;
1823     else
1824       nhost = argv[0];
1825     if (!strcmp(nhost, "rlogin") || !strcmp(nhost, "rsh"))
1826       argv[0] = UCB_RLOGIN;
1827     
1828 #ifdef POSIX_SIGNALS
1829     sigemptyset(&mask);
1830     sigprocmask(SIG_SETMASK, &mask, NULL);
1831 #endif
1832
1833     execv(UCB_RLOGIN, argv);
1834     perror("exec");
1835     exit(1);
1836 }
1837 #endif
1838
1839
1840
1841 krb5_sigtype lostpeer(signo)
1842     int signo;
1843 {
1844 #ifdef POSIX_SIGNALS
1845     struct sigaction sa;
1846
1847     (void) sigemptyset(&sa.sa_mask);
1848     sa.sa_flags = 0;
1849     sa.sa_handler = SIG_IGN;
1850     (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
1851 #else
1852     (void) signal(SIGPIPE, SIG_IGN);
1853 #endif
1854     
1855     prf("\007Connection closed.");
1856     done(1);
1857 }