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