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