1 /* $NetBSD: print.c,v 1.1.1.3 2014/07/12 11:57:46 spz Exp $ */ 2 /* print.c 3 4 Turn data structures into printable text. */ 5 6 /* 7 * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1995-2003 by Internet Software Consortium 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Internet Systems Consortium, Inc. 24 * 950 Charter Street 25 * Redwood City, CA 94063 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: print.c,v 1.1.1.3 2014/07/12 11:57:46 spz Exp $"); 33 34 #include "dhcpd.h" 35 36 int db_time_format = DEFAULT_TIME_FORMAT; 37 38 char *quotify_string (const char *s, const char *file, int line) 39 { 40 unsigned len = 0; 41 const char *sp; 42 char *buf, *nsp; 43 44 for (sp = s; sp && *sp; sp++) { 45 if (*sp == ' ') 46 len++; 47 else if (!isascii ((int)*sp) || !isprint ((int)*sp)) 48 len += 4; 49 else if (*sp == '"' || *sp == '\\') 50 len += 2; 51 else 52 len++; 53 } 54 55 buf = dmalloc (len + 1, file, line); 56 if (buf) { 57 nsp = buf; 58 for (sp = s; sp && *sp; sp++) { 59 if (*sp == ' ') 60 *nsp++ = ' '; 61 else if (!isascii ((int)*sp) || !isprint ((int)*sp)) { 62 sprintf (nsp, "\\%03o", 63 *(const unsigned char *)sp); 64 nsp += 4; 65 } else if (*sp == '"' || *sp == '\\') { 66 *nsp++ = '\\'; 67 *nsp++ = *sp; 68 } else 69 *nsp++ = *sp; 70 } 71 *nsp++ = 0; 72 } 73 return buf; 74 } 75 76 char *quotify_buf (const unsigned char *s, unsigned len, 77 const char *file, int line) 78 { 79 unsigned nulen = 0; 80 char *buf, *nsp; 81 int i; 82 83 for (i = 0; i < len; i++) { 84 if (s [i] == ' ') 85 nulen++; 86 else if (!isascii (s [i]) || !isprint (s [i])) 87 nulen += 4; 88 else if (s [i] == '"' || s [i] == '\\') 89 nulen += 2; 90 else 91 nulen++; 92 } 93 94 buf = dmalloc (nulen + 1, MDL); 95 if (buf) { 96 nsp = buf; 97 for (i = 0; i < len; i++) { 98 if (s [i] == ' ') 99 *nsp++ = ' '; 100 else if (!isascii (s [i]) || !isprint (s [i])) { 101 sprintf (nsp, "\\%03o", s [i]); 102 nsp += 4; 103 } else if (s [i] == '"' || s [i] == '\\') { 104 *nsp++ = '\\'; 105 *nsp++ = s [i]; 106 } else 107 *nsp++ = s [i]; 108 } 109 *nsp++ = 0; 110 } 111 return buf; 112 } 113 114 char *print_base64 (const unsigned char *buf, unsigned len, 115 const char *file, int line) 116 { 117 char *s, *b; 118 unsigned bl; 119 int i; 120 unsigned val, extra; 121 static char to64 [] = 122 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 123 124 bl = ((len * 4 + 2) / 3) + 1; 125 b = dmalloc (bl + 1, file, line); 126 if (!b) 127 return (char *)0; 128 129 i = 0; 130 s = b; 131 while (i != len) { 132 val = buf [i++]; 133 extra = val & 3; 134 val = val >> 2; 135 *s++ = to64 [val]; 136 if (i == len) { 137 *s++ = to64 [extra << 4]; 138 *s++ = '='; 139 break; 140 } 141 val = (extra << 8) + buf [i++]; 142 extra = val & 15; 143 val = val >> 4; 144 *s++ = to64 [val]; 145 if (i == len) { 146 *s++ = to64 [extra << 2]; 147 *s++ = '='; 148 break; 149 } 150 val = (extra << 8) + buf [i++]; 151 extra = val & 0x3f; 152 val = val >> 6; 153 *s++ = to64 [val]; 154 *s++ = to64 [extra]; 155 } 156 if (!len) 157 *s++ = '='; 158 *s++ = 0; 159 if (s > b + bl + 1) 160 abort (); 161 return b; 162 } 163 164 char *print_hw_addr (htype, hlen, data) 165 const int htype; 166 const int hlen; 167 const unsigned char *data; 168 { 169 static char habuf [49]; 170 char *s; 171 int i; 172 173 if (hlen <= 0) 174 habuf [0] = 0; 175 else { 176 s = habuf; 177 for (i = 0; i < hlen; i++) { 178 sprintf (s, "%02x", data [i]); 179 s += strlen (s); 180 *s++ = ':'; 181 } 182 *--s = 0; 183 } 184 return habuf; 185 } 186 187 void print_lease (lease) 188 struct lease *lease; 189 { 190 struct tm *t; 191 char tbuf [32]; 192 193 log_debug (" Lease %s", 194 piaddr (lease -> ip_addr)); 195 196 t = gmtime (&lease -> starts); 197 strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); 198 log_debug (" start %s", tbuf); 199 200 t = gmtime (&lease -> ends); 201 strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); 202 log_debug (" end %s", tbuf); 203 204 if (lease -> hardware_addr.hlen) 205 log_debug (" hardware addr = %s", 206 print_hw_addr (lease -> hardware_addr.hbuf [0], 207 lease -> hardware_addr.hlen - 1, 208 &lease -> hardware_addr.hbuf [1])); 209 log_debug (" host %s ", 210 lease -> host ? lease -> host -> name : "<none>"); 211 } 212 213 #if defined (DEBUG_PACKET) 214 void dump_packet_option (struct option_cache *oc, 215 struct packet *packet, 216 struct lease *lease, 217 struct client_state *client, 218 struct option_state *in_options, 219 struct option_state *cfg_options, 220 struct binding_scope **scope, 221 struct universe *u, void *foo) 222 { 223 const char *name, *dot; 224 struct data_string ds; 225 memset (&ds, 0, sizeof ds); 226 227 if (u != &dhcp_universe) { 228 name = u -> name; 229 dot = "."; 230 } else { 231 name = ""; 232 dot = ""; 233 } 234 if (evaluate_option_cache (&ds, packet, lease, client, 235 in_options, cfg_options, scope, oc, MDL)) { 236 log_debug (" option %s%s%s %s;\n", 237 name, dot, oc -> option -> name, 238 pretty_print_option (oc -> option, 239 ds.data, ds.len, 1, 1)); 240 data_string_forget (&ds, MDL); 241 } 242 } 243 244 void dump_packet (tp) 245 struct packet *tp; 246 { 247 struct dhcp_packet *tdp = tp -> raw; 248 249 log_debug ("packet length %d", tp -> packet_length); 250 log_debug ("op = %d htype = %d hlen = %d hops = %d", 251 tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops); 252 log_debug ("xid = %x secs = %ld flags = %x", 253 tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags); 254 log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr)); 255 log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr)); 256 log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr)); 257 log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr)); 258 log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", 259 ((unsigned char *)(tdp -> chaddr)) [0], 260 ((unsigned char *)(tdp -> chaddr)) [1], 261 ((unsigned char *)(tdp -> chaddr)) [2], 262 ((unsigned char *)(tdp -> chaddr)) [3], 263 ((unsigned char *)(tdp -> chaddr)) [4], 264 ((unsigned char *)(tdp -> chaddr)) [5]); 265 log_debug ("filename = %s", tdp -> file); 266 log_debug ("server_name = %s", tdp -> sname); 267 if (tp -> options_valid) { 268 int i; 269 270 for (i = 0; i < tp -> options -> universe_count; i++) { 271 if (tp -> options -> universes [i]) { 272 option_space_foreach (tp, (struct lease *)0, 273 (struct client_state *)0, 274 (struct option_state *)0, 275 tp -> options, 276 &global_scope, 277 universes [i], 0, 278 dump_packet_option); 279 } 280 } 281 } 282 log_debug ("%s", ""); 283 } 284 #endif 285 286 void dump_raw (buf, len) 287 const unsigned char *buf; 288 unsigned len; 289 { 290 int i; 291 char lbuf [80]; 292 int lbix = 0; 293 294 /* 295 1 2 3 4 5 6 7 296 01234567890123456789012345678901234567890123456789012345678901234567890123 297 280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................. 298 */ 299 300 memset(lbuf, ' ', 79); 301 lbuf [79] = 0; 302 303 for (i = 0; i < len; i++) { 304 if ((i & 15) == 0) { 305 if (lbix) { 306 lbuf[53]=' '; 307 lbuf[54]=' '; 308 lbuf[55]=' '; 309 lbuf[73]='\0'; 310 log_info ("%s", lbuf); 311 } 312 memset(lbuf, ' ', 79); 313 lbuf [79] = 0; 314 sprintf (lbuf, "%03x:", i); 315 lbix = 4; 316 } else if ((i & 7) == 0) 317 lbuf [lbix++] = ' '; 318 319 if(isprint(buf[i])) { 320 lbuf[56+(i%16)]=buf[i]; 321 } else { 322 lbuf[56+(i%16)]='.'; 323 } 324 325 sprintf (&lbuf [lbix], " %02x", buf [i]); 326 lbix += 3; 327 lbuf[lbix]=' '; 328 329 } 330 lbuf[53]=' '; 331 lbuf[54]=' '; 332 lbuf[55]=' '; 333 lbuf[73]='\0'; 334 log_info ("%s", lbuf); 335 } 336 337 void hash_dump (table) 338 struct hash_table *table; 339 { 340 int i; 341 struct hash_bucket *bp; 342 343 if (!table) 344 return; 345 346 for (i = 0; i < table -> hash_count; i++) { 347 if (!table -> buckets [i]) 348 continue; 349 log_info ("hash bucket %d:", i); 350 for (bp = table -> buckets [i]; bp; bp = bp -> next) { 351 if (bp -> len) 352 dump_raw (bp -> name, bp -> len); 353 else 354 log_info ("%s", (const char *)bp -> name); 355 } 356 } 357 } 358 359 /* 360 * print a string as hex. This only outputs 361 * colon separated hex list no matter what 362 * the input looks like. See print_hex 363 * for a function that prints either cshl 364 * or a string if all bytes are printible 365 * It only uses limit characters from buf 366 * and doesn't do anything if buf == NULL 367 * 368 * len - length of data 369 * data - input data 370 * limit - length of buf to use 371 * buf - output buffer 372 */ 373 void print_hex_only (len, data, limit, buf) 374 unsigned len; 375 const u_int8_t *data; 376 unsigned limit; 377 char *buf; 378 { 379 unsigned i; 380 381 if ((buf == NULL) || (limit < 3)) 382 return; 383 384 for (i = 0; (i < limit / 3) && (i < len); i++) { 385 sprintf(&buf[i*3], "%02x:", data[i]); 386 } 387 buf[(i * 3) - 1] = 0; 388 return; 389 } 390 391 /* 392 * print a string as either text if all the characters 393 * are printable or colon separated hex if they aren't 394 * 395 * len - length of data 396 * data - input data 397 * limit - length of buf to use 398 * buf - output buffer 399 */ 400 void print_hex_or_string (len, data, limit, buf) 401 unsigned len; 402 const u_int8_t *data; 403 unsigned limit; 404 char *buf; 405 { 406 unsigned i; 407 if ((buf == NULL) || (limit < 3)) 408 return; 409 410 for (i = 0; (i < (limit - 3)) && (i < len); i++) { 411 if (!isascii(data[i]) || !isprint(data[i])) { 412 print_hex_only(len, data, limit, buf); 413 return; 414 } 415 } 416 417 buf[0] = '"'; 418 i = len; 419 if (i > (limit - 3)) 420 i = limit - 3; 421 memcpy(&buf[1], data, i); 422 buf[i + 1] = '"'; 423 buf[i + 2] = 0; 424 return; 425 } 426 427 /* 428 * print a string as either hex or text 429 * using static buffers to hold the output 430 * 431 * len - length of data 432 * data - input data 433 * limit - length of buf 434 * buf_num - the output buffer to use 435 */ 436 #define HBLEN 1024 437 char *print_hex(len, data, limit, buf_num) 438 unsigned len; 439 const u_int8_t *data; 440 unsigned limit; 441 unsigned buf_num; 442 { 443 static char hex_buf_1[HBLEN + 1]; 444 static char hex_buf_2[HBLEN + 1]; 445 static char hex_buf_3[HBLEN + 1]; 446 char *hex_buf; 447 448 switch(buf_num) { 449 case 0: 450 hex_buf = hex_buf_1; 451 if (limit >= sizeof(hex_buf_1)) 452 limit = sizeof(hex_buf_1); 453 break; 454 case 1: 455 hex_buf = hex_buf_2; 456 if (limit >= sizeof(hex_buf_2)) 457 limit = sizeof(hex_buf_2); 458 break; 459 case 2: 460 hex_buf = hex_buf_3; 461 if (limit >= sizeof(hex_buf_3)) 462 limit = sizeof(hex_buf_3); 463 break; 464 default: 465 return(NULL); 466 } 467 468 print_hex_or_string(len, data, limit, hex_buf); 469 return(hex_buf); 470 } 471 472 #define DQLEN 80 473 474 char *print_dotted_quads (len, data) 475 unsigned len; 476 const u_int8_t *data; 477 { 478 static char dq_buf [DQLEN + 1]; 479 int i; 480 char *s; 481 482 s = &dq_buf [0]; 483 484 i = 0; 485 486 /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe% 487 * The sprintf can't exceed 18 bytes, and since the loop enforces 488 * 21 bytes of space per iteration at no time can we exit the 489 * loop without at least 3 bytes spare. 490 */ 491 do { 492 sprintf (s, "%u.%u.%u.%u, ", 493 data [i], data [i + 1], data [i + 2], data [i + 3]); 494 s += strlen (s); 495 i += 4; 496 } while ((s - &dq_buf [0] > DQLEN - 21) && 497 i + 3 < len); 498 if (i == len) 499 s [-2] = 0; 500 else 501 strcpy (s, "..."); 502 return dq_buf; 503 } 504 505 char *print_dec_1 (val) 506 unsigned long val; 507 { 508 static char vbuf [32]; 509 sprintf (vbuf, "%lu", val); 510 return vbuf; 511 } 512 513 char *print_dec_2 (val) 514 unsigned long val; 515 { 516 static char vbuf [32]; 517 sprintf (vbuf, "%lu", val); 518 return vbuf; 519 } 520 521 static unsigned print_subexpression (struct expression *, char *, unsigned); 522 523 static unsigned print_subexpression (expr, buf, len) 524 struct expression *expr; 525 char *buf; 526 unsigned len; 527 { 528 unsigned rv, left; 529 const char *s; 530 531 switch (expr -> op) { 532 case expr_none: 533 if (len > 3) { 534 strcpy (buf, "nil"); 535 return 3; 536 } 537 break; 538 539 case expr_match: 540 if (len > 7) { 541 strcpy (buf, "(match)"); 542 return 7; 543 } 544 break; 545 546 case expr_check: 547 rv = 10 + strlen (expr -> data.check -> name); 548 if (len > rv) { 549 sprintf (buf, "(check %s)", 550 expr -> data.check -> name); 551 return rv; 552 } 553 break; 554 555 case expr_equal: 556 if (len > 6) { 557 rv = 4; 558 strcpy (buf, "(eq "); 559 rv += print_subexpression (expr -> data.equal [0], 560 buf + rv, len - rv - 2); 561 buf [rv++] = ' '; 562 rv += print_subexpression (expr -> data.equal [1], 563 buf + rv, len - rv - 1); 564 buf [rv++] = ')'; 565 buf [rv] = 0; 566 return rv; 567 } 568 break; 569 570 case expr_not_equal: 571 if (len > 7) { 572 rv = 5; 573 strcpy (buf, "(neq "); 574 rv += print_subexpression (expr -> data.equal [0], 575 buf + rv, len - rv - 2); 576 buf [rv++] = ' '; 577 rv += print_subexpression (expr -> data.equal [1], 578 buf + rv, len - rv - 1); 579 buf [rv++] = ')'; 580 buf [rv] = 0; 581 return rv; 582 } 583 break; 584 585 case expr_regex_match: 586 if (len > 10) { 587 rv = 4; 588 strcpy(buf, "(regex "); 589 rv += print_subexpression(expr->data.equal[0], 590 buf + rv, len - rv - 2); 591 buf[rv++] = ' '; 592 rv += print_subexpression(expr->data.equal[1], 593 buf + rv, len - rv - 1); 594 buf[rv++] = ')'; 595 buf[rv] = 0; 596 return rv; 597 } 598 break; 599 600 case expr_substring: 601 if (len > 11) { 602 rv = 8; 603 strcpy (buf, "(substr "); 604 rv += print_subexpression (expr -> data.substring.expr, 605 buf + rv, len - rv - 3); 606 buf [rv++] = ' '; 607 rv += print_subexpression 608 (expr -> data.substring.offset, 609 buf + rv, len - rv - 2); 610 buf [rv++] = ' '; 611 rv += print_subexpression (expr -> data.substring.len, 612 buf + rv, len - rv - 1); 613 buf [rv++] = ')'; 614 buf [rv] = 0; 615 return rv; 616 } 617 break; 618 619 case expr_suffix: 620 if (len > 10) { 621 rv = 8; 622 strcpy (buf, "(suffix "); 623 rv += print_subexpression (expr -> data.suffix.expr, 624 buf + rv, len - rv - 2); 625 if (len > rv) 626 buf [rv++] = ' '; 627 rv += print_subexpression (expr -> data.suffix.len, 628 buf + rv, len - rv - 1); 629 if (len > rv) 630 buf [rv++] = ')'; 631 buf [rv] = 0; 632 return rv; 633 } 634 break; 635 636 case expr_lcase: 637 if (len > 9) { 638 rv = 7; 639 strcpy(buf, "(lcase "); 640 rv += print_subexpression(expr->data.lcase, 641 buf + rv, len - rv - 1); 642 buf[rv++] = ')'; 643 buf[rv] = 0; 644 return rv; 645 } 646 break; 647 648 case expr_ucase: 649 if (len > 9) { 650 rv = 7; 651 strcpy(buf, "(ucase "); 652 rv += print_subexpression(expr->data.ucase, 653 buf + rv, len - rv - 1); 654 buf[rv++] = ')'; 655 buf[rv] = 0; 656 return rv; 657 } 658 break; 659 660 case expr_concat: 661 if (len > 10) { 662 rv = 8; 663 strcpy (buf, "(concat "); 664 rv += print_subexpression (expr -> data.concat [0], 665 buf + rv, len - rv - 2); 666 buf [rv++] = ' '; 667 rv += print_subexpression (expr -> data.concat [1], 668 buf + rv, len - rv - 1); 669 buf [rv++] = ')'; 670 buf [rv] = 0; 671 return rv; 672 } 673 break; 674 675 case expr_pick_first_value: 676 if (len > 8) { 677 rv = 6; 678 strcpy (buf, "(pick1st "); 679 rv += print_subexpression 680 (expr -> data.pick_first_value.car, 681 buf + rv, len - rv - 2); 682 buf [rv++] = ' '; 683 rv += print_subexpression 684 (expr -> data.pick_first_value.cdr, 685 buf + rv, len - rv - 1); 686 buf [rv++] = ')'; 687 buf [rv] = 0; 688 return rv; 689 } 690 break; 691 692 case expr_host_lookup: 693 rv = 15 + strlen (expr -> data.host_lookup -> hostname); 694 if (len > rv) { 695 sprintf (buf, "(dns-lookup %s)", 696 expr -> data.host_lookup -> hostname); 697 return rv; 698 } 699 break; 700 701 case expr_and: 702 s = "and"; 703 binop: 704 rv = strlen (s); 705 if (len > rv + 4) { 706 buf [0] = '('; 707 strcpy (&buf [1], s); 708 rv += 1; 709 buf [rv++] = ' '; 710 rv += print_subexpression (expr -> data.and [0], 711 buf + rv, len - rv - 2); 712 buf [rv++] = ' '; 713 rv += print_subexpression (expr -> data.and [1], 714 buf + rv, len - rv - 1); 715 buf [rv++] = ')'; 716 buf [rv] = 0; 717 return rv; 718 } 719 break; 720 721 case expr_or: 722 s = "or"; 723 goto binop; 724 725 case expr_add: 726 s = "+"; 727 goto binop; 728 729 case expr_subtract: 730 s = "-"; 731 goto binop; 732 733 case expr_multiply: 734 s = "*"; 735 goto binop; 736 737 case expr_divide: 738 s = "/"; 739 goto binop; 740 741 case expr_remainder: 742 s = "%"; 743 goto binop; 744 745 case expr_binary_and: 746 s = "&"; 747 goto binop; 748 749 case expr_binary_or: 750 s = "|"; 751 goto binop; 752 753 case expr_binary_xor: 754 s = "^"; 755 goto binop; 756 757 case expr_not: 758 if (len > 6) { 759 rv = 5; 760 strcpy (buf, "(not "); 761 rv += print_subexpression (expr -> data.not, 762 buf + rv, len - rv - 1); 763 buf [rv++] = ')'; 764 buf [rv] = 0; 765 return rv; 766 } 767 break; 768 769 case expr_config_option: 770 s = "cfg-option"; 771 goto dooption; 772 773 case expr_option: 774 s = "option"; 775 dooption: 776 rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) + 777 strlen (expr -> data.option -> universe -> name)); 778 if (len > rv) { 779 sprintf (buf, "(option %s.%s)", 780 expr -> data.option -> universe -> name, 781 expr -> data.option -> name); 782 return rv; 783 } 784 break; 785 786 case expr_hardware: 787 if (len > 10) { 788 strcpy (buf, "(hardware)"); 789 return 10; 790 } 791 break; 792 793 case expr_packet: 794 if (len > 10) { 795 rv = 8; 796 strcpy (buf, "(substr "); 797 rv += print_subexpression (expr -> data.packet.offset, 798 buf + rv, len - rv - 2); 799 buf [rv++] = ' '; 800 rv += print_subexpression (expr -> data.packet.len, 801 buf + rv, len - rv - 1); 802 buf [rv++] = ')'; 803 buf [rv] = 0; 804 return rv; 805 } 806 break; 807 808 case expr_const_data: 809 s = print_hex_1 (expr -> data.const_data.len, 810 expr -> data.const_data.data, len); 811 rv = strlen (s); 812 if (rv >= len) 813 rv = len - 1; 814 strncpy (buf, s, rv); 815 buf [rv] = 0; 816 return rv; 817 818 case expr_encapsulate: 819 rv = 13; 820 strcpy (buf, "(encapsulate "); 821 rv += expr -> data.encapsulate.len; 822 if (rv + 2 > len) 823 rv = len - 2; 824 strncpy (buf, 825 (const char *)expr -> data.encapsulate.data, rv - 13); 826 buf [rv++] = ')'; 827 buf [rv++] = 0; 828 break; 829 830 case expr_extract_int8: 831 if (len > 7) { 832 rv = 6; 833 strcpy (buf, "(int8 "); 834 rv += print_subexpression (expr -> data.extract_int, 835 buf + rv, len - rv - 1); 836 buf [rv++] = ')'; 837 buf [rv] = 0; 838 return rv; 839 } 840 break; 841 842 case expr_extract_int16: 843 if (len > 8) { 844 rv = 7; 845 strcpy (buf, "(int16 "); 846 rv += print_subexpression (expr -> data.extract_int, 847 buf + rv, len - rv - 1); 848 buf [rv++] = ')'; 849 buf [rv] = 0; 850 return rv; 851 } 852 break; 853 854 case expr_extract_int32: 855 if (len > 8) { 856 rv = 7; 857 strcpy (buf, "(int32 "); 858 rv += print_subexpression (expr -> data.extract_int, 859 buf + rv, len - rv - 1); 860 buf [rv++] = ')'; 861 buf [rv] = 0; 862 return rv; 863 } 864 break; 865 866 case expr_encode_int8: 867 if (len > 7) { 868 rv = 6; 869 strcpy (buf, "(to-int8 "); 870 rv += print_subexpression (expr -> data.encode_int, 871 buf + rv, len - rv - 1); 872 buf [rv++] = ')'; 873 buf [rv] = 0; 874 return rv; 875 } 876 break; 877 878 case expr_encode_int16: 879 if (len > 8) { 880 rv = 7; 881 strcpy (buf, "(to-int16 "); 882 rv += print_subexpression (expr -> data.encode_int, 883 buf + rv, len - rv - 1); 884 buf [rv++] = ')'; 885 buf [rv] = 0; 886 return rv; 887 } 888 break; 889 890 case expr_encode_int32: 891 if (len > 8) { 892 rv = 7; 893 strcpy (buf, "(to-int32 "); 894 rv += print_subexpression (expr -> data.encode_int, 895 buf + rv, len - rv - 1); 896 buf [rv++] = ')'; 897 buf [rv] = 0; 898 return rv; 899 } 900 break; 901 902 case expr_const_int: 903 s = print_dec_1 (expr -> data.const_int); 904 rv = strlen (s); 905 if (len > rv) { 906 strcpy (buf, s); 907 return rv; 908 } 909 break; 910 911 case expr_exists: 912 rv = 10 + (strlen (expr -> data.option -> name) + 913 strlen (expr -> data.option -> universe -> name)); 914 if (len > rv) { 915 sprintf (buf, "(exists %s.%s)", 916 expr -> data.option -> universe -> name, 917 expr -> data.option -> name); 918 return rv; 919 } 920 break; 921 922 case expr_variable_exists: 923 rv = 10 + strlen (expr -> data.variable); 924 if (len > rv) { 925 sprintf (buf, "(defined %s)", expr -> data.variable); 926 return rv; 927 } 928 break; 929 930 case expr_variable_reference: 931 rv = strlen (expr -> data.variable); 932 if (len > rv) { 933 sprintf (buf, "%s", expr -> data.variable); 934 return rv; 935 } 936 break; 937 938 case expr_known: 939 s = "known"; 940 astring: 941 rv = strlen (s); 942 if (len > rv) { 943 strcpy (buf, s); 944 return rv; 945 } 946 break; 947 948 case expr_leased_address: 949 s = "leased-address"; 950 goto astring; 951 952 case expr_client_state: 953 s = "client-state"; 954 goto astring; 955 956 case expr_host_decl_name: 957 s = "host-decl-name"; 958 goto astring; 959 960 case expr_lease_time: 961 s = "lease-time"; 962 goto astring; 963 964 case expr_static: 965 s = "static"; 966 goto astring; 967 968 case expr_filename: 969 s = "filename"; 970 goto astring; 971 972 case expr_sname: 973 s = "server-name"; 974 goto astring; 975 976 case expr_reverse: 977 if (len > 11) { 978 rv = 13; 979 strcpy (buf, "(reverse "); 980 rv += print_subexpression (expr -> data.reverse.width, 981 buf + rv, len - rv - 2); 982 buf [rv++] = ' '; 983 rv += print_subexpression (expr -> data.reverse.buffer, 984 buf + rv, len - rv - 1); 985 buf [rv++] = ')'; 986 buf [rv] = 0; 987 return rv; 988 } 989 break; 990 991 case expr_binary_to_ascii: 992 if (len > 5) { 993 rv = 9; 994 strcpy (buf, "(b2a "); 995 rv += print_subexpression (expr -> data.b2a.base, 996 buf + rv, len - rv - 4); 997 buf [rv++] = ' '; 998 rv += print_subexpression (expr -> data.b2a.width, 999 buf + rv, len - rv - 3); 1000 buf [rv++] = ' '; 1001 rv += print_subexpression (expr -> data.b2a.separator, 1002 buf + rv, len - rv - 2); 1003 buf [rv++] = ' '; 1004 rv += print_subexpression (expr -> data.b2a.buffer, 1005 buf + rv, len - rv - 1); 1006 buf [rv++] = ')'; 1007 buf [rv] = 0; 1008 return rv; 1009 } 1010 break; 1011 1012 case expr_dns_transaction: 1013 rv = 10; 1014 if (len < rv + 2) { 1015 buf [0] = '('; 1016 strcpy (&buf [1], "ns-update "); 1017 while (len < rv + 2) { 1018 rv += print_subexpression 1019 (expr -> data.dns_transaction.car, 1020 buf + rv, len - rv - 2); 1021 buf [rv++] = ' '; 1022 expr = expr -> data.dns_transaction.cdr; 1023 } 1024 buf [rv - 1] = ')'; 1025 buf [rv] = 0; 1026 return rv; 1027 } 1028 return 0; 1029 1030 case expr_ns_delete: 1031 s = "delete"; 1032 left = 4; 1033 goto dodnsupd; 1034 case expr_ns_exists: 1035 s = "exists"; 1036 left = 4; 1037 goto dodnsupd; 1038 case expr_ns_not_exists: 1039 s = "not_exists"; 1040 left = 4; 1041 goto dodnsupd; 1042 case expr_ns_add: 1043 s = "update"; 1044 left = 5; 1045 dodnsupd: 1046 rv = strlen (s); 1047 if (len > strlen (s) + 1) { 1048 buf [0] = '('; 1049 strcpy (buf + 1, s); 1050 rv++; 1051 buf [rv++] = ' '; 1052 s = print_dec_1 (expr -> data.ns_add.rrclass); 1053 if (len > rv + strlen (s) + left) { 1054 strcpy (&buf [rv], s); 1055 rv += strlen (&buf [rv]); 1056 } 1057 buf [rv++] = ' '; 1058 left--; 1059 s = print_dec_1 (expr -> data.ns_add.rrtype); 1060 if (len > rv + strlen (s) + left) { 1061 strcpy (&buf [rv], s); 1062 rv += strlen (&buf [rv]); 1063 } 1064 buf [rv++] = ' '; 1065 left--; 1066 rv += print_subexpression 1067 (expr -> data.ns_add.rrname, 1068 buf + rv, len - rv - left); 1069 buf [rv++] = ' '; 1070 left--; 1071 rv += print_subexpression 1072 (expr -> data.ns_add.rrdata, 1073 buf + rv, len - rv - left); 1074 buf [rv++] = ' '; 1075 left--; 1076 rv += print_subexpression 1077 (expr -> data.ns_add.ttl, 1078 buf + rv, len - rv - left); 1079 buf [rv++] = ')'; 1080 buf [rv] = 0; 1081 return rv; 1082 } 1083 break; 1084 1085 case expr_null: 1086 if (len > 6) { 1087 strcpy (buf, "(null)"); 1088 return 6; 1089 } 1090 break; 1091 case expr_funcall: 1092 rv = 12 + strlen (expr -> data.funcall.name); 1093 if (len > rv + 1) { 1094 strcpy (buf, "(funcall "); 1095 strcpy (buf + 9, expr -> data.funcall.name); 1096 buf [rv++] = ' '; 1097 rv += print_subexpression 1098 (expr -> data.funcall.arglist, buf + rv, 1099 len - rv - 1); 1100 buf [rv++] = ')'; 1101 buf [rv] = 0; 1102 return rv; 1103 } 1104 break; 1105 1106 case expr_arg: 1107 rv = print_subexpression (expr -> data.arg.val, buf, len); 1108 if (expr -> data.arg.next && rv + 2 < len) { 1109 buf [rv++] = ' '; 1110 rv += print_subexpression (expr -> data.arg.next, 1111 buf, len); 1112 if (rv + 1 < len) 1113 buf [rv++] = 0; 1114 return rv; 1115 } 1116 break; 1117 1118 case expr_function: 1119 rv = 9; 1120 if (len > rv + 1) { 1121 struct string_list *foo; 1122 strcpy (buf, "(function"); 1123 for (foo = expr -> data.func -> args; 1124 foo; foo = foo -> next) { 1125 if (len > rv + 2 + strlen (foo -> string)) { 1126 buf [rv - 1] = ' '; 1127 strcpy (&buf [rv], foo -> string); 1128 rv += strlen (foo -> string); 1129 } 1130 } 1131 buf [rv++] = ')'; 1132 buf [rv] = 0; 1133 return rv; 1134 } 1135 break; 1136 1137 case expr_gethostname: 1138 if (len > 13) { 1139 strcpy(buf, "(gethostname)"); 1140 return 13; 1141 } 1142 break; 1143 1144 default: 1145 log_fatal("Impossible case at %s:%d (undefined expression " 1146 "%d).", MDL, expr->op); 1147 break; 1148 } 1149 return 0; 1150 } 1151 1152 void print_expression (name, expr) 1153 const char *name; 1154 struct expression *expr; 1155 { 1156 char buf [1024]; 1157 1158 print_subexpression (expr, buf, sizeof buf); 1159 log_info ("%s: %s", name, buf); 1160 } 1161 1162 int token_print_indent_concat (FILE *file, int col, int indent, 1163 const char *prefix, 1164 const char *suffix, ...) 1165 { 1166 va_list list; 1167 unsigned len; 1168 char *s, *t, *u; 1169 1170 va_start (list, suffix); 1171 s = va_arg (list, char *); 1172 len = 0; 1173 while (s) { 1174 len += strlen (s); 1175 s = va_arg (list, char *); 1176 } 1177 va_end (list); 1178 1179 t = dmalloc (len + 1, MDL); 1180 if (!t) 1181 log_fatal ("token_print_indent: no memory for copy buffer"); 1182 1183 va_start (list, suffix); 1184 s = va_arg (list, char *); 1185 u = t; 1186 while (s) { 1187 len = strlen (s); 1188 strcpy (u, s); 1189 u += len; 1190 s = va_arg (list, char *); 1191 } 1192 va_end (list); 1193 1194 col = token_print_indent (file, col, indent, 1195 prefix, suffix, t); 1196 dfree (t, MDL); 1197 return col; 1198 } 1199 1200 int token_indent_data_string (FILE *file, int col, int indent, 1201 const char *prefix, const char *suffix, 1202 struct data_string *data) 1203 { 1204 int i; 1205 char *buf; 1206 char obuf [3]; 1207 1208 /* See if this is just ASCII. */ 1209 for (i = 0; i < data -> len; i++) 1210 if (!isascii (data -> data [i]) || 1211 !isprint (data -> data [i])) 1212 break; 1213 1214 /* If we have a purely ASCII string, output it as text. */ 1215 if (i == data -> len) { 1216 buf = dmalloc (data -> len + 3, MDL); 1217 if (buf) { 1218 buf [0] = '"'; 1219 memcpy (buf + 1, data -> data, data -> len); 1220 buf [data -> len + 1] = '"'; 1221 buf [data -> len + 2] = 0; 1222 i = token_print_indent (file, col, indent, 1223 prefix, suffix, buf); 1224 dfree (buf, MDL); 1225 return i; 1226 } 1227 } 1228 1229 for (i = 0; i < data -> len; i++) { 1230 sprintf (obuf, "%2.2x", data -> data [i]); 1231 col = token_print_indent (file, col, indent, 1232 i == 0 ? prefix : "", 1233 (i + 1 == data -> len 1234 ? suffix 1235 : ""), obuf); 1236 if (i + 1 != data -> len) 1237 col = token_print_indent (file, col, indent, 1238 prefix, suffix, ":"); 1239 } 1240 return col; 1241 } 1242 1243 int token_print_indent (FILE *file, int col, int indent, 1244 const char *prefix, 1245 const char *suffix, const char *buf) 1246 { 1247 int len = 0; 1248 if (prefix != NULL) 1249 len += strlen (prefix); 1250 if (buf != NULL) 1251 len += strlen (buf); 1252 1253 if (col + len > 79) { 1254 if (indent + len < 79) { 1255 indent_spaces (file, indent); 1256 col = indent; 1257 } else { 1258 indent_spaces (file, col); 1259 col = len > 79 ? 0 : 79 - len - 1; 1260 } 1261 } else if (prefix && *prefix) { 1262 fputs (prefix, file); 1263 col += strlen (prefix); 1264 } 1265 if ((buf != NULL) && (*buf != 0)) { 1266 fputs (buf, file); 1267 col += strlen(buf); 1268 } 1269 if (suffix && *suffix) { 1270 if (col + strlen (suffix) > 79) { 1271 indent_spaces (file, indent); 1272 col = indent; 1273 } else { 1274 fputs (suffix, file); 1275 col += strlen (suffix); 1276 } 1277 } 1278 return col; 1279 } 1280 1281 void indent_spaces (FILE *file, int indent) 1282 { 1283 int i; 1284 fputc ('\n', file); 1285 for (i = 0; i < indent; i++) 1286 fputc (' ', file); 1287 } 1288 1289 #if defined (NSUPDATE) 1290 #if defined (DEBUG_DNS_UPDATES) 1291 /* 1292 * direction outbound (messages to the dns server) 1293 * inbound (messages from the dns server) 1294 * ddns_cb is the control block associated with the message 1295 * result is the result from the dns code. For outbound calls 1296 * it is from the call to pass the message to the dns library. 1297 * For inbound calls it is from the event returned by the library. 1298 * 1299 * For outbound messages we print whatever we think is interesting 1300 * from the control block. 1301 * For inbound messages we only print the transaction id pointer 1302 * and the result and expect that the user will match them up as 1303 * necessary. Note well: the transaction information is opaque to 1304 * us so we simply print the pointer to it. This should be sufficient 1305 * to match requests and replys in a short sequence but is awkward 1306 * when trying to use it for longer sequences. 1307 */ 1308 void 1309 print_dns_status (int direction, 1310 struct dhcp_ddns_cb *ddns_cb, 1311 isc_result_t result) 1312 { 1313 char obuf[1024]; 1314 char *s = obuf, *end = &obuf[sizeof(obuf)-2]; 1315 char *en; 1316 const char *result_str; 1317 char ddns_address[ 1318 sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 1319 1320 if (direction == DDNS_PRINT_INBOUND) { 1321 log_info("DDNS reply: id ptr %p, result: %s", 1322 ddns_cb->transaction, isc_result_totext(result)); 1323 return; 1324 } 1325 1326 /* 1327 * To avoid having to figure out if any of the strings 1328 * aren't NULL terminated, just 0 the whole string 1329 */ 1330 memset(obuf, 0, 1024); 1331 1332 en = "DDNS request: id ptr "; 1333 if (s + strlen(en) + 16 < end) { 1334 sprintf(s, "%s%p", en, ddns_cb->transaction); 1335 s += strlen(s); 1336 } else { 1337 goto bailout; 1338 } 1339 1340 switch (ddns_cb->state) { 1341 case DDNS_STATE_ADD_FW_NXDOMAIN: 1342 en = " add forward "; 1343 break; 1344 case DDNS_STATE_ADD_FW_YXDHCID: 1345 en = " modify forward "; 1346 break; 1347 1348 case DDNS_STATE_ADD_PTR: 1349 en = " add reverse "; 1350 break; 1351 1352 case DDNS_STATE_REM_FW_YXDHCID: 1353 en = " remove forward "; 1354 break; 1355 1356 case DDNS_STATE_REM_FW_NXRR: 1357 en = " remove rrset "; 1358 break; 1359 1360 case DDNS_STATE_REM_PTR: 1361 en = " remove reverse "; 1362 break; 1363 1364 case DDNS_STATE_CLEANUP: 1365 en = " cleanup "; 1366 break; 1367 1368 default: 1369 en = " unknown state "; 1370 break; 1371 } 1372 1373 switch (ddns_cb->state) { 1374 case DDNS_STATE_ADD_FW_NXDOMAIN: 1375 case DDNS_STATE_ADD_FW_YXDHCID: 1376 case DDNS_STATE_REM_FW_YXDHCID: 1377 case DDNS_STATE_REM_FW_NXRR: 1378 strcpy(ddns_address, piaddr(ddns_cb->address)); 1379 if (s + strlen(en) + strlen(ddns_address) + 1380 ddns_cb->fwd_name.len + 5 < end) { 1381 sprintf(s, "%s%s for %.*s", en, ddns_address, 1382 ddns_cb->fwd_name.len, 1383 ddns_cb->fwd_name.data); 1384 s += strlen(s); 1385 } else { 1386 goto bailout; 1387 } 1388 break; 1389 1390 case DDNS_STATE_ADD_PTR: 1391 case DDNS_STATE_REM_PTR: 1392 if (s + strlen(en) + ddns_cb->fwd_name.len + 1393 ddns_cb->rev_name.len + 5 < end) { 1394 sprintf(s, "%s%.*s for %.*s", en, 1395 ddns_cb->fwd_name.len, 1396 ddns_cb->fwd_name.data, 1397 ddns_cb->rev_name.len, 1398 ddns_cb->rev_name.data); 1399 s += strlen(s); 1400 } else { 1401 goto bailout; 1402 } 1403 break; 1404 1405 case DDNS_STATE_CLEANUP: 1406 default: 1407 if (s + strlen(en) < end) { 1408 sprintf(s, "%s", en); 1409 s += strlen(s); 1410 } else { 1411 goto bailout; 1412 } 1413 break; 1414 } 1415 1416 en = " zone: "; 1417 if (s + strlen(en) + strlen((char *)ddns_cb->zone_name) < end) { 1418 sprintf(s, "%s%s", en, ddns_cb->zone_name); 1419 s += strlen(s); 1420 } else { 1421 goto bailout; 1422 } 1423 1424 en = " dhcid: "; 1425 if (ddns_cb->dhcid.len > 0) { 1426 if (s + strlen(en) + ddns_cb->dhcid.len-1 < end) { 1427 strcpy(s, en); 1428 s += strlen(s); 1429 strncpy(s, (char *)ddns_cb->dhcid.data+1, 1430 ddns_cb->dhcid.len-1); 1431 s += strlen(s); 1432 } else { 1433 goto bailout; 1434 } 1435 } else { 1436 en = " dhcid: <empty>"; 1437 if (s + strlen(en) < end) { 1438 strcpy(s, en); 1439 s += strlen(s); 1440 } else { 1441 goto bailout; 1442 } 1443 } 1444 1445 en = " ttl: "; 1446 if (s + strlen(en) + 10 < end) { 1447 sprintf(s, "%s%ld", en, ddns_cb->ttl); 1448 s += strlen(s); 1449 } else { 1450 goto bailout; 1451 } 1452 1453 en = " result: "; 1454 result_str = isc_result_totext(result); 1455 if (s + strlen(en) + strlen(result_str) < end) { 1456 sprintf(s, "%s%s", en, result_str); 1457 s += strlen(s); 1458 } else { 1459 goto bailout; 1460 } 1461 1462 bailout: 1463 /* 1464 * We either finished building the string or ran out 1465 * of space, print whatever we have in case it is useful 1466 */ 1467 log_info("%s", obuf); 1468 1469 return; 1470 } 1471 #endif 1472 #endif /* NSUPDATE */ 1473 1474 /* Format the given time as "A; # B", where A is the format 1475 * used by the parser, and B is the local time, for humans. 1476 */ 1477 const char * 1478 print_time(TIME t) 1479 { 1480 static char buf[sizeof("epoch 9223372036854775807; " 1481 "# Wed Jun 30 21:49:08 2147483647")]; 1482 static char buf1[sizeof("# Wed Jun 30 21:49:08 2147483647")]; 1483 time_t since_epoch; 1484 /* The string: "6 2147483647/12/31 23:59:60;" 1485 * is smaller than the other, used to declare the buffer size, so 1486 * we can use one buffer for both. 1487 */ 1488 1489 if (t == MAX_TIME) 1490 return "never;"; 1491 1492 if (t < 0) 1493 return NULL; 1494 1495 /* For those lucky enough to have a 128-bit time_t, ensure that 1496 * whatever (corrupt) value we're given doesn't exceed the static 1497 * buffer. 1498 */ 1499 #if (MAX_TIME > 0x7fffffffffffffff) 1500 if (t > 0x7fffffffffffffff) 1501 return NULL; 1502 #endif 1503 1504 if (db_time_format == LOCAL_TIME_FORMAT) { 1505 since_epoch = mktime(localtime(&t)); 1506 if ((strftime(buf1, sizeof(buf1), 1507 "# %a %b %d %H:%M:%S %Y", 1508 localtime(&t)) == 0) || 1509 (snprintf(buf, sizeof(buf), "epoch %lu; %s", 1510 (unsigned long)since_epoch, buf1) >= sizeof(buf))) 1511 return NULL; 1512 1513 } else { 1514 /* No bounds check for the year is necessary - in this case, 1515 * strftime() will run out of space and assert an error. 1516 */ 1517 if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;", 1518 gmtime(&t)) == 0) 1519 return NULL; 1520 } 1521 1522 return buf; 1523 } 1524