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
ns_sprintrr(const ns_msg * handle,const ns_rr * rr,const char * name_ctx,const char * origin,char * buf,size_t buflen)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
ns_sprintrrf(const u_char * msg,size_t msglen,const char * name,ns_class class,ns_type type,u_long ttl,const u_char * rdata,size_t rdlen,const char * name_ctx,const char * origin,char * buf,size_t buflen)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
prune_origin(const char * name,const char * origin)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
charstr(const u_char * rdata,const u_char * edata,char ** buf,size_t * buflen)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
addname(const u_char * msg,size_t msglen,const u_char ** pp,const char * origin,char ** buf,size_t * buflen)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
addlen(size_t len,char ** buf,size_t * buflen)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
addstr(const char * src,size_t len,char ** buf,size_t * buflen)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
addtab(size_t len,size_t target,int spaced,char ** buf,size_t * buflen)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