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