ns_print.c revision d7ce700605e1af0e455e31ec11f19ff21d26b525
1/* 2 * Copyright (c) 1996, 1998 by Internet Software Consortium. 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 15 * SOFTWARE. 16 */ 17 18/* 19 * Portions copyright (c) 1999, 2000 20 * Intel Corporation. 21 * All rights reserved. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 27 * 1. Redistributions of source code must retain the above copyright 28 * notice, this list of conditions and the following disclaimer. 29 * 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 34 * 3. All advertising materials mentioning features or use of this software 35 * must display the following acknowledgement: 36 * 37 * This product includes software developed by Intel Corporation and 38 * its contributors. 39 * 40 * 4. Neither the name of Intel Corporation or its contributors may be 41 * used to endorse or promote products derived from this software 42 * without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' 45 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE 48 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 54 * THE POSSIBILITY OF SUCH DAMAGE. 55 * 56 */ 57 58#ifndef lint 59static char rcsid[] = "$Id: ns_print.c,v 1.1.1.1 2003/11/19 01:51:34 kyu3 Exp $"; 60#endif 61 62/* Import. */ 63 64#include <sys/types.h> 65#include <sys/socket.h> 66 67#include <netinet/in.h> 68#include <arpa/nameser.h> 69#include <arpa/inet.h> 70 71#include <assert.h> 72#include <errno.h> 73#include <resolv.h> 74#include <string.h> 75#include <ctype.h> 76 77#define SPRINTF(x) (sprintf x) 78 79/* Forward. */ 80 81static size_t prune_origin(const char *name, const char *origin); 82static int charstr(const u_char *rdata, const u_char *edata, 83 char **buf, size_t *buflen); 84static int addname(const u_char *msg, size_t msglen, 85 const u_char **p, const char *origin, 86 char **buf, size_t *buflen); 87static void addlen(size_t len, char **buf, size_t *buflen); 88static int addstr(const char *src, size_t len, 89 char **buf, size_t *buflen); 90static int addtab(size_t len, size_t target, int spaced, 91 char **buf, size_t *buflen); 92 93/* Macros. */ 94 95#define T(x) \ 96 do { \ 97 if ((ssize_t)(x) < 0) \ 98 return (-1); \ 99 } while (0) 100 101/* Public. */ 102 103/* 104 * int 105 * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen) 106 * Convert an RR to presentation format. 107 * return: 108 * Number of characters written to buf, or -1 (check errno). 109 */ 110int 111ns_sprintrr(const ns_msg *handle, const ns_rr *rr, 112 const char *name_ctx, const char *origin, 113 char *buf, size_t buflen) 114{ 115 int n; 116 117 n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), 118 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), 119 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), 120 name_ctx, origin, buf, buflen); 121 return (n); 122} 123 124/* 125 * int 126 * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen, 127 * name_ctx, origin, buf, buflen) 128 * Convert the fields of an RR into presentation format. 129 * return: 130 * Number of characters written to buf, or -1 (check errno). 131 */ 132int 133ns_sprintrrf(const u_char *msg, size_t msglen, 134 const char *name, ns_class class, ns_type type, 135 u_long ttl, const u_char *rdata, size_t rdlen, 136 const char *name_ctx, const char *origin, 137 char *buf, size_t buflen) 138{ 139 const char *obuf = buf; 140 const u_char *edata = rdata + rdlen; 141 int spaced = 0; 142 143 const char *comment; 144 char tmp[100]; 145 int x; 146 size_t len; 147 148 static char base64_key[NS_MD5RSA_MAX_BASE64]; 149 static char t[255*3]; 150 151 /* 152 * Owner. 153 */ 154 if (name_ctx != NULL && strcasecmp(name_ctx, name) == 0) { 155 T(addstr("\t\t\t", 3, &buf, &buflen)); 156 } else { 157 len = prune_origin(name, origin); 158 if (len == 0) { 159 T(addstr("@\t\t\t", 4, &buf, &buflen)); 160 } else { 161 T(addstr(name, len, &buf, &buflen)); 162 /* Origin not used and no trailing dot? */ 163 if ((!origin || !origin[0] || name[len] == '\0') && 164 name[len - 1] != '.') { 165 T(addstr(".", 1, &buf, &buflen)); 166 len++; 167 } 168 T(spaced = addtab(len, 24, spaced, &buf, &buflen)); 169 } 170 } 171 172 /* 173 * TTL, Class, Type. 174 */ 175 T(x = ns_format_ttl(ttl, buf, buflen)); 176 addlen(x, &buf, &buflen); 177 len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); 178 T(addstr(tmp, len, &buf, &buflen)); 179 T(spaced = addtab(x + len, 16, spaced, &buf, &buflen)); 180 181 /* 182 * RData. 183 */ 184 switch (type) { 185 case ns_t_a: 186 if (rdlen != NS_INADDRSZ) 187 goto formerr; 188 (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen); 189 addlen(strlen(buf), &buf, &buflen); 190 break; 191 192 case ns_t_cname: 193 case ns_t_mb: 194 case ns_t_mg: 195 case ns_t_mr: 196 case ns_t_ns: 197 case ns_t_ptr: 198 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 199 break; 200 201 case ns_t_hinfo: 202 case ns_t_isdn: 203 /* First word. */ 204 T(len = charstr(rdata, edata, &buf, &buflen)); 205 if (len == 0) 206 goto formerr; 207 rdata += len; 208 T(addstr(" ", 1, &buf, &buflen)); 209 210 /* Second word. */ 211 T(len = charstr(rdata, edata, &buf, &buflen)); 212 if (len == 0) 213 goto formerr; 214 rdata += len; 215 break; 216 217 case ns_t_soa: { 218 u_long t; 219 220 /* Server name. */ 221 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 222 T(addstr(" ", 1, &buf, &buflen)); 223 224 /* Administrator name. */ 225 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 226 T(addstr(" (\n", 3, &buf, &buflen)); 227 spaced = 0; 228 229 if ((edata - rdata) != 5*NS_INT32SZ) 230 goto formerr; 231 232 /* Serial number. */ 233 t = ns_get32(rdata); rdata += NS_INT32SZ; 234 T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); 235 len = SPRINTF((tmp, "%lu", t)); 236 T(addstr(tmp, len, &buf, &buflen)); 237 T(spaced = addtab(len, 16, spaced, &buf, &buflen)); 238 T(addstr("; serial\n", 9, &buf, &buflen)); 239 spaced = 0; 240 241 /* Refresh interval. */ 242 t = ns_get32(rdata); rdata += NS_INT32SZ; 243 T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); 244 T(len = ns_format_ttl(t, buf, buflen)); 245 addlen(len, &buf, &buflen); 246 T(spaced = addtab(len, 16, spaced, &buf, &buflen)); 247 T(addstr("; refresh\n", 10, &buf, &buflen)); 248 spaced = 0; 249 250 /* Retry interval. */ 251 t = ns_get32(rdata); rdata += NS_INT32SZ; 252 T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); 253 T(len = ns_format_ttl(t, buf, buflen)); 254 addlen(len, &buf, &buflen); 255 T(spaced = addtab(len, 16, spaced, &buf, &buflen)); 256 T(addstr("; retry\n", 8, &buf, &buflen)); 257 spaced = 0; 258 259 /* Expiry. */ 260 t = ns_get32(rdata); rdata += NS_INT32SZ; 261 T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); 262 T(len = ns_format_ttl(t, buf, buflen)); 263 addlen(len, &buf, &buflen); 264 T(spaced = addtab(len, 16, spaced, &buf, &buflen)); 265 T(addstr("; expiry\n", 9, &buf, &buflen)); 266 spaced = 0; 267 268 /* Minimum TTL. */ 269 t = ns_get32(rdata); rdata += NS_INT32SZ; 270 T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); 271 T(len = ns_format_ttl(t, buf, buflen)); 272 addlen(len, &buf, &buflen); 273 T(addstr(" )", 2, &buf, &buflen)); 274 T(spaced = addtab(len, 16, spaced, &buf, &buflen)); 275 T(addstr("; minimum\n", 10, &buf, &buflen)); 276 277 break; 278 } 279 280 case ns_t_mx: 281 case ns_t_afsdb: 282 case ns_t_rt: { 283 u_int t; 284 285 if (rdlen < NS_INT16SZ) 286 goto formerr; 287 288 /* Priority. */ 289 t = ns_get16(rdata); 290 rdata += NS_INT16SZ; 291 len = SPRINTF((tmp, "%u ", t)); 292 T(addstr(tmp, len, &buf, &buflen)); 293 294 /* Target. */ 295 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 296 297 break; 298 } 299 300 case ns_t_px: { 301 u_int t; 302 303 if (rdlen < NS_INT16SZ) 304 goto formerr; 305 306 /* Priority. */ 307 t = ns_get16(rdata); 308 rdata += NS_INT16SZ; 309 len = SPRINTF((tmp, "%u ", t)); 310 T(addstr(tmp, len, &buf, &buflen)); 311 312 /* Name1. */ 313 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 314 T(addstr(" ", 1, &buf, &buflen)); 315 316 /* Name2. */ 317 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 318 319 break; 320 } 321 322 case ns_t_x25: 323 T(len = charstr(rdata, edata, &buf, &buflen)); 324 if (len == 0) 325 goto formerr; 326 rdata += len; 327 break; 328 329 case ns_t_txt: 330 while (rdata < edata) { 331 T(len = charstr(rdata, edata, &buf, &buflen)); 332 if (len == 0) 333 goto formerr; 334 rdata += len; 335 if (rdata < edata) 336 T(addstr(" ", 1, &buf, &buflen)); 337 } 338 break; 339 340 case ns_t_nsap: { 341 342 (void) inet_nsap_ntoa((int)rdlen, rdata, t); 343 T(addstr(t, strlen(t), &buf, &buflen)); 344 break; 345 } 346 347 case ns_t_aaaa: 348 if (rdlen != NS_IN6ADDRSZ) 349 goto formerr; 350 (void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen); 351 addlen(strlen(buf), &buf, &buflen); 352 break; 353 354 case ns_t_loc: { 355 /* XXX protocol format checking? */ 356 (void) loc_ntoa(rdata, t); 357 T(addstr(t, strlen(t), &buf, &buflen)); 358 break; 359 } 360 361 case ns_t_naptr: { 362 u_int order, preference; 363 364 if (rdlen < 2*NS_INT16SZ) 365 goto formerr; 366 367 /* Order, Precedence. */ 368 order = ns_get16(rdata); rdata += NS_INT16SZ; 369 preference = ns_get16(rdata); rdata += NS_INT16SZ; 370 len = SPRINTF((t, "%u %u ", order, preference)); 371 T(addstr(t, len, &buf, &buflen)); 372 373 /* Flags. */ 374 T(len = charstr(rdata, edata, &buf, &buflen)); 375 if (len == 0) 376 goto formerr; 377 rdata += len; 378 T(addstr(" ", 1, &buf, &buflen)); 379 380 /* Service. */ 381 T(len = charstr(rdata, edata, &buf, &buflen)); 382 if (len == 0) 383 goto formerr; 384 rdata += len; 385 T(addstr(" ", 1, &buf, &buflen)); 386 387 /* Regexp. */ 388 T(len = charstr(rdata, edata, &buf, &buflen)); 389 if ((ssize_t)len < 0) 390 return (-1); 391 if (len == 0) 392 goto formerr; 393 rdata += len; 394 T(addstr(" ", 1, &buf, &buflen)); 395 396 /* Server. */ 397 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 398 break; 399 } 400 401 case ns_t_srv: { 402 u_int priority, weight, port; 403 404 if (rdlen < NS_INT16SZ*3) 405 goto formerr; 406 407 /* Priority, Weight, Port. */ 408 priority = ns_get16(rdata); rdata += NS_INT16SZ; 409 weight = ns_get16(rdata); rdata += NS_INT16SZ; 410 port = ns_get16(rdata); rdata += NS_INT16SZ; 411 len = SPRINTF((t, "%u %u %u ", priority, weight, port)); 412 T(addstr(t, len, &buf, &buflen)); 413 414 /* Server. */ 415 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 416 break; 417 } 418 419 case ns_t_minfo: 420 case ns_t_rp: 421 /* Name1. */ 422 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 423 T(addstr(" ", 1, &buf, &buflen)); 424 425 /* Name2. */ 426 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 427 428 break; 429 430 case ns_t_wks: { 431 int n, lcnt; 432 433 if (rdlen < NS_INT32SZ + 1) 434 goto formerr; 435 436 /* Address. */ 437 (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen); 438 addlen(strlen(buf), &buf, &buflen); 439 rdata += NS_INADDRSZ; 440 441 /* Protocol. */ 442 len = SPRINTF((tmp, " %u ( ", *rdata)); 443 T(addstr(tmp, len, &buf, &buflen)); 444 rdata += NS_INT8SZ; 445 446 /* Bit map. */ 447 n = 0; 448 lcnt = 0; 449 while (rdata < edata) { 450 u_int c = *rdata++; 451 do { 452 if (c & 0200) { 453 if (lcnt == 0) { 454 T(addstr("\n\t\t\t\t", 5, 455 &buf, &buflen)); 456 lcnt = 10; 457 spaced = 0; 458 } 459 len = SPRINTF((tmp, "%d ", n)); 460 T(addstr(tmp, len, &buf, &buflen)); 461 lcnt--; 462 } 463 c <<= 1; 464 } while (++n & 07); 465 } 466 T(addstr(")", 1, &buf, &buflen)); 467 468 break; 469 } 470 471 case ns_t_key: { 472 u_int keyflags, protocol, algorithm; 473 const char *leader; 474 int n; 475 476 if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) 477 goto formerr; 478 479 /* Key flags, Protocol, Algorithm. */ 480 keyflags = ns_get16(rdata); rdata += NS_INT16SZ; 481 protocol = *rdata++; 482 algorithm = *rdata++; 483 len = SPRINTF((tmp, "0x%04x %u %u", 484 keyflags, protocol, algorithm)); 485 T(addstr(tmp, len, &buf, &buflen)); 486 487 /* Public key data. */ 488 len = b64_ntop(rdata, edata - rdata, 489 base64_key, sizeof base64_key); 490 if ((ssize_t)len < 0) 491 goto formerr; 492 if (len > 15) { 493 T(addstr(" (", 2, &buf, &buflen)); 494 leader = "\n\t\t"; 495 spaced = 0; 496 } else 497 leader = " "; 498 for (n = 0; n < (int)len; n += 48) { 499 T(addstr(leader, strlen(leader), &buf, &buflen)); 500 T(addstr(base64_key + n, MIN(len - n, 48), 501 &buf, &buflen)); 502 } 503 if (len > 15) 504 T(addstr(" )", 2, &buf, &buflen)); 505 506 break; 507 } 508 509 case ns_t_sig: { 510 u_int type, algorithm, labels, footprint; 511 const char *leader; 512 u_long t; 513 int n; 514 515 if (rdlen < 22) 516 goto formerr; 517 518 /* Type covered, Algorithm, Label count, Original TTL. */ 519 type = ns_get16(rdata); rdata += NS_INT16SZ; 520 algorithm = *rdata++; 521 labels = *rdata++; 522 t = ns_get32(rdata); rdata += NS_INT32SZ; 523 len = SPRINTF((tmp, " %s %d %lu ", 524 p_type((int)type), algorithm, t)); 525 T(addstr(tmp, len, &buf, &buflen)); 526 if (labels != (u_int)dn_count_labels(name)) 527 goto formerr; 528 529 /* Signature expiry. */ 530 t = ns_get32(rdata); rdata += NS_INT32SZ; 531 len = SPRINTF((tmp, "%s ", p_secstodate(t))); 532 T(addstr(tmp, len, &buf, &buflen)); 533 534 /* Time signed. */ 535 t = ns_get32(rdata); rdata += NS_INT32SZ; 536 len = SPRINTF((tmp, "%s ", p_secstodate(t))); 537 T(addstr(tmp, len, &buf, &buflen)); 538 539 /* Signature Footprint. */ 540 footprint = ns_get16(rdata); rdata += NS_INT16SZ; 541 len = SPRINTF((tmp, "%u ", footprint)); 542 T(addstr(tmp, len, &buf, &buflen)); 543 544 /* Signer's name. */ 545 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 546 547 /* Signature. */ 548 len = b64_ntop(rdata, edata - rdata, 549 base64_key, sizeof base64_key); 550 if (len > 15) { 551 T(addstr(" (", 2, &buf, &buflen)); 552 leader = "\n\t\t"; 553 spaced = 0; 554 } else 555 leader = " "; 556 if ((ssize_t)len < 0) 557 goto formerr; 558 for (n = 0; n < (int)len; n += 48) { 559 T(addstr(leader, strlen(leader), &buf, &buflen)); 560 T(addstr(base64_key + n, MIN(len - n, 48), 561 &buf, &buflen)); 562 } 563 if (len > 15) 564 T(addstr(" )", 2, &buf, &buflen)); 565 566 break; 567 } 568 569 case ns_t_nxt: { 570 int n, c; 571 572 /* Next domain name. */ 573 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 574 575 /* Type bit map. */ 576 n = (int)(edata - rdata); 577 for (c = 0; c < n*8; c++) 578 if (NS_NXT_BIT_ISSET(c, rdata)) { 579 len = SPRINTF((tmp, " %s", p_type(c))); 580 T(addstr(tmp, len, &buf, &buflen)); 581 } 582 break; 583 } 584 585 default: 586 comment = "unknown RR type"; 587 goto hexify; 588 } 589 return ((int)(buf - obuf)); 590 formerr: 591 comment = "RR format error"; 592 hexify: { 593 int n, m; 594 char *p; 595 596 len = SPRINTF((tmp, "\\#(\t\t; %s", comment)); 597 T(addstr(tmp, len, &buf, &buflen)); 598 while (rdata < edata) { 599 p = tmp; 600 p += SPRINTF((p, "\n\t")); 601 spaced = 0; 602 n = MIN(16, (int)(edata - rdata)); 603 for (m = 0; m < n; m++) 604 p += SPRINTF((p, "%02x ", rdata[m])); 605 T(addstr(tmp, (u_int)(p - tmp), &buf, &buflen)); 606 if (n < 16) { 607 T(addstr(")", 1, &buf, &buflen)); 608 T(addtab((u_int)(p - tmp) + 1, 48, spaced, &buf, &buflen)); 609 } 610 p = tmp; 611 p += SPRINTF((p, "; ")); 612 for (m = 0; m < n; m++) 613 *p++ = (isascii(rdata[m]) && isprint(rdata[m])) 614 ? rdata[m] 615 : '.'; 616 T(addstr(tmp, (u_int)(p - tmp), &buf, &buflen)); 617 rdata += n; 618 } 619 return ((int)(buf - obuf)); 620 } 621} 622 623/* Private. */ 624 625/* 626 * size_t 627 * prune_origin(name, origin) 628 * Find out if the name is at or under the current origin. 629 * return: 630 * Number of characters in name before start of origin, 631 * or length of name if origin does not match. 632 * notes: 633 * This function should share code with samedomain(). 634 */ 635static size_t 636prune_origin(const char *name, const char *origin) { 637 const char *oname = name; 638 639 while (*name != '\0') { 640 if (origin != NULL && strcasecmp(name, origin) == 0) 641 return ((size_t)(name - oname) - (name > oname)); 642 while (*name != '\0') { 643 if (*name == '\\') { 644 name++; 645 /* XXX need to handle \nnn form. */ 646 if (*name == '\0') 647 break; 648 } else if (*name == '.') { 649 name++; 650 break; 651 } 652 name++; 653 } 654 } 655 return ((size_t)(name - oname)); 656} 657 658/* 659 * int 660 * charstr(rdata, edata, buf, buflen) 661 * Format a <character-string> into the presentation buffer. 662 * return: 663 * Number of rdata octets consumed 664 * 0 for protocol format error 665 * -1 for output buffer error 666 * side effects: 667 * buffer is advanced on success. 668 */ 669static int 670charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { 671 const u_char *odata = rdata; 672 size_t save_buflen = *buflen; 673 char *save_buf = *buf; 674 675 if (addstr("\"", 1, buf, buflen) < 0) 676 goto enospc; 677 if (rdata < edata) { 678 int n = *rdata; 679 680 if (rdata + 1 + n <= edata) { 681 rdata++; 682 while (n-- > 0) { 683 if (strchr("\n\"\\", *rdata) != NULL) 684 if (addstr("\\", 1, buf, buflen) < 0) 685 goto enospc; 686 if (addstr((const char *)rdata, 1, 687 buf, buflen) < 0) 688 goto enospc; 689 rdata++; 690 } 691 } 692 } 693 if (addstr("\"", 1, buf, buflen) < 0) 694 goto enospc; 695 return ((int)(rdata - odata)); 696 enospc: 697 errno = ENOSPC; 698 *buf = save_buf; 699 *buflen = save_buflen; 700 return (-1); 701} 702 703static int 704addname(const u_char *msg, size_t msglen, 705 const u_char **pp, const char *origin, 706 char **buf, size_t *buflen) 707{ 708 size_t newlen, save_buflen = *buflen; 709 char *save_buf = *buf; 710 int n; 711 712 n = dn_expand(msg, msg + msglen, *pp, *buf, (int)(*buflen)); 713 if (n < 0) 714 goto enospc; /* Guess. */ 715 newlen = prune_origin(*buf, origin); 716 if ((origin == NULL || origin[0] == '\0' || (*buf)[newlen] == '\0') && 717 (newlen == 0 || (*buf)[newlen - 1] != '.')) { 718 /* No trailing dot. */ 719 if (newlen + 2 > *buflen) 720 goto enospc; /* No room for ".\0". */ 721 (*buf)[newlen++] = '.'; 722 (*buf)[newlen] = '\0'; 723 } 724 if (newlen == 0) { 725 /* Use "@" instead of name. */ 726 if (newlen + 2 > *buflen) 727 goto enospc; /* No room for "@\0". */ 728 (*buf)[newlen++] = '@'; 729 (*buf)[newlen] = '\0'; 730 } 731 *pp += n; 732 addlen(newlen, buf, buflen); 733 **buf = '\0'; 734 return ((int)newlen); 735 enospc: 736 errno = ENOSPC; 737 *buf = save_buf; 738 *buflen = save_buflen; 739 return (-1); 740} 741 742static void 743addlen(size_t len, char **buf, size_t *buflen) { 744 assert(len <= *buflen); 745 *buf += len; 746 *buflen -= len; 747} 748 749static int 750addstr(const char *src, size_t len, char **buf, size_t *buflen) { 751 if (len > *buflen) { 752 errno = ENOSPC; 753 return (-1); 754 } 755 memcpy(*buf, src, len); 756 addlen(len, buf, buflen); 757 **buf = '\0'; 758 return (0); 759} 760 761static int 762addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { 763 size_t save_buflen = *buflen; 764 char *save_buf = *buf; 765 int t; 766 767 if (spaced || len >= target - 1) { 768 T(addstr(" ", 2, buf, buflen)); 769 spaced = 1; 770 } else { 771 for (t = (int)(target - len - 1) / 8; t >= 0; t--) 772 if (addstr("\t", 1, buf, buflen) < 0) { 773 *buflen = save_buflen; 774 *buf = save_buf; 775 return (-1); 776 } 777 spaced = 0; 778 } 779 return (spaced); 780} 781