Commit | Line | Data |
---|---|---|
ea139302 PB |
1 | /* |
2 | * Copyright (c) 1989 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
836fe169 | 5 | * %sccs.include.redist.c% |
ea139302 PB |
6 | */ |
7 | ||
8 | #ifndef lint | |
b7c8f459 | 9 | static char sccsid[] = "@(#)utility.c 5.8 (Berkeley) %G%"; |
ea139302 PB |
10 | #endif /* not lint */ |
11 | ||
4a8a7128 | 12 | #define PRINTOPTIONS |
ea139302 PB |
13 | #include "telnetd.h" |
14 | ||
15 | /* | |
16 | * utility functions performing io related tasks | |
17 | */ | |
18 | ||
19 | /* | |
20 | * ttloop | |
21 | * | |
22 | * A small subroutine to flush the network output buffer, get some data | |
23 | * from the network, and pass it through the telnet state machine. We | |
24 | * also flush the pty input buffer (by dropping its data) if it becomes | |
25 | * too full. | |
26 | */ | |
27 | ||
1af3d848 | 28 | void |
ea139302 PB |
29 | ttloop() |
30 | { | |
31 | void netflush(); | |
32 | ||
1af3d848 DB |
33 | DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n"); |
34 | nfrontp += strlen(nfrontp);}); | |
ea139302 PB |
35 | if (nfrontp-nbackp) { |
36 | netflush(); | |
37 | } | |
38 | ncc = read(net, netibuf, sizeof netibuf); | |
39 | if (ncc < 0) { | |
40 | syslog(LOG_INFO, "ttloop: read: %m\n"); | |
41 | exit(1); | |
42 | } else if (ncc == 0) { | |
43 | syslog(LOG_INFO, "ttloop: peer died: %m\n"); | |
44 | exit(1); | |
45 | } | |
1af3d848 DB |
46 | DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); |
47 | nfrontp += strlen(nfrontp);}); | |
ea139302 PB |
48 | netip = netibuf; |
49 | telrcv(); /* state machine */ | |
50 | if (ncc > 0) { | |
51 | pfrontp = pbackp = ptyobuf; | |
52 | telrcv(); | |
53 | } | |
54 | } /* end of ttloop */ | |
55 | ||
56 | /* | |
57 | * Check a descriptor to see if out of band data exists on it. | |
58 | */ | |
1af3d848 | 59 | int |
ea139302 | 60 | stilloob(s) |
1af3d848 | 61 | int s; /* socket number */ |
ea139302 PB |
62 | { |
63 | static struct timeval timeout = { 0 }; | |
64 | fd_set excepts; | |
65 | int value; | |
66 | ||
67 | do { | |
68 | FD_ZERO(&excepts); | |
69 | FD_SET(s, &excepts); | |
70 | value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); | |
71 | } while ((value == -1) && (errno == EINTR)); | |
72 | ||
73 | if (value < 0) { | |
74 | fatalperror(pty, "select"); | |
75 | } | |
76 | if (FD_ISSET(s, &excepts)) { | |
77 | return 1; | |
78 | } else { | |
79 | return 0; | |
80 | } | |
81 | } | |
82 | ||
1af3d848 | 83 | void |
ea139302 PB |
84 | ptyflush() |
85 | { | |
86 | int n; | |
87 | ||
4a8a7128 | 88 | if ((n = pfrontp - pbackp) > 0) { |
1af3d848 DB |
89 | DIAG((TD_REPORT | TD_PTYDATA), |
90 | { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n); | |
91 | nfrontp += strlen(nfrontp); }); | |
92 | DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); | |
ea139302 | 93 | n = write(pty, pbackp, n); |
4a8a7128 | 94 | } |
1af3d848 DB |
95 | if (n < 0) { |
96 | if (errno == EWOULDBLOCK || errno == EINTR) | |
97 | return; | |
98 | cleanup(0); | |
99 | } | |
ea139302 PB |
100 | pbackp += n; |
101 | if (pbackp == pfrontp) | |
102 | pbackp = pfrontp = ptyobuf; | |
103 | } | |
104 | ||
105 | /* | |
106 | * nextitem() | |
107 | * | |
108 | * Return the address of the next "item" in the TELNET data | |
109 | * stream. This will be the address of the next character if | |
110 | * the current address is a user data character, or it will | |
111 | * be the address of the character following the TELNET command | |
112 | * if the current address is a TELNET IAC ("I Am a Command") | |
113 | * character. | |
114 | */ | |
1af3d848 | 115 | char * |
ea139302 | 116 | nextitem(current) |
1af3d848 | 117 | char *current; |
ea139302 PB |
118 | { |
119 | if ((*current&0xff) != IAC) { | |
120 | return current+1; | |
121 | } | |
122 | switch (*(current+1)&0xff) { | |
123 | case DO: | |
124 | case DONT: | |
125 | case WILL: | |
126 | case WONT: | |
127 | return current+3; | |
128 | case SB: /* loop forever looking for the SE */ | |
129 | { | |
130 | register char *look = current+2; | |
131 | ||
132 | for (;;) { | |
133 | if ((*look++&0xff) == IAC) { | |
134 | if ((*look++&0xff) == SE) { | |
135 | return look; | |
136 | } | |
137 | } | |
138 | } | |
139 | } | |
140 | default: | |
141 | return current+2; | |
142 | } | |
143 | } /* end of nextitem */ | |
144 | ||
145 | ||
146 | /* | |
147 | * netclear() | |
148 | * | |
149 | * We are about to do a TELNET SYNCH operation. Clear | |
150 | * the path to the network. | |
151 | * | |
152 | * Things are a bit tricky since we may have sent the first | |
153 | * byte or so of a previous TELNET command into the network. | |
154 | * So, we have to scan the network buffer from the beginning | |
155 | * until we are up to where we want to be. | |
156 | * | |
157 | * A side effect of what we do, just to keep things | |
158 | * simple, is to clear the urgent data pointer. The principal | |
159 | * caller should be setting the urgent data pointer AFTER calling | |
160 | * us in any case. | |
161 | */ | |
1af3d848 | 162 | void |
ea139302 PB |
163 | netclear() |
164 | { | |
165 | register char *thisitem, *next; | |
166 | char *good; | |
167 | #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ | |
168 | ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) | |
169 | ||
1af3d848 DB |
170 | #if defined(ENCRYPT) |
171 | thisitem = nclearto > netobuf ? nclearto : netobuf; | |
172 | #else | |
ea139302 | 173 | thisitem = netobuf; |
1af3d848 | 174 | #endif |
ea139302 PB |
175 | |
176 | while ((next = nextitem(thisitem)) <= nbackp) { | |
177 | thisitem = next; | |
178 | } | |
179 | ||
180 | /* Now, thisitem is first before/at boundary. */ | |
181 | ||
1af3d848 DB |
182 | #if defined(ENCRYPT) |
183 | good = nclearto > netobuf ? nclearto : netobuf; | |
184 | #else | |
ea139302 | 185 | good = netobuf; /* where the good bytes go */ |
1af3d848 | 186 | #endif |
ea139302 PB |
187 | |
188 | while (nfrontp > thisitem) { | |
189 | if (wewant(thisitem)) { | |
190 | int length; | |
191 | ||
192 | next = thisitem; | |
193 | do { | |
194 | next = nextitem(next); | |
195 | } while (wewant(next) && (nfrontp > next)); | |
196 | length = next-thisitem; | |
197 | bcopy(thisitem, good, length); | |
198 | good += length; | |
199 | thisitem = next; | |
200 | } else { | |
201 | thisitem = nextitem(thisitem); | |
202 | } | |
203 | } | |
204 | ||
205 | nbackp = netobuf; | |
206 | nfrontp = good; /* next byte to be sent */ | |
207 | neturg = 0; | |
208 | } /* end of netclear */ | |
209 | ||
210 | /* | |
211 | * netflush | |
212 | * Send as much data as possible to the network, | |
213 | * handling requests for urgent data. | |
214 | */ | |
1af3d848 | 215 | void |
ea139302 PB |
216 | netflush() |
217 | { | |
218 | int n; | |
219 | extern int not42; | |
220 | ||
221 | if ((n = nfrontp - nbackp) > 0) { | |
1af3d848 DB |
222 | DIAG(TD_REPORT, |
223 | { sprintf(nfrontp, "td: netflush %d chars\r\n", n); | |
224 | n += strlen(nfrontp); /* get count first */ | |
225 | nfrontp += strlen(nfrontp); /* then move pointer */ | |
226 | }); | |
227 | #if defined(ENCRYPT) | |
228 | if (encrypt_output) { | |
229 | char *s = nclearto ? nclearto : nbackp; | |
230 | if (nfrontp - s > 0) { | |
231 | (*encrypt_output)((unsigned char *)s, nfrontp-s); | |
232 | nclearto = nfrontp; | |
233 | } | |
4a8a7128 | 234 | } |
1af3d848 | 235 | #endif |
ea139302 PB |
236 | /* |
237 | * if no urgent data, or if the other side appears to be an | |
238 | * old 4.2 client (and thus unable to survive TCP urgent data), | |
239 | * write the entire buffer in non-OOB mode. | |
240 | */ | |
241 | if ((neturg == 0) || (not42 == 0)) { | |
242 | n = write(net, nbackp, n); /* normal write */ | |
243 | } else { | |
244 | n = neturg - nbackp; | |
245 | /* | |
246 | * In 4.2 (and 4.3) systems, there is some question about | |
247 | * what byte in a sendOOB operation is the "OOB" data. | |
248 | * To make ourselves compatible, we only send ONE byte | |
249 | * out of band, the one WE THINK should be OOB (though | |
250 | * we really have more the TCP philosophy of urgent data | |
251 | * rather than the Unix philosophy of OOB data). | |
252 | */ | |
253 | if (n > 1) { | |
254 | n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ | |
255 | } else { | |
256 | n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ | |
257 | } | |
258 | } | |
259 | } | |
260 | if (n < 0) { | |
261 | if (errno == EWOULDBLOCK || errno == EINTR) | |
262 | return; | |
1af3d848 | 263 | cleanup(0); |
ea139302 PB |
264 | } |
265 | nbackp += n; | |
1af3d848 DB |
266 | #if defined(ENCRYPT) |
267 | if (nbackp > nclearto) | |
268 | nclearto = 0; | |
269 | #endif | |
ea139302 PB |
270 | if (nbackp >= neturg) { |
271 | neturg = 0; | |
272 | } | |
273 | if (nbackp == nfrontp) { | |
274 | nbackp = nfrontp = netobuf; | |
1af3d848 DB |
275 | #if defined(ENCRYPT) |
276 | nclearto = 0; | |
277 | #endif | |
ea139302 PB |
278 | } |
279 | return; | |
280 | } /* end of netflush */ | |
281 | ||
282 | ||
283 | /* | |
284 | * writenet | |
285 | * | |
286 | * Just a handy little function to write a bit of raw data to the net. | |
287 | * It will force a transmit of the buffer if necessary | |
288 | * | |
289 | * arguments | |
290 | * ptr - A pointer to a character string to write | |
291 | * len - How many bytes to write | |
292 | */ | |
1af3d848 | 293 | void |
ea139302 | 294 | writenet(ptr, len) |
1af3d848 DB |
295 | register unsigned char *ptr; |
296 | register int len; | |
ea139302 PB |
297 | { |
298 | /* flush buffer if no room for new data) */ | |
299 | if ((&netobuf[BUFSIZ] - nfrontp) < len) { | |
300 | /* if this fails, don't worry, buffer is a little big */ | |
301 | netflush(); | |
302 | } | |
303 | ||
304 | bcopy(ptr, nfrontp, len); | |
305 | nfrontp += len; | |
306 | ||
307 | } /* end of writenet */ | |
308 | ||
309 | ||
310 | /* | |
311 | * miscellaneous functions doing a variety of little jobs follow ... | |
312 | */ | |
313 | ||
314 | ||
1af3d848 | 315 | void |
ea139302 PB |
316 | fatal(f, msg) |
317 | int f; | |
318 | char *msg; | |
319 | { | |
320 | char buf[BUFSIZ]; | |
321 | ||
322 | (void) sprintf(buf, "telnetd: %s.\r\n", msg); | |
1af3d848 DB |
323 | #if defined(ENCRYPT) |
324 | if (encrypt_output) { | |
325 | /* | |
326 | * Better turn off encryption first.... | |
327 | * Hope it flushes... | |
328 | */ | |
329 | encrypt_send_end(); | |
330 | netflush(); | |
331 | } | |
332 | #endif | |
ea139302 PB |
333 | (void) write(f, buf, (int)strlen(buf)); |
334 | sleep(1); /*XXX*/ | |
335 | exit(1); | |
336 | } | |
337 | ||
1af3d848 | 338 | void |
ea139302 PB |
339 | fatalperror(f, msg) |
340 | int f; | |
341 | char *msg; | |
342 | { | |
396aa79f | 343 | char buf[BUFSIZ], *strerror(); |
ea139302 | 344 | |
396aa79f | 345 | (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno)); |
ea139302 PB |
346 | fatal(f, buf); |
347 | } | |
348 | ||
349 | char editedhost[32]; | |
350 | ||
1af3d848 | 351 | void |
ea139302 PB |
352 | edithost(pat, host) |
353 | register char *pat; | |
354 | register char *host; | |
355 | { | |
356 | register char *res = editedhost; | |
357 | char *strncpy(); | |
358 | ||
359 | if (!pat) | |
360 | pat = ""; | |
361 | while (*pat) { | |
362 | switch (*pat) { | |
363 | ||
364 | case '#': | |
365 | if (*host) | |
366 | host++; | |
367 | break; | |
368 | ||
369 | case '@': | |
370 | if (*host) | |
371 | *res++ = *host++; | |
372 | break; | |
373 | ||
374 | default: | |
375 | *res++ = *pat; | |
376 | break; | |
377 | } | |
378 | if (res == &editedhost[sizeof editedhost - 1]) { | |
379 | *res = '\0'; | |
380 | return; | |
381 | } | |
382 | pat++; | |
383 | } | |
384 | if (*host) | |
385 | (void) strncpy(res, host, | |
386 | sizeof editedhost - (res - editedhost) -1); | |
387 | else | |
388 | *res = '\0'; | |
389 | editedhost[sizeof editedhost - 1] = '\0'; | |
390 | } | |
391 | ||
392 | static char *putlocation; | |
393 | ||
1af3d848 | 394 | void |
ea139302 | 395 | putstr(s) |
1af3d848 | 396 | register char *s; |
ea139302 PB |
397 | { |
398 | ||
399 | while (*s) | |
400 | putchr(*s++); | |
401 | } | |
402 | ||
1af3d848 | 403 | void |
ea139302 | 404 | putchr(cc) |
1af3d848 | 405 | int cc; |
ea139302 PB |
406 | { |
407 | *putlocation++ = cc; | |
408 | } | |
409 | ||
1af3d848 DB |
410 | /* |
411 | * This is split on two lines so that SCCS will not see the M | |
412 | * between two % signs and expand it... | |
413 | */ | |
414 | static char fmtstr[] = { "%l:%M\ | |
415 | %P on %A, %d %B %Y" }; | |
416 | ||
417 | void | |
ea139302 | 418 | putf(cp, where) |
1af3d848 DB |
419 | register char *cp; |
420 | char *where; | |
ea139302 | 421 | { |
1af3d848 | 422 | char *slash; |
977a0c8c | 423 | time_t t; |
1af3d848 | 424 | char db[100]; |
ea139302 PB |
425 | extern char *rindex(); |
426 | ||
427 | putlocation = where; | |
428 | ||
429 | while (*cp) { | |
430 | if (*cp != '%') { | |
431 | putchr(*cp++); | |
432 | continue; | |
433 | } | |
434 | switch (*++cp) { | |
435 | ||
436 | case 't': | |
437 | slash = rindex(line, '/'); | |
438 | if (slash == (char *) 0) | |
439 | putstr(line); | |
440 | else | |
441 | putstr(&slash[1]); | |
442 | break; | |
443 | ||
444 | case 'h': | |
445 | putstr(editedhost); | |
446 | break; | |
447 | ||
1af3d848 | 448 | case 'd': |
977a0c8c | 449 | (void)time(&t); |
1af3d848 | 450 | (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); |
977a0c8c | 451 | putstr(db); |
ea139302 | 452 | break; |
ea139302 PB |
453 | |
454 | case '%': | |
455 | putchr('%'); | |
456 | break; | |
457 | } | |
458 | cp++; | |
459 | } | |
460 | } | |
461 | ||
4a8a7128 PB |
462 | #ifdef DIAGNOSTICS |
463 | /* | |
464 | * Print telnet options and commands in plain text, if possible. | |
465 | */ | |
1af3d848 | 466 | void |
4a8a7128 | 467 | printoption(fmt, option) |
1af3d848 DB |
468 | register char *fmt; |
469 | register int option; | |
4a8a7128 PB |
470 | { |
471 | if (TELOPT_OK(option)) | |
472 | sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); | |
473 | else if (TELCMD_OK(option)) | |
474 | sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); | |
475 | else | |
476 | sprintf(nfrontp, "%s %d\r\n", fmt, option); | |
477 | nfrontp += strlen(nfrontp); | |
478 | return; | |
479 | } | |
480 | ||
1af3d848 DB |
481 | void |
482 | printsub(direction, pointer, length) | |
483 | char direction; /* '<' or '>' */ | |
484 | unsigned char *pointer; /* where suboption data sits */ | |
485 | int length; /* length of suboption data */ | |
4a8a7128 PB |
486 | { |
487 | register int i; | |
b7c8f459 | 488 | char buf[512]; |
4a8a7128 | 489 | |
1af3d848 DB |
490 | if (!(diagnostic & TD_OPTIONS)) |
491 | return; | |
492 | ||
493 | if (direction) { | |
494 | sprintf(nfrontp, "td: %s suboption ", | |
495 | direction == '<' ? "recv" : "send"); | |
4a8a7128 PB |
496 | nfrontp += strlen(nfrontp); |
497 | if (length >= 3) { | |
498 | register int j; | |
499 | ||
500 | i = pointer[length-2]; | |
501 | j = pointer[length-1]; | |
502 | ||
503 | if (i != IAC || j != SE) { | |
504 | sprintf(nfrontp, "(terminated by "); | |
505 | nfrontp += strlen(nfrontp); | |
506 | if (TELOPT_OK(i)) | |
507 | sprintf(nfrontp, "%s ", TELOPT(i)); | |
508 | else if (TELCMD_OK(i)) | |
509 | sprintf(nfrontp, "%s ", TELCMD(i)); | |
510 | else | |
511 | sprintf(nfrontp, "%d ", i); | |
512 | nfrontp += strlen(nfrontp); | |
513 | if (TELOPT_OK(j)) | |
514 | sprintf(nfrontp, "%s", TELOPT(j)); | |
515 | else if (TELCMD_OK(j)) | |
516 | sprintf(nfrontp, "%s", TELCMD(j)); | |
517 | else | |
518 | sprintf(nfrontp, "%d", j); | |
519 | nfrontp += strlen(nfrontp); | |
520 | sprintf(nfrontp, ", not IAC SE!) "); | |
521 | nfrontp += strlen(nfrontp); | |
522 | } | |
523 | } | |
524 | length -= 2; | |
525 | } | |
526 | if (length < 1) { | |
527 | sprintf(nfrontp, "(Empty suboption???)"); | |
528 | nfrontp += strlen(nfrontp); | |
529 | return; | |
530 | } | |
531 | switch (pointer[0]) { | |
532 | case TELOPT_TTYPE: | |
533 | sprintf(nfrontp, "TERMINAL-TYPE "); | |
534 | nfrontp += strlen(nfrontp); | |
535 | switch (pointer[1]) { | |
536 | case TELQUAL_IS: | |
537 | sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); | |
538 | break; | |
539 | case TELQUAL_SEND: | |
540 | sprintf(nfrontp, "SEND"); | |
541 | break; | |
542 | default: | |
543 | sprintf(nfrontp, | |
544 | "- unknown qualifier %d (0x%x).", | |
545 | pointer[1], pointer[1]); | |
546 | } | |
547 | nfrontp += strlen(nfrontp); | |
548 | break; | |
549 | case TELOPT_TSPEED: | |
550 | sprintf(nfrontp, "TERMINAL-SPEED"); | |
551 | nfrontp += strlen(nfrontp); | |
552 | if (length < 2) { | |
553 | sprintf(nfrontp, " (empty suboption???)"); | |
554 | nfrontp += strlen(nfrontp); | |
555 | break; | |
556 | } | |
557 | switch (pointer[1]) { | |
558 | case TELQUAL_IS: | |
559 | sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); | |
560 | nfrontp += strlen(nfrontp); | |
561 | break; | |
562 | default: | |
563 | if (pointer[1] == 1) | |
564 | sprintf(nfrontp, " SEND"); | |
565 | else | |
566 | sprintf(nfrontp, " %d (unknown)", pointer[1]); | |
567 | nfrontp += strlen(nfrontp); | |
568 | for (i = 2; i < length; i++) { | |
569 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
570 | nfrontp += strlen(nfrontp); | |
571 | } | |
572 | break; | |
573 | } | |
574 | break; | |
575 | ||
576 | case TELOPT_LFLOW: | |
577 | sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); | |
578 | nfrontp += strlen(nfrontp); | |
579 | if (length < 2) { | |
580 | sprintf(nfrontp, " (empty suboption???)"); | |
581 | nfrontp += strlen(nfrontp); | |
582 | break; | |
583 | } | |
584 | switch (pointer[1]) { | |
585 | case 0: | |
586 | sprintf(nfrontp, " OFF"); break; | |
587 | case 1: | |
588 | sprintf(nfrontp, " ON"); break; | |
589 | default: | |
590 | sprintf(nfrontp, " %d (unknown)", pointer[1]); | |
591 | } | |
592 | nfrontp += strlen(nfrontp); | |
593 | for (i = 2; i < length; i++) { | |
594 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
595 | nfrontp += strlen(nfrontp); | |
596 | } | |
597 | break; | |
598 | ||
599 | case TELOPT_NAWS: | |
600 | sprintf(nfrontp, "NAWS"); | |
601 | nfrontp += strlen(nfrontp); | |
602 | if (length < 2) { | |
603 | sprintf(nfrontp, " (empty suboption???)"); | |
604 | nfrontp += strlen(nfrontp); | |
605 | break; | |
606 | } | |
607 | if (length == 2) { | |
608 | sprintf(nfrontp, " ?%d?", pointer[1]); | |
609 | nfrontp += strlen(nfrontp); | |
610 | break; | |
611 | } | |
612 | sprintf(nfrontp, " %d %d (%d)", | |
613 | pointer[1], pointer[2], | |
614 | (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); | |
615 | nfrontp += strlen(nfrontp); | |
616 | if (length == 4) { | |
617 | sprintf(nfrontp, " ?%d?", pointer[3]); | |
618 | nfrontp += strlen(nfrontp); | |
619 | break; | |
620 | } | |
621 | sprintf(nfrontp, " %d %d (%d)", | |
622 | pointer[3], pointer[4], | |
623 | (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); | |
624 | nfrontp += strlen(nfrontp); | |
625 | for (i = 5; i < length; i++) { | |
626 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
627 | nfrontp += strlen(nfrontp); | |
628 | } | |
629 | break; | |
630 | ||
631 | case TELOPT_LINEMODE: | |
632 | sprintf(nfrontp, "LINEMODE "); | |
633 | nfrontp += strlen(nfrontp); | |
634 | if (length < 2) { | |
635 | sprintf(nfrontp, " (empty suboption???)"); | |
636 | nfrontp += strlen(nfrontp); | |
637 | break; | |
638 | } | |
639 | switch (pointer[1]) { | |
640 | case WILL: | |
641 | sprintf(nfrontp, "WILL "); | |
642 | goto common; | |
643 | case WONT: | |
644 | sprintf(nfrontp, "WONT "); | |
645 | goto common; | |
646 | case DO: | |
647 | sprintf(nfrontp, "DO "); | |
648 | goto common; | |
649 | case DONT: | |
650 | sprintf(nfrontp, "DONT "); | |
651 | common: | |
652 | nfrontp += strlen(nfrontp); | |
653 | if (length < 3) { | |
654 | sprintf(nfrontp, "(no option???)"); | |
655 | nfrontp += strlen(nfrontp); | |
656 | break; | |
657 | } | |
658 | switch (pointer[2]) { | |
659 | case LM_FORWARDMASK: | |
660 | sprintf(nfrontp, "Forward Mask"); | |
661 | nfrontp += strlen(nfrontp); | |
662 | for (i = 3; i < length; i++) { | |
663 | sprintf(nfrontp, " %x", pointer[i]); | |
664 | nfrontp += strlen(nfrontp); | |
665 | } | |
666 | break; | |
667 | default: | |
668 | sprintf(nfrontp, "%d (unknown)", pointer[2]); | |
669 | nfrontp += strlen(nfrontp); | |
670 | for (i = 3; i < length; i++) { | |
671 | sprintf(nfrontp, " %d", pointer[i]); | |
672 | nfrontp += strlen(nfrontp); | |
673 | } | |
674 | break; | |
675 | } | |
676 | break; | |
677 | ||
678 | case LM_SLC: | |
679 | sprintf(nfrontp, "SLC"); | |
680 | nfrontp += strlen(nfrontp); | |
681 | for (i = 2; i < length - 2; i += 3) { | |
1af3d848 DB |
682 | if (SLC_NAME_OK(pointer[i+SLC_FUNC])) |
683 | sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC])); | |
4a8a7128 PB |
684 | else |
685 | sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); | |
686 | nfrontp += strlen(nfrontp); | |
687 | switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { | |
688 | case SLC_NOSUPPORT: | |
689 | sprintf(nfrontp, " NOSUPPORT"); break; | |
690 | case SLC_CANTCHANGE: | |
691 | sprintf(nfrontp, " CANTCHANGE"); break; | |
692 | case SLC_VARIABLE: | |
693 | sprintf(nfrontp, " VARIABLE"); break; | |
694 | case SLC_DEFAULT: | |
695 | sprintf(nfrontp, " DEFAULT"); break; | |
696 | } | |
697 | nfrontp += strlen(nfrontp); | |
698 | sprintf(nfrontp, "%s%s%s", | |
699 | pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", | |
700 | pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", | |
701 | pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); | |
702 | nfrontp += strlen(nfrontp); | |
703 | if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| | |
704 | SLC_FLUSHOUT| SLC_LEVELBITS)) { | |
705 | sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); | |
706 | nfrontp += strlen(nfrontp); | |
707 | } | |
708 | sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); | |
709 | nfrontp += strlen(nfrontp); | |
710 | if ((pointer[i+SLC_VALUE] == IAC) && | |
711 | (pointer[i+SLC_VALUE+1] == IAC)) | |
712 | i++; | |
713 | } | |
714 | for (; i < length; i++) { | |
715 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
716 | nfrontp += strlen(nfrontp); | |
717 | } | |
718 | break; | |
719 | ||
720 | case LM_MODE: | |
721 | sprintf(nfrontp, "MODE "); | |
722 | nfrontp += strlen(nfrontp); | |
723 | if (length < 3) { | |
724 | sprintf(nfrontp, "(no mode???)"); | |
725 | nfrontp += strlen(nfrontp); | |
726 | break; | |
727 | } | |
728 | { | |
729 | char tbuf[32]; | |
730 | sprintf(tbuf, "%s%s%s%s%s", | |
731 | pointer[2]&MODE_EDIT ? "|EDIT" : "", | |
732 | pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", | |
733 | pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", | |
734 | pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", | |
735 | pointer[2]&MODE_ACK ? "|ACK" : ""); | |
736 | sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); | |
737 | nfrontp += strlen(nfrontp); | |
738 | } | |
739 | if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { | |
740 | sprintf(nfrontp, " (0x%x)", pointer[2]); | |
741 | nfrontp += strlen(nfrontp); | |
742 | } | |
743 | for (i = 3; i < length; i++) { | |
744 | sprintf(nfrontp, " ?0x%x?", pointer[i]); | |
745 | nfrontp += strlen(nfrontp); | |
746 | } | |
747 | break; | |
748 | default: | |
749 | sprintf(nfrontp, "%d (unknown)", pointer[1]); | |
750 | nfrontp += strlen(nfrontp); | |
751 | for (i = 2; i < length; i++) { | |
752 | sprintf(nfrontp, " %d", pointer[i]); | |
753 | nfrontp += strlen(nfrontp); | |
754 | } | |
755 | } | |
756 | break; | |
757 | ||
758 | case TELOPT_STATUS: { | |
759 | register char *cp; | |
760 | register int j, k; | |
761 | ||
762 | sprintf(nfrontp, "STATUS"); | |
763 | nfrontp += strlen(nfrontp); | |
764 | ||
765 | switch (pointer[1]) { | |
766 | default: | |
767 | if (pointer[1] == TELQUAL_SEND) | |
768 | sprintf(nfrontp, " SEND"); | |
769 | else | |
770 | sprintf(nfrontp, " %d (unknown)", pointer[1]); | |
771 | nfrontp += strlen(nfrontp); | |
772 | for (i = 2; i < length; i++) { | |
773 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
774 | nfrontp += strlen(nfrontp); | |
775 | } | |
776 | break; | |
777 | case TELQUAL_IS: | |
778 | sprintf(nfrontp, " IS\r\n"); | |
779 | nfrontp += strlen(nfrontp); | |
780 | ||
781 | for (i = 2; i < length; i++) { | |
782 | switch(pointer[i]) { | |
783 | case DO: cp = "DO"; goto common2; | |
784 | case DONT: cp = "DONT"; goto common2; | |
785 | case WILL: cp = "WILL"; goto common2; | |
786 | case WONT: cp = "WONT"; goto common2; | |
787 | common2: | |
788 | i++; | |
789 | if (TELOPT_OK((int)pointer[i])) | |
790 | sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); | |
791 | else | |
792 | sprintf(nfrontp, " %s %d", cp, pointer[i]); | |
793 | nfrontp += strlen(nfrontp); | |
794 | ||
795 | sprintf(nfrontp, "\r\n"); | |
796 | nfrontp += strlen(nfrontp); | |
797 | break; | |
798 | ||
799 | case SB: | |
800 | sprintf(nfrontp, " SB "); | |
801 | nfrontp += strlen(nfrontp); | |
802 | i++; | |
803 | j = k = i; | |
804 | while (j < length) { | |
805 | if (pointer[j] == SE) { | |
806 | if (j+1 == length) | |
807 | break; | |
808 | if (pointer[j+1] == SE) | |
809 | j++; | |
810 | else | |
811 | break; | |
812 | } | |
813 | pointer[k++] = pointer[j++]; | |
814 | } | |
815 | printsub(0, &pointer[i], k - i); | |
816 | if (i < length) { | |
817 | sprintf(nfrontp, " SE"); | |
818 | nfrontp += strlen(nfrontp); | |
819 | i = j; | |
820 | } else | |
821 | i = j - 1; | |
822 | ||
823 | sprintf(nfrontp, "\r\n"); | |
824 | nfrontp += strlen(nfrontp); | |
825 | ||
826 | break; | |
827 | ||
828 | default: | |
829 | sprintf(nfrontp, " %d", pointer[i]); | |
830 | nfrontp += strlen(nfrontp); | |
831 | break; | |
832 | } | |
833 | } | |
834 | break; | |
835 | } | |
836 | break; | |
837 | } | |
838 | ||
839 | case TELOPT_XDISPLOC: | |
840 | sprintf(nfrontp, "X-DISPLAY-LOCATION "); | |
841 | nfrontp += strlen(nfrontp); | |
842 | switch (pointer[1]) { | |
843 | case TELQUAL_IS: | |
844 | sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); | |
845 | break; | |
846 | case TELQUAL_SEND: | |
847 | sprintf(nfrontp, "SEND"); | |
848 | break; | |
849 | default: | |
850 | sprintf(nfrontp, "- unknown qualifier %d (0x%x).", | |
851 | pointer[1], pointer[1]); | |
852 | } | |
853 | nfrontp += strlen(nfrontp); | |
854 | break; | |
855 | ||
856 | case TELOPT_ENVIRON: | |
857 | sprintf(nfrontp, "ENVIRON "); | |
858 | nfrontp += strlen(nfrontp); | |
859 | switch (pointer[1]) { | |
860 | case TELQUAL_IS: | |
861 | sprintf(nfrontp, "IS "); | |
862 | goto env_common; | |
863 | case TELQUAL_SEND: | |
864 | sprintf(nfrontp, "SEND "); | |
865 | goto env_common; | |
866 | case TELQUAL_INFO: | |
867 | sprintf(nfrontp, "INFO "); | |
868 | env_common: | |
869 | nfrontp += strlen(nfrontp); | |
870 | { | |
871 | register int noquote = 2; | |
872 | for (i = 2; i < length; i++ ) { | |
873 | switch (pointer[i]) { | |
874 | case ENV_VAR: | |
875 | if (pointer[1] == TELQUAL_SEND) | |
876 | goto def_case; | |
877 | sprintf(nfrontp, "\" VAR " + noquote); | |
878 | nfrontp += strlen(nfrontp); | |
879 | noquote = 2; | |
880 | break; | |
881 | ||
882 | case ENV_VALUE: | |
883 | sprintf(nfrontp, "\" VALUE " + noquote); | |
884 | nfrontp += strlen(nfrontp); | |
885 | noquote = 2; | |
886 | break; | |
887 | ||
888 | case ENV_ESC: | |
889 | sprintf(nfrontp, "\" ESC " + noquote); | |
890 | nfrontp += strlen(nfrontp); | |
891 | noquote = 2; | |
892 | break; | |
893 | ||
894 | default: | |
895 | def_case: | |
896 | if (isprint(pointer[i]) && pointer[i] != '"') { | |
897 | if (noquote) { | |
898 | *nfrontp++ = '"'; | |
899 | noquote = 0; | |
900 | } | |
901 | *nfrontp++ = pointer[i]; | |
902 | } else { | |
903 | sprintf(nfrontp, "\" %03o " + noquote, | |
904 | pointer[i]); | |
905 | nfrontp += strlen(nfrontp); | |
906 | noquote = 2; | |
907 | } | |
908 | break; | |
909 | } | |
910 | } | |
911 | if (!noquote) | |
912 | *nfrontp++ = '"'; | |
913 | break; | |
914 | } | |
915 | } | |
916 | break; | |
917 | ||
1af3d848 DB |
918 | #if defined(AUTHENTICATE) |
919 | case TELOPT_AUTHENTICATION: | |
920 | sprintf(nfrontp, "AUTHENTICATION"); | |
921 | nfrontp += strlen(nfrontp); | |
922 | ||
923 | if (length < 2) { | |
924 | sprintf(nfrontp, " (empty suboption???)"); | |
925 | nfrontp += strlen(nfrontp); | |
926 | break; | |
927 | } | |
928 | switch (pointer[1]) { | |
929 | case TELQUAL_REPLY: | |
930 | case TELQUAL_IS: | |
931 | sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ? | |
932 | "IS" : "REPLY"); | |
933 | nfrontp += strlen(nfrontp); | |
934 | if (AUTHTYPE_NAME_OK(pointer[2])) | |
935 | sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2])); | |
936 | else | |
937 | sprintf(nfrontp, "%d ", pointer[2]); | |
938 | nfrontp += strlen(nfrontp); | |
939 | if (length < 3) { | |
940 | sprintf(nfrontp, "(partial suboption???)"); | |
941 | nfrontp += strlen(nfrontp); | |
942 | break; | |
943 | } | |
944 | sprintf(nfrontp, "%s|%s", | |
b7c8f459 | 945 | ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? |
1af3d848 | 946 | "CLIENT" : "SERVER", |
b7c8f459 | 947 | ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? |
1af3d848 DB |
948 | "MUTUAL" : "ONE-WAY"); |
949 | nfrontp += strlen(nfrontp); | |
950 | ||
951 | auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); | |
952 | sprintf(nfrontp, "%s", buf); | |
953 | nfrontp += strlen(nfrontp); | |
954 | break; | |
955 | ||
956 | case TELQUAL_SEND: | |
957 | i = 2; | |
958 | sprintf(nfrontp, " SEND "); | |
959 | nfrontp += strlen(nfrontp); | |
960 | while (i < length) { | |
961 | if (AUTHTYPE_NAME_OK(pointer[i])) | |
962 | sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i])); | |
963 | else | |
964 | sprintf(nfrontp, "%d ", pointer[i]); | |
965 | nfrontp += strlen(nfrontp); | |
966 | if (++i >= length) { | |
967 | sprintf(nfrontp, "(partial suboption???)"); | |
968 | nfrontp += strlen(nfrontp); | |
969 | break; | |
970 | } | |
971 | sprintf(nfrontp, "%s|%s ", | |
b7c8f459 | 972 | ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? |
1af3d848 | 973 | "CLIENT" : "SERVER", |
b7c8f459 | 974 | ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? |
1af3d848 DB |
975 | "MUTUAL" : "ONE-WAY"); |
976 | nfrontp += strlen(nfrontp); | |
977 | ++i; | |
978 | } | |
979 | break; | |
980 | ||
b7c8f459 DB |
981 | case TELQUAL_NAME: |
982 | i = 2; | |
983 | sprintf(nfrontp, " NAME \""); | |
984 | nfrontp += strlen(nfrontp); | |
985 | while (i < length) | |
986 | *nfrontp += pointer[i++]; | |
987 | *nfrontp += '"'; | |
988 | break; | |
989 | ||
1af3d848 DB |
990 | default: |
991 | for (i = 2; i < length; i++) { | |
992 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
993 | nfrontp += strlen(nfrontp); | |
994 | } | |
995 | break; | |
996 | } | |
997 | break; | |
998 | #endif | |
999 | ||
1000 | #if defined(ENCRYPT) | |
1001 | case TELOPT_ENCRYPT: | |
1002 | sprintf(nfrontp, "ENCRYPT"); | |
1003 | nfrontp += strlen(nfrontp); | |
1004 | if (length < 2) { | |
1005 | sprintf(nfrontp, " (empty suboption???)"); | |
1006 | nfrontp += strlen(nfrontp); | |
1007 | break; | |
1008 | } | |
1009 | switch (pointer[1]) { | |
1010 | case ENCRYPT_START: | |
1011 | sprintf(nfrontp, " START"); | |
1012 | nfrontp += strlen(nfrontp); | |
1013 | break; | |
1014 | ||
1015 | case ENCRYPT_END: | |
1016 | sprintf(nfrontp, " END"); | |
1017 | nfrontp += strlen(nfrontp); | |
1018 | break; | |
1019 | ||
1020 | case ENCRYPT_REQSTART: | |
1021 | sprintf(nfrontp, " REQUEST-START"); | |
1022 | nfrontp += strlen(nfrontp); | |
1023 | break; | |
1024 | ||
1025 | case ENCRYPT_REQEND: | |
1026 | sprintf(nfrontp, " REQUEST-END"); | |
1027 | nfrontp += strlen(nfrontp); | |
1028 | break; | |
1029 | ||
1030 | case ENCRYPT_IS: | |
1031 | case ENCRYPT_REPLY: | |
1032 | sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ? | |
1033 | "IS" : "REPLY"); | |
1034 | nfrontp += strlen(nfrontp); | |
1035 | if (length < 3) { | |
1036 | sprintf(nfrontp, " (partial suboption???)"); | |
1037 | nfrontp += strlen(nfrontp); | |
1038 | break; | |
1039 | } | |
1040 | if (ENCTYPE_NAME_OK(pointer[2])) | |
1041 | sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2])); | |
1042 | else | |
1043 | sprintf(nfrontp, " %d (unknown)", pointer[2]); | |
1044 | nfrontp += strlen(nfrontp); | |
1045 | ||
1046 | encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); | |
1047 | sprintf(nfrontp, "%s", buf); | |
1048 | nfrontp += strlen(nfrontp); | |
1049 | break; | |
1050 | ||
1051 | case ENCRYPT_SUPPORT: | |
1052 | i = 2; | |
1053 | sprintf(nfrontp, " SUPPORT "); | |
1054 | nfrontp += strlen(nfrontp); | |
1055 | while (i < length) { | |
1056 | if (ENCTYPE_NAME_OK(pointer[i])) | |
1057 | sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i])); | |
1058 | else | |
1059 | sprintf(nfrontp, "%d ", pointer[i]); | |
1060 | nfrontp += strlen(nfrontp); | |
1061 | i++; | |
1062 | } | |
1063 | break; | |
1064 | ||
b7c8f459 DB |
1065 | case ENCRYPT_ENC_KEYID: |
1066 | sprintf(nfrontp, " ENC_KEYID", pointer[1]); | |
1067 | nfrontp += strlen(nfrontp); | |
1068 | goto encommon; | |
1069 | ||
1070 | case ENCRYPT_DEC_KEYID: | |
1071 | sprintf(nfrontp, " DEC_KEYID", pointer[1]); | |
1072 | nfrontp += strlen(nfrontp); | |
1073 | goto encommon; | |
1074 | ||
1af3d848 | 1075 | default: |
b7c8f459 | 1076 | sprintf(nfrontp, " %d (unknown)", pointer[1]); |
1af3d848 | 1077 | nfrontp += strlen(nfrontp); |
b7c8f459 | 1078 | encommon: |
1af3d848 DB |
1079 | for (i = 2; i < length; i++) { |
1080 | sprintf(nfrontp, " %d", pointer[i]); | |
1081 | nfrontp += strlen(nfrontp); | |
1082 | } | |
1083 | break; | |
1084 | } | |
1085 | break; | |
1086 | #endif | |
1087 | ||
4a8a7128 | 1088 | default: |
1af3d848 DB |
1089 | if (TELOPT_OK(pointer[0])) |
1090 | sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0])); | |
1091 | else | |
1092 | sprintf(nfrontp, "%d (unknown)", pointer[i]); | |
4a8a7128 | 1093 | nfrontp += strlen(nfrontp); |
1af3d848 | 1094 | for (i = 1; i < length; i++) { |
4a8a7128 PB |
1095 | sprintf(nfrontp, " %d", pointer[i]); |
1096 | nfrontp += strlen(nfrontp); | |
1097 | } | |
1098 | break; | |
1099 | } | |
1100 | sprintf(nfrontp, "\r\n"); | |
1101 | nfrontp += strlen(nfrontp); | |
1102 | } | |
1103 | ||
1104 | /* | |
1105 | * Dump a data buffer in hex and ascii to the output data stream. | |
1106 | */ | |
1af3d848 | 1107 | void |
4a8a7128 | 1108 | printdata(tag, ptr, cnt) |
1af3d848 DB |
1109 | register char *tag; |
1110 | register char *ptr; | |
1111 | register int cnt; | |
4a8a7128 | 1112 | { |
1af3d848 DB |
1113 | register int i; |
1114 | char xbuf[30]; | |
4a8a7128 PB |
1115 | |
1116 | while (cnt) { | |
1117 | /* flush net output buffer if no room for new data) */ | |
1118 | if ((&netobuf[BUFSIZ] - nfrontp) < 80) { | |
1119 | netflush(); | |
1120 | } | |
1121 | ||
1122 | /* add a line of output */ | |
1123 | sprintf(nfrontp, "%s: ", tag); | |
1124 | nfrontp += strlen(nfrontp); | |
1125 | for (i = 0; i < 20 && cnt; i++) { | |
1126 | sprintf(nfrontp, "%02x", *ptr); | |
1127 | nfrontp += strlen(nfrontp); | |
1128 | if (isprint(*ptr)) { | |
1129 | xbuf[i] = *ptr; | |
1130 | } else { | |
1131 | xbuf[i] = '.'; | |
1132 | } | |
1133 | if (i % 2) { | |
1134 | *nfrontp = ' '; | |
1135 | nfrontp++; | |
1136 | } | |
1137 | cnt--; | |
1138 | ptr++; | |
1139 | } | |
1140 | xbuf[i] = '\0'; | |
1141 | sprintf(nfrontp, " %s\r\n", xbuf ); | |
1142 | nfrontp += strlen(nfrontp); | |
1143 | } | |
1144 | } | |
4a8a7128 | 1145 | #endif /* DIAGNOSTICS */ |