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