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