]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/telnetd/telnetd.c
Move OBJFORMAT hack to the correct line; what can I say, it was very
[FreeBSD/FreeBSD.git] / libexec / telnetd / telnetd.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1989, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)telnetd.c   8.2 (Berkeley) 12/15/93";
43 #endif
44 static const char rcsid[] =
45         "$Id: telnetd.c,v 1.13 1997/12/03 07:16:05 charnier Exp $";
46 #endif /* not lint */
47
48 #include "telnetd.h"
49 #include "pathnames.h"
50
51 #if     defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
52 /*
53  * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
54  * use it to tell us to turn off all the socket security code,
55  * since that is only used in UNICOS 7.0 and later.
56  */
57 # undef _SC_CRAY_SECURE_SYS
58 #endif
59
60 #include <err.h>
61 #include <arpa/inet.h>
62
63 #include <sys/mman.h>
64
65 #if     defined(_SC_CRAY_SECURE_SYS)
66 #include <sys/sysv.h>
67 #include <sys/secdev.h>
68 # ifdef SO_SEC_MULTI            /* 8.0 code */
69 #include <sys/secparm.h>
70 #include <sys/usrv.h>
71 # endif /* SO_SEC_MULTI */
72 int     secflag;
73 char    tty_dev[16];
74 struct  secdev dv;
75 struct  sysv sysv;
76 # ifdef SO_SEC_MULTI            /* 8.0 code */
77 struct  socksec ss;
78 # else /* SO_SEC_MULTI */       /* 7.0 code */
79 struct  socket_security ss;
80 # endif /* SO_SEC_MULTI */
81 #endif  /* _SC_CRAY_SECURE_SYS */
82
83 #if     defined(AUTHENTICATION)
84 #include <libtelnet/auth.h>
85 int     auth_level = 0;
86 #endif
87 #if     defined(SecurID)
88 int     require_SecurID = 0;
89 #endif
90
91 extern  int utmp_len;
92 int     registerd_host_only = 0;
93
94 #ifdef  STREAMSPTY
95 # include <stropts.h>
96 # include <termio.h>
97 /* make sure we don't get the bsd version */
98 # include "/usr/include/sys/tty.h"
99 # include <sys/ptyvar.h>
100
101 /*
102  * Because of the way ptyibuf is used with streams messages, we need
103  * ptyibuf+1 to be on a full-word boundary.  The following wierdness
104  * is simply to make that happen.
105  */
106 long    ptyibufbuf[BUFSIZ/sizeof(long)+1];
107 char    *ptyibuf = ((char *)&ptyibufbuf[1])-1;
108 char    *ptyip = ((char *)&ptyibufbuf[1])-1;
109 char    ptyibuf2[BUFSIZ];
110 unsigned char ctlbuf[BUFSIZ];
111 struct  strbuf strbufc, strbufd;
112
113 int readstream();
114
115 #else   /* ! STREAMPTY */
116
117 /*
118  * I/O data buffers,
119  * pointers, and counters.
120  */
121 char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
122 char    ptyibuf2[BUFSIZ];
123
124 #endif /* ! STREAMPTY */
125
126 int     hostinfo = 1;                   /* do we print login banner? */
127
128 #ifdef  CRAY
129 extern int      newmap; /* nonzero if \n maps to ^M^J */
130 int     lowpty = 0, highpty;    /* low, high pty numbers */
131 #endif /* CRAY */
132
133 int debug = 0;
134 int keepalive = 1;
135 char *altlogin;
136
137 void doit __P((struct sockaddr_in *));
138 int terminaltypeok __P((char *));
139 void startslave __P((char *, int, char *));
140 extern void usage P((void));
141
142 /*
143  * The string to pass to getopt().  We do it this way so
144  * that only the actual options that we support will be
145  * passed off to getopt().
146  */
147 char valid_opts[] = {
148         'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
149 #ifdef  AUTHENTICATION
150         'a', ':', 'X', ':',
151 #endif
152 #ifdef BFTPDAEMON
153         'B',
154 #endif
155 #ifdef DIAGNOSTICS
156         'D', ':',
157 #endif
158 #if     defined(CRAY) && defined(NEWINIT)
159         'I', ':',
160 #endif
161 #ifdef  LINEMODE
162         'l',
163 #endif
164 #ifdef CRAY
165         'r', ':',
166 #endif
167 #ifdef  SecurID
168         's',
169 #endif
170         '\0'
171 };
172
173         int
174 main(argc, argv)
175         char *argv[];
176 {
177         struct sockaddr_in from;
178         int on = 1, fromlen;
179         register int ch;
180 #if     defined(IPPROTO_IP) && defined(IP_TOS)
181         int tos = -1;
182 #endif
183
184         pfrontp = pbackp = ptyobuf;
185         netip = netibuf;
186         nfrontp = nbackp = netobuf;
187
188         /*
189          * This initialization causes linemode to default to a configuration
190          * that works on all telnet clients, including the FreeBSD client.
191          * This is not quite the same as the telnet client issuing a "mode
192          * character" command, but has most of the same benefits, and is
193          * preferable since some clients (like usofts) don't have the
194          * mode character command anyway and linemode breaks things.
195          * The most notable symptom of fix is that csh "set filec" operations
196          * like <ESC> (filename completion) and ^D (choices) keys now work
197          * in telnet sessions and can be used more than once on the same line.
198          * CR/LF handling is also corrected in some termio modes.  This 
199          * change resolves problem reports bin/771 and bin/1037.
200          */
201
202         linemode=1;     /*Default to mode that works on bulk of clients*/
203
204 #ifdef CRAY
205         /*
206          * Get number of pty's before trying to process options,
207          * which may include changing pty range.
208          */
209         highpty = getnpty();
210 #endif /* CRAY */
211
212         while ((ch = getopt(argc, argv, valid_opts)) != -1) {
213                 switch(ch) {
214
215 #ifdef  AUTHENTICATION
216                 case 'a':
217                         /*
218                          * Check for required authentication level
219                          */
220                         if (strcmp(optarg, "debug") == 0) {
221                                 extern int auth_debug_mode;
222                                 auth_debug_mode = 1;
223                         } else if (strcasecmp(optarg, "none") == 0) {
224                                 auth_level = 0;
225                         } else if (strcasecmp(optarg, "other") == 0) {
226                                 auth_level = AUTH_OTHER;
227                         } else if (strcasecmp(optarg, "user") == 0) {
228                                 auth_level = AUTH_USER;
229                         } else if (strcasecmp(optarg, "valid") == 0) {
230                                 auth_level = AUTH_VALID;
231                         } else if (strcasecmp(optarg, "off") == 0) {
232                                 /*
233                                  * This hack turns off authentication
234                                  */
235                                 auth_level = -1;
236                         } else {
237                                 warnx("unknown authorization level for -a");
238                         }
239                         break;
240 #endif  /* AUTHENTICATION */
241
242 #ifdef BFTPDAEMON
243                 case 'B':
244                         bftpd++;
245                         break;
246 #endif /* BFTPDAEMON */
247
248                 case 'd':
249                         if (strcmp(optarg, "ebug") == 0) {
250                                 debug++;
251                                 break;
252                         }
253                         usage();
254                         /* NOTREACHED */
255                         break;
256
257 #ifdef DIAGNOSTICS
258                 case 'D':
259                         /*
260                          * Check for desired diagnostics capabilities.
261                          */
262                         if (!strcmp(optarg, "report")) {
263                                 diagnostic |= TD_REPORT|TD_OPTIONS;
264                         } else if (!strcmp(optarg, "exercise")) {
265                                 diagnostic |= TD_EXERCISE;
266                         } else if (!strcmp(optarg, "netdata")) {
267                                 diagnostic |= TD_NETDATA;
268                         } else if (!strcmp(optarg, "ptydata")) {
269                                 diagnostic |= TD_PTYDATA;
270                         } else if (!strcmp(optarg, "options")) {
271                                 diagnostic |= TD_OPTIONS;
272                         } else {
273                                 usage();
274                                 /* NOT REACHED */
275                         }
276                         break;
277 #endif /* DIAGNOSTICS */
278
279
280                 case 'h':
281                         hostinfo = 0;
282                         break;
283
284 #if     defined(CRAY) && defined(NEWINIT)
285                 case 'I':
286                     {
287                         extern char *gen_id;
288                         gen_id = optarg;
289                         break;
290                     }
291 #endif  /* defined(CRAY) && defined(NEWINIT) */
292
293 #ifdef  LINEMODE
294                 case 'l':
295                         alwayslinemode = 1;
296                         break;
297 #endif  /* LINEMODE */
298
299                 case 'k':
300 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
301                         lmodetype = NO_AUTOKLUDGE;
302 #else
303                         /* ignore -k option if built without kludge linemode */
304 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
305                         break;
306
307                 case 'n':
308                         keepalive = 0;
309                         break;
310
311                 case 'p':
312                         altlogin = optarg;
313                         break;
314
315 #ifdef CRAY
316                 case 'r':
317                     {
318                         char *strchr();
319                         char *c;
320
321                         /*
322                          * Allow the specification of alterations
323                          * to the pty search range.  It is legal to
324                          * specify only one, and not change the
325                          * other from its default.
326                          */
327                         c = strchr(optarg, '-');
328                         if (c) {
329                                 *c++ = '\0';
330                                 highpty = atoi(c);
331                         }
332                         if (*optarg != '\0')
333                                 lowpty = atoi(optarg);
334                         if ((lowpty > highpty) || (lowpty < 0) ||
335                                                         (highpty > 32767)) {
336                                 usage();
337                                 /* NOT REACHED */
338                         }
339                         break;
340                     }
341 #endif  /* CRAY */
342
343 #ifdef  SecurID
344                 case 's':
345                         /* SecurID required */
346                         require_SecurID = 1;
347                         break;
348 #endif  /* SecurID */
349                 case 'S':
350 #ifdef  HAS_GETTOS
351                         if ((tos = parsetos(optarg, "tcp")) < 0)
352                                 warnx("%s%s%s",
353                                         "bad TOS argument '", optarg,
354                                         "'; will try to use default TOS");
355 #else
356                         warnx("TOS option unavailable; -S flag not supported");
357 #endif
358                         break;
359
360                 case 'u':
361                         utmp_len = atoi(optarg);
362                         break;
363
364                 case 'U':
365                         registerd_host_only = 1;
366                         break;
367
368 #ifdef  AUTHENTICATION
369                 case 'X':
370                         /*
371                          * Check for invalid authentication types
372                          */
373                         auth_disable_name(optarg);
374                         break;
375 #endif  /* AUTHENTICATION */
376
377                 default:
378                         warnx("%c: unknown option", ch);
379                         /* FALLTHROUGH */
380                 case '?':
381                         usage();
382                         /* NOTREACHED */
383                 }
384         }
385
386         argc -= optind;
387         argv += optind;
388
389         if (debug) {
390             int s, ns, foo;
391             struct servent *sp;
392             static struct sockaddr_in sin = { AF_INET };
393
394             if (argc > 1) {
395                 usage();
396                 /* NOT REACHED */
397             } else if (argc == 1) {
398                     if ((sp = getservbyname(*argv, "tcp"))) {
399                         sin.sin_port = sp->s_port;
400                     } else {
401                         sin.sin_port = atoi(*argv);
402                         if ((int)sin.sin_port <= 0) {
403                             warnx("%s: bad port #", *argv);
404                             usage();
405                             /* NOT REACHED */
406                         }
407                         sin.sin_port = htons((u_short)sin.sin_port);
408                    }
409             } else {
410                 sp = getservbyname("telnet", "tcp");
411                 if (sp == 0)
412                     errx(1, "tcp/telnet: unknown service");
413                 sin.sin_port = sp->s_port;
414             }
415
416             s = socket(AF_INET, SOCK_STREAM, 0);
417             if (s < 0)
418                     err(1, "socket");
419             (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
420                                 (char *)&on, sizeof(on));
421             if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
422                 err(1, "bind");
423             if (listen(s, 1) < 0)
424                 err(1, "listen");
425             foo = sizeof sin;
426             ns = accept(s, (struct sockaddr *)&sin, &foo);
427             if (ns < 0)
428                 err(1, "accept");
429             (void) dup2(ns, 0);
430             (void) close(ns);
431             (void) close(s);
432 #ifdef convex
433         } else if (argc == 1) {
434                 ; /* VOID*/             /* Just ignore the host/port name */
435 #endif
436         } else if (argc > 0) {
437                 usage();
438                 /* NOT REACHED */
439         }
440
441 #if     defined(_SC_CRAY_SECURE_SYS)
442         secflag = sysconf(_SC_CRAY_SECURE_SYS);
443
444         /*
445          *      Get socket's security label
446          */
447         if (secflag)  {
448                 int szss = sizeof(ss);
449 #ifdef SO_SEC_MULTI                     /* 8.0 code */
450                 int sock_multi;
451                 int szi = sizeof(int);
452 #endif /* SO_SEC_MULTI */
453
454                 bzero((char *)&dv, sizeof(dv));
455
456                 if (getsysv(&sysv, sizeof(struct sysv)) != 0)
457                         err(1, "getsysv");
458
459                 /*
460                  *      Get socket security label and set device values
461                  *         {security label to be set on ttyp device}
462                  */
463 #ifdef SO_SEC_MULTI                     /* 8.0 code */
464                 if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
465                                (char *)&ss, &szss) < 0) ||
466                     (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
467                                 (char *)&sock_multi, &szi) < 0)) {
468                         err(1, "getsockopt");
469                 } else {
470                         dv.dv_actlvl = ss.ss_actlabel.lt_level;
471                         dv.dv_actcmp = ss.ss_actlabel.lt_compart;
472                         if (!sock_multi) {
473                                 dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
474                                 dv.dv_valcmp = dv.dv_actcmp;
475                         } else {
476                                 dv.dv_minlvl = ss.ss_minlabel.lt_level;
477                                 dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
478                                 dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
479                         }
480                         dv.dv_devflg = 0;
481                 }
482 #else /* SO_SEC_MULTI */                /* 7.0 code */
483                 if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
484                                 (char *)&ss, &szss) >= 0) {
485                         dv.dv_actlvl = ss.ss_slevel;
486                         dv.dv_actcmp = ss.ss_compart;
487                         dv.dv_minlvl = ss.ss_minlvl;
488                         dv.dv_maxlvl = ss.ss_maxlvl;
489                         dv.dv_valcmp = ss.ss_maxcmp;
490                 }
491 #endif /* SO_SEC_MULTI */
492         }
493 #endif  /* _SC_CRAY_SECURE_SYS */
494
495         openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
496         fromlen = sizeof (from);
497         if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
498                 warn("getpeername");
499                 _exit(1);
500         }
501         if (keepalive &&
502             setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
503                         (char *)&on, sizeof (on)) < 0) {
504                 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
505         }
506
507 #if     defined(IPPROTO_IP) && defined(IP_TOS)
508         {
509 # if    defined(HAS_GETTOS)
510                 struct tosent *tp;
511                 if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
512                         tos = tp->t_tos;
513 # endif
514                 if (tos < 0)
515                         tos = 020;      /* Low Delay bit */
516                 if (tos
517                    && (setsockopt(0, IPPROTO_IP, IP_TOS,
518                                   (char *)&tos, sizeof(tos)) < 0)
519                    && (errno != ENOPROTOOPT) )
520                         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
521         }
522 #endif  /* defined(IPPROTO_IP) && defined(IP_TOS) */
523         net = 0;
524         doit(&from);
525         /* NOTREACHED */
526         return(0);
527 }  /* end of main */
528
529         void
530 usage()
531 {
532         fprintf(stderr, "usage: telnetd");
533 #ifdef  AUTHENTICATION
534         fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
535 #endif
536 #ifdef BFTPDAEMON
537         fprintf(stderr, " [-B]");
538 #endif
539         fprintf(stderr, " [-debug]");
540 #ifdef DIAGNOSTICS
541         fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
542 #endif
543 #ifdef  AUTHENTICATION
544         fprintf(stderr, " [-edebug]");
545 #endif
546         fprintf(stderr, " [-h]");
547 #if     defined(CRAY) && defined(NEWINIT)
548         fprintf(stderr, " [-Iinitid]");
549 #endif
550 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
551         fprintf(stderr, " [-k]");
552 #endif
553 #ifdef LINEMODE
554         fprintf(stderr, " [-l]");
555 #endif
556         fprintf(stderr, " [-n]");
557 #ifdef  CRAY
558         fprintf(stderr, " [-r[lowpty]-[highpty]]");
559 #endif
560         fprintf(stderr, "\n\t");
561 #ifdef  SecurID
562         fprintf(stderr, " [-s]");
563 #endif
564 #ifdef  HAS_GETTOS
565         fprintf(stderr, " [-S tos]");
566 #endif
567 #ifdef  AUTHENTICATION
568         fprintf(stderr, " [-X auth-type]");
569 #endif
570         fprintf(stderr, " [-u utmp_hostname_length] [-U]");
571         fprintf(stderr, " [port]\n");
572         exit(1);
573 }
574
575 /*
576  * getterminaltype
577  *
578  *      Ask the other end to send along its terminal type and speed.
579  * Output is the variable terminaltype filled in.
580  */
581 static unsigned char ttytype_sbbuf[] = {
582         IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
583 };
584
585     int
586 getterminaltype(name)
587     char *name;
588 {
589     int retval = -1;
590     void _gettermname();
591
592     settimer(baseline);
593 #if     defined(AUTHENTICATION)
594     /*
595      * Handle the Authentication option before we do anything else.
596      */
597     send_do(TELOPT_AUTHENTICATION, 1);
598     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
599         ttloop();
600     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
601         retval = auth_wait(name);
602     }
603 #endif
604
605     send_do(TELOPT_TTYPE, 1);
606     send_do(TELOPT_TSPEED, 1);
607     send_do(TELOPT_XDISPLOC, 1);
608     send_do(TELOPT_NEW_ENVIRON, 1);
609     send_do(TELOPT_OLD_ENVIRON, 1);
610     while (
611            his_will_wont_is_changing(TELOPT_TTYPE) ||
612            his_will_wont_is_changing(TELOPT_TSPEED) ||
613            his_will_wont_is_changing(TELOPT_XDISPLOC) ||
614            his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
615            his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
616         ttloop();
617     }
618     if (his_state_is_will(TELOPT_TSPEED)) {
619         static unsigned char sb[] =
620                         { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
621
622         bcopy(sb, nfrontp, sizeof sb);
623         nfrontp += sizeof sb;
624     }
625     if (his_state_is_will(TELOPT_XDISPLOC)) {
626         static unsigned char sb[] =
627                         { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
628
629         bcopy(sb, nfrontp, sizeof sb);
630         nfrontp += sizeof sb;
631     }
632     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
633         static unsigned char sb[] =
634                         { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
635
636         bcopy(sb, nfrontp, sizeof sb);
637         nfrontp += sizeof sb;
638     }
639     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
640         static unsigned char sb[] =
641                         { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
642
643         bcopy(sb, nfrontp, sizeof sb);
644         nfrontp += sizeof sb;
645     }
646     if (his_state_is_will(TELOPT_TTYPE)) {
647
648         bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
649         nfrontp += sizeof ttytype_sbbuf;
650     }
651     if (his_state_is_will(TELOPT_TSPEED)) {
652         while (sequenceIs(tspeedsubopt, baseline))
653             ttloop();
654     }
655     if (his_state_is_will(TELOPT_XDISPLOC)) {
656         while (sequenceIs(xdisplocsubopt, baseline))
657             ttloop();
658     }
659     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
660         while (sequenceIs(environsubopt, baseline))
661             ttloop();
662     }
663     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
664         while (sequenceIs(oenvironsubopt, baseline))
665             ttloop();
666     }
667     if (his_state_is_will(TELOPT_TTYPE)) {
668         char first[256], last[256];
669
670         while (sequenceIs(ttypesubopt, baseline))
671             ttloop();
672
673         /*
674          * If the other side has already disabled the option, then
675          * we have to just go with what we (might) have already gotten.
676          */
677         if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
678             (void) strncpy(first, terminaltype, sizeof(first)-1);
679             first[sizeof(first)-1] = '\0';
680             for(;;) {
681                 /*
682                  * Save the unknown name, and request the next name.
683                  */
684                 (void) strncpy(last, terminaltype, sizeof(last)-1);
685                 last[sizeof(last)-1] = '\0';
686                 _gettermname();
687                 if (terminaltypeok(terminaltype))
688                     break;
689                 if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
690                     his_state_is_wont(TELOPT_TTYPE)) {
691                     /*
692                      * We've hit the end.  If this is the same as
693                      * the first name, just go with it.
694                      */
695                     if (strncmp(first, terminaltype, sizeof(first)) == 0)
696                         break;
697                     /*
698                      * Get the terminal name one more time, so that
699                      * RFC1091 compliant telnets will cycle back to
700                      * the start of the list.
701                      */
702                      _gettermname();
703                     if (strncmp(first, terminaltype, sizeof(first)) != 0) {
704                         (void) strncpy(terminaltype, first, sizeof(terminaltype)-1);
705                         terminaltype[sizeof(terminaltype)-1] = '\0';
706                     }
707                     break;
708                 }
709             }
710         }
711     }
712     return(retval);
713 }  /* end of getterminaltype */
714
715     void
716 _gettermname()
717 {
718     /*
719      * If the client turned off the option,
720      * we can't send another request, so we
721      * just return.
722      */
723     if (his_state_is_wont(TELOPT_TTYPE))
724         return;
725     settimer(baseline);
726     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
727     nfrontp += sizeof ttytype_sbbuf;
728     while (sequenceIs(ttypesubopt, baseline))
729         ttloop();
730 }
731
732     int
733 terminaltypeok(s)
734     char *s;
735 {
736     char buf[1024];
737
738     if (terminaltype == NULL)
739         return(1);
740
741     /*
742      * tgetent() will return 1 if the type is known, and
743      * 0 if it is not known.  If it returns -1, it couldn't
744      * open the database.  But if we can't open the database,
745      * it won't help to say we failed, because we won't be
746      * able to verify anything else.  So, we treat -1 like 1.
747      */
748     if (tgetent(buf, s) == 0)
749         return(0);
750     return(1);
751 }
752
753 #ifndef MAXHOSTNAMELEN
754 #define MAXHOSTNAMELEN 64
755 #endif  /* MAXHOSTNAMELEN */
756
757 char *hostname;
758 char host_name[MAXHOSTNAMELEN];
759 char remote_host_name[MAXHOSTNAMELEN];
760
761 extern void telnet P((int, int, char *));
762
763 int level;
764 char user_name[256];
765 /*
766  * Get a pty, scan input lines.
767  */
768         void
769 doit(who)
770         struct sockaddr_in *who;
771 {
772         char *host = NULL;
773         struct hostent *hp;
774         int ptynum;
775
776         /*
777          * Find an available pty to use.
778          */
779 #ifndef convex
780         pty = getpty(&ptynum);
781         if (pty < 0)
782                 fatal(net, "All network ports in use");
783 #else
784         for (;;) {
785                 char *lp;
786                 extern char *line, *getpty();
787
788                 if ((lp = getpty()) == NULL)
789                         fatal(net, "Out of ptys");
790
791                 if ((pty = open(lp, 2)) >= 0) {
792                         strcpy(line,lp);
793                         line[5] = 't';
794                         break;
795                 }
796         }
797 #endif
798
799 #if     defined(_SC_CRAY_SECURE_SYS)
800         /*
801          *      set ttyp line security label
802          */
803         if (secflag) {
804                 char slave_dev[16];
805
806                 sprintf(tty_dev, "/dev/pty/%03d", ptynum);
807                 if (setdevs(tty_dev, &dv) < 0)
808                         fatal(net, "cannot set pty security");
809                 sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
810                 if (setdevs(slave_dev, &dv) < 0)
811                         fatal(net, "cannot set tty security");
812         }
813 #endif  /* _SC_CRAY_SECURE_SYS */
814
815         /* get name of connected client */
816         hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
817                 who->sin_family);
818
819         if (hp == NULL && registerd_host_only) {
820                 fatal(net, "Couldn't resolve your address into a host name.\r\n\
821          Please contact your net administrator");
822         } else if (hp &&
823             (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) {
824                 host = hp->h_name;
825         } else {
826                 host = inet_ntoa(who->sin_addr);
827         }
828         /*
829          * We must make a copy because Kerberos is probably going
830          * to also do a gethost* and overwrite the static data...
831          */
832         strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
833         remote_host_name[sizeof(remote_host_name)-1] = 0;
834         host = remote_host_name;
835
836         (void) gethostname(host_name, sizeof (host_name));
837         hostname = host_name;
838
839 #if     defined(AUTHENTICATION)
840         auth_encrypt_init(hostname, host, "TELNETD", 1);
841 #endif
842
843         init_env();
844         /*
845          * get terminal type.
846          */
847         *user_name = 0;
848         level = getterminaltype(user_name);
849         setenv("TERM", terminaltype ? terminaltype : "network", 1);
850
851 #if     defined(_SC_CRAY_SECURE_SYS)
852         if (secflag) {
853                 if (setulvl(dv.dv_actlvl) < 0)
854                         fatal(net,"cannot setulvl()");
855                 if (setucmp(dv.dv_actcmp) < 0)
856                         fatal(net, "cannot setucmp()");
857         }
858 #endif  /* _SC_CRAY_SECURE_SYS */
859
860         telnet(net, pty, host);         /* begin server process */
861
862         /*NOTREACHED*/
863 }  /* end of doit */
864
865 #if     defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
866         int
867 Xterm_output(ibufp, obuf, icountp, ocount)
868         char **ibufp, *obuf;
869         int *icountp, ocount;
870 {
871         int ret;
872         ret = term_output(*ibufp, obuf, *icountp, ocount);
873         *ibufp += *icountp;
874         *icountp = 0;
875         return(ret);
876 }
877 #define term_output     Xterm_output
878 #endif  /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
879
880 /*
881  * Main loop.  Select from pty and network, and
882  * hand data to telnet receiver finite state machine.
883  */
884         void
885 telnet(f, p, host)
886         int f, p;
887         char *host;
888 {
889         int on = 1;
890 #define TABBUFSIZ       512
891         char    defent[TABBUFSIZ];
892         char    defstrs[TABBUFSIZ];
893 #undef  TABBUFSIZ
894         char *HE;
895         char *HN;
896         char *IM;
897         char *IF;
898         char *if_buf;
899         int if_fd;
900         struct stat statbuf;
901
902         void netflush();
903
904         /*
905          * Initialize the slc mapping table.
906          */
907         get_slc_defaults();
908
909         /*
910          * Do some tests where it is desireable to wait for a response.
911          * Rather than doing them slowly, one at a time, do them all
912          * at once.
913          */
914         if (my_state_is_wont(TELOPT_SGA))
915                 send_will(TELOPT_SGA, 1);
916         /*
917          * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
918          * because 4.2 clients are unable to deal with TCP urgent data.
919          *
920          * To find out, we send out a "DO ECHO".  If the remote system
921          * answers "WILL ECHO" it is probably a 4.2 client, and we note
922          * that fact ("WILL ECHO" ==> that the client will echo what
923          * WE, the server, sends it; it does NOT mean that the client will
924          * echo the terminal input).
925          */
926         send_do(TELOPT_ECHO, 1);
927
928 #ifdef  LINEMODE
929         if (his_state_is_wont(TELOPT_LINEMODE)) {
930                 /* Query the peer for linemode support by trying to negotiate
931                  * the linemode option.
932                  */
933                 linemode = 0;
934                 editmode = 0;
935                 send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
936         }
937 #endif  /* LINEMODE */
938
939         /*
940          * Send along a couple of other options that we wish to negotiate.
941          */
942         send_do(TELOPT_NAWS, 1);
943         send_will(TELOPT_STATUS, 1);
944         flowmode = 1;           /* default flow control state */
945         restartany = -1;        /* uninitialized... */
946         send_do(TELOPT_LFLOW, 1);
947
948         /*
949          * Spin, waiting for a response from the DO ECHO.  However,
950          * some REALLY DUMB telnets out there might not respond
951          * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
952          * telnets so far seem to respond with WONT for a DO that
953          * they don't understand...) because by the time we get the
954          * response, it will already have processed the DO ECHO.
955          * Kludge upon kludge.
956          */
957         while (his_will_wont_is_changing(TELOPT_NAWS))
958                 ttloop();
959
960         /*
961          * But...
962          * The client might have sent a WILL NAWS as part of its
963          * startup code; if so, we'll be here before we get the
964          * response to the DO ECHO.  We'll make the assumption
965          * that any implementation that understands about NAWS
966          * is a modern enough implementation that it will respond
967          * to our DO ECHO request; hence we'll do another spin
968          * waiting for the ECHO option to settle down, which is
969          * what we wanted to do in the first place...
970          */
971         if (his_want_state_is_will(TELOPT_ECHO) &&
972             his_state_is_will(TELOPT_NAWS)) {
973                 while (his_will_wont_is_changing(TELOPT_ECHO))
974                         ttloop();
975         }
976         /*
977          * On the off chance that the telnet client is broken and does not
978          * respond to the DO ECHO we sent, (after all, we did send the
979          * DO NAWS negotiation after the DO ECHO, and we won't get here
980          * until a response to the DO NAWS comes back) simulate the
981          * receipt of a will echo.  This will also send a WONT ECHO
982          * to the client, since we assume that the client failed to
983          * respond because it believes that it is already in DO ECHO
984          * mode, which we do not want.
985          */
986         if (his_want_state_is_will(TELOPT_ECHO)) {
987                 DIAG(TD_OPTIONS,
988                         {sprintf(nfrontp, "td: simulating recv\r\n");
989                          nfrontp += strlen(nfrontp);});
990                 willoption(TELOPT_ECHO);
991         }
992
993         /*
994          * Finally, to clean things up, we turn on our echo.  This
995          * will break stupid 4.2 telnets out of local terminal echo.
996          */
997
998         if (my_state_is_wont(TELOPT_ECHO))
999                 send_will(TELOPT_ECHO, 1);
1000
1001 #ifndef STREAMSPTY
1002         /*
1003          * Turn on packet mode
1004          */
1005         (void) ioctl(p, TIOCPKT, (char *)&on);
1006 #endif
1007
1008 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
1009         /*
1010          * Continuing line mode support.  If client does not support
1011          * real linemode, attempt to negotiate kludge linemode by sending
1012          * the do timing mark sequence.
1013          */
1014         if (lmodetype < REAL_LINEMODE)
1015                 send_do(TELOPT_TM, 1);
1016 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1017
1018         /*
1019          * Call telrcv() once to pick up anything received during
1020          * terminal type negotiation, 4.2/4.3 determination, and
1021          * linemode negotiation.
1022          */
1023         telrcv();
1024
1025         (void) ioctl(f, FIONBIO, (char *)&on);
1026         (void) ioctl(p, FIONBIO, (char *)&on);
1027 #if     defined(CRAY2) && defined(UNICOS5)
1028         init_termdriver(f, p, interrupt, sendbrk);
1029 #endif
1030
1031 #if     defined(SO_OOBINLINE)
1032         (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
1033                                 (char *)&on, sizeof on);
1034 #endif  /* defined(SO_OOBINLINE) */
1035
1036 #ifdef  SIGTSTP
1037         (void) signal(SIGTSTP, SIG_IGN);
1038 #endif
1039 #ifdef  SIGTTOU
1040         /*
1041          * Ignoring SIGTTOU keeps the kernel from blocking us
1042          * in ttioct() in /sys/tty.c.
1043          */
1044         (void) signal(SIGTTOU, SIG_IGN);
1045 #endif
1046
1047         (void) signal(SIGCHLD, cleanup);
1048
1049 #if     defined(CRAY2) && defined(UNICOS5)
1050         /*
1051          * Cray-2 will send a signal when pty modes are changed by slave
1052          * side.  Set up signal handler now.
1053          */
1054         if ((int)signal(SIGUSR1, termstat) < 0)
1055                 warn("signal");
1056         else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
1057                 warn("ioctl:TCSIGME");
1058         /*
1059          * Make processing loop check terminal characteristics early on.
1060          */
1061         termstat();
1062 #endif
1063
1064 #ifdef  TIOCNOTTY
1065         {
1066                 register int t;
1067                 t = open(_PATH_TTY, O_RDWR);
1068                 if (t >= 0) {
1069                         (void) ioctl(t, TIOCNOTTY, (char *)0);
1070                         (void) close(t);
1071                 }
1072         }
1073 #endif
1074
1075 #if     defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
1076         (void) setsid();
1077         ioctl(p, TIOCSCTTY, 0);
1078 #endif
1079
1080         /*
1081          * Show banner that getty never gave.
1082          *
1083          * We put the banner in the pty input buffer.  This way, it
1084          * gets carriage return null processing, etc., just like all
1085          * other pty --> client data.
1086          */
1087
1088 #if     !defined(CRAY) || !defined(NEWINIT)
1089         if (getenv("USER"))
1090                 hostinfo = 0;
1091 #endif
1092
1093         if (getent(defent, "default") == 1) {
1094                 char *getstr();
1095                 char *cp=defstrs;
1096
1097                 HE = getstr("he", &cp);
1098                 HN = getstr("hn", &cp);
1099                 IM = getstr("im", &cp);
1100                 IF = getstr("if", &cp);
1101                 if (HN && *HN)
1102                         (void) strcpy(host_name, HN);
1103                 if (IF && (if_fd = open(IF, O_RDONLY, 000)) != -1)
1104                         IM = 0;
1105                 if (IM == 0)
1106                         IM = "";
1107         } else {
1108                 IM = DEFAULT_IM;
1109                 HE = 0;
1110         }
1111         edithost(HE, host_name);
1112         if (hostinfo && *IM)
1113                 putf(IM, ptyibuf2);
1114         else if (IF && if_fd != -1) {
1115                 fstat (if_fd, &statbuf);
1116                 if_buf = (char *) mmap (0, statbuf.st_size, PROT_READ, 
1117                     0, if_fd, 0);
1118                 putf(if_buf, ptyibuf2);
1119                 munmap (if_buf, statbuf.st_size);
1120                 close (if_fd);
1121         }
1122
1123         if (pcc)
1124                 (void) strncat(ptyibuf2, ptyip, pcc+1);
1125         ptyip = ptyibuf2;
1126         pcc = strlen(ptyip);
1127 #ifdef  LINEMODE
1128         /*
1129          * Last check to make sure all our states are correct.
1130          */
1131         init_termbuf();
1132         localstat();
1133 #endif  /* LINEMODE */
1134
1135         DIAG(TD_REPORT,
1136                 {sprintf(nfrontp, "td: Entering processing loop\r\n");
1137                  nfrontp += strlen(nfrontp);});
1138
1139         /*
1140          * Startup the login process on the slave side of the terminal
1141          * now.  We delay this until here to insure option negotiation
1142          * is complete.
1143          */
1144         startslave(host, level, user_name);
1145
1146         for (;;) {
1147                 fd_set ibits, obits, xbits;
1148                 register int c;
1149
1150                 if (ncc < 0 && pcc < 0)
1151                         break;
1152
1153 #if     defined(CRAY2) && defined(UNICOS5)
1154                 if (needtermstat)
1155                         _termstat();
1156 #endif  /* defined(CRAY2) && defined(UNICOS5) */
1157                 FD_ZERO(&ibits);
1158                 FD_ZERO(&obits);
1159                 FD_ZERO(&xbits);
1160                 /*
1161                  * Never look for input if there's still
1162                  * stuff in the corresponding output buffer
1163                  */
1164                 if (nfrontp - nbackp || pcc > 0) {
1165                         FD_SET(f, &obits);
1166                 } else {
1167                         FD_SET(p, &ibits);
1168                 }
1169                 if (pfrontp - pbackp || ncc > 0) {
1170                         FD_SET(p, &obits);
1171                 } else {
1172                         FD_SET(f, &ibits);
1173                 }
1174                 if (!SYNCHing) {
1175                         FD_SET(f, &xbits);
1176                 }
1177                 if ((c = select(16, &ibits, &obits, &xbits,
1178                                                 (struct timeval *)0)) < 1) {
1179                         if (c == -1) {
1180                                 if (errno == EINTR) {
1181                                         continue;
1182                                 }
1183                         }
1184                         sleep(5);
1185                         continue;
1186                 }
1187
1188                 /*
1189                  * Any urgent data?
1190                  */
1191                 if (FD_ISSET(net, &xbits)) {
1192                     SYNCHing = 1;
1193                 }
1194
1195                 /*
1196                  * Something to read from the network...
1197                  */
1198                 if (FD_ISSET(net, &ibits)) {
1199 #if     !defined(SO_OOBINLINE)
1200                         /*
1201                          * In 4.2 (and 4.3 beta) systems, the
1202                          * OOB indication and data handling in the kernel
1203                          * is such that if two separate TCP Urgent requests
1204                          * come in, one byte of TCP data will be overlaid.
1205                          * This is fatal for Telnet, but we try to live
1206                          * with it.
1207                          *
1208                          * In addition, in 4.2 (and...), a special protocol
1209                          * is needed to pick up the TCP Urgent data in
1210                          * the correct sequence.
1211                          *
1212                          * What we do is:  if we think we are in urgent
1213                          * mode, we look to see if we are "at the mark".
1214                          * If we are, we do an OOB receive.  If we run
1215                          * this twice, we will do the OOB receive twice,
1216                          * but the second will fail, since the second
1217                          * time we were "at the mark", but there wasn't
1218                          * any data there (the kernel doesn't reset
1219                          * "at the mark" until we do a normal read).
1220                          * Once we've read the OOB data, we go ahead
1221                          * and do normal reads.
1222                          *
1223                          * There is also another problem, which is that
1224                          * since the OOB byte we read doesn't put us
1225                          * out of OOB state, and since that byte is most
1226                          * likely the TELNET DM (data mark), we would
1227                          * stay in the TELNET SYNCH (SYNCHing) state.
1228                          * So, clocks to the rescue.  If we've "just"
1229                          * received a DM, then we test for the
1230                          * presence of OOB data when the receive OOB
1231                          * fails (and AFTER we did the normal mode read
1232                          * to clear "at the mark").
1233                          */
1234                     if (SYNCHing) {
1235                         int atmark;
1236
1237                         (void) ioctl(net, SIOCATMARK, (char *)&atmark);
1238                         if (atmark) {
1239                             ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
1240                             if ((ncc == -1) && (errno == EINVAL)) {
1241                                 ncc = read(net, netibuf, sizeof (netibuf));
1242                                 if (sequenceIs(didnetreceive, gotDM)) {
1243                                     SYNCHing = stilloob(net);
1244                                 }
1245                             }
1246                         } else {
1247                             ncc = read(net, netibuf, sizeof (netibuf));
1248                         }
1249                     } else {
1250                         ncc = read(net, netibuf, sizeof (netibuf));
1251                     }
1252                     settimer(didnetreceive);
1253 #else   /* !defined(SO_OOBINLINE)) */
1254                     ncc = read(net, netibuf, sizeof (netibuf));
1255 #endif  /* !defined(SO_OOBINLINE)) */
1256                     if (ncc < 0 && errno == EWOULDBLOCK)
1257                         ncc = 0;
1258                     else {
1259                         if (ncc <= 0) {
1260                             break;
1261                         }
1262                         netip = netibuf;
1263                     }
1264                     DIAG((TD_REPORT | TD_NETDATA),
1265                             {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
1266                              nfrontp += strlen(nfrontp);});
1267                     DIAG(TD_NETDATA, printdata("nd", netip, ncc));
1268                 }
1269
1270                 /*
1271                  * Something to read from the pty...
1272                  */
1273                 if (FD_ISSET(p, &ibits)) {
1274 #ifndef STREAMSPTY
1275                         pcc = read(p, ptyibuf, BUFSIZ);
1276 #else
1277                         pcc = readstream(p, ptyibuf, BUFSIZ);
1278 #endif
1279                         /*
1280                          * On some systems, if we try to read something
1281                          * off the master side before the slave side is
1282                          * opened, we get EIO.
1283                          */
1284                         if (pcc < 0 && (errno == EWOULDBLOCK ||
1285 #ifdef  EAGAIN
1286                                         errno == EAGAIN ||
1287 #endif
1288                                         errno == EIO)) {
1289                                 pcc = 0;
1290                         } else {
1291                                 if (pcc <= 0)
1292                                         break;
1293 #if     !defined(CRAY2) || !defined(UNICOS5)
1294 #ifdef  LINEMODE
1295                                 /*
1296                                  * If ioctl from pty, pass it through net
1297                                  */
1298                                 if (ptyibuf[0] & TIOCPKT_IOCTL) {
1299                                         copy_termbuf(ptyibuf+1, pcc-1);
1300                                         localstat();
1301                                         pcc = 1;
1302                                 }
1303 #endif  /* LINEMODE */
1304                                 if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
1305                                         netclear();     /* clear buffer back */
1306 #ifndef NO_URGENT
1307                                         /*
1308                                          * There are client telnets on some
1309                                          * operating systems get screwed up
1310                                          * royally if we send them urgent
1311                                          * mode data.
1312                                          */
1313                                         *nfrontp++ = IAC;
1314                                         *nfrontp++ = DM;
1315                                         neturg = nfrontp-1; /* off by one XXX */
1316 #endif
1317                                 }
1318                                 if (his_state_is_will(TELOPT_LFLOW) &&
1319                                     (ptyibuf[0] &
1320                                      (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
1321                                         int newflow =
1322                                             ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
1323                                         if (newflow != flowmode) {
1324                                                 flowmode = newflow;
1325                                                 (void) sprintf(nfrontp,
1326                                                         "%c%c%c%c%c%c",
1327                                                         IAC, SB, TELOPT_LFLOW,
1328                                                         flowmode ? LFLOW_ON
1329                                                                  : LFLOW_OFF,
1330                                                         IAC, SE);
1331                                                 nfrontp += 6;
1332                                         }
1333                                 }
1334                                 pcc--;
1335                                 ptyip = ptyibuf+1;
1336 #else   /* defined(CRAY2) && defined(UNICOS5) */
1337                                 if (!uselinemode) {
1338                                         unpcc = pcc;
1339                                         unptyip = ptyibuf;
1340                                         pcc = term_output(&unptyip, ptyibuf2,
1341                                                                 &unpcc, BUFSIZ);
1342                                         ptyip = ptyibuf2;
1343                                 } else
1344                                         ptyip = ptyibuf;
1345 #endif  /* defined(CRAY2) && defined(UNICOS5) */
1346                         }
1347                 }
1348
1349                 while (pcc > 0) {
1350                         if ((&netobuf[BUFSIZ] - nfrontp) < 2)
1351                                 break;
1352                         c = *ptyip++ & 0377, pcc--;
1353                         if (c == IAC)
1354                                 *nfrontp++ = c;
1355 #if     defined(CRAY2) && defined(UNICOS5)
1356                         else if (c == '\n' &&
1357                                      my_state_is_wont(TELOPT_BINARY) && newmap)
1358                                 *nfrontp++ = '\r';
1359 #endif  /* defined(CRAY2) && defined(UNICOS5) */
1360                         *nfrontp++ = c;
1361                         if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
1362                                 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
1363                                         *nfrontp++ = *ptyip++ & 0377;
1364                                         pcc--;
1365                                 } else
1366                                         *nfrontp++ = '\0';
1367                         }
1368                 }
1369 #if     defined(CRAY2) && defined(UNICOS5)
1370                 /*
1371                  * If chars were left over from the terminal driver,
1372                  * note their existence.
1373                  */
1374                 if (!uselinemode && unpcc) {
1375                         pcc = unpcc;
1376                         unpcc = 0;
1377                         ptyip = unptyip;
1378                 }
1379 #endif  /* defined(CRAY2) && defined(UNICOS5) */
1380
1381                 if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
1382                         netflush();
1383                 if (ncc > 0)
1384                         telrcv();
1385                 if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
1386                         ptyflush();
1387         }
1388         cleanup(0);
1389 }  /* end of telnet */
1390
1391 #ifndef TCSIG
1392 # ifdef TIOCSIG
1393 #  define TCSIG TIOCSIG
1394 # endif
1395 #endif
1396
1397 #ifdef  STREAMSPTY
1398
1399 int flowison = -1;  /* current state of flow: -1 is unknown */
1400
1401 int readstream(p, ibuf, bufsize)
1402         int p;
1403         char *ibuf;
1404         int bufsize;
1405 {
1406         int flags = 0;
1407         int ret = 0;
1408         struct termios *tsp;
1409         struct termio *tp;
1410         struct iocblk *ip;
1411         char vstop, vstart;
1412         int ixon;
1413         int newflow;
1414
1415         strbufc.maxlen = BUFSIZ;
1416         strbufc.buf = (char *)ctlbuf;
1417         strbufd.maxlen = bufsize-1;
1418         strbufd.len = 0;
1419         strbufd.buf = ibuf+1;
1420         ibuf[0] = 0;
1421
1422         ret = getmsg(p, &strbufc, &strbufd, &flags);
1423         if (ret < 0)  /* error of some sort -- probably EAGAIN */
1424                 return(-1);
1425
1426         if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
1427                 /* data message */
1428                 if (strbufd.len > 0) {                  /* real data */
1429                         return(strbufd.len + 1);        /* count header char */
1430                 } else {
1431                         /* nothing there */
1432                         errno = EAGAIN;
1433                         return(-1);
1434                 }
1435         }
1436
1437         /*
1438          * It's a control message.  Return 1, to look at the flag we set
1439          */
1440
1441         switch (ctlbuf[0]) {
1442         case M_FLUSH:
1443                 if (ibuf[1] & FLUSHW)
1444                         ibuf[0] = TIOCPKT_FLUSHWRITE;
1445                 return(1);
1446
1447         case M_IOCTL:
1448                 ip = (struct iocblk *) (ibuf+1);
1449
1450                 switch (ip->ioc_cmd) {
1451                 case TCSETS:
1452                 case TCSETSW:
1453                 case TCSETSF:
1454                         tsp = (struct termios *)
1455                                         (ibuf+1 + sizeof(struct iocblk));
1456                         vstop = tsp->c_cc[VSTOP];
1457                         vstart = tsp->c_cc[VSTART];
1458                         ixon = tsp->c_iflag & IXON;
1459                         break;
1460                 case TCSETA:
1461                 case TCSETAW:
1462                 case TCSETAF:
1463                         tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
1464                         vstop = tp->c_cc[VSTOP];
1465                         vstart = tp->c_cc[VSTART];
1466                         ixon = tp->c_iflag & IXON;
1467                         break;
1468                 default:
1469                         errno = EAGAIN;
1470                         return(-1);
1471                 }
1472
1473                 newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
1474                 if (newflow != flowison) {  /* it's a change */
1475                         flowison = newflow;
1476                         ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
1477                         return(1);
1478                 }
1479         }
1480
1481         /* nothing worth doing anything about */
1482         errno = EAGAIN;
1483         return(-1);
1484 }
1485 #endif /* STREAMSPTY */
1486
1487 /*
1488  * Send interrupt to process on other side of pty.
1489  * If it is in raw mode, just write NULL;
1490  * otherwise, write intr char.
1491  */
1492         void
1493 interrupt()
1494 {
1495         ptyflush();     /* half-hearted */
1496
1497 #ifdef  TCSIG
1498         (void) ioctl(pty, TCSIG, (char *)SIGINT);
1499 #else   /* TCSIG */
1500         init_termbuf();
1501         *pfrontp++ = slctab[SLC_IP].sptr ?
1502                         (unsigned char)*slctab[SLC_IP].sptr : '\177';
1503 #endif  /* TCSIG */
1504 }
1505
1506 /*
1507  * Send quit to process on other side of pty.
1508  * If it is in raw mode, just write NULL;
1509  * otherwise, write quit char.
1510  */
1511         void
1512 sendbrk()
1513 {
1514         ptyflush();     /* half-hearted */
1515 #ifdef  TCSIG
1516         (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
1517 #else   /* TCSIG */
1518         init_termbuf();
1519         *pfrontp++ = slctab[SLC_ABORT].sptr ?
1520                         (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
1521 #endif  /* TCSIG */
1522 }
1523
1524         void
1525 sendsusp()
1526 {
1527 #ifdef  SIGTSTP
1528         ptyflush();     /* half-hearted */
1529 # ifdef TCSIG
1530         (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
1531 # else  /* TCSIG */
1532         *pfrontp++ = slctab[SLC_SUSP].sptr ?
1533                         (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
1534 # endif /* TCSIG */
1535 #endif  /* SIGTSTP */
1536 }
1537
1538 /*
1539  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
1540  * just send back "[Yes]".
1541  */
1542         void
1543 recv_ayt()
1544 {
1545 #if     defined(SIGINFO) && defined(TCSIG)
1546         if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
1547                 (void) ioctl(pty, TCSIG, (char *)SIGINFO);
1548                 return;
1549         }
1550 #endif
1551         (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
1552         nfrontp += 9;
1553 }
1554
1555         void
1556 doeof()
1557 {
1558         init_termbuf();
1559
1560 #if     defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
1561         if (!tty_isediting()) {
1562                 extern char oldeofc;
1563                 *pfrontp++ = oldeofc;
1564                 return;
1565         }
1566 #endif
1567         *pfrontp++ = slctab[SLC_EOF].sptr ?
1568                         (unsigned char)*slctab[SLC_EOF].sptr : '\004';
1569 }