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