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