Added the code for the Gateway Ethernet card into if_ed.c. The whole code
[unix-history] / libexec / telnetd / telnetd.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1989 Regents of the University of California.
3 * 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
35char copyright[] =
36"@(#) Copyright (c) 1989 Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)telnetd.c 5.48 (Berkeley) 3/1/91";
42#endif /* not lint */
43
44#include "telnetd.h"
45#include "pathnames.h"
46
47#if defined(AUTHENTICATE)
48#include <libtelnet/auth.h>
49int auth_level = 0;
50#endif
51#if defined(SecurID)
52int require_SecurID = 0;
53#endif
54
55/*
56 * I/O data buffers,
57 * pointers, and counters.
58 */
59char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
60char ptyibuf2[BUFSIZ];
61
62int hostinfo = 1; /* do we print login banner? */
63
64#ifdef CRAY
65extern int newmap; /* nonzero if \n maps to ^M^J */
66int lowpty = 0, highpty; /* low, high pty numbers */
67#endif /* CRAY */
68
69int debug = 0;
70int keepalive = 1;
71char *progname;
72
73extern void usage P((void));
74
75main(argc, argv)
76 char *argv[];
77{
78 struct sockaddr_in from;
79 int on = 1, fromlen;
80 register int ch;
81 extern char *optarg;
82 extern int optind;
83#if defined(IPPROTO_IP) && defined(IP_TOS)
84 int tos = -1;
85#endif
86
87 pfrontp = pbackp = ptyobuf;
88 netip = netibuf;
89 nfrontp = nbackp = netobuf;
90#if defined(ENCRYPT)
91 nclearto = 0;
92#endif
93
94 progname = *argv;
95
96#ifdef CRAY
97 /*
98 * Get number of pty's before trying to process options,
99 * which may include changing pty range.
100 */
101 highpty = getnpty();
102#endif /* CRAY */
103
104 while ((ch = getopt(argc, argv, "d:a:e:lhnr:I:D:B:sS:a:X:")) != EOF) {
105 switch(ch) {
106
107#ifdef AUTHENTICATE
108 case 'a':
109 /*
110 * Check for required authentication level
111 */
112 if (strcmp(optarg, "debug") == 0) {
113 extern int auth_debug_mode;
114 auth_debug_mode = 1;
115 } else if (strcasecmp(optarg, "none") == 0) {
116 auth_level = 0;
117 } else if (strcasecmp(optarg, "other") == 0) {
118 auth_level = AUTH_OTHER;
119 } else if (strcasecmp(optarg, "user") == 0) {
120 auth_level = AUTH_USER;
121 } else if (strcasecmp(optarg, "valid") == 0) {
122 auth_level = AUTH_VALID;
123 } else if (strcasecmp(optarg, "off") == 0) {
124 /*
125 * This hack turns off authentication
126 */
127 auth_level = -1;
128 } else {
129 fprintf(stderr,
130 "telnetd: unknown authorization level for -a\n");
131 }
132 break;
133#endif /* AUTHENTICATE */
134
135#ifdef BFTPDAEMON
136 case 'B':
137 bftpd++;
138 break;
139#endif /* BFTPDAEMON */
140
141 case 'd':
142 if (strcmp(optarg, "ebug") == 0) {
143 debug++;
144 break;
145 }
146 usage();
147 /* NOTREACHED */
148 break;
149
150#ifdef DIAGNOSTICS
151 case 'D':
152 /*
153 * Check for desired diagnostics capabilities.
154 */
155 if (!strcmp(optarg, "report")) {
156 diagnostic |= TD_REPORT|TD_OPTIONS;
157 } else if (!strcmp(optarg, "exercise")) {
158 diagnostic |= TD_EXERCISE;
159 } else if (!strcmp(optarg, "netdata")) {
160 diagnostic |= TD_NETDATA;
161 } else if (!strcmp(optarg, "ptydata")) {
162 diagnostic |= TD_PTYDATA;
163 } else if (!strcmp(optarg, "options")) {
164 diagnostic |= TD_OPTIONS;
165 } else {
166 usage();
167 /* NOT REACHED */
168 }
169 break;
170#endif /* DIAGNOSTICS */
171
172#ifdef AUTHENTICATE
173 case 'e':
174 if (strcmp(optarg, "debug") == 0) {
175 extern int encrypt_debug_mode;
176 encrypt_debug_mode = 1;
177 break;
178 }
179 usage();
180 /* NOTREACHED */
181 break;
182#endif /* AUTHENTICATE */
183
184 case 'h':
185 hostinfo = 0;
186 break;
187
188#if defined(CRAY) && defined(NEWINIT)
189 case 'I':
190 {
191 extern char *gen_id;
192 gen_id = optarg;
193 break;
194 }
195#endif /* defined(CRAY) && defined(NEWINIT) */
196
197#ifdef LINEMODE
198 case 'l':
199 alwayslinemode = 1;
200 break;
201#endif /* LINEMODE */
202
203 case 'n':
204 keepalive = 0;
205 break;
206
207#ifdef CRAY
208 case 'r':
209 {
210 char *strchr();
211 char *c;
212
213 /*
214 * Allow the specification of alterations
215 * to the pty search range. It is legal to
216 * specify only one, and not change the
217 * other from its default.
218 */
219 c = strchr(optarg, '-');
220 if (c) {
221 *c++ = '\0';
222 highpty = atoi(c);
223 }
224 if (*optarg != '\0')
225 lowpty = atoi(optarg);
226 if ((lowpty > highpty) || (lowpty < 0) ||
227 (highpty > 32767)) {
228 usage();
229 /* NOT REACHED */
230 }
231 break;
232 }
233#endif /* CRAY */
234
235#ifdef SecurID
236 case 's':
237 /* SecurID required */
238 require_SecurID = 1;
239 break;
240#endif /* SecurID */
241 case 'S':
242#ifdef HAS_GETTOS
243 if ((tos = parsetos(optarg, "tcp")) < 0)
244 fprintf(stderr, "%s%s%s\n",
245 "telnetd: Bad TOS argument '", optarg,
246 "'; will try to use default TOS");
247#else
248 fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
249 "-S flag not supported\n");
250#endif
251 break;
252
253#ifdef AUTHENTICATE
254 case 'X':
255 /*
256 * Check for invalid authentication types
257 */
258 auth_disable_name(optarg);
259 break;
260#endif /* AUTHENTICATE */
261
262 default:
263 fprintf(stderr, "telnetd: %s: unknown option\n", ch);
264 /* FALLTHROUGH */
265 case '?':
266 usage();
267 /* NOTREACHED */
268 }
269 }
270
271 argc -= optind;
272 argv += optind;
273
274 if (debug) {
275 int s, ns, foo;
276 struct servent *sp;
277 static struct sockaddr_in sin = { AF_INET };
278
279 if (argc > 1) {
280 usage();
281 /* NOT REACHED */
282 } else if (argc == 1) {
283 if (sp = getservbyname(*argv, "tcp")) {
284 sin.sin_port = sp->s_port;
285 } else {
286 sin.sin_port = atoi(*argv);
287 if ((int)sin.sin_port <= 0) {
288 fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
289 usage();
290 /* NOT REACHED */
291 }
292 sin.sin_port = htons((u_short)sin.sin_port);
293 }
294 } else {
295 sp = getservbyname("telnet", "tcp");
296 if (sp == 0) {
297 fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
298 exit(1);
299 }
300 sin.sin_port = sp->s_port;
301 }
302
303 s = socket(AF_INET, SOCK_STREAM, 0);
304 if (s < 0) {
305 perror("telnetd: socket");;
306 exit(1);
307 }
308 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
309 if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
310 perror("bind");
311 exit(1);
312 }
313 if (listen(s, 1) < 0) {
314 perror("listen");
315 exit(1);
316 }
317 foo = sizeof sin;
318 ns = accept(s, (struct sockaddr *)&sin, &foo);
319 if (ns < 0) {
320 perror("accept");
321 exit(1);
322 }
323 (void) dup2(ns, 0);
324 (void) close(ns);
325 (void) close(s);
326#ifdef convex
327 } else if (argc == 1) {
328 ; /* VOID*/ /* Just ignore the host/port name */
329#endif
330 } else if (argc > 0) {
331 usage();
332 /* NOT REACHED */
333 }
334
335 openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
336 fromlen = sizeof (from);
337 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
338 fprintf(stderr, "%s: ", progname);
339 perror("getpeername");
340 _exit(1);
341 }
342 if (keepalive &&
343 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
344 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
345 }
346
347#if defined(IPPROTO_IP) && defined(IP_TOS)
348 {
349# if defined(HAS_GETTOS)
350 struct tosent *tp;
351 if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
352 tos = tp->t_tos;
353# endif
354 if (tos < 0)
355 tos = 020; /* Low Delay bit */
356 if (tos
357 && (setsockopt(0, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
358 && (errno != ENOPROTOOPT) )
359 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
360 }
361#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
362 net = 0;
363 doit(&from);
364 /* NOTREACHED */
365} /* end of main */
366
367 void
368usage()
369{
370 fprintf(stderr, "Usage: telnetd");
371#ifdef AUTHENTICATE
372 fprintf(stderr, " [-a (debug|other|user|valid|off)]\n\t");
373#endif
374#ifdef BFTPDAEMON
375 fprintf(stderr, " [-B]");
376#endif
377 fprintf(stderr, " [-debug]");
378#ifdef DIAGNOSTICS
379 fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
380#endif
381#ifdef AUTHENTICATE
382 fprintf(stderr, " [-edebug]");
383#endif
384 fprintf(stderr, " [-h]");
385#if defined(CRAY) && defined(NEWINIT)
386 fprintf(stderr, " [-Iinitid]");
387#endif
388#ifdef LINEMODE
389 fprintf(stderr, " [-l]");
390#endif
391 fprintf(stderr, " [-n]");
392#ifdef CRAY
393 fprintf(stderr, " [-r[lowpty]-[highpty]]");
394#endif
395#ifdef SecurID
396 fprintf(stderr, " [-s]");
397#endif
398#ifdef AUTHENTICATE
399 fprintf(stderr, " [-X auth-type]");
400#endif
401 fprintf(stderr, " [port]\n");
402 exit(1);
403}
404
405/*
406 * getterminaltype
407 *
408 * Ask the other end to send along its terminal type and speed.
409 * Output is the variable terminaltype filled in.
410 */
411static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
412
413 int
414getterminaltype(name)
415 char *name;
416{
417 int retval = -1;
418 void _gettermname();
419
420 settimer(baseline);
421#if defined(AUTHENTICATE)
422 /*
423 * Handle the Authentication option before we do anything else.
424 */
425 send_do(TELOPT_AUTHENTICATION, 1);
426 while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
427 ttloop();
428 if (his_state_is_will(TELOPT_AUTHENTICATION)) {
429 retval = auth_wait(name);
430 }
431#endif
432
433#if defined(ENCRYPT)
434 send_will(TELOPT_ENCRYPT, 1);
435#endif
436 send_do(TELOPT_TTYPE, 1);
437 send_do(TELOPT_TSPEED, 1);
438 send_do(TELOPT_XDISPLOC, 1);
439 send_do(TELOPT_ENVIRON, 1);
440 while (
441#if defined(ENCRYPT)
442 his_do_dont_is_changing(TELOPT_ENCRYPT) ||
443#endif
444 his_will_wont_is_changing(TELOPT_TTYPE) ||
445 his_will_wont_is_changing(TELOPT_TSPEED) ||
446 his_will_wont_is_changing(TELOPT_XDISPLOC) ||
447 his_will_wont_is_changing(TELOPT_ENVIRON)) {
448 ttloop();
449 }
450#if defined(ENCRYPT)
451 /*
452 * Wait for the negotiation of what type of encryption we can
453 * send with. If autoencrypt is not set, this will just return.
454 */
455 if (his_state_is_will(TELOPT_ENCRYPT)) {
456 encrypt_wait();
457 }
458#endif
459 if (his_state_is_will(TELOPT_TSPEED)) {
460 static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
461
462 bcopy(sbbuf, nfrontp, sizeof sbbuf);
463 nfrontp += sizeof sbbuf;
464 }
465 if (his_state_is_will(TELOPT_XDISPLOC)) {
466 static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
467
468 bcopy(sbbuf, nfrontp, sizeof sbbuf);
469 nfrontp += sizeof sbbuf;
470 }
471 if (his_state_is_will(TELOPT_ENVIRON)) {
472 static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
473
474 bcopy(sbbuf, nfrontp, sizeof sbbuf);
475 nfrontp += sizeof sbbuf;
476 }
477 if (his_state_is_will(TELOPT_TTYPE)) {
478
479 bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
480 nfrontp += sizeof ttytype_sbbuf;
481 }
482 if (his_state_is_will(TELOPT_TSPEED)) {
483 while (sequenceIs(tspeedsubopt, baseline))
484 ttloop();
485 }
486 if (his_state_is_will(TELOPT_XDISPLOC)) {
487 while (sequenceIs(xdisplocsubopt, baseline))
488 ttloop();
489 }
490 if (his_state_is_will(TELOPT_ENVIRON)) {
491 while (sequenceIs(environsubopt, baseline))
492 ttloop();
493 }
494 if (his_state_is_will(TELOPT_TTYPE)) {
495 char first[256], last[256];
496
497 while (sequenceIs(ttypesubopt, baseline))
498 ttloop();
499
500 /*
501 * If the other side has already disabled the option, then
502 * we have to just go with what we (might) have already gotten.
503 */
504 if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
505 (void) strncpy(first, terminaltype, sizeof(first));
506 for(;;) {
507 /*
508 * Save the unknown name, and request the next name.
509 */
510 (void) strncpy(last, terminaltype, sizeof(last));
511 _gettermname();
512 if (terminaltypeok(terminaltype))
513 break;
514 if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
515 his_state_is_wont(TELOPT_TTYPE)) {
516 /*
517 * We've hit the end. If this is the same as
518 * the first name, just go with it.
519 */
520 if (strncmp(first, terminaltype, sizeof(first)) == 0)
521 break;
522 /*
523 * Get the terminal name one more time, so that
524 * RFC1091 compliant telnets will cycle back to
525 * the start of the list.
526 */
527 _gettermname();
528 if (strncmp(first, terminaltype, sizeof(first)) != 0)
529 (void) strncpy(terminaltype, first, sizeof(first));
530 break;
531 }
532 }
533 }
534 }
535 return(retval);
536} /* end of getterminaltype */
537
538 void
539_gettermname()
540{
541 /*
542 * If the client turned off the option,
543 * we can't send another request, so we
544 * just return.
545 */
546 if (his_state_is_wont(TELOPT_TTYPE))
547 return;
548 settimer(baseline);
549 bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
550 nfrontp += sizeof ttytype_sbbuf;
551 while (sequenceIs(ttypesubopt, baseline))
552 ttloop();
553}
554
555 int
556terminaltypeok(s)
557 char *s;
558{
559 char buf[1024];
560
561 if (terminaltype == NULL)
562 return(1);
563
564 /*
565 * tgetent() will return 1 if the type is known, and
566 * 0 if it is not known. If it returns -1, it couldn't
567 * open the database. But if we can't open the database,
568 * it won't help to say we failed, because we won't be
569 * able to verify anything else. So, we treat -1 like 1.
570 */
571 if (tgetent(buf, s) == 0)
572 return(0);
573 return(1);
574}
575
576#ifndef MAXHOSTNAMELEN
577#define MAXHOSTNAMELEN 64
578#endif /* MAXHOSTNAMELEN */
579
580char *hostname;
581char host_name[MAXHOSTNAMELEN];
582char remote_host_name[MAXHOSTNAMELEN];
583
584#ifndef convex
585extern void telnet P((int, int));
586#else
587extern void telnet P((int, int, char *));
588#endif
589
590/*
591 * Get a pty, scan input lines.
592 */
593doit(who)
594 struct sockaddr_in *who;
595{
596 char *host, *inet_ntoa();
597 int t;
598 struct hostent *hp;
599 int level;
600 char user_name[256];
601
602 /*
603 * Find an available pty to use.
604 */
605#ifndef convex
606 pty = getpty();
607 if (pty < 0)
608 fatal(net, "All network ports in use");
609#else
610 for (;;) {
611 char *lp;
612 extern char *line, *getpty();
613
614 if ((lp = getpty()) == NULL)
615 fatal(net, "Out of ptys");
616
617 if ((pty = open(lp, 2)) >= 0) {
618 strcpy(line,lp);
619 line[5] = 't';
620 break;
621 }
622 }
623#endif
624
625 /* get name of connected client */
626 hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
627 who->sin_family);
628 if (hp)
629 host = hp->h_name;
630 else
631 host = inet_ntoa(who->sin_addr);
632 /*
633 * We must make a copy because Kerberos is probably going
634 * to also do a gethost* and overwrite the static data...
635 */
636 strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
637 remote_host_name[sizeof(remote_host_name)-1] = 0;
638 host = remote_host_name;
639
640 (void) gethostname(host_name, sizeof (host_name));
641 hostname = host_name;
642
643#if defined(AUTHENTICATE) || defined(ENCRYPT)
644 auth_encrypt_init(hostname, host, "TELNETD", 1);
645#endif
646
647 init_env();
648 /*
649 * get terminal type.
650 */
651 *user_name = 0;
652 level = getterminaltype(user_name);
653 setenv("TERM", terminaltype ? terminaltype : "network", 1);
654
655 /*
656 * Start up the login process on the slave side of the terminal
657 */
658#ifndef convex
659 startslave(host, level, user_name);
660
661 telnet(net, pty); /* begin server processing */
662#else
663 telnet(net, pty, host);
664#endif
665 /*NOTREACHED*/
666} /* end of doit */
667
668#if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
669 int
670Xterm_output(ibufp, obuf, icountp, ocount)
671 char **ibufp, *obuf;
672 int *icountp, ocount;
673{
674 int ret;
675 ret = term_output(*ibufp, obuf, *icountp, ocount);
676 *ibufp += *icountp;
677 *icountp = 0;
678 return(ret);
679}
680#define term_output Xterm_output
681#endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
682
683/*
684 * Main loop. Select from pty and network, and
685 * hand data to telnet receiver finite state machine.
686 */
687 void
688#ifndef convex
689telnet(f, p)
690#else
691telnet(f, p, host)
692#endif
693 int f, p;
694#ifdef convex
695 char *host;
696#endif
697{
698 int on = 1;
699#define TABBUFSIZ 512
700 char defent[TABBUFSIZ];
701 char defstrs[TABBUFSIZ];
702#undef TABBUFSIZ
703 char *HE;
704 char *HN;
705 char *IM;
706 void netflush();
707
708 /*
709 * Initialize the slc mapping table.
710 */
711 get_slc_defaults();
712
713 /*
714 * Do some tests where it is desireable to wait for a response.
715 * Rather than doing them slowly, one at a time, do them all
716 * at once.
717 */
718 if (my_state_is_wont(TELOPT_SGA))
719 send_will(TELOPT_SGA, 1);
720 /*
721 * Is the client side a 4.2 (NOT 4.3) system? We need to know this
722 * because 4.2 clients are unable to deal with TCP urgent data.
723 *
724 * To find out, we send out a "DO ECHO". If the remote system
725 * answers "WILL ECHO" it is probably a 4.2 client, and we note
726 * that fact ("WILL ECHO" ==> that the client will echo what
727 * WE, the server, sends it; it does NOT mean that the client will
728 * echo the terminal input).
729 */
730 send_do(TELOPT_ECHO, 1);
731
732#ifdef LINEMODE
733 if (his_state_is_wont(TELOPT_LINEMODE)) {
734 /* Query the peer for linemode support by trying to negotiate
735 * the linemode option.
736 */
737 linemode = 0;
738 editmode = 0;
739 send_do(TELOPT_LINEMODE, 1); /* send do linemode */
740 }
741#endif /* LINEMODE */
742
743 /*
744 * Send along a couple of other options that we wish to negotiate.
745 */
746 send_do(TELOPT_NAWS, 1);
747 send_will(TELOPT_STATUS, 1);
748 flowmode = 1; /* default flow control state */
749 send_do(TELOPT_LFLOW, 1);
750
751 /*
752 * Spin, waiting for a response from the DO ECHO. However,
753 * some REALLY DUMB telnets out there might not respond
754 * to the DO ECHO. So, we spin looking for NAWS, (most dumb
755 * telnets so far seem to respond with WONT for a DO that
756 * they don't understand...) because by the time we get the
757 * response, it will already have processed the DO ECHO.
758 * Kludge upon kludge.
759 */
760 while (his_will_wont_is_changing(TELOPT_NAWS))
761 ttloop();
762
763 /*
764 * But...
765 * The client might have sent a WILL NAWS as part of its
766 * startup code; if so, we'll be here before we get the
767 * response to the DO ECHO. We'll make the assumption
768 * that any implementation that understands about NAWS
769 * is a modern enough implementation that it will respond
770 * to our DO ECHO request; hence we'll do another spin
771 * waiting for the ECHO option to settle down, which is
772 * what we wanted to do in the first place...
773 */
774 if (his_want_state_is_will(TELOPT_ECHO) &&
775 his_state_is_will(TELOPT_NAWS)) {
776 while (his_will_wont_is_changing(TELOPT_ECHO))
777 ttloop();
778 }
779 /*
780 * On the off chance that the telnet client is broken and does not
781 * respond to the DO ECHO we sent, (after all, we did send the
782 * DO NAWS negotiation after the DO ECHO, and we won't get here
783 * until a response to the DO NAWS comes back) simulate the
784 * receipt of a will echo. This will also send a WONT ECHO
785 * to the client, since we assume that the client failed to
786 * respond because it believes that it is already in DO ECHO
787 * mode, which we do not want.
788 */
789 if (his_want_state_is_will(TELOPT_ECHO)) {
790 DIAG(TD_OPTIONS,
791 {sprintf(nfrontp, "td: simulating recv\r\n");
792 nfrontp += strlen(nfrontp);});
793 willoption(TELOPT_ECHO);
794 }
795
796 /*
797 * Finally, to clean things up, we turn on our echo. This
798 * will break stupid 4.2 telnets out of local terminal echo.
799 */
800
801 if (my_state_is_wont(TELOPT_ECHO))
802 send_will(TELOPT_ECHO, 1);
803
804 /*
805 * Turn on packet mode
806 */
807 (void) ioctl(p, TIOCPKT, (char *)&on);
808#if defined(LINEMODE) && defined(KLUDGELINEMODE)
809 /*
810 * Continuing line mode support. If client does not support
811 * real linemode, attempt to negotiate kludge linemode by sending
812 * the do timing mark sequence.
813 */
814 if (lmodetype < REAL_LINEMODE)
815 send_do(TELOPT_TM, 1);
816#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
817
818 /*
819 * Call telrcv() once to pick up anything received during
820 * terminal type negotiation, 4.2/4.3 determination, and
821 * linemode negotiation.
822 */
823 telrcv();
824
825 (void) ioctl(f, FIONBIO, (char *)&on);
826 (void) ioctl(p, FIONBIO, (char *)&on);
827#if defined(CRAY2) && defined(UNICOS5)
828 init_termdriver(f, p, interrupt, sendbrk);
829#endif
830
831#if defined(SO_OOBINLINE)
832 (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
833#endif /* defined(SO_OOBINLINE) */
834
835#ifdef SIGTSTP
836 (void) signal(SIGTSTP, SIG_IGN);
837#endif
838#ifdef SIGTTOU
839 /*
840 * Ignoring SIGTTOU keeps the kernel from blocking us
841 * in ttioct() in /sys/tty.c.
842 */
843 (void) signal(SIGTTOU, SIG_IGN);
844#endif
845
846 (void) signal(SIGCHLD, cleanup);
847
848#if defined(CRAY2) && defined(UNICOS5)
849 /*
850 * Cray-2 will send a signal when pty modes are changed by slave
851 * side. Set up signal handler now.
852 */
853 if ((int)signal(SIGUSR1, termstat) < 0)
854 perror("signal");
855 else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
856 perror("ioctl:TCSIGME");
857 /*
858 * Make processing loop check terminal characteristics early on.
859 */
860 termstat();
861#endif
862
863#ifdef TIOCNOTTY
864 {
865 register int t;
866 t = open(_PATH_TTY, O_RDWR);
867 if (t >= 0) {
868 (void) ioctl(t, TIOCNOTTY, (char *)0);
869 (void) close(t);
870 }
871 }
872#endif
873
874#if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
875 (void) setsid();
876 ioctl(p, TIOCSCTTY, 0);
877#endif
878
879 /*
880 * Show banner that getty never gave.
881 *
882 * We put the banner in the pty input buffer. This way, it
883 * gets carriage return null processing, etc., just like all
884 * other pty --> client data.
885 */
886
887#if !defined(CRAY) || !defined(NEWINIT)
888 if (getenv("USER"))
889 hostinfo = 0;
890#endif
891
892 if (getent(defent, "default") == 1) {
893 char *getstr();
894 char *cp=defstrs;
895
896 HE = getstr("he", &cp);
897 HN = getstr("hn", &cp);
898 IM = getstr("im", &cp);
899 if (HN && *HN)
900 (void) strcpy(host_name, HN);
901 if (IM == 0)
902 IM = "";
903 } else {
a5cd4249
GW
904#ifdef __FreeBSD__
905 static char issue_message[256];
906 extern char *_osnamever();
907 snprintf(issue_message, sizeof issue_message,
908 DEFAULT_IM, _osnamever());
909 IM = issue_message;
910#else
15637ed4 911 IM = DEFAULT_IM;
a5cd4249 912#endif
15637ed4
RG
913 HE = 0;
914 }
915 edithost(HE, host_name);
916 if (hostinfo && *IM)
917 putf(IM, ptyibuf2);
918
919 if (pcc)
920 (void) strncat(ptyibuf2, ptyip, pcc+1);
921 ptyip = ptyibuf2;
922 pcc = strlen(ptyip);
923#ifdef LINEMODE
924 /*
925 * Last check to make sure all our states are correct.
926 */
927 init_termbuf();
928 localstat();
929#endif /* LINEMODE */
930
931 DIAG(TD_REPORT,
932 {sprintf(nfrontp, "td: Entering processing loop\r\n");
933 nfrontp += strlen(nfrontp);});
934
935#ifdef convex
936 startslave(host);
937#endif
938
939 for (;;) {
940 fd_set ibits, obits, xbits;
941 register int c;
942
943 if (ncc < 0 && pcc < 0)
944 break;
945
946#if defined(CRAY2) && defined(UNICOS5)
947 if (needtermstat)
948 _termstat();
949#endif /* defined(CRAY2) && defined(UNICOS5) */
950 FD_ZERO(&ibits);
951 FD_ZERO(&obits);
952 FD_ZERO(&xbits);
953 /*
954 * Never look for input if there's still
955 * stuff in the corresponding output buffer
956 */
957 if (nfrontp - nbackp || pcc > 0) {
958 FD_SET(f, &obits);
959 } else {
960 FD_SET(p, &ibits);
961 }
962 if (pfrontp - pbackp || ncc > 0) {
963 FD_SET(p, &obits);
964 } else {
965 FD_SET(f, &ibits);
966 }
967 if (!SYNCHing) {
968 FD_SET(f, &xbits);
969 }
970 if ((c = select(16, &ibits, &obits, &xbits,
971 (struct timeval *)0)) < 1) {
972 if (c == -1) {
973 if (errno == EINTR) {
974 continue;
975 }
976 }
977 sleep(5);
978 continue;
979 }
980
981 /*
982 * Any urgent data?
983 */
984 if (FD_ISSET(net, &xbits)) {
985 SYNCHing = 1;
986 }
987
988 /*
989 * Something to read from the network...
990 */
991 if (FD_ISSET(net, &ibits)) {
992#if !defined(SO_OOBINLINE)
993 /*
994 * In 4.2 (and 4.3 beta) systems, the
995 * OOB indication and data handling in the kernel
996 * is such that if two separate TCP Urgent requests
997 * come in, one byte of TCP data will be overlaid.
998 * This is fatal for Telnet, but we try to live
999 * with it.
1000 *
1001 * In addition, in 4.2 (and...), a special protocol
1002 * is needed to pick up the TCP Urgent data in
1003 * the correct sequence.
1004 *
1005 * What we do is: if we think we are in urgent
1006 * mode, we look to see if we are "at the mark".
1007 * If we are, we do an OOB receive. If we run
1008 * this twice, we will do the OOB receive twice,
1009 * but the second will fail, since the second
1010 * time we were "at the mark", but there wasn't
1011 * any data there (the kernel doesn't reset
1012 * "at the mark" until we do a normal read).
1013 * Once we've read the OOB data, we go ahead
1014 * and do normal reads.
1015 *
1016 * There is also another problem, which is that
1017 * since the OOB byte we read doesn't put us
1018 * out of OOB state, and since that byte is most
1019 * likely the TELNET DM (data mark), we would
1020 * stay in the TELNET SYNCH (SYNCHing) state.
1021 * So, clocks to the rescue. If we've "just"
1022 * received a DM, then we test for the
1023 * presence of OOB data when the receive OOB
1024 * fails (and AFTER we did the normal mode read
1025 * to clear "at the mark").
1026 */
1027 if (SYNCHing) {
1028 int atmark;
1029
1030 (void) ioctl(net, SIOCATMARK, (char *)&atmark);
1031 if (atmark) {
1032 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
1033 if ((ncc == -1) && (errno == EINVAL)) {
1034 ncc = read(net, netibuf, sizeof (netibuf));
1035 if (sequenceIs(didnetreceive, gotDM)) {
1036 SYNCHing = stilloob(net);
1037 }
1038 }
1039 } else {
1040 ncc = read(net, netibuf, sizeof (netibuf));
1041 }
1042 } else {
1043 ncc = read(net, netibuf, sizeof (netibuf));
1044 }
1045 settimer(didnetreceive);
1046#else /* !defined(SO_OOBINLINE)) */
1047 ncc = read(net, netibuf, sizeof (netibuf));
1048#endif /* !defined(SO_OOBINLINE)) */
1049 if (ncc < 0 && errno == EWOULDBLOCK)
1050 ncc = 0;
1051 else {
1052 if (ncc <= 0) {
1053 break;
1054 }
1055 netip = netibuf;
1056 }
1057 DIAG((TD_REPORT | TD_NETDATA),
1058 {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
1059 nfrontp += strlen(nfrontp);});
1060 DIAG(TD_NETDATA, printdata("nd", netip, ncc));
1061 }
1062
1063 /*
1064 * Something to read from the pty...
1065 */
1066 if (FD_ISSET(p, &ibits)) {
1067 pcc = read(p, ptyibuf, BUFSIZ);
1068 /*
1069 * On some systems, if we try to read something
1070 * off the master side before the slave side is
1071 * opened, we get EIO.
1072 */
1073 if (pcc < 0 && (errno == EWOULDBLOCK || errno == EIO)) {
1074 pcc = 0;
1075 } else {
1076 if (pcc <= 0)
1077 break;
1078#if !defined(CRAY2) || !defined(UNICOS5)
1079#ifdef LINEMODE
1080 /*
1081 * If ioctl from pty, pass it through net
1082 */
1083 if (ptyibuf[0] & TIOCPKT_IOCTL) {
1084 copy_termbuf(ptyibuf+1, pcc-1);
1085 localstat();
1086 pcc = 1;
1087 }
1088#endif /* LINEMODE */
1089 if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
1090 netclear(); /* clear buffer back */
1091#ifndef NO_URGENT
1092 /*
1093 * There are client telnets on some
1094 * operating systems get screwed up
1095 * royally if we send them urgent
1096 * mode data.
1097 */
1098 *nfrontp++ = IAC;
1099 *nfrontp++ = DM;
1100 neturg = nfrontp-1; /* off by one XXX */
1101#endif
1102 }
1103 if (his_state_is_will(TELOPT_LFLOW) &&
1104 (ptyibuf[0] &
1105 (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
1106 (void) sprintf(nfrontp, "%c%c%c%c%c%c",
1107 IAC, SB, TELOPT_LFLOW,
1108 ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
1109 IAC, SE);
1110 nfrontp += 6;
1111 }
1112 pcc--;
1113 ptyip = ptyibuf+1;
1114#else /* defined(CRAY2) && defined(UNICOS5) */
1115 if (!uselinemode) {
1116 unpcc = pcc;
1117 unptyip = ptyibuf;
1118 pcc = term_output(&unptyip, ptyibuf2,
1119 &unpcc, BUFSIZ);
1120 ptyip = ptyibuf2;
1121 } else
1122 ptyip = ptyibuf;
1123#endif /* defined(CRAY2) && defined(UNICOS5) */
1124 }
1125 }
1126
1127 while (pcc > 0) {
1128 if ((&netobuf[BUFSIZ] - nfrontp) < 2)
1129 break;
1130 c = *ptyip++ & 0377, pcc--;
1131 if (c == IAC)
1132 *nfrontp++ = c;
1133#if defined(CRAY2) && defined(UNICOS5)
1134 else if (c == '\n' &&
1135 my_state_is_wont(TELOPT_BINARY) && newmap)
1136 *nfrontp++ = '\r';
1137#endif /* defined(CRAY2) && defined(UNICOS5) */
1138 *nfrontp++ = c;
1139 if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
1140 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
1141 *nfrontp++ = *ptyip++ & 0377;
1142 pcc--;
1143 } else
1144 *nfrontp++ = '\0';
1145 }
1146 }
1147#if defined(CRAY2) && defined(UNICOS5)
1148 /*
1149 * If chars were left over from the terminal driver,
1150 * note their existence.
1151 */
1152 if (!uselinemode && unpcc) {
1153 pcc = unpcc;
1154 unpcc = 0;
1155 ptyip = unptyip;
1156 }
1157#endif /* defined(CRAY2) && defined(UNICOS5) */
1158
1159 if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
1160 netflush();
1161 if (ncc > 0)
1162 telrcv();
1163 if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
1164 ptyflush();
1165 }
1166 cleanup(0);
1167} /* end of telnet */
1168
1169#ifndef TCSIG
1170# ifdef TIOCSIG
1171# define TCSIG TIOCSIG
1172# endif
1173#endif
1174
1175/*
1176 * Send interrupt to process on other side of pty.
1177 * If it is in raw mode, just write NULL;
1178 * otherwise, write intr char.
1179 */
1180 void
1181interrupt()
1182{
1183 ptyflush(); /* half-hearted */
1184
1185#ifdef TCSIG
1186 (void) ioctl(pty, TCSIG, (char *)SIGINT);
1187#else /* TCSIG */
1188 init_termbuf();
1189 *pfrontp++ = slctab[SLC_IP].sptr ?
1190 (unsigned char)*slctab[SLC_IP].sptr : '\177';
1191#endif /* TCSIG */
1192}
1193
1194/*
1195 * Send quit to process on other side of pty.
1196 * If it is in raw mode, just write NULL;
1197 * otherwise, write quit char.
1198 */
1199 void
1200sendbrk()
1201{
1202 ptyflush(); /* half-hearted */
1203#ifdef TCSIG
1204 (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
1205#else /* TCSIG */
1206 init_termbuf();
1207 *pfrontp++ = slctab[SLC_ABORT].sptr ?
1208 (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
1209#endif /* TCSIG */
1210}
1211
1212 void
1213sendsusp()
1214{
1215#ifdef SIGTSTP
1216 ptyflush(); /* half-hearted */
1217# ifdef TCSIG
1218 (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
1219# else /* TCSIG */
1220 *pfrontp++ = slctab[SLC_SUSP].sptr ?
1221 (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
1222# endif /* TCSIG */
1223#endif /* SIGTSTP */
1224}
1225
1226/*
1227 * When we get an AYT, if ^T is enabled, use that. Otherwise,
1228 * just send back "[Yes]".
1229 */
1230 void
1231recv_ayt()
1232{
1233#if defined(SIGINFO) && defined(TCSIG)
1234 if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
1235 (void) ioctl(pty, TCSIG, (char *)SIGINFO);
1236 return;
1237 }
1238#endif
1239 (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
1240 nfrontp += 9;
1241}
1242
1243 void
1244doeof()
1245{
1246 init_termbuf();
1247
1248#if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
1249 if (!tty_isediting()) {
1250 extern char oldeofc;
1251 *pfrontp++ = oldeofc;
1252 return;
1253 }
1254#endif
1255 *pfrontp++ = slctab[SLC_EOF].sptr ?
1256 (unsigned char)*slctab[SLC_EOF].sptr : '\004';
1257}