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