Updated to fedora-glibc-20080305T0857
[glibc.git] / resolv / ns_print.c
blobb0b7a1046ebcfe464a3a13f3c8ecd20bcc436f2e
1 /*
2 * Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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.
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
22 /* Import. */
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/nameser.h>
29 #include <arpa/inet.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <resolv.h>
34 #include <string.h>
35 #include <ctype.h>
37 #ifdef SPRINTF_CHAR
38 # define SPRINTF(x) strlen(sprintf/**/x)
39 #else
40 # define SPRINTF(x) ((size_t)sprintf x)
41 #endif
43 /* Forward. */
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);
57 /* Proto. */
59 #ifndef _LIBC
60 u_int16_t dst_s_dns_key_id(const u_char *, const int);
61 #endif
63 /* Macros. */
65 #define T(x) \
66 do { \
67 if ((x) < 0) \
68 return (-1); \
69 } while (0)
71 /* Public. */
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).
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)
85 int n;
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);
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).
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)
109 const char *obuf = buf;
110 const u_char *edata = rdata + rdlen;
111 int spaced = 0;
113 const char *comment;
114 char tmp[100];
115 char errbuf[40];
116 int len, x;
119 * Owner.
121 if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
122 T(addstr("\t\t\t", 3, &buf, &buflen));
123 } else {
124 len = prune_origin(name, origin);
125 if (len == 0) {
126 T(addstr("@\t\t\t", 4, &buf, &buflen));
127 } else {
128 T(addstr(name, len, &buf, &buflen));
129 /* Origin not used or not root, and no trailing dot? */
130 if (((origin == NULL || origin[0] == '\0') ||
131 (origin[0] != '.' && origin[1] != '\0' &&
132 name[len] == '\0')) && name[len - 1] != '.') {
133 T(addstr(".", 1, &buf, &buflen));
134 len++;
136 T(spaced = addtab(len, 24, spaced, &buf, &buflen));
141 * TTL, Class, Type.
143 T(x = ns_format_ttl(ttl, buf, buflen));
144 addlen(x, &buf, &buflen);
145 len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
146 T(addstr(tmp, len, &buf, &buflen));
147 T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
150 * RData.
152 switch (type) {
153 case ns_t_a:
154 if (rdlen != NS_INADDRSZ)
155 goto formerr;
156 (void) inet_ntop(AF_INET, rdata, buf, buflen);
157 addlen(strlen(buf), &buf, &buflen);
158 break;
160 case ns_t_cname:
161 case ns_t_mb:
162 case ns_t_mg:
163 case ns_t_mr:
164 case ns_t_ns:
165 case ns_t_ptr:
166 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
167 break;
169 case ns_t_hinfo:
170 case ns_t_isdn:
171 /* First word. */
172 T(len = charstr(rdata, edata, &buf, &buflen));
173 if (len == 0)
174 goto formerr;
175 rdata += len;
176 T(addstr(" ", 1, &buf, &buflen));
179 /* Second word, optional in ISDN records. */
180 if (type == ns_t_isdn && rdata == edata)
181 break;
183 T(len = charstr(rdata, edata, &buf, &buflen));
184 if (len == 0)
185 goto formerr;
186 rdata += len;
187 break;
189 case ns_t_soa: {
190 u_long t;
192 /* Server name. */
193 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
194 T(addstr(" ", 1, &buf, &buflen));
196 /* Administrator name. */
197 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
198 T(addstr(" (\n", 3, &buf, &buflen));
199 spaced = 0;
201 if ((edata - rdata) != 5*NS_INT32SZ)
202 goto formerr;
204 /* Serial number. */
205 t = ns_get32(rdata); rdata += NS_INT32SZ;
206 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
207 len = SPRINTF((tmp, "%lu", t));
208 T(addstr(tmp, len, &buf, &buflen));
209 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
210 T(addstr("; serial\n", 9, &buf, &buflen));
211 spaced = 0;
213 /* Refresh interval. */
214 t = ns_get32(rdata); rdata += NS_INT32SZ;
215 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
216 T(len = ns_format_ttl(t, buf, buflen));
217 addlen(len, &buf, &buflen);
218 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
219 T(addstr("; refresh\n", 10, &buf, &buflen));
220 spaced = 0;
222 /* Retry interval. */
223 t = ns_get32(rdata); rdata += NS_INT32SZ;
224 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
225 T(len = ns_format_ttl(t, buf, buflen));
226 addlen(len, &buf, &buflen);
227 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
228 T(addstr("; retry\n", 8, &buf, &buflen));
229 spaced = 0;
231 /* Expiry. */
232 t = ns_get32(rdata); rdata += NS_INT32SZ;
233 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
234 T(len = ns_format_ttl(t, buf, buflen));
235 addlen(len, &buf, &buflen);
236 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
237 T(addstr("; expiry\n", 9, &buf, &buflen));
238 spaced = 0;
240 /* Minimum TTL. */
241 t = ns_get32(rdata); rdata += NS_INT32SZ;
242 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
243 T(len = ns_format_ttl(t, buf, buflen));
244 addlen(len, &buf, &buflen);
245 T(addstr(" )", 2, &buf, &buflen));
246 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
247 T(addstr("; minimum\n", 10, &buf, &buflen));
249 break;
252 case ns_t_mx:
253 case ns_t_afsdb:
254 case ns_t_rt: {
255 u_int t;
257 if (rdlen < NS_INT16SZ)
258 goto formerr;
260 /* Priority. */
261 t = ns_get16(rdata);
262 rdata += NS_INT16SZ;
263 len = SPRINTF((tmp, "%u ", t));
264 T(addstr(tmp, len, &buf, &buflen));
266 /* Target. */
267 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
269 break;
272 case ns_t_px: {
273 u_int t;
275 if (rdlen < NS_INT16SZ)
276 goto formerr;
278 /* Priority. */
279 t = ns_get16(rdata);
280 rdata += NS_INT16SZ;
281 len = SPRINTF((tmp, "%u ", t));
282 T(addstr(tmp, len, &buf, &buflen));
284 /* Name1. */
285 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
286 T(addstr(" ", 1, &buf, &buflen));
288 /* Name2. */
289 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
291 break;
294 case ns_t_x25:
295 T(len = charstr(rdata, edata, &buf, &buflen));
296 if (len == 0)
297 goto formerr;
298 rdata += len;
299 break;
301 case ns_t_txt:
302 while (rdata < edata) {
303 T(len = charstr(rdata, edata, &buf, &buflen));
304 if (len == 0)
305 goto formerr;
306 rdata += len;
307 if (rdata < edata)
308 T(addstr(" ", 1, &buf, &buflen));
310 break;
312 case ns_t_nsap: {
313 /* 2*255 for hex digits, 128 for '.' and '\0', 2 for
314 0x if inet_nsap_ntoa starts using it. */
315 char t[255*2 + 128 + 2];
317 (void) inet_nsap_ntoa(rdlen, rdata, t);
318 T(addstr(t, strlen(t), &buf, &buflen));
319 break;
322 case ns_t_aaaa:
323 if (rdlen != NS_IN6ADDRSZ)
324 goto formerr;
325 (void) inet_ntop(AF_INET6, rdata, buf, buflen);
326 addlen(strlen(buf), &buf, &buflen);
327 break;
329 case ns_t_loc: {
330 char t[255];
332 /* XXX protocol format checking? */
333 (void) loc_ntoa(rdata, t);
334 T(addstr(t, strlen(t), &buf, &buflen));
335 break;
338 case ns_t_naptr: {
339 u_int order, preference;
340 char t[50];
342 if (rdlen < 2*NS_INT16SZ)
343 goto formerr;
345 /* Order, Precedence. */
346 order = ns_get16(rdata); rdata += NS_INT16SZ;
347 preference = ns_get16(rdata); rdata += NS_INT16SZ;
348 len = SPRINTF((t, "%u %u ", order, preference));
349 T(addstr(t, len, &buf, &buflen));
351 /* Flags. */
352 T(len = charstr(rdata, edata, &buf, &buflen));
353 if (len == 0)
354 goto formerr;
355 rdata += len;
356 T(addstr(" ", 1, &buf, &buflen));
358 /* Service. */
359 T(len = charstr(rdata, edata, &buf, &buflen));
360 if (len == 0)
361 goto formerr;
362 rdata += len;
363 T(addstr(" ", 1, &buf, &buflen));
365 /* Regexp. */
366 T(len = charstr(rdata, edata, &buf, &buflen));
367 if (len < 0)
368 return (-1);
369 if (len == 0)
370 goto formerr;
371 rdata += len;
372 T(addstr(" ", 1, &buf, &buflen));
374 /* Server. */
375 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
376 break;
379 case ns_t_srv: {
380 u_int priority, weight, port;
381 char t[50];
383 if (rdlen < NS_INT16SZ*3)
384 goto formerr;
386 /* Priority, Weight, Port. */
387 priority = ns_get16(rdata); rdata += NS_INT16SZ;
388 weight = ns_get16(rdata); rdata += NS_INT16SZ;
389 port = ns_get16(rdata); rdata += NS_INT16SZ;
390 len = SPRINTF((t, "%u %u %u ", priority, weight, port));
391 T(addstr(t, len, &buf, &buflen));
393 /* Server. */
394 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
395 break;
398 case ns_t_minfo:
399 case ns_t_rp:
400 /* Name1. */
401 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
402 T(addstr(" ", 1, &buf, &buflen));
404 /* Name2. */
405 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
407 break;
409 case ns_t_wks: {
410 int n, lcnt;
412 if (rdlen < NS_INT32SZ + 1)
413 goto formerr;
415 /* Address. */
416 (void) inet_ntop(AF_INET, rdata, buf, buflen);
417 addlen(strlen(buf), &buf, &buflen);
418 rdata += NS_INADDRSZ;
420 /* Protocol. */
421 len = SPRINTF((tmp, " %u ( ", *rdata));
422 T(addstr(tmp, len, &buf, &buflen));
423 rdata += NS_INT8SZ;
425 /* Bit map. */
426 n = 0;
427 lcnt = 0;
428 while (rdata < edata) {
429 u_int c = *rdata++;
430 do {
431 if (c & 0200) {
432 if (lcnt == 0) {
433 T(addstr("\n\t\t\t\t", 5,
434 &buf, &buflen));
435 lcnt = 10;
436 spaced = 0;
438 len = SPRINTF((tmp, "%d ", n));
439 T(addstr(tmp, len, &buf, &buflen));
440 lcnt--;
442 c <<= 1;
443 } while (++n & 07);
445 T(addstr(")", 1, &buf, &buflen));
447 break;
450 case ns_t_key: {
451 #ifndef _LIBC
452 char base64_key[NS_MD5RSA_MAX_BASE64];
453 u_int keyflags, protocol, algorithm, key_id;
454 const char *leader;
455 int n;
457 if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
458 goto formerr;
460 /* Key flags, Protocol, Algorithm. */
461 key_id = dst_s_dns_key_id(rdata, edata-rdata);
462 keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
463 protocol = *rdata++;
464 algorithm = *rdata++;
465 len = SPRINTF((tmp, "0x%04x %u %u",
466 keyflags, protocol, algorithm));
467 T(addstr(tmp, len, &buf, &buflen));
469 /* Public key data. */
470 len = b64_ntop(rdata, edata - rdata,
471 base64_key, sizeof base64_key);
472 if (len < 0)
473 goto formerr;
474 if (len > 15) {
475 T(addstr(" (", 2, &buf, &buflen));
476 leader = "\n\t\t";
477 spaced = 0;
478 } else
479 leader = " ";
480 for (n = 0; n < len; n += 48) {
481 T(addstr(leader, strlen(leader), &buf, &buflen));
482 T(addstr(base64_key + n, MIN(len - n, 48),
483 &buf, &buflen));
485 if (len > 15)
486 T(addstr(" )", 2, &buf, &buflen));
487 n = SPRINTF((tmp, " ; key_tag= %u", key_id));
488 T(addstr(tmp, n, &buf, &buflen));
489 #endif /* !_LIBC */
491 break;
494 case ns_t_sig: {
495 #ifndef _LIBC
496 char base64_key[NS_MD5RSA_MAX_BASE64];
497 u_int type, algorithm, labels, footprint;
498 const char *leader;
499 u_long t;
500 int n;
502 if (rdlen < 22)
503 goto formerr;
505 /* Type covered, Algorithm, Label count, Original TTL. */
506 type = ns_get16(rdata); rdata += NS_INT16SZ;
507 algorithm = *rdata++;
508 labels = *rdata++;
509 t = ns_get32(rdata); rdata += NS_INT32SZ;
510 len = SPRINTF((tmp, "%s %d %d %lu ",
511 p_type(type), algorithm, labels, t));
512 T(addstr(tmp, len, &buf, &buflen));
513 if (labels > (u_int)dn_count_labels(name))
514 goto formerr;
516 /* Signature expiry. */
517 t = ns_get32(rdata); rdata += NS_INT32SZ;
518 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
519 T(addstr(tmp, len, &buf, &buflen));
521 /* Time signed. */
522 t = ns_get32(rdata); rdata += NS_INT32SZ;
523 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
524 T(addstr(tmp, len, &buf, &buflen));
526 /* Signature Footprint. */
527 footprint = ns_get16(rdata); rdata += NS_INT16SZ;
528 len = SPRINTF((tmp, "%u ", footprint));
529 T(addstr(tmp, len, &buf, &buflen));
531 /* Signer's name. */
532 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
534 /* Signature. */
535 len = b64_ntop(rdata, edata - rdata,
536 base64_key, sizeof base64_key);
537 if (len > 15) {
538 T(addstr(" (", 2, &buf, &buflen));
539 leader = "\n\t\t";
540 spaced = 0;
541 } else
542 leader = " ";
543 if (len < 0)
544 goto formerr;
545 for (n = 0; n < len; n += 48) {
546 T(addstr(leader, strlen(leader), &buf, &buflen));
547 T(addstr(base64_key + n, MIN(len - n, 48),
548 &buf, &buflen));
550 if (len > 15)
551 T(addstr(" )", 2, &buf, &buflen));
552 #endif /* !_LIBC */
553 break;
556 case ns_t_nxt: {
557 int n, c;
559 /* Next domain name. */
560 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
562 /* Type bit map. */
563 n = edata - rdata;
564 for (c = 0; c < n*8; c++)
565 if (NS_NXT_BIT_ISSET(c, rdata)) {
566 len = SPRINTF((tmp, " %s", p_type(c)));
567 T(addstr(tmp, len, &buf, &buflen));
569 break;
572 case ns_t_cert: {
573 u_int c_type, key_tag, alg;
574 int n, siz;
575 char base64_cert[8192], *leader, tmp[40];
577 c_type = ns_get16(rdata); rdata += NS_INT16SZ;
578 key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
579 alg = (u_int) *rdata++;
581 len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
582 T(addstr(tmp, len, &buf, &buflen));
583 siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
584 if (siz > sizeof(base64_cert) * 3/4) {
585 char *str = "record too long to print";
586 T(addstr(str, strlen(str), &buf, &buflen));
588 else {
589 len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
591 if (len < 0)
592 goto formerr;
593 else if (len > 15) {
594 T(addstr(" (", 2, &buf, &buflen));
595 leader = "\n\t\t";
596 spaced = 0;
598 else
599 leader = " ";
601 for (n = 0; n < len; n += 48) {
602 T(addstr(leader, strlen(leader),
603 &buf, &buflen));
604 T(addstr(base64_cert + n, MIN(len - n, 48),
605 &buf, &buflen));
607 if (len > 15)
608 T(addstr(" )", 2, &buf, &buflen));
610 break;
613 case ns_t_tsig: {
614 /* BEW - need to complete this */
615 int n;
617 T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
618 T(addstr(" ", 1, &buf, &buflen));
619 rdata += 8; /* time */
620 n = ns_get16(rdata); rdata += INT16SZ;
621 rdata += n; /* sig */
622 n = ns_get16(rdata); rdata += INT16SZ; /* original id */
623 sprintf(buf, "%d", ns_get16(rdata));
624 rdata += INT16SZ;
625 addlen(strlen(buf), &buf, &buflen);
626 break;
629 case ns_t_a6: {
630 struct in6_addr a;
631 int pbyte, pbit;
633 /* prefix length */
634 if (rdlen == 0U) goto formerr;
635 len = SPRINTF((tmp, "%d ", *rdata));
636 T(addstr(tmp, len, &buf, &buflen));
637 pbit = *rdata;
638 if (pbit > 128) goto formerr;
639 pbyte = (pbit & ~7) / 8;
640 rdata++;
642 /* address suffix: provided only when prefix len != 128 */
643 if (pbit < 128) {
644 if (rdata + pbyte >= edata) goto formerr;
645 memset(&a, 0, sizeof(a));
646 memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
647 (void) inet_ntop(AF_INET6, &a, buf, buflen);
648 addlen(strlen(buf), &buf, &buflen);
649 rdata += sizeof(a) - pbyte;
652 /* prefix name: provided only when prefix len > 0 */
653 if (pbit == 0)
654 break;
655 if (rdata >= edata) goto formerr;
656 T(addstr(" ", 1, &buf, &buflen));
657 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
659 break;
662 case ns_t_opt: {
663 len = SPRINTF((tmp, "%u bytes", class));
664 T(addstr(tmp, len, &buf, &buflen));
665 break;
668 default:
669 snprintf (errbuf, sizeof (errbuf), "unknown RR type %d", type);
670 comment = errbuf;
671 goto hexify;
673 return (buf - obuf);
674 formerr:
675 comment = "RR format error";
676 hexify: {
677 int n, m;
678 char *p;
680 len = SPRINTF((tmp, "\\#(\t\t; %s", comment));
681 T(addstr(tmp, len, &buf, &buflen));
682 while (rdata < edata) {
683 p = tmp;
684 p += SPRINTF((p, "\n\t"));
685 spaced = 0;
686 n = MIN(16, edata - rdata);
687 for (m = 0; m < n; m++)
688 p += SPRINTF((p, "%02x ", rdata[m]));
689 T(addstr(tmp, p - tmp, &buf, &buflen));
690 if (n < 16) {
691 T(addstr(")", 1, &buf, &buflen));
692 T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
694 p = tmp;
695 p += SPRINTF((p, "; "));
696 for (m = 0; m < n; m++)
697 *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
698 ? rdata[m]
699 : '.';
700 T(addstr(tmp, p - tmp, &buf, &buflen));
701 rdata += n;
703 return (buf - obuf);
707 /* Private. */
710 * size_t
711 * prune_origin(name, origin)
712 * Find out if the name is at or under the current origin.
713 * return:
714 * Number of characters in name before start of origin,
715 * or length of name if origin does not match.
716 * notes:
717 * This function should share code with samedomain().
719 static size_t
720 prune_origin(const char *name, const char *origin) {
721 const char *oname = name;
723 while (*name != '\0') {
724 if (origin != NULL && ns_samename(name, origin) == 1)
725 return (name - oname - (name > oname));
726 while (*name != '\0') {
727 if (*name == '\\') {
728 name++;
729 /* XXX need to handle \nnn form. */
730 if (*name == '\0')
731 break;
732 } else if (*name == '.') {
733 name++;
734 break;
736 name++;
739 return (name - oname);
743 * int
744 * charstr(rdata, edata, buf, buflen)
745 * Format a <character-string> into the presentation buffer.
746 * return:
747 * Number of rdata octets consumed
748 * 0 for protocol format error
749 * -1 for output buffer error
750 * side effects:
751 * buffer is advanced on success.
753 static int
754 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
755 const u_char *odata = rdata;
756 size_t save_buflen = *buflen;
757 char *save_buf = *buf;
759 if (addstr("\"", 1, buf, buflen) < 0)
760 goto enospc;
761 if (rdata < edata) {
762 int n = *rdata;
764 if (rdata + 1 + n <= edata) {
765 rdata++;
766 while (n-- > 0) {
767 if (strchr("\n\"\\", *rdata) != NULL)
768 if (addstr("\\", 1, buf, buflen) < 0)
769 goto enospc;
770 if (addstr((const char *)rdata, 1,
771 buf, buflen) < 0)
772 goto enospc;
773 rdata++;
777 if (addstr("\"", 1, buf, buflen) < 0)
778 goto enospc;
779 return (rdata - odata);
780 enospc:
781 __set_errno (ENOSPC);
782 *buf = save_buf;
783 *buflen = save_buflen;
784 return (-1);
787 static int
788 addname(const u_char *msg, size_t msglen,
789 const u_char **pp, const char *origin,
790 char **buf, size_t *buflen)
792 size_t newlen, save_buflen = *buflen;
793 char *save_buf = *buf;
794 int n;
796 n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
797 if (n < 0)
798 goto enospc; /* Guess. */
799 newlen = prune_origin(*buf, origin);
800 if (newlen == 0) {
801 /* Use "@" instead of name. */
802 if (newlen + 2 > *buflen)
803 goto enospc; /* No room for "@\0". */
804 (*buf)[newlen++] = '@';
805 (*buf)[newlen] = '\0';
806 } else {
807 if (((origin == NULL || origin[0] == '\0') ||
808 (origin[0] != '.' && origin[1] != '\0' &&
809 (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
810 /* No trailing dot. */
811 if (newlen + 2 > *buflen)
812 goto enospc; /* No room for ".\0". */
813 (*buf)[newlen++] = '.';
814 (*buf)[newlen] = '\0';
817 *pp += n;
818 addlen(newlen, buf, buflen);
819 **buf = '\0';
820 return (newlen);
821 enospc:
822 __set_errno (ENOSPC);
823 *buf = save_buf;
824 *buflen = save_buflen;
825 return (-1);
828 static void
829 addlen(size_t len, char **buf, size_t *buflen) {
830 assert(len <= *buflen);
831 *buf += len;
832 *buflen -= len;
835 static int
836 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
837 if (len >= *buflen) {
838 __set_errno (ENOSPC);
839 return (-1);
841 memcpy(*buf, src, len);
842 addlen(len, buf, buflen);
843 **buf = '\0';
844 return (0);
847 static int
848 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
849 size_t save_buflen = *buflen;
850 char *save_buf = *buf;
851 int t;
853 if (spaced || len >= target - 1) {
854 T(addstr(" ", 2, buf, buflen));
855 spaced = 1;
856 } else {
857 for (t = (target - len - 1) / 8; t >= 0; t--)
858 if (addstr("\t", 1, buf, buflen) < 0) {
859 *buflen = save_buflen;
860 *buf = save_buf;
861 return (-1);
863 spaced = 0;
865 return (spaced);