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