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