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