Open /etc/resolv.conf with FD_CLOEXEC
[platform/upstream/linaro-glibc.git] / resolv / ns_print.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1996-1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
12  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
15  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
16  * SOFTWARE.
17  */
18
19 #if !defined(_LIBC) && !defined(lint)
20 static const char rcsid[] = "$BINDId: ns_print.c,v 8.18 2000/02/29 05:48:12 vixie Exp $";
21 #endif
22
23 /* Import. */
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27
28 #include <netinet/in.h>
29 #include <arpa/nameser.h>
30 #include <arpa/inet.h>
31
32 #include <assert.h>
33 #include <errno.h>
34 #include <resolv.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #define SPRINTF(x) ((size_t)sprintf x)
39
40 /* Forward. */
41
42 static size_t   prune_origin(const char *name, const char *origin);
43 static int      charstr(const u_char *rdata, const u_char *edata,
44                         char **buf, size_t *buflen);
45 static int      addname(const u_char *msg, size_t msglen,
46                         const u_char **p, const char *origin,
47                         char **buf, size_t *buflen);
48 static void     addlen(size_t len, char **buf, size_t *buflen);
49 static int      addstr(const char *src, size_t len,
50                        char **buf, size_t *buflen);
51 static int      addtab(size_t len, size_t target, int spaced,
52                        char **buf, size_t *buflen);
53
54 static u_int16_t dst_s_dns_key_id(const u_char *, const int);
55
56 /* Macros. */
57
58 #define T(x) \
59         do { \
60                 if ((x) < 0) \
61                         return (-1); \
62         } while (0)
63
64 /* Public. */
65
66 /*%
67  *      Convert an RR to presentation format.
68  *
69  * return:
70  *\li   Number of characters written to buf, or -1 (check errno).
71  */
72 int
73 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
74             const char *name_ctx, const char *origin,
75             char *buf, size_t buflen)
76 {
77         int n;
78
79         n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
80                          ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
81                          ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
82                          name_ctx, origin, buf, buflen);
83         return (n);
84 }
85 libresolv_hidden_def (ns_sprintrr)
86
87 /*%
88  *      Convert the fields of an RR into presentation format.
89  *
90  * return:
91  *\li   Number of characters written to buf, or -1 (check errno).
92  */
93 int
94 ns_sprintrrf(const u_char *msg, size_t msglen,
95             const char *name, ns_class class, ns_type type,
96             u_long ttl, const u_char *rdata, size_t rdlen,
97             const char *name_ctx, const char *origin,
98             char *buf, size_t buflen)
99 {
100         const char *obuf = buf;
101         const u_char *edata = rdata + rdlen;
102         int spaced = 0;
103
104         const char *comment;
105         char tmp[100];
106         char errbuf[40];
107         int len, x;
108
109         /*
110          * Owner.
111          */
112         if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
113                 T(addstr("\t\t\t", 3, &buf, &buflen));
114         } else {
115                 len = prune_origin(name, origin);
116                 if (*name == '\0') {
117                         goto root;
118                 } else if (len == 0) {
119                         T(addstr("@\t\t\t", 4, &buf, &buflen));
120                 } else {
121                         T(addstr(name, len, &buf, &buflen));
122                         /* Origin not used or not root, and no trailing dot? */
123                         if (((origin == NULL || origin[0] == '\0') ||
124                              (origin[0] != '.' && origin[1] != '\0' &&
125                               name[len] == '\0')) && name[len - 1] != '.') {
126  root:
127                                 T(addstr(".", 1, &buf, &buflen));
128                                 len++;
129                         }
130                         T(spaced = addtab(len, 24, spaced, &buf, &buflen));
131                 }
132         }
133
134         /*
135          * TTL, Class, Type.
136          */
137         T(x = ns_format_ttl(ttl, buf, buflen));
138         addlen(x, &buf, &buflen);
139         len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
140         T(addstr(tmp, len, &buf, &buflen));
141         T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
142
143         /*
144          * RData.
145          */
146         switch (type) {
147         case ns_t_a:
148           if (rdlen != (size_t)NS_INADDRSZ)
149                         goto formerr;
150                 (void) inet_ntop(AF_INET, rdata, buf, buflen);
151                 addlen(strlen(buf), &buf, &buflen);
152                 break;
153
154         case ns_t_cname:
155         case ns_t_mb:
156         case ns_t_mg:
157         case ns_t_mr:
158         case ns_t_ns:
159         case ns_t_ptr:
160         case ns_t_dname:
161                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
162                 break;
163
164         case ns_t_hinfo:
165         case ns_t_isdn:
166                 /* First word. */
167                 T(len = charstr(rdata, edata, &buf, &buflen));
168                 if (len == 0)
169                         goto formerr;
170                 rdata += len;
171                 T(addstr(" ", 1, &buf, &buflen));
172
173
174                 /* Second word, optional in ISDN records. */
175                 if (type == ns_t_isdn && rdata == edata)
176                         break;
177
178                 T(len = charstr(rdata, edata, &buf, &buflen));
179                 if (len == 0)
180                         goto formerr;
181                 rdata += len;
182                 break;
183
184         case ns_t_soa: {
185                 u_long t;
186
187                 /* Server name. */
188                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
189                 T(addstr(" ", 1, &buf, &buflen));
190
191                 /* Administrator name. */
192                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
193                 T(addstr(" (\n", 3, &buf, &buflen));
194                 spaced = 0;
195
196                 if ((edata - rdata) != 5*NS_INT32SZ)
197                         goto formerr;
198
199                 /* Serial number. */
200                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
201                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
202                 len = SPRINTF((tmp, "%lu", t));
203                 T(addstr(tmp, len, &buf, &buflen));
204                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
205                 T(addstr("; serial\n", 9, &buf, &buflen));
206                 spaced = 0;
207
208                 /* Refresh interval. */
209                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
210                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
211                 T(len = ns_format_ttl(t, buf, buflen));
212                 addlen(len, &buf, &buflen);
213                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
214                 T(addstr("; refresh\n", 10, &buf, &buflen));
215                 spaced = 0;
216
217                 /* Retry interval. */
218                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
219                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
220                 T(len = ns_format_ttl(t, buf, buflen));
221                 addlen(len, &buf, &buflen);
222                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
223                 T(addstr("; retry\n", 8, &buf, &buflen));
224                 spaced = 0;
225
226                 /* Expiry. */
227                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
228                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
229                 T(len = ns_format_ttl(t, buf, buflen));
230                 addlen(len, &buf, &buflen);
231                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
232                 T(addstr("; expiry\n", 9, &buf, &buflen));
233                 spaced = 0;
234
235                 /* Minimum TTL. */
236                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
237                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
238                 T(len = ns_format_ttl(t, buf, buflen));
239                 addlen(len, &buf, &buflen);
240                 T(addstr(" )", 2, &buf, &buflen));
241                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
242                 T(addstr("; minimum\n", 10, &buf, &buflen));
243
244                 break;
245             }
246
247         case ns_t_mx:
248         case ns_t_afsdb:
249         case ns_t_rt: {
250                 u_int t;
251
252                 if (rdlen < (size_t)NS_INT16SZ)
253                         goto formerr;
254
255                 /* Priority. */
256                 t = ns_get16(rdata);
257                 rdata += NS_INT16SZ;
258                 len = SPRINTF((tmp, "%u ", t));
259                 T(addstr(tmp, len, &buf, &buflen));
260
261                 /* Target. */
262                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
263
264                 break;
265             }
266
267         case ns_t_px: {
268                 u_int t;
269
270                 if (rdlen < (size_t)NS_INT16SZ)
271                         goto formerr;
272
273                 /* Priority. */
274                 t = ns_get16(rdata);
275                 rdata += NS_INT16SZ;
276                 len = SPRINTF((tmp, "%u ", t));
277                 T(addstr(tmp, len, &buf, &buflen));
278
279                 /* Name1. */
280                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
281                 T(addstr(" ", 1, &buf, &buflen));
282
283                 /* Name2. */
284                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
285
286                 break;
287             }
288
289         case ns_t_x25:
290                 T(len = charstr(rdata, edata, &buf, &buflen));
291                 if (len == 0)
292                         goto formerr;
293                 rdata += len;
294                 break;
295
296         case ns_t_txt:
297                 while (rdata < edata) {
298                         T(len = charstr(rdata, edata, &buf, &buflen));
299                         if (len == 0)
300                                 goto formerr;
301                         rdata += len;
302                         if (rdata < edata)
303                                 T(addstr(" ", 1, &buf, &buflen));
304                 }
305                 break;
306
307         case ns_t_nsap: {
308                 char t[2+255*3];
309
310                 (void) inet_nsap_ntoa(rdlen, rdata, t);
311                 T(addstr(t, strlen(t), &buf, &buflen));
312                 break;
313             }
314
315         case ns_t_aaaa:
316           if (rdlen != (size_t)NS_IN6ADDRSZ)
317                         goto formerr;
318                 (void) inet_ntop(AF_INET6, rdata, buf, buflen);
319                 addlen(strlen(buf), &buf, &buflen);
320                 break;
321
322         case ns_t_loc: {
323                 char t[255];
324
325                 /* XXX protocol format checking? */
326                 (void) loc_ntoa(rdata, t);
327                 T(addstr(t, strlen(t), &buf, &buflen));
328                 break;
329             }
330
331         case ns_t_naptr: {
332                 u_int order, preference;
333                 char t[50];
334
335                 if (rdlen < 2U*NS_INT16SZ)
336                         goto formerr;
337
338                 /* Order, Precedence. */
339                 order = ns_get16(rdata);        rdata += NS_INT16SZ;
340                 preference = ns_get16(rdata);   rdata += NS_INT16SZ;
341                 len = SPRINTF((t, "%u %u ", order, preference));
342                 T(addstr(t, len, &buf, &buflen));
343
344                 /* Flags. */
345                 T(len = charstr(rdata, edata, &buf, &buflen));
346                 if (len == 0)
347                         goto formerr;
348                 rdata += len;
349                 T(addstr(" ", 1, &buf, &buflen));
350
351                 /* Service. */
352                 T(len = charstr(rdata, edata, &buf, &buflen));
353                 if (len == 0)
354                         goto formerr;
355                 rdata += len;
356                 T(addstr(" ", 1, &buf, &buflen));
357
358                 /* Regexp. */
359                 T(len = charstr(rdata, edata, &buf, &buflen));
360                 if (len < 0)
361                         return (-1);
362                 if (len == 0)
363                         goto formerr;
364                 rdata += len;
365                 T(addstr(" ", 1, &buf, &buflen));
366
367                 /* Server. */
368                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
369                 break;
370             }
371
372         case ns_t_srv: {
373                 u_int priority, weight, port;
374                 char t[50];
375
376                 if (rdlen < 3U*NS_INT16SZ)
377                         goto formerr;
378
379                 /* Priority, Weight, Port. */
380                 priority = ns_get16(rdata);  rdata += NS_INT16SZ;
381                 weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
382                 port     = ns_get16(rdata);  rdata += NS_INT16SZ;
383                 len = SPRINTF((t, "%u %u %u ", priority, weight, port));
384                 T(addstr(t, len, &buf, &buflen));
385
386                 /* Server. */
387                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
388                 break;
389             }
390
391         case ns_t_minfo:
392         case ns_t_rp:
393                 /* Name1. */
394                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
395                 T(addstr(" ", 1, &buf, &buflen));
396
397                 /* Name2. */
398                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
399
400                 break;
401
402         case ns_t_wks: {
403                 int n, lcnt;
404
405                 if (rdlen < 1U + NS_INT32SZ)
406                         goto formerr;
407
408                 /* Address. */
409                 (void) inet_ntop(AF_INET, rdata, buf, buflen);
410                 addlen(strlen(buf), &buf, &buflen);
411                 rdata += NS_INADDRSZ;
412
413                 /* Protocol. */
414                 len = SPRINTF((tmp, " %u ( ", *rdata));
415                 T(addstr(tmp, len, &buf, &buflen));
416                 rdata += NS_INT8SZ;
417
418                 /* Bit map. */
419                 n = 0;
420                 lcnt = 0;
421                 while (rdata < edata) {
422                         u_int c = *rdata++;
423                         do {
424                                 if (c & 0200) {
425                                         if (lcnt == 0) {
426                                                 T(addstr("\n\t\t\t\t", 5,
427                                                          &buf, &buflen));
428                                                 lcnt = 10;
429                                                 spaced = 0;
430                                         }
431                                         len = SPRINTF((tmp, "%d ", n));
432                                         T(addstr(tmp, len, &buf, &buflen));
433                                         lcnt--;
434                                 }
435                                 c <<= 1;
436                         } while (++n & 07);
437                 }
438                 T(addstr(")", 1, &buf, &buflen));
439
440                 break;
441             }
442
443         case ns_t_key: {
444                 char base64_key[NS_MD5RSA_MAX_BASE64];
445                 u_int keyflags, protocol, algorithm, key_id;
446                 const char *leader;
447                 int n;
448
449                 if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
450                         goto formerr;
451
452                 /* Key flags, Protocol, Algorithm. */
453                 key_id = dst_s_dns_key_id(rdata, edata-rdata);
454                 keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
455                 protocol = *rdata++;
456                 algorithm = *rdata++;
457                 len = SPRINTF((tmp, "0x%04x %u %u",
458                                keyflags, protocol, algorithm));
459                 T(addstr(tmp, len, &buf, &buflen));
460
461                 /* Public key data. */
462                 len = b64_ntop(rdata, edata - rdata,
463                                base64_key, sizeof base64_key);
464                 if (len < 0)
465                         goto formerr;
466                 if (len > 15) {
467                         T(addstr(" (", 2, &buf, &buflen));
468                         leader = "\n\t\t";
469                         spaced = 0;
470                 } else
471                         leader = " ";
472                 for (n = 0; n < len; n += 48) {
473                         T(addstr(leader, strlen(leader), &buf, &buflen));
474                         T(addstr(base64_key + n, MIN(len - n, 48),
475                                  &buf, &buflen));
476                 }
477                 if (len > 15)
478                         T(addstr(" )", 2, &buf, &buflen));
479                 n = SPRINTF((tmp, " ; key_tag= %u", key_id));
480                 T(addstr(tmp, n, &buf, &buflen));
481
482                 break;
483             }
484
485         case ns_t_sig: {
486                 char base64_key[NS_MD5RSA_MAX_BASE64];
487                 u_int type, algorithm, labels, footprint;
488                 const char *leader;
489                 u_long t;
490                 int n;
491
492                 if (rdlen < 22U)
493                         goto formerr;
494
495                 /* Type covered, Algorithm, Label count, Original TTL. */
496                 type = ns_get16(rdata);  rdata += NS_INT16SZ;
497                 algorithm = *rdata++;
498                 labels = *rdata++;
499                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
500                 len = SPRINTF((tmp, "%s %d %d %lu ",
501                                p_type(type), algorithm, labels, t));
502                 T(addstr(tmp, len, &buf, &buflen));
503                 if (labels > (u_int)dn_count_labels(name))
504                         goto formerr;
505
506                 /* Signature expiry. */
507                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
508                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
509                 T(addstr(tmp, len, &buf, &buflen));
510
511                 /* Time signed. */
512                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
513                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
514                 T(addstr(tmp, len, &buf, &buflen));
515
516                 /* Signature Footprint. */
517                 footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
518                 len = SPRINTF((tmp, "%u ", footprint));
519                 T(addstr(tmp, len, &buf, &buflen));
520
521                 /* Signer's name. */
522                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
523
524                 /* Signature. */
525                 len = b64_ntop(rdata, edata - rdata,
526                                base64_key, sizeof base64_key);
527                 if (len > 15) {
528                         T(addstr(" (", 2, &buf, &buflen));
529                         leader = "\n\t\t";
530                         spaced = 0;
531                 } else
532                         leader = " ";
533                 if (len < 0)
534                         goto formerr;
535                 for (n = 0; n < len; n += 48) {
536                         T(addstr(leader, strlen(leader), &buf, &buflen));
537                         T(addstr(base64_key + n, MIN(len - n, 48),
538                                  &buf, &buflen));
539                 }
540                 if (len > 15)
541                         T(addstr(" )", 2, &buf, &buflen));
542                 break;
543             }
544
545         case ns_t_nxt: {
546                 int n, c;
547
548                 /* Next domain name. */
549                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
550
551                 /* Type bit map. */
552                 n = edata - rdata;
553                 for (c = 0; c < n*8; c++)
554                         if (NS_NXT_BIT_ISSET(c, rdata)) {
555                                 len = SPRINTF((tmp, " %s", p_type(c)));
556                                 T(addstr(tmp, len, &buf, &buflen));
557                         }
558                 break;
559             }
560
561         case ns_t_cert: {
562                 u_int c_type, key_tag, alg;
563                 int n;
564                 unsigned int siz;
565                 char base64_cert[8192], tmp[40];
566                 const char *leader;
567
568                 c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
569                 key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
570                 alg = (u_int) *rdata++;
571
572                 len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
573                 T(addstr(tmp, len, &buf, &buflen));
574                 siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
575                 if (siz > sizeof(base64_cert) * 3/4) {
576                         const char *str = "record too long to print";
577                         T(addstr(str, strlen(str), &buf, &buflen));
578                 }
579                 else {
580                         len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
581
582                         if (len < 0)
583                                 goto formerr;
584                         else if (len > 15) {
585                                 T(addstr(" (", 2, &buf, &buflen));
586                                 leader = "\n\t\t";
587                                 spaced = 0;
588                         }
589                         else
590                                 leader = " ";
591
592                         for (n = 0; n < len; n += 48) {
593                                 T(addstr(leader, strlen(leader),
594                                          &buf, &buflen));
595                                 T(addstr(base64_cert + n, MIN(len - n, 48),
596                                          &buf, &buflen));
597                         }
598                         if (len > 15)
599                                 T(addstr(" )", 2, &buf, &buflen));
600                 }
601                 break;
602             }
603
604         case ns_t_tkey: {
605                 /* KJD - need to complete this */
606                 u_long t;
607                 int mode, err, keysize;
608
609                 /* Algorithm name. */
610                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
611                 T(addstr(" ", 1, &buf, &buflen));
612
613                 /* Inception. */
614                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
615                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
616                 T(addstr(tmp, len, &buf, &buflen));
617
618                 /* Experation. */
619                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
620                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
621                 T(addstr(tmp, len, &buf, &buflen));
622
623                 /* Mode , Error, Key Size. */
624                 /* Priority, Weight, Port. */
625                 mode = ns_get16(rdata);  rdata += NS_INT16SZ;
626                 err  = ns_get16(rdata);  rdata += NS_INT16SZ;
627                 keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
628                 len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
629                 T(addstr(tmp, len, &buf, &buflen));
630
631                 /* XXX need to dump key, print otherdata length & other data */
632                 break;
633             }
634
635         case ns_t_tsig: {
636                 /* BEW - need to complete this */
637                 int n;
638
639                 T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
640                 T(addstr(" ", 1, &buf, &buflen));
641                 rdata += 8; /*%< time */
642                 n = ns_get16(rdata); rdata += INT16SZ;
643                 rdata += n; /*%< sig */
644                 n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
645                 sprintf(buf, "%d", ns_get16(rdata));
646                 rdata += INT16SZ;
647                 addlen(strlen(buf), &buf, &buflen);
648                 break;
649             }
650
651         case ns_t_a6: {
652                 struct in6_addr a;
653                 int pbyte, pbit;
654
655                 /* prefix length */
656                 if (rdlen == 0U) goto formerr;
657                 len = SPRINTF((tmp, "%d ", *rdata));
658                 T(addstr(tmp, len, &buf, &buflen));
659                 pbit = *rdata;
660                 if (pbit > 128) goto formerr;
661                 pbyte = (pbit & ~7) / 8;
662                 rdata++;
663
664                 /* address suffix: provided only when prefix len != 128 */
665                 if (pbit < 128) {
666                         if (rdata + pbyte >= edata) goto formerr;
667                         memset(&a, 0, sizeof(a));
668                         memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
669                         (void) inet_ntop(AF_INET6, &a, buf, buflen);
670                         addlen(strlen(buf), &buf, &buflen);
671                         rdata += sizeof(a) - pbyte;
672                 }
673
674                 /* prefix name: provided only when prefix len > 0 */
675                 if (pbit == 0)
676                         break;
677                 if (rdata >= edata) goto formerr;
678                 T(addstr(" ", 1, &buf, &buflen));
679                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
680
681                 break;
682             }
683
684         case ns_t_opt: {
685                 len = SPRINTF((tmp, "%u bytes", class));
686                 T(addstr(tmp, len, &buf, &buflen));
687                 break;
688             }
689
690         default:
691                 snprintf (errbuf, sizeof (errbuf), "unknown RR type %d", type);
692                 comment = errbuf;
693                 goto hexify;
694         }
695         return (buf - obuf);
696  formerr:
697         comment = "RR format error";
698  hexify: {
699         int n, m;
700         char *p;
701
702         len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
703                        rdlen != 0U ? " (" : "", comment));
704         T(addstr(tmp, len, &buf, &buflen));
705         while (rdata < edata) {
706                 p = tmp;
707                 p += SPRINTF((p, "\n\t"));
708                 spaced = 0;
709                 n = MIN(16, edata - rdata);
710                 for (m = 0; m < n; m++)
711                         p += SPRINTF((p, "%02x ", rdata[m]));
712                 T(addstr(tmp, p - tmp, &buf, &buflen));
713                 if (n < 16) {
714                         T(addstr(")", 1, &buf, &buflen));
715                         T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
716                 }
717                 p = tmp;
718                 p += SPRINTF((p, "; "));
719                 for (m = 0; m < n; m++)
720                         *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
721                                 ? rdata[m]
722                                 : '.';
723                 T(addstr(tmp, p - tmp, &buf, &buflen));
724                 rdata += n;
725         }
726         return (buf - obuf);
727     }
728 }
729 libresolv_hidden_def (ns_sprintrrf)
730
731 /* Private. */
732
733 /*%
734  * size_t
735  * prune_origin(name, origin)
736  *      Find out if the name is at or under the current origin.
737  * return:
738  *      Number of characters in name before start of origin,
739  *      or length of name if origin does not match.
740  * notes:
741  *      This function should share code with samedomain().
742  */
743 static size_t
744 prune_origin(const char *name, const char *origin) {
745         const char *oname = name;
746
747         while (*name != '\0') {
748                 if (origin != NULL && ns_samename(name, origin) == 1)
749                         return (name - oname - (name > oname));
750                 while (*name != '\0') {
751                         if (*name == '\\') {
752                                 name++;
753                                 /* XXX need to handle \nnn form. */
754                                 if (*name == '\0')
755                                         break;
756                         } else if (*name == '.') {
757                                 name++;
758                                 break;
759                         }
760                         name++;
761                 }
762         }
763         return (name - oname);
764 }
765
766 /*%
767  * int
768  * charstr(rdata, edata, buf, buflen)
769  *      Format a <character-string> into the presentation buffer.
770  * return:
771  *      Number of rdata octets consumed
772  *      0 for protocol format error
773  *      -1 for output buffer error
774  * side effects:
775  *      buffer is advanced on success.
776  */
777 static int
778 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
779         const u_char *odata = rdata;
780         size_t save_buflen = *buflen;
781         char *save_buf = *buf;
782
783         if (addstr("\"", 1, buf, buflen) < 0)
784                 goto enospc;
785         if (rdata < edata) {
786                 int n = *rdata;
787
788                 if (rdata + 1 + n <= edata) {
789                         rdata++;
790                         while (n-- > 0) {
791                                 if (strchr("\n\"\\", *rdata) != NULL)
792                                         if (addstr("\\", 1, buf, buflen) < 0)
793                                                 goto enospc;
794                                 if (addstr((const char *)rdata, 1,
795                                            buf, buflen) < 0)
796                                         goto enospc;
797                                 rdata++;
798                         }
799                 }
800         }
801         if (addstr("\"", 1, buf, buflen) < 0)
802                 goto enospc;
803         return (rdata - odata);
804  enospc:
805         __set_errno (ENOSPC);
806         *buf = save_buf;
807         *buflen = save_buflen;
808         return (-1);
809 }
810
811 static int
812 addname(const u_char *msg, size_t msglen,
813         const u_char **pp, const char *origin,
814         char **buf, size_t *buflen)
815 {
816         size_t newlen, save_buflen = *buflen;
817         char *save_buf = *buf;
818         int n;
819
820         n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
821         if (n < 0)
822                 goto enospc;    /*%< Guess. */
823         newlen = prune_origin(*buf, origin);
824         if (**buf == '\0') {
825                 goto root;
826         } else if (newlen == 0U) {
827                 /* Use "@" instead of name. */
828                 if (newlen + 2 > *buflen)
829                         goto enospc;        /* No room for "@\0". */
830                 (*buf)[newlen++] = '@';
831                 (*buf)[newlen] = '\0';
832         } else {
833                 if (((origin == NULL || origin[0] == '\0') ||
834                     (origin[0] != '.' && origin[1] != '\0' &&
835                     (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
836                         /* No trailing dot. */
837  root:
838                         if (newlen + 2 > *buflen)
839                                 goto enospc;    /* No room for ".\0". */
840                         (*buf)[newlen++] = '.';
841                         (*buf)[newlen] = '\0';
842                 }
843         }
844         *pp += n;
845         addlen(newlen, buf, buflen);
846         **buf = '\0';
847         return (newlen);
848  enospc:
849         __set_errno (ENOSPC);
850         *buf = save_buf;
851         *buflen = save_buflen;
852         return (-1);
853 }
854
855 static void
856 addlen(size_t len, char **buf, size_t *buflen) {
857         assert(len <= *buflen);
858         *buf += len;
859         *buflen -= len;
860 }
861
862 static int
863 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
864         if (len >= *buflen) {
865                 __set_errno (ENOSPC);
866                 return (-1);
867         }
868         memcpy(*buf, src, len);
869         addlen(len, buf, buflen);
870         **buf = '\0';
871         return (0);
872 }
873
874 static int
875 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
876         size_t save_buflen = *buflen;
877         char *save_buf = *buf;
878         int t;
879
880         if (spaced || len >= target - 1) {
881                 T(addstr("  ", 2, buf, buflen));
882                 spaced = 1;
883         } else {
884                 for (t = (target - len - 1) / 8; t >= 0; t--)
885                         if (addstr("\t", 1, buf, buflen) < 0) {
886                                 *buflen = save_buflen;
887                                 *buf = save_buf;
888                                 return (-1);
889                         }
890                 spaced = 0;
891         }
892         return (spaced);
893 }
894
895 /* DST algorithm codes */
896 #define KEY_RSA                 1
897 #define KEY_HMAC_MD5            157
898
899 /*%
900  * calculates a checksum used in dst for an id.
901  * takes an array of bytes and a length.
902  * returns a 16  bit checksum.
903  */
904 static u_int16_t
905 dst_s_id_calc(const u_char *key, const int keysize)
906 {
907         u_int32_t ac;
908         const u_char *kp = key;
909         int size = keysize;
910
911         if (!key || (keysize <= 0))
912                 return (0xffffU);
913
914         for (ac = 0; size > 1; size -= 2, kp += 2)
915                 ac += ((*kp) << 8) + *(kp + 1);
916
917         if (size > 0)
918                 ac += ((*kp) << 8);
919         ac += (ac >> 16) & 0xffff;
920
921         return (ac & 0xffff);
922 }
923
924 /*%
925  * dst_s_get_int16
926  *     This routine extracts a 16 bit integer from a two byte character
927  *     string.  The character string is assumed to be in network byte
928  *     order and may be unaligned.  The number returned is in host order.
929  * Parameter
930  *     buf     A two byte character string.
931  * Return
932  *     The converted integer value.
933  */
934
935 static u_int16_t
936 dst_s_get_int16(const u_char *buf)
937 {
938         register u_int16_t a = 0;
939         a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
940         return (a);
941 }
942
943 /*%
944  * dst_s_dns_key_id() Function to calculate DNSSEC footprint from KEY record
945  *   rdata
946  * Input:
947  *      dns_key_rdata: the raw data in wire format
948  *      rdata_len: the size of the input data
949  * Output:
950  *      the key footprint/id calculated from the key data
951  */
952 static u_int16_t
953 dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len)
954 {
955         if (!dns_key_rdata)
956                 return 0;
957
958         /* compute id */
959         if (dns_key_rdata[3] == KEY_RSA)        /*%< Algorithm RSA */
960                 return dst_s_get_int16((const u_char *)
961                                        &dns_key_rdata[rdata_len - 3]);
962         else if (dns_key_rdata[3] == KEY_HMAC_MD5)
963                 /* compatibility */
964                 return 0;
965         else
966                 /* compute a checksum on the key part of the key rr */
967                 return dst_s_id_calc(dns_key_rdata, rdata_len);
968 }
969
970
971 /*! \file */