]>
Commit | Line | Data |
---|---|---|
b7080c8e A |
1 | /* |
2 | * Copyright (c) 1988, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
7ba0088d A |
34 | #include <sys/cdefs.h> |
35 | ||
36 | #ifdef __FBSDID | |
37 | __FBSDID("$FreeBSD: src/crypto/telnet/telnet/utilities.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $"); | |
38 | #endif | |
39 | ||
b7080c8e | 40 | #ifndef lint |
7ba0088d A |
41 | static const char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; |
42 | #endif | |
b7080c8e A |
43 | |
44 | #define TELOPTS | |
45 | #define TELCMDS | |
46 | #define SLC_NAMES | |
47 | #include <arpa/telnet.h> | |
48 | #include <sys/types.h> | |
7ba0088d | 49 | #include <sys/socket.h> |
b7080c8e | 50 | #include <sys/time.h> |
b7080c8e | 51 | #include <ctype.h> |
7ba0088d | 52 | #include <unistd.h> |
b7080c8e A |
53 | |
54 | #include "general.h" | |
55 | ||
56 | #include "fdset.h" | |
57 | ||
58 | #include "ring.h" | |
59 | ||
60 | #include "defines.h" | |
61 | ||
62 | #include "externs.h" | |
63 | ||
7ba0088d A |
64 | #ifdef AUTHENTICATION |
65 | #include <libtelnet/auth.h> | |
66 | #endif | |
67 | #ifdef ENCRYPTION | |
68 | #include <libtelnet/encrypt.h> | |
69 | #endif | |
70 | ||
b7080c8e A |
71 | FILE *NetTrace = 0; /* Not in bss, since needs to stay */ |
72 | int prettydump; | |
73 | ||
74 | /* | |
75 | * upcase() | |
76 | * | |
77 | * Upcase (in place) the argument. | |
78 | */ | |
79 | ||
7ba0088d A |
80 | void |
81 | upcase(char *argument) | |
b7080c8e | 82 | { |
7ba0088d | 83 | int c; |
b7080c8e A |
84 | |
85 | while ((c = *argument) != 0) { | |
86 | if (islower(c)) { | |
87 | *argument = toupper(c); | |
88 | } | |
89 | argument++; | |
90 | } | |
91 | } | |
92 | ||
93 | /* | |
94 | * SetSockOpt() | |
95 | * | |
96 | * Compensate for differences in 4.2 and 4.3 systems. | |
97 | */ | |
98 | ||
7ba0088d A |
99 | int |
100 | SetSockOpt(int fd, int level, int option, int yesno) | |
b7080c8e | 101 | { |
b7080c8e A |
102 | return setsockopt(fd, level, option, |
103 | (char *)&yesno, sizeof yesno); | |
b7080c8e A |
104 | } |
105 | \f | |
106 | /* | |
107 | * The following are routines used to print out debugging information. | |
108 | */ | |
109 | ||
110 | unsigned char NetTraceFile[256] = "(standard output)"; | |
111 | ||
7ba0088d A |
112 | void |
113 | SetNetTrace(char *file) | |
b7080c8e A |
114 | { |
115 | if (NetTrace && NetTrace != stdout) | |
116 | fclose(NetTrace); | |
117 | if (file && (strcmp(file, "-") != 0)) { | |
118 | NetTrace = fopen(file, "w"); | |
119 | if (NetTrace) { | |
120 | strcpy((char *)NetTraceFile, file); | |
121 | return; | |
122 | } | |
123 | fprintf(stderr, "Cannot open %s.\n", file); | |
124 | } | |
125 | NetTrace = stdout; | |
126 | strcpy((char *)NetTraceFile, "(standard output)"); | |
127 | } | |
128 | ||
7ba0088d A |
129 | void |
130 | Dump(char direction, unsigned char *buffer, int length) | |
b7080c8e A |
131 | { |
132 | # define BYTES_PER_LINE 32 | |
133 | # define min(x,y) ((x<y)? x:y) | |
134 | unsigned char *pThis; | |
135 | int offset; | |
b7080c8e A |
136 | |
137 | offset = 0; | |
138 | ||
139 | while (length) { | |
140 | /* print one line */ | |
141 | fprintf(NetTrace, "%c 0x%x\t", direction, offset); | |
142 | pThis = buffer; | |
143 | if (prettydump) { | |
144 | buffer = buffer + min(length, BYTES_PER_LINE/2); | |
145 | while (pThis < buffer) { | |
146 | fprintf(NetTrace, "%c%.2x", | |
147 | (((*pThis)&0xff) == 0xff) ? '*' : ' ', | |
148 | (*pThis)&0xff); | |
149 | pThis++; | |
150 | } | |
151 | length -= BYTES_PER_LINE/2; | |
152 | offset += BYTES_PER_LINE/2; | |
153 | } else { | |
154 | buffer = buffer + min(length, BYTES_PER_LINE); | |
155 | while (pThis < buffer) { | |
156 | fprintf(NetTrace, "%.2x", (*pThis)&0xff); | |
157 | pThis++; | |
158 | } | |
159 | length -= BYTES_PER_LINE; | |
160 | offset += BYTES_PER_LINE; | |
161 | } | |
162 | if (NetTrace == stdout) { | |
163 | fprintf(NetTrace, "\r\n"); | |
164 | } else { | |
165 | fprintf(NetTrace, "\n"); | |
166 | } | |
167 | if (length < 0) { | |
168 | fflush(NetTrace); | |
169 | return; | |
170 | } | |
171 | /* find next unique line */ | |
172 | } | |
173 | fflush(NetTrace); | |
174 | } | |
175 | ||
176 | ||
7ba0088d A |
177 | void |
178 | printoption(const char *direction, int cmd, int option) | |
b7080c8e A |
179 | { |
180 | if (!showoptions) | |
181 | return; | |
182 | if (cmd == IAC) { | |
183 | if (TELCMD_OK(option)) | |
184 | fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option)); | |
185 | else | |
186 | fprintf(NetTrace, "%s IAC %d", direction, option); | |
187 | } else { | |
7ba0088d | 188 | const char *fmt; |
b7080c8e A |
189 | fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : |
190 | (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; | |
191 | if (fmt) { | |
192 | fprintf(NetTrace, "%s %s ", direction, fmt); | |
193 | if (TELOPT_OK(option)) | |
194 | fprintf(NetTrace, "%s", TELOPT(option)); | |
195 | else if (option == TELOPT_EXOPL) | |
196 | fprintf(NetTrace, "EXOPL"); | |
197 | else | |
198 | fprintf(NetTrace, "%d", option); | |
199 | } else | |
200 | fprintf(NetTrace, "%s %d %d", direction, cmd, option); | |
201 | } | |
202 | if (NetTrace == stdout) { | |
203 | fprintf(NetTrace, "\r\n"); | |
204 | fflush(NetTrace); | |
205 | } else { | |
206 | fprintf(NetTrace, "\n"); | |
207 | } | |
208 | return; | |
209 | } | |
210 | ||
7ba0088d A |
211 | void |
212 | optionstatus(void) | |
b7080c8e | 213 | { |
7ba0088d | 214 | int i; |
b7080c8e A |
215 | extern char will_wont_resp[], do_dont_resp[]; |
216 | ||
217 | for (i = 0; i < 256; i++) { | |
218 | if (do_dont_resp[i]) { | |
219 | if (TELOPT_OK(i)) | |
220 | printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]); | |
221 | else if (TELCMD_OK(i)) | |
222 | printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]); | |
223 | else | |
224 | printf("resp DO_DONT %d: %d\n", i, | |
225 | do_dont_resp[i]); | |
226 | if (my_want_state_is_do(i)) { | |
227 | if (TELOPT_OK(i)) | |
228 | printf("want DO %s\n", TELOPT(i)); | |
229 | else if (TELCMD_OK(i)) | |
230 | printf("want DO %s\n", TELCMD(i)); | |
231 | else | |
232 | printf("want DO %d\n", i); | |
233 | } else { | |
234 | if (TELOPT_OK(i)) | |
235 | printf("want DONT %s\n", TELOPT(i)); | |
236 | else if (TELCMD_OK(i)) | |
237 | printf("want DONT %s\n", TELCMD(i)); | |
238 | else | |
239 | printf("want DONT %d\n", i); | |
240 | } | |
241 | } else { | |
242 | if (my_state_is_do(i)) { | |
243 | if (TELOPT_OK(i)) | |
244 | printf(" DO %s\n", TELOPT(i)); | |
245 | else if (TELCMD_OK(i)) | |
246 | printf(" DO %s\n", TELCMD(i)); | |
247 | else | |
248 | printf(" DO %d\n", i); | |
249 | } | |
250 | } | |
251 | if (will_wont_resp[i]) { | |
252 | if (TELOPT_OK(i)) | |
253 | printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]); | |
254 | else if (TELCMD_OK(i)) | |
255 | printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]); | |
256 | else | |
257 | printf("resp WILL_WONT %d: %d\n", | |
258 | i, will_wont_resp[i]); | |
259 | if (my_want_state_is_will(i)) { | |
260 | if (TELOPT_OK(i)) | |
261 | printf("want WILL %s\n", TELOPT(i)); | |
262 | else if (TELCMD_OK(i)) | |
263 | printf("want WILL %s\n", TELCMD(i)); | |
264 | else | |
265 | printf("want WILL %d\n", i); | |
266 | } else { | |
267 | if (TELOPT_OK(i)) | |
268 | printf("want WONT %s\n", TELOPT(i)); | |
269 | else if (TELCMD_OK(i)) | |
270 | printf("want WONT %s\n", TELCMD(i)); | |
271 | else | |
272 | printf("want WONT %d\n", i); | |
273 | } | |
274 | } else { | |
275 | if (my_state_is_will(i)) { | |
276 | if (TELOPT_OK(i)) | |
277 | printf(" WILL %s\n", TELOPT(i)); | |
278 | else if (TELCMD_OK(i)) | |
279 | printf(" WILL %s\n", TELCMD(i)); | |
280 | else | |
281 | printf(" WILL %d\n", i); | |
282 | } | |
283 | } | |
284 | } | |
285 | ||
286 | } | |
287 | ||
7ba0088d A |
288 | void |
289 | printsub(char direction, unsigned char *pointer, int length) | |
b7080c8e | 290 | { |
7ba0088d A |
291 | int i; |
292 | #ifdef AUTHENTICATION | |
b7080c8e | 293 | char buf[512]; |
7ba0088d | 294 | #endif |
b7080c8e A |
295 | extern int want_status_response; |
296 | ||
297 | if (showoptions || direction == 0 || | |
298 | (want_status_response && (pointer[0] == TELOPT_STATUS))) { | |
299 | if (direction) { | |
300 | fprintf(NetTrace, "%s IAC SB ", | |
301 | (direction == '<')? "RCVD":"SENT"); | |
302 | if (length >= 3) { | |
7ba0088d | 303 | int j; |
b7080c8e A |
304 | |
305 | i = pointer[length-2]; | |
306 | j = pointer[length-1]; | |
307 | ||
308 | if (i != IAC || j != SE) { | |
309 | fprintf(NetTrace, "(terminated by "); | |
310 | if (TELOPT_OK(i)) | |
311 | fprintf(NetTrace, "%s ", TELOPT(i)); | |
312 | else if (TELCMD_OK(i)) | |
313 | fprintf(NetTrace, "%s ", TELCMD(i)); | |
314 | else | |
315 | fprintf(NetTrace, "%d ", i); | |
316 | if (TELOPT_OK(j)) | |
317 | fprintf(NetTrace, "%s", TELOPT(j)); | |
318 | else if (TELCMD_OK(j)) | |
319 | fprintf(NetTrace, "%s", TELCMD(j)); | |
320 | else | |
321 | fprintf(NetTrace, "%d", j); | |
322 | fprintf(NetTrace, ", not IAC SE!) "); | |
323 | } | |
324 | } | |
325 | length -= 2; | |
326 | } | |
327 | if (length < 1) { | |
328 | fprintf(NetTrace, "(Empty suboption??\?)"); | |
329 | if (NetTrace == stdout) | |
330 | fflush(NetTrace); | |
331 | return; | |
332 | } | |
333 | switch (pointer[0]) { | |
334 | case TELOPT_TTYPE: | |
335 | fprintf(NetTrace, "TERMINAL-TYPE "); | |
336 | switch (pointer[1]) { | |
337 | case TELQUAL_IS: | |
338 | fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); | |
339 | break; | |
340 | case TELQUAL_SEND: | |
341 | fprintf(NetTrace, "SEND"); | |
342 | break; | |
343 | default: | |
344 | fprintf(NetTrace, | |
345 | "- unknown qualifier %d (0x%x).", | |
346 | pointer[1], pointer[1]); | |
347 | } | |
348 | break; | |
349 | case TELOPT_TSPEED: | |
350 | fprintf(NetTrace, "TERMINAL-SPEED"); | |
351 | if (length < 2) { | |
352 | fprintf(NetTrace, " (empty suboption??\?)"); | |
353 | break; | |
354 | } | |
355 | switch (pointer[1]) { | |
356 | case TELQUAL_IS: | |
357 | fprintf(NetTrace, " IS "); | |
358 | fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); | |
359 | break; | |
360 | default: | |
361 | if (pointer[1] == 1) | |
362 | fprintf(NetTrace, " SEND"); | |
363 | else | |
364 | fprintf(NetTrace, " %d (unknown)", pointer[1]); | |
365 | for (i = 2; i < length; i++) | |
366 | fprintf(NetTrace, " ?%d?", pointer[i]); | |
367 | break; | |
368 | } | |
369 | break; | |
370 | ||
371 | case TELOPT_LFLOW: | |
372 | fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); | |
373 | if (length < 2) { | |
374 | fprintf(NetTrace, " (empty suboption??\?)"); | |
375 | break; | |
376 | } | |
377 | switch (pointer[1]) { | |
378 | case LFLOW_OFF: | |
379 | fprintf(NetTrace, " OFF"); break; | |
380 | case LFLOW_ON: | |
381 | fprintf(NetTrace, " ON"); break; | |
382 | case LFLOW_RESTART_ANY: | |
383 | fprintf(NetTrace, " RESTART-ANY"); break; | |
384 | case LFLOW_RESTART_XON: | |
385 | fprintf(NetTrace, " RESTART-XON"); break; | |
386 | default: | |
387 | fprintf(NetTrace, " %d (unknown)", pointer[1]); | |
388 | } | |
389 | for (i = 2; i < length; i++) | |
390 | fprintf(NetTrace, " ?%d?", pointer[i]); | |
391 | break; | |
392 | ||
393 | case TELOPT_NAWS: | |
394 | fprintf(NetTrace, "NAWS"); | |
395 | if (length < 2) { | |
396 | fprintf(NetTrace, " (empty suboption??\?)"); | |
397 | break; | |
398 | } | |
399 | if (length == 2) { | |
400 | fprintf(NetTrace, " ?%d?", pointer[1]); | |
401 | break; | |
402 | } | |
403 | fprintf(NetTrace, " %d %d (%d)", | |
404 | pointer[1], pointer[2], | |
405 | (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); | |
406 | if (length == 4) { | |
407 | fprintf(NetTrace, " ?%d?", pointer[3]); | |
408 | break; | |
409 | } | |
410 | fprintf(NetTrace, " %d %d (%d)", | |
411 | pointer[3], pointer[4], | |
412 | (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); | |
413 | for (i = 5; i < length; i++) | |
414 | fprintf(NetTrace, " ?%d?", pointer[i]); | |
415 | break; | |
416 | ||
7ba0088d | 417 | #ifdef AUTHENTICATION |
b7080c8e A |
418 | case TELOPT_AUTHENTICATION: |
419 | fprintf(NetTrace, "AUTHENTICATION"); | |
420 | if (length < 2) { | |
421 | fprintf(NetTrace, " (empty suboption??\?)"); | |
422 | break; | |
423 | } | |
424 | switch (pointer[1]) { | |
425 | case TELQUAL_REPLY: | |
426 | case TELQUAL_IS: | |
427 | fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? | |
428 | "IS" : "REPLY"); | |
429 | if (AUTHTYPE_NAME_OK(pointer[2])) | |
430 | fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2])); | |
431 | else | |
432 | fprintf(NetTrace, "%d ", pointer[2]); | |
433 | if (length < 3) { | |
434 | fprintf(NetTrace, "(partial suboption??\?)"); | |
435 | break; | |
436 | } | |
437 | fprintf(NetTrace, "%s|%s", | |
438 | ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? | |
439 | "CLIENT" : "SERVER", | |
440 | ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? | |
441 | "MUTUAL" : "ONE-WAY"); | |
442 | ||
443 | auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); | |
444 | fprintf(NetTrace, "%s", buf); | |
445 | break; | |
446 | ||
447 | case TELQUAL_SEND: | |
448 | i = 2; | |
449 | fprintf(NetTrace, " SEND "); | |
450 | while (i < length) { | |
451 | if (AUTHTYPE_NAME_OK(pointer[i])) | |
452 | fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i])); | |
453 | else | |
454 | fprintf(NetTrace, "%d ", pointer[i]); | |
455 | if (++i >= length) { | |
456 | fprintf(NetTrace, "(partial suboption??\?)"); | |
457 | break; | |
458 | } | |
459 | fprintf(NetTrace, "%s|%s ", | |
460 | ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? | |
461 | "CLIENT" : "SERVER", | |
462 | ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? | |
463 | "MUTUAL" : "ONE-WAY"); | |
464 | ++i; | |
465 | } | |
466 | break; | |
467 | ||
468 | case TELQUAL_NAME: | |
469 | i = 2; | |
470 | fprintf(NetTrace, " NAME \""); | |
471 | while (i < length) | |
472 | putc(pointer[i++], NetTrace); | |
473 | putc('"', NetTrace); | |
474 | break; | |
475 | ||
476 | default: | |
477 | for (i = 2; i < length; i++) | |
478 | fprintf(NetTrace, " ?%d?", pointer[i]); | |
479 | break; | |
480 | } | |
481 | break; | |
482 | #endif | |
483 | ||
484 | #ifdef ENCRYPTION | |
485 | case TELOPT_ENCRYPT: | |
486 | fprintf(NetTrace, "ENCRYPT"); | |
487 | if (length < 2) { | |
488 | fprintf(NetTrace, " (empty suboption??\?)"); | |
489 | break; | |
490 | } | |
491 | switch (pointer[1]) { | |
492 | case ENCRYPT_START: | |
493 | fprintf(NetTrace, " START"); | |
494 | break; | |
495 | ||
496 | case ENCRYPT_END: | |
497 | fprintf(NetTrace, " END"); | |
498 | break; | |
499 | ||
500 | case ENCRYPT_REQSTART: | |
501 | fprintf(NetTrace, " REQUEST-START"); | |
502 | break; | |
503 | ||
504 | case ENCRYPT_REQEND: | |
505 | fprintf(NetTrace, " REQUEST-END"); | |
506 | break; | |
507 | ||
508 | case ENCRYPT_IS: | |
509 | case ENCRYPT_REPLY: | |
510 | fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? | |
511 | "IS" : "REPLY"); | |
512 | if (length < 3) { | |
513 | fprintf(NetTrace, " (partial suboption??\?)"); | |
514 | break; | |
515 | } | |
516 | if (ENCTYPE_NAME_OK(pointer[2])) | |
517 | fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2])); | |
518 | else | |
519 | fprintf(NetTrace, " %d (unknown)", pointer[2]); | |
520 | ||
521 | encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); | |
522 | fprintf(NetTrace, "%s", buf); | |
523 | break; | |
524 | ||
525 | case ENCRYPT_SUPPORT: | |
526 | i = 2; | |
527 | fprintf(NetTrace, " SUPPORT "); | |
528 | while (i < length) { | |
529 | if (ENCTYPE_NAME_OK(pointer[i])) | |
530 | fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i])); | |
531 | else | |
532 | fprintf(NetTrace, "%d ", pointer[i]); | |
533 | i++; | |
534 | } | |
535 | break; | |
536 | ||
537 | case ENCRYPT_ENC_KEYID: | |
538 | fprintf(NetTrace, " ENC_KEYID "); | |
539 | goto encommon; | |
540 | ||
541 | case ENCRYPT_DEC_KEYID: | |
542 | fprintf(NetTrace, " DEC_KEYID "); | |
543 | goto encommon; | |
544 | ||
545 | default: | |
546 | fprintf(NetTrace, " %d (unknown)", pointer[1]); | |
547 | encommon: | |
548 | for (i = 2; i < length; i++) | |
549 | fprintf(NetTrace, " %d", pointer[i]); | |
550 | break; | |
551 | } | |
552 | break; | |
553 | #endif /* ENCRYPTION */ | |
554 | ||
555 | case TELOPT_LINEMODE: | |
556 | fprintf(NetTrace, "LINEMODE "); | |
557 | if (length < 2) { | |
558 | fprintf(NetTrace, " (empty suboption??\?)"); | |
559 | break; | |
560 | } | |
561 | switch (pointer[1]) { | |
562 | case WILL: | |
563 | fprintf(NetTrace, "WILL "); | |
564 | goto common; | |
565 | case WONT: | |
566 | fprintf(NetTrace, "WONT "); | |
567 | goto common; | |
568 | case DO: | |
569 | fprintf(NetTrace, "DO "); | |
570 | goto common; | |
571 | case DONT: | |
572 | fprintf(NetTrace, "DONT "); | |
573 | common: | |
574 | if (length < 3) { | |
575 | fprintf(NetTrace, "(no option??\?)"); | |
576 | break; | |
577 | } | |
578 | switch (pointer[2]) { | |
579 | case LM_FORWARDMASK: | |
580 | fprintf(NetTrace, "Forward Mask"); | |
581 | for (i = 3; i < length; i++) | |
582 | fprintf(NetTrace, " %x", pointer[i]); | |
583 | break; | |
584 | default: | |
585 | fprintf(NetTrace, "%d (unknown)", pointer[2]); | |
586 | for (i = 3; i < length; i++) | |
587 | fprintf(NetTrace, " %d", pointer[i]); | |
588 | break; | |
589 | } | |
590 | break; | |
591 | ||
592 | case LM_SLC: | |
593 | fprintf(NetTrace, "SLC"); | |
594 | for (i = 2; i < length - 2; i += 3) { | |
595 | if (SLC_NAME_OK(pointer[i+SLC_FUNC])) | |
596 | fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); | |
597 | else | |
598 | fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); | |
599 | switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { | |
600 | case SLC_NOSUPPORT: | |
601 | fprintf(NetTrace, " NOSUPPORT"); break; | |
602 | case SLC_CANTCHANGE: | |
603 | fprintf(NetTrace, " CANTCHANGE"); break; | |
604 | case SLC_VARIABLE: | |
605 | fprintf(NetTrace, " VARIABLE"); break; | |
606 | case SLC_DEFAULT: | |
607 | fprintf(NetTrace, " DEFAULT"); break; | |
608 | } | |
609 | fprintf(NetTrace, "%s%s%s", | |
610 | pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", | |
611 | pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", | |
612 | pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); | |
613 | if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| | |
614 | SLC_FLUSHOUT| SLC_LEVELBITS)) | |
615 | fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); | |
616 | fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); | |
617 | if ((pointer[i+SLC_VALUE] == IAC) && | |
618 | (pointer[i+SLC_VALUE+1] == IAC)) | |
619 | i++; | |
620 | } | |
621 | for (; i < length; i++) | |
622 | fprintf(NetTrace, " ?%d?", pointer[i]); | |
623 | break; | |
624 | ||
625 | case LM_MODE: | |
626 | fprintf(NetTrace, "MODE "); | |
627 | if (length < 3) { | |
628 | fprintf(NetTrace, "(no mode??\?)"); | |
629 | break; | |
630 | } | |
631 | { | |
632 | char tbuf[64]; | |
633 | sprintf(tbuf, "%s%s%s%s%s", | |
634 | pointer[2]&MODE_EDIT ? "|EDIT" : "", | |
635 | pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", | |
636 | pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", | |
637 | pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", | |
638 | pointer[2]&MODE_ACK ? "|ACK" : ""); | |
639 | fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); | |
640 | } | |
641 | if (pointer[2]&~(MODE_MASK)) | |
642 | fprintf(NetTrace, " (0x%x)", pointer[2]); | |
643 | for (i = 3; i < length; i++) | |
644 | fprintf(NetTrace, " ?0x%x?", pointer[i]); | |
645 | break; | |
646 | default: | |
647 | fprintf(NetTrace, "%d (unknown)", pointer[1]); | |
648 | for (i = 2; i < length; i++) | |
649 | fprintf(NetTrace, " %d", pointer[i]); | |
650 | } | |
651 | break; | |
652 | ||
653 | case TELOPT_STATUS: { | |
7ba0088d A |
654 | const char *cp; |
655 | int j, k; | |
b7080c8e A |
656 | |
657 | fprintf(NetTrace, "STATUS"); | |
658 | ||
659 | switch (pointer[1]) { | |
660 | default: | |
661 | if (pointer[1] == TELQUAL_SEND) | |
662 | fprintf(NetTrace, " SEND"); | |
663 | else | |
664 | fprintf(NetTrace, " %d (unknown)", pointer[1]); | |
665 | for (i = 2; i < length; i++) | |
666 | fprintf(NetTrace, " ?%d?", pointer[i]); | |
667 | break; | |
668 | case TELQUAL_IS: | |
669 | if (--want_status_response < 0) | |
670 | want_status_response = 0; | |
671 | if (NetTrace == stdout) | |
672 | fprintf(NetTrace, " IS\r\n"); | |
673 | else | |
674 | fprintf(NetTrace, " IS\n"); | |
675 | ||
676 | for (i = 2; i < length; i++) { | |
677 | switch(pointer[i]) { | |
678 | case DO: cp = "DO"; goto common2; | |
679 | case DONT: cp = "DONT"; goto common2; | |
680 | case WILL: cp = "WILL"; goto common2; | |
681 | case WONT: cp = "WONT"; goto common2; | |
682 | common2: | |
683 | i++; | |
684 | if (TELOPT_OK((int)pointer[i])) | |
685 | fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); | |
686 | else | |
687 | fprintf(NetTrace, " %s %d", cp, pointer[i]); | |
688 | ||
689 | if (NetTrace == stdout) | |
690 | fprintf(NetTrace, "\r\n"); | |
691 | else | |
692 | fprintf(NetTrace, "\n"); | |
693 | break; | |
694 | ||
695 | case SB: | |
696 | fprintf(NetTrace, " SB "); | |
697 | i++; | |
698 | j = k = i; | |
699 | while (j < length) { | |
700 | if (pointer[j] == SE) { | |
701 | if (j+1 == length) | |
702 | break; | |
703 | if (pointer[j+1] == SE) | |
704 | j++; | |
705 | else | |
706 | break; | |
707 | } | |
708 | pointer[k++] = pointer[j++]; | |
709 | } | |
710 | printsub(0, &pointer[i], k - i); | |
711 | if (i < length) { | |
712 | fprintf(NetTrace, " SE"); | |
713 | i = j; | |
714 | } else | |
715 | i = j - 1; | |
716 | ||
717 | if (NetTrace == stdout) | |
718 | fprintf(NetTrace, "\r\n"); | |
719 | else | |
720 | fprintf(NetTrace, "\n"); | |
721 | ||
722 | break; | |
723 | ||
724 | default: | |
725 | fprintf(NetTrace, " %d", pointer[i]); | |
726 | break; | |
727 | } | |
728 | } | |
729 | break; | |
730 | } | |
731 | break; | |
732 | } | |
733 | ||
734 | case TELOPT_XDISPLOC: | |
735 | fprintf(NetTrace, "X-DISPLAY-LOCATION "); | |
736 | switch (pointer[1]) { | |
737 | case TELQUAL_IS: | |
738 | fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); | |
739 | break; | |
740 | case TELQUAL_SEND: | |
741 | fprintf(NetTrace, "SEND"); | |
742 | break; | |
743 | default: | |
744 | fprintf(NetTrace, "- unknown qualifier %d (0x%x).", | |
745 | pointer[1], pointer[1]); | |
746 | } | |
747 | break; | |
748 | ||
749 | case TELOPT_NEW_ENVIRON: | |
750 | fprintf(NetTrace, "NEW-ENVIRON "); | |
751 | #ifdef OLD_ENVIRON | |
752 | goto env_common1; | |
753 | case TELOPT_OLD_ENVIRON: | |
754 | fprintf(NetTrace, "OLD-ENVIRON"); | |
755 | env_common1: | |
756 | #endif | |
757 | switch (pointer[1]) { | |
758 | case TELQUAL_IS: | |
759 | fprintf(NetTrace, "IS "); | |
760 | goto env_common; | |
761 | case TELQUAL_SEND: | |
762 | fprintf(NetTrace, "SEND "); | |
763 | goto env_common; | |
764 | case TELQUAL_INFO: | |
765 | fprintf(NetTrace, "INFO "); | |
766 | env_common: | |
767 | { | |
7ba0088d | 768 | int noquote = 2; |
b7080c8e A |
769 | #if defined(ENV_HACK) && defined(OLD_ENVIRON) |
770 | extern int old_env_var, old_env_value; | |
771 | #endif | |
772 | for (i = 2; i < length; i++ ) { | |
773 | switch (pointer[i]) { | |
774 | case NEW_ENV_VALUE: | |
775 | #ifdef OLD_ENVIRON | |
776 | /* case NEW_ENV_OVAR: */ | |
777 | if (pointer[0] == TELOPT_OLD_ENVIRON) { | |
778 | # ifdef ENV_HACK | |
779 | if (old_env_var == OLD_ENV_VALUE) | |
780 | fprintf(NetTrace, "\" (VALUE) " + noquote); | |
781 | else | |
782 | # endif | |
783 | fprintf(NetTrace, "\" VAR " + noquote); | |
784 | } else | |
785 | #endif /* OLD_ENVIRON */ | |
786 | fprintf(NetTrace, "\" VALUE " + noquote); | |
787 | noquote = 2; | |
788 | break; | |
789 | ||
790 | case NEW_ENV_VAR: | |
791 | #ifdef OLD_ENVIRON | |
792 | /* case OLD_ENV_VALUE: */ | |
793 | if (pointer[0] == TELOPT_OLD_ENVIRON) { | |
794 | # ifdef ENV_HACK | |
795 | if (old_env_value == OLD_ENV_VAR) | |
796 | fprintf(NetTrace, "\" (VAR) " + noquote); | |
797 | else | |
798 | # endif | |
799 | fprintf(NetTrace, "\" VALUE " + noquote); | |
800 | } else | |
801 | #endif /* OLD_ENVIRON */ | |
802 | fprintf(NetTrace, "\" VAR " + noquote); | |
803 | noquote = 2; | |
804 | break; | |
805 | ||
806 | case ENV_ESC: | |
807 | fprintf(NetTrace, "\" ESC " + noquote); | |
808 | noquote = 2; | |
809 | break; | |
810 | ||
811 | case ENV_USERVAR: | |
812 | fprintf(NetTrace, "\" USERVAR " + noquote); | |
813 | noquote = 2; | |
814 | break; | |
815 | ||
816 | default: | |
b7080c8e A |
817 | if (isprint(pointer[i]) && pointer[i] != '"') { |
818 | if (noquote) { | |
819 | putc('"', NetTrace); | |
820 | noquote = 0; | |
821 | } | |
822 | putc(pointer[i], NetTrace); | |
823 | } else { | |
824 | fprintf(NetTrace, "\" %03o " + noquote, | |
825 | pointer[i]); | |
826 | noquote = 2; | |
827 | } | |
828 | break; | |
829 | } | |
830 | } | |
831 | if (!noquote) | |
832 | putc('"', NetTrace); | |
833 | break; | |
834 | } | |
835 | } | |
836 | break; | |
837 | ||
838 | default: | |
839 | if (TELOPT_OK(pointer[0])) | |
840 | fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); | |
841 | else | |
842 | fprintf(NetTrace, "%d (unknown)", pointer[0]); | |
843 | for (i = 1; i < length; i++) | |
844 | fprintf(NetTrace, " %d", pointer[i]); | |
845 | break; | |
846 | } | |
847 | if (direction) { | |
848 | if (NetTrace == stdout) | |
849 | fprintf(NetTrace, "\r\n"); | |
850 | else | |
851 | fprintf(NetTrace, "\n"); | |
852 | } | |
853 | if (NetTrace == stdout) | |
854 | fflush(NetTrace); | |
855 | } | |
856 | } | |
857 | ||
858 | /* EmptyTerminal - called to make sure that the terminal buffer is empty. | |
859 | * Note that we consider the buffer to run all the | |
860 | * way to the kernel (thus the select). | |
861 | */ | |
862 | ||
7ba0088d A |
863 | static void |
864 | EmptyTerminal(void) | |
b7080c8e | 865 | { |
b7080c8e A |
866 | fd_set o; |
867 | ||
868 | FD_ZERO(&o); | |
b7080c8e A |
869 | |
870 | if (TTYBYTES() == 0) { | |
b7080c8e A |
871 | FD_SET(tout, &o); |
872 | (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, | |
873 | (struct timeval *) 0); /* wait for TTLOWAT */ | |
b7080c8e A |
874 | } else { |
875 | while (TTYBYTES()) { | |
876 | (void) ttyflush(0); | |
b7080c8e A |
877 | FD_SET(tout, &o); |
878 | (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, | |
879 | (struct timeval *) 0); /* wait for TTLOWAT */ | |
b7080c8e A |
880 | } |
881 | } | |
882 | } | |
883 | ||
7ba0088d A |
884 | static void |
885 | SetForExit(void) | |
b7080c8e A |
886 | { |
887 | setconnmode(0); | |
b7080c8e A |
888 | do { |
889 | (void)telrcv(); /* Process any incoming data */ | |
890 | EmptyTerminal(); | |
891 | } while (ring_full_count(&netiring)); /* While there is any */ | |
b7080c8e A |
892 | setcommandmode(); |
893 | fflush(stdout); | |
894 | fflush(stderr); | |
b7080c8e A |
895 | setconnmode(0); |
896 | EmptyTerminal(); /* Flush the path to the tty */ | |
897 | setcommandmode(); | |
898 | } | |
899 | ||
7ba0088d A |
900 | void |
901 | Exit(int returnCode) | |
b7080c8e A |
902 | { |
903 | SetForExit(); | |
904 | exit(returnCode); | |
905 | } | |
906 | ||
7ba0088d A |
907 | void |
908 | ExitString(const char *string, int returnCode) | |
b7080c8e A |
909 | { |
910 | SetForExit(); | |
911 | fwrite(string, 1, strlen(string), stderr); | |
912 | exit(returnCode); | |
913 | } |