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
77static size_t prune_origin(const char *name, const char *origin);
78static int  charstr(const u_char *rdata, const u_char *edata,
79      char **buf, size_t *buflen);
80static int  addname(const u_char *msg, size_t msglen,
81      const u_char **p, const char *origin,
82      char **buf, size_t *buflen);
83static void addlen(size_t len, char **buf, size_t *buflen);
84static int  addstr(const char *src, size_t len,
85           char **buf, size_t *buflen);
86static 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 */
106int
107ns_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 */
128int
129ns_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 */
631static size_t
632prune_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 */
665static int
666charstr(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
699static int
700addname(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
738static void
739addlen(size_t len, char **buf, size_t *buflen) {
740  assert(len <= *buflen);
741  *buf += len;
742  *buflen -= len;
743}
744
745static int
746addstr(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
757static int
758addtab(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