Home | History | Annotate | Download | only in nameser
      1 /*	$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 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.12 2009/03/03 05:29:58 each Exp";
     24 #else
     25 __RCSID("$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 christos Exp $");
     26 #endif
     27 #endif
     28 
     29 /* Import. */
     30 
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 
     34 #include <netinet/in.h>
     35 #include <arpa/nameser.h>
     36 #include <arpa/inet.h>
     37 
     38 #include <isc/assertions.h>
     39 #include <isc/dst.h>
     40 #include <assert.h>
     41 #include <errno.h>
     42 #ifdef ANDROID_CHANGES
     43 #include "resolv_private.h"
     44 #else
     45 #include <resolv.h>
     46 #endif
     47 #include <stddef.h>
     48 #include <string.h>
     49 #include <ctype.h>
     50 
     51 #ifdef SPRINTF_CHAR
     52 # define SPRINTF(x) ((int)strlen(sprintf/**/x))
     53 #else
     54 # define SPRINTF(x) (sprintf x)
     55 #endif
     56 
     57 #ifndef MIN
     58 #define	MIN(x,y)	((x)<(y)?(x):(y))
     59 #endif
     60 
     61 /* Forward. */
     62 
     63 static size_t	prune_origin(const char *name, const char *origin);
     64 static int	charstr(const u_char *rdata, const u_char *edata,
     65 			char **buf, size_t *buflen);
     66 static int	addname(const u_char *msg, size_t msglen,
     67 			const u_char **p, const char *origin,
     68 			char **buf, size_t *buflen);
     69 static void	addlen(size_t len, char **buf, size_t *buflen);
     70 static int	addstr(const char *src, size_t len,
     71 		       char **buf, size_t *buflen);
     72 static int	addtab(size_t len, size_t target, int spaced,
     73 		       char **buf, size_t *buflen);
     74 
     75 /* Macros. */
     76 
     77 #define	T(x) \
     78 	do { \
     79 		if ((x) < 0) \
     80 			return (-1); \
     81 	} while (/*CONSTCOND*/0)
     82 
     83 static const char base32hex[] =
     84         "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
     85 /* Public. */
     86 
     87 /*
     88  *	Convert an RR to presentation format.
     89  *
     90  * return:
     91  *	Number of characters written to buf, or -1 (check errno).
     92  */
     93 int
     94 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
     95 	    const char *name_ctx, const char *origin,
     96 	    char *buf, size_t buflen)
     97 {
     98 	int n;
     99 
    100 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
    101 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
    102 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
    103 			 name_ctx, origin, buf, buflen);
    104 	return (n);
    105 }
    106 
    107 /*
    108  *	Convert the fields of an RR into presentation format.
    109  *
    110  * return:
    111  *	Number of characters written to buf, or -1 (check errno).
    112  */
    113 int
    114 ns_sprintrrf(const u_char *msg, size_t msglen,
    115 	    const char *name, ns_class class, ns_type type,
    116 	    u_long ttl, const u_char *rdata, size_t rdlen,
    117 	    const char *name_ctx, const char *origin,
    118 	    char *buf, size_t buflen)
    119 {
    120 	const char *obuf = buf;
    121 	const u_char *edata = rdata + rdlen;
    122 	int spaced = 0;
    123 
    124 	const char *comment;
    125 	char tmp[100];
    126 	int len, x;
    127 
    128 	/*
    129 	 * Owner.
    130 	 */
    131 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
    132 		T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
    133 	} else {
    134 		len = (int)prune_origin(name, origin);
    135 		if (*name == '\0') {
    136 			goto root;
    137 		} else if (len == 0) {
    138 			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
    139 		} else {
    140 			T(addstr(name, (size_t)len, &buf, &buflen));
    141 			/* Origin not used or not root, and no trailing dot? */
    142 			if (((origin == NULL || origin[0] == '\0') ||
    143 			    (origin[0] != '.' && origin[1] != '\0' &&
    144 			    name[len] == '\0')) && name[len - 1] != '.') {
    145  root:
    146 				T(addstr(".", (size_t)1, &buf, &buflen));
    147 				len++;
    148 			}
    149 			T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
    150 		}
    151 	}
    152 
    153 	/*
    154 	 * TTL, Class, Type.
    155 	 */
    156 	T(x = ns_format_ttl(ttl, buf, buflen));
    157 	addlen((size_t)x, &buf, &buflen);
    158 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
    159 	T(addstr(tmp, (size_t)len, &buf, &buflen));
    160 	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
    161 
    162 	/*
    163 	 * RData.
    164 	 */
    165 	switch (type) {
    166 	case ns_t_a:
    167 		if (rdlen != (size_t)NS_INADDRSZ)
    168 			goto formerr;
    169 		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
    170 		addlen(strlen(buf), &buf, &buflen);
    171 		break;
    172 
    173 	case ns_t_cname:
    174 	case ns_t_mb:
    175 	case ns_t_mg:
    176 	case ns_t_mr:
    177 	case ns_t_ns:
    178 	case ns_t_ptr:
    179 	case ns_t_dname:
    180 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    181 		break;
    182 
    183 	case ns_t_hinfo:
    184 	case ns_t_isdn:
    185 		/* First word. */
    186 		T(len = charstr(rdata, edata, &buf, &buflen));
    187 		if (len == 0)
    188 			goto formerr;
    189 		rdata += len;
    190 		T(addstr(" ", (size_t)1, &buf, &buflen));
    191 
    192 
    193 		/* Second word, optional in ISDN records. */
    194 		if (type == ns_t_isdn && rdata == edata)
    195 			break;
    196 
    197 		T(len = charstr(rdata, edata, &buf, &buflen));
    198 		if (len == 0)
    199 			goto formerr;
    200 		rdata += len;
    201 		break;
    202 
    203 	case ns_t_soa: {
    204 		u_long t;
    205 
    206 		/* Server name. */
    207 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    208 		T(addstr(" ", (size_t)1, &buf, &buflen));
    209 
    210 		/* Administrator name. */
    211 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    212 		T(addstr(" (\n", (size_t)3, &buf, &buflen));
    213 		spaced = 0;
    214 
    215 		if ((edata - rdata) != 5*NS_INT32SZ)
    216 			goto formerr;
    217 
    218 		/* Serial number. */
    219 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    220 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    221 		len = SPRINTF((tmp, "%lu", t));
    222 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    223 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    224 		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
    225 		spaced = 0;
    226 
    227 		/* Refresh interval. */
    228 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    229 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    230 		T(len = ns_format_ttl(t, buf, buflen));
    231 		addlen((size_t)len, &buf, &buflen);
    232 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    233 		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
    234 		spaced = 0;
    235 
    236 		/* Retry interval. */
    237 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    238 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    239 		T(len = ns_format_ttl(t, buf, buflen));
    240 		addlen((size_t)len, &buf, &buflen);
    241 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    242 		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
    243 		spaced = 0;
    244 
    245 		/* Expiry. */
    246 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    247 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    248 		T(len = ns_format_ttl(t, buf, buflen));
    249 		addlen((size_t)len, &buf, &buflen);
    250 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    251 		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
    252 		spaced = 0;
    253 
    254 		/* Minimum TTL. */
    255 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    256 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    257 		T(len = ns_format_ttl(t, buf, buflen));
    258 		addlen((size_t)len, &buf, &buflen);
    259 		T(addstr(" )", (size_t)2, &buf, &buflen));
    260 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    261 		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
    262 
    263 		break;
    264 	    }
    265 
    266 	case ns_t_mx:
    267 	case ns_t_afsdb:
    268 	case ns_t_rt:
    269 	case ns_t_kx: {
    270 		u_int t;
    271 
    272 		if (rdlen < (size_t)NS_INT16SZ)
    273 			goto formerr;
    274 
    275 		/* Priority. */
    276 		t = ns_get16(rdata);
    277 		rdata += NS_INT16SZ;
    278 		len = SPRINTF((tmp, "%u ", t));
    279 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    280 
    281 		/* Target. */
    282 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    283 
    284 		break;
    285 	    }
    286 
    287 	case ns_t_px: {
    288 		u_int t;
    289 
    290 		if (rdlen < (size_t)NS_INT16SZ)
    291 			goto formerr;
    292 
    293 		/* Priority. */
    294 		t = ns_get16(rdata);
    295 		rdata += NS_INT16SZ;
    296 		len = SPRINTF((tmp, "%u ", t));
    297 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    298 
    299 		/* Name1. */
    300 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    301 		T(addstr(" ", (size_t)1, &buf, &buflen));
    302 
    303 		/* Name2. */
    304 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    305 
    306 		break;
    307 	    }
    308 
    309 	case ns_t_x25:
    310 		T(len = charstr(rdata, edata, &buf, &buflen));
    311 		if (len == 0)
    312 			goto formerr;
    313 		rdata += len;
    314 		break;
    315 
    316 	case ns_t_txt:
    317 	case ns_t_spf:
    318 		while (rdata < edata) {
    319 			T(len = charstr(rdata, edata, &buf, &buflen));
    320 			if (len == 0)
    321 				goto formerr;
    322 			rdata += len;
    323 			if (rdata < edata)
    324 				T(addstr(" ", (size_t)1, &buf, &buflen));
    325 		}
    326 		break;
    327 
    328 	case ns_t_nsap: {
    329 		char t[2+255*3];
    330 
    331 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
    332 		T(addstr(t, strlen(t), &buf, &buflen));
    333 		break;
    334 	    }
    335 
    336 	case ns_t_aaaa:
    337 		if (rdlen != (size_t)NS_IN6ADDRSZ)
    338 			goto formerr;
    339 		(void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
    340 		addlen(strlen(buf), &buf, &buflen);
    341 		break;
    342 
    343 	case ns_t_loc: {
    344 		char t[255];
    345 
    346 		/* XXX protocol format checking? */
    347 		(void) loc_ntoa(rdata, t);
    348 		T(addstr(t, strlen(t), &buf, &buflen));
    349 		break;
    350 	    }
    351 
    352 	case ns_t_naptr: {
    353 		u_int order, preference;
    354 		char t[50];
    355 
    356 		if (rdlen < 2U*NS_INT16SZ)
    357 			goto formerr;
    358 
    359 		/* Order, Precedence. */
    360 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
    361 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
    362 		len = SPRINTF((t, "%u %u ", order, preference));
    363 		T(addstr(t, (size_t)len, &buf, &buflen));
    364 
    365 		/* Flags. */
    366 		T(len = charstr(rdata, edata, &buf, &buflen));
    367 		if (len == 0)
    368 			goto formerr;
    369 		rdata += len;
    370 		T(addstr(" ", (size_t)1, &buf, &buflen));
    371 
    372 		/* Service. */
    373 		T(len = charstr(rdata, edata, &buf, &buflen));
    374 		if (len == 0)
    375 			goto formerr;
    376 		rdata += len;
    377 		T(addstr(" ", (size_t)1, &buf, &buflen));
    378 
    379 		/* Regexp. */
    380 		T(len = charstr(rdata, edata, &buf, &buflen));
    381 		if (len < 0)
    382 			return (-1);
    383 		if (len == 0)
    384 			goto formerr;
    385 		rdata += len;
    386 		T(addstr(" ", (size_t)1, &buf, &buflen));
    387 
    388 		/* Server. */
    389 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    390 		break;
    391 	    }
    392 
    393 	case ns_t_srv: {
    394 		u_int priority, weight, port;
    395 		char t[50];
    396 
    397 		if (rdlen < 3U*NS_INT16SZ)
    398 			goto formerr;
    399 
    400 		/* Priority, Weight, Port. */
    401 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
    402 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
    403 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
    404 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
    405 		T(addstr(t, (size_t)len, &buf, &buflen));
    406 
    407 		/* Server. */
    408 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    409 		break;
    410 	    }
    411 
    412 	case ns_t_minfo:
    413 	case ns_t_rp:
    414 		/* Name1. */
    415 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    416 		T(addstr(" ", (size_t)1, &buf, &buflen));
    417 
    418 		/* Name2. */
    419 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    420 
    421 		break;
    422 
    423 	case ns_t_wks: {
    424 		int n, lcnt;
    425 
    426 		if (rdlen < 1U + NS_INT32SZ)
    427 			goto formerr;
    428 
    429 		/* Address. */
    430 		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
    431 		addlen(strlen(buf), &buf, &buflen);
    432 		rdata += NS_INADDRSZ;
    433 
    434 		/* Protocol. */
    435 		len = SPRINTF((tmp, " %u ( ", *rdata));
    436 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    437 		rdata += NS_INT8SZ;
    438 
    439 		/* Bit map. */
    440 		n = 0;
    441 		lcnt = 0;
    442 		while (rdata < edata) {
    443 			u_int c = *rdata++;
    444 			do {
    445 				if (c & 0200) {
    446 					if (lcnt == 0) {
    447 						T(addstr("\n\t\t\t\t", (size_t)5,
    448 							 &buf, &buflen));
    449 						lcnt = 10;
    450 						spaced = 0;
    451 					}
    452 					len = SPRINTF((tmp, "%d ", n));
    453 					T(addstr(tmp, (size_t)len, &buf, &buflen));
    454 					lcnt--;
    455 				}
    456 				c <<= 1;
    457 			} while (++n & 07);
    458 		}
    459 		T(addstr(")", (size_t)1, &buf, &buflen));
    460 
    461 		break;
    462 	    }
    463 
    464 	case ns_t_key:
    465 	case ns_t_dnskey: {
    466 		char base64_key[NS_MD5RSA_MAX_BASE64];
    467 		u_int keyflags, protocol, algorithm, key_id;
    468 		const char *leader;
    469 		int n;
    470 
    471 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
    472 			goto formerr;
    473 
    474 		/* Key flags, Protocol, Algorithm. */
    475 #ifndef _LIBC
    476 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
    477 #else
    478 		key_id = 0;
    479 #endif
    480 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
    481 		protocol = *rdata++;
    482 		algorithm = *rdata++;
    483 		len = SPRINTF((tmp, "0x%04x %u %u",
    484 			       keyflags, protocol, algorithm));
    485 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    486 
    487 		/* Public key data. */
    488 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    489 			       base64_key, sizeof base64_key);
    490 		if (len < 0)
    491 			goto formerr;
    492 		if (len > 15) {
    493 			T(addstr(" (", (size_t)2, &buf, &buflen));
    494 			leader = "\n\t\t";
    495 			spaced = 0;
    496 		} else
    497 			leader = " ";
    498 		for (n = 0; n < len; n += 48) {
    499 			T(addstr(leader, strlen(leader), &buf, &buflen));
    500 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    501 				 &buf, &buflen));
    502 		}
    503 		if (len > 15)
    504 			T(addstr(" )", (size_t)2, &buf, &buflen));
    505 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
    506 		T(addstr(tmp, (size_t)n, &buf, &buflen));
    507 
    508 		break;
    509 	    }
    510 
    511 	case ns_t_sig:
    512 	case ns_t_rrsig: {
    513 		char base64_key[NS_MD5RSA_MAX_BASE64];
    514 		u_int typ, algorithm, labels, footprint;
    515 		const char *leader;
    516 		u_long t;
    517 		int n;
    518 
    519 		if (rdlen < 22U)
    520 			goto formerr;
    521 
    522 		/* Type covered, Algorithm, Label count, Original TTL. */
    523 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
    524 		algorithm = *rdata++;
    525 		labels = *rdata++;
    526 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    527 		len = SPRINTF((tmp, "%s %d %d %lu ",
    528 			       p_type((int)typ), algorithm, labels, t));
    529 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    530 		if (labels > (u_int)dn_count_labels(name))
    531 			goto formerr;
    532 
    533 		/* Signature expiry. */
    534 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    535 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    536 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    537 
    538 		/* Time signed. */
    539 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    540 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    541 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    542 
    543 		/* Signature Footprint. */
    544 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
    545 		len = SPRINTF((tmp, "%u ", footprint));
    546 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    547 
    548 		/* Signer's name. */
    549 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    550 
    551 		/* Signature. */
    552 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    553 			       base64_key, sizeof base64_key);
    554 		if (len > 15) {
    555 			T(addstr(" (", (size_t)2, &buf, &buflen));
    556 			leader = "\n\t\t";
    557 			spaced = 0;
    558 		} else
    559 			leader = " ";
    560 		if (len < 0)
    561 			goto formerr;
    562 		for (n = 0; n < len; n += 48) {
    563 			T(addstr(leader, strlen(leader), &buf, &buflen));
    564 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    565 				 &buf, &buflen));
    566 		}
    567 		if (len > 15)
    568 			T(addstr(" )", (size_t)2, &buf, &buflen));
    569 		break;
    570 	    }
    571 
    572 	case ns_t_nxt: {
    573 		ptrdiff_t n, c;
    574 
    575 		/* Next domain name. */
    576 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    577 
    578 		/* Type bit map. */
    579 		n = edata - rdata;
    580 		for (c = 0; c < n*8; c++)
    581 			if (NS_NXT_BIT_ISSET(c, rdata)) {
    582 				len = SPRINTF((tmp, " %s", p_type((int)c)));
    583 				T(addstr(tmp, (size_t)len, &buf, &buflen));
    584 			}
    585 		break;
    586 	    }
    587 
    588 	case ns_t_cert: {
    589 		u_int c_type, key_tag, alg;
    590 		int n;
    591 		size_t siz;
    592 		char base64_cert[8192], tmp1[40];
    593 		const char *leader;
    594 
    595 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
    596 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
    597 		alg = (u_int) *rdata++;
    598 
    599 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
    600 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
    601 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    602 		if (siz > sizeof(base64_cert) * 3/4) {
    603 			const char *str = "record too long to print";
    604 			T(addstr(str, strlen(str), &buf, &buflen));
    605 		}
    606 		else {
    607 			len = b64_ntop(rdata, (size_t)(edata-rdata),
    608 			    base64_cert, siz);
    609 
    610 			if (len < 0)
    611 				goto formerr;
    612 			else if (len > 15) {
    613 				T(addstr(" (", (size_t)2, &buf, &buflen));
    614 				leader = "\n\t\t";
    615 				spaced = 0;
    616 			}
    617 			else
    618 				leader = " ";
    619 
    620 			for (n = 0; n < len; n += 48) {
    621 				T(addstr(leader, strlen(leader),
    622 					 &buf, &buflen));
    623 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
    624 					 &buf, &buflen));
    625 			}
    626 			if (len > 15)
    627 				T(addstr(" )", (size_t)2, &buf, &buflen));
    628 		}
    629 		break;
    630 	    }
    631 
    632 	case ns_t_tkey: {
    633 		/* KJD - need to complete this */
    634 		u_long t;
    635 		int mode, err, keysize;
    636 
    637 		/* Algorithm name. */
    638 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    639 		T(addstr(" ", (size_t)1, &buf, &buflen));
    640 
    641 		/* Inception. */
    642 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    643 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    644 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    645 
    646 		/* Experation. */
    647 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    648 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    649 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    650 
    651 		/* Mode , Error, Key Size. */
    652 		/* Priority, Weight, Port. */
    653 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
    654 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
    655 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
    656 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
    657 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    658 
    659 		/* XXX need to dump key, print otherdata length & other data */
    660 		break;
    661 	    }
    662 
    663 	case ns_t_tsig: {
    664 		/* BEW - need to complete this */
    665 		int n;
    666 
    667 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
    668 		T(addstr(" ", (size_t)1, &buf, &buflen));
    669 		rdata += 8; /* time */
    670 		n = ns_get16(rdata); rdata += INT16SZ;
    671 		rdata += n; /* sig */
    672 		n = ns_get16(rdata); rdata += INT16SZ; /* original id */
    673 		sprintf(buf, "%d", ns_get16(rdata));
    674 		rdata += INT16SZ;
    675 		addlen(strlen(buf), &buf, &buflen);
    676 		break;
    677 	    }
    678 
    679 	case ns_t_a6: {
    680 		struct in6_addr a;
    681 		int pbyte, pbit;
    682 
    683 		/* prefix length */
    684 		if (rdlen == 0U) goto formerr;
    685 		len = SPRINTF((tmp, "%d ", *rdata));
    686 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    687 		pbit = *rdata;
    688 		if (pbit > 128) goto formerr;
    689 		pbyte = (pbit & ~7) / 8;
    690 		rdata++;
    691 
    692 		/* address suffix: provided only when prefix len != 128 */
    693 		if (pbit < 128) {
    694 			if (rdata + pbyte >= edata) goto formerr;
    695 			memset(&a, 0, sizeof(a));
    696 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
    697 			(void) inet_ntop(AF_INET6, &a, buf, (socklen_t)buflen);
    698 			addlen(strlen(buf), &buf, &buflen);
    699 			rdata += sizeof(a) - pbyte;
    700 		}
    701 
    702 		/* prefix name: provided only when prefix len > 0 */
    703 		if (pbit == 0)
    704 			break;
    705 		if (rdata >= edata) goto formerr;
    706 		T(addstr(" ", (size_t)1, &buf, &buflen));
    707 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    708 
    709 		break;
    710 	    }
    711 
    712 	case ns_t_opt: {
    713 		len = SPRINTF((tmp, "%u bytes", class));
    714 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    715 		break;
    716 	    }
    717 
    718 	case ns_t_ds:
    719 	case ns_t_dlv:
    720 	case ns_t_sshfp: {
    721 		u_int t;
    722 
    723 		if (type == ns_t_ds || type == ns_t_dlv) {
    724 			if (rdlen < 4U) goto formerr;
    725 			t = ns_get16(rdata);
    726 			rdata += NS_INT16SZ;
    727 			len = SPRINTF((tmp, "%u ", t));
    728 			T(addstr(tmp, (size_t)len, &buf, &buflen));
    729 		} else
    730 			if (rdlen < 2U) goto formerr;
    731 
    732 		len = SPRINTF((tmp, "%u ", *rdata));
    733 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    734 		rdata++;
    735 
    736 		len = SPRINTF((tmp, "%u ", *rdata));
    737 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    738 		rdata++;
    739 
    740 		while (rdata < edata) {
    741 			len = SPRINTF((tmp, "%02X", *rdata));
    742 			T(addstr(tmp, (size_t)len, &buf, &buflen));
    743 			rdata++;
    744 		}
    745 		break;
    746 	    }
    747 
    748 	case ns_t_nsec3:
    749 	case ns_t_nsec3param: {
    750 		u_int t, w, l, j, k, c;
    751 
    752 		len = SPRINTF((tmp, "%u ", *rdata));
    753 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    754 		rdata++;
    755 
    756 		len = SPRINTF((tmp, "%u ", *rdata));
    757 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    758 		rdata++;
    759 
    760 		t = ns_get16(rdata);
    761 		rdata += NS_INT16SZ;
    762 		len = SPRINTF((tmp, "%u ", t));
    763 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    764 
    765 		t = *rdata++;
    766 		if (t == 0) {
    767 			T(addstr("-", 1, &buf, &buflen));
    768 		} else {
    769 			while (t-- > 0) {
    770 				len = SPRINTF((tmp, "%02X", *rdata));
    771 				T(addstr(tmp, (size_t)len, &buf, &buflen));
    772 				rdata++;
    773 			}
    774 		}
    775 		if (type == ns_t_nsec3param)
    776 			break;
    777 		T(addstr(" ", 1, &buf, &buflen));
    778 
    779 		t = *rdata++;
    780 		while (t > 0) {
    781 			switch (t) {
    782 			case 1:
    783 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
    784 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)];
    785 				tmp[2] = tmp[3] = tmp[4] = '=';
    786 				tmp[5] = tmp[6] = tmp[7] = '=';
    787 				break;
    788 			case 2:
    789 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
    790 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
    791 						   (((uint32_t)rdata[1]>>6)&0x03)];
    792 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
    793 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)];
    794 				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
    795 				break;
    796 			case 3:
    797 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
    798 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
    799 						   (((uint32_t)rdata[1]>>6)&0x03)];
    800 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
    801 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
    802 						   (((uint32_t)rdata[2]>>4)&0x0f)];
    803 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)];
    804 				tmp[5] = tmp[6] = tmp[7] = '=';
    805 				break;
    806 			case 4:
    807 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
    808 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
    809 						   (((uint32_t)rdata[1]>>6)&0x03)];
    810 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
    811 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
    812 						   (((uint32_t)rdata[2]>>4)&0x0f)];
    813 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
    814 						   (((uint32_t)rdata[3]>>7)&0x01)];
    815 				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
    816 				tmp[6] = base32hex[((uint32_t)rdata[3]<<3)&0x18];
    817 				tmp[7] = '=';
    818 				break;
    819 			default:
    820 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
    821 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
    822 						   (((uint32_t)rdata[1]>>6)&0x03)];
    823 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
    824 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
    825 						   (((uint32_t)rdata[2]>>4)&0x0f)];
    826 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
    827 						   (((uint32_t)rdata[3]>>7)&0x01)];
    828 				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
    829 				tmp[6] = base32hex[(((uint32_t)rdata[3]<<3)&0x18)|
    830 						   (((uint32_t)rdata[4]>>5)&0x07)];
    831 				tmp[7] = base32hex[(rdata[4]&0x1f)];
    832 				break;
    833 			}
    834 			T(addstr(tmp, 8, &buf, &buflen));
    835 			if (t >= 5) {
    836 				rdata += 5;
    837 				t -= 5;
    838 			} else {
    839 				rdata += t;
    840 				t -= t;
    841 			}
    842 		}
    843 
    844 		while (rdata < edata) {
    845 			w = *rdata++;
    846 			l = *rdata++;
    847 			for (j = 0; j < l; j++) {
    848 				if (rdata[j] == 0)
    849 					continue;
    850 				for (k = 0; k < 8; k++) {
    851 					if ((rdata[j] & (0x80 >> k)) == 0)
    852 						continue;
    853 					c = w * 256 + j * 8 + k;
    854 					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
    855 					T(addstr(tmp, (size_t)len, &buf, &buflen));
    856 				}
    857 			}
    858 			rdata += l;
    859 		}
    860 		break;
    861 	    }
    862 
    863 	case ns_t_nsec: {
    864 		u_int w, l, j, k, c;
    865 
    866 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    867 
    868 		while (rdata < edata) {
    869 			w = *rdata++;
    870 			l = *rdata++;
    871 			for (j = 0; j < l; j++) {
    872 				if (rdata[j] == 0)
    873 					continue;
    874 				for (k = 0; k < 8; k++) {
    875 					if ((rdata[j] & (0x80 >> k)) == 0)
    876 						continue;
    877 					c = w * 256 + j * 8 + k;
    878 					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
    879 					T(addstr(tmp, (size_t)len, &buf, &buflen));
    880 				}
    881 			}
    882 			rdata += l;
    883 		}
    884 		break;
    885 	    }
    886 
    887 	case ns_t_dhcid: {
    888 		int n;
    889 		unsigned int siz;
    890 		char base64_dhcid[8192];
    891 		const char *leader;
    892 
    893 		siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    894 		if (siz > sizeof(base64_dhcid) * 3/4) {
    895 			const char *str = "record too long to print";
    896 			T(addstr(str, strlen(str), &buf, &buflen));
    897 		} else {
    898 			len = b64_ntop(rdata, (size_t)(edata-rdata),
    899 			    base64_dhcid, siz);
    900 
    901 			if (len < 0)
    902 				goto formerr;
    903 
    904 			else if (len > 15) {
    905 				T(addstr(" (", 2, &buf, &buflen));
    906 				leader = "\n\t\t";
    907 				spaced = 0;
    908 			}
    909 			else
    910 				leader = " ";
    911 
    912 			for (n = 0; n < len; n += 48) {
    913 				T(addstr(leader, strlen(leader),
    914 					 &buf, &buflen));
    915 				T(addstr(base64_dhcid + n,
    916 				    (size_t)MIN(len - n, 48), &buf, &buflen));
    917 			}
    918 			if (len > 15)
    919 				T(addstr(" )", 2, &buf, &buflen));
    920 		}
    921 		break;
    922 	}
    923 
    924 	case ns_t_ipseckey: {
    925 		int n;
    926 		unsigned int siz;
    927 		char base64_key[8192];
    928 		const char *leader;
    929 
    930 		if (rdlen < 2)
    931 			goto formerr;
    932 
    933 		switch (rdata[1]) {
    934 		case 0:
    935 		case 3:
    936 			if (rdlen < 3)
    937 				goto formerr;
    938 			break;
    939 		case 1:
    940 			if (rdlen < 7)
    941 				goto formerr;
    942 			break;
    943 		case 2:
    944 			if (rdlen < 19)
    945 				goto formerr;
    946 			break;
    947 		default:
    948 			comment = "unknown IPSECKEY gateway type";
    949 			goto hexify;
    950 		}
    951 
    952 		len = SPRINTF((tmp, "%u ", *rdata));
    953 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    954 		rdata++;
    955 
    956 		len = SPRINTF((tmp, "%u ", *rdata));
    957 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    958 		rdata++;
    959 
    960 		len = SPRINTF((tmp, "%u ", *rdata));
    961 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    962 		rdata++;
    963 
    964 		switch (rdata[-2]) {
    965 		case 0:
    966 			T(addstr(".", 1, &buf, &buflen));
    967 			break;
    968 		case 1:
    969 			(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
    970 			addlen(strlen(buf), &buf, &buflen);
    971 			rdata += 4;
    972 			break;
    973 		case 2:
    974 			(void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
    975 			addlen(strlen(buf), &buf, &buflen);
    976 			rdata += 16;
    977 			break;
    978 		case 3:
    979 			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    980 			break;
    981 		}
    982 
    983 		if (rdata >= edata)
    984 			break;
    985 
    986 		siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    987 		if (siz > sizeof(base64_key) * 3/4) {
    988 			const char *str = "record too long to print";
    989 			T(addstr(str, strlen(str), &buf, &buflen));
    990 		} else {
    991 			len = b64_ntop(rdata, (size_t)(edata-rdata),
    992 			    base64_key, siz);
    993 
    994 			if (len < 0)
    995 				goto formerr;
    996 
    997 			else if (len > 15) {
    998 				T(addstr(" (", 2, &buf, &buflen));
    999 				leader = "\n\t\t";
   1000 				spaced = 0;
   1001 			}
   1002 			else
   1003 				leader = " ";
   1004 
   1005 			for (n = 0; n < len; n += 48) {
   1006 				T(addstr(leader, strlen(leader),
   1007 					 &buf, &buflen));
   1008 				T(addstr(base64_key + n,
   1009 				    (size_t)MIN(len - n, 48), &buf, &buflen));
   1010 			}
   1011 			if (len > 15)
   1012 				T(addstr(" )", 2, &buf, &buflen));
   1013 		}
   1014 		break;
   1015 	}
   1016 
   1017 	case ns_t_hip: {
   1018 		unsigned int i, hip_len, algorithm, key_len;
   1019 		char base64_key[NS_MD5RSA_MAX_BASE64];
   1020 		unsigned int siz;
   1021 		const char *leader = "\n\t\t\t\t\t";
   1022 
   1023 		hip_len = *rdata++;
   1024 		algorithm = *rdata++;
   1025 		key_len = ns_get16(rdata);
   1026 		rdata += NS_INT16SZ;
   1027 
   1028 		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
   1029 		if (siz > sizeof(base64_key) * 3/4) {
   1030 			const char *str = "record too long to print";
   1031 			T(addstr(str, strlen(str), &buf, &buflen));
   1032 		} else {
   1033 			len = sprintf(tmp, "( %u ", algorithm);
   1034 			T(addstr(tmp, (size_t)len, &buf, &buflen));
   1035 
   1036 			for (i = 0; i < hip_len; i++) {
   1037 				len = sprintf(tmp, "%02X", *rdata);
   1038 				T(addstr(tmp, (size_t)len, &buf, &buflen));
   1039 				rdata++;
   1040 			}
   1041 			T(addstr(leader, strlen(leader), &buf, &buflen));
   1042 
   1043 			len = b64_ntop(rdata, key_len, base64_key, siz);
   1044 			if (len < 0)
   1045 				goto formerr;
   1046 
   1047 			T(addstr(base64_key, (size_t)len, &buf, &buflen));
   1048 
   1049 			rdata += key_len;
   1050 			while (rdata < edata) {
   1051 				T(addstr(leader, strlen(leader), &buf, &buflen));
   1052 				T(addname(msg, msglen, &rdata, origin,
   1053 					  &buf, &buflen));
   1054 			}
   1055 			T(addstr(" )", 2, &buf, &buflen));
   1056 		}
   1057 		break;
   1058 	    }
   1059 
   1060 	default:
   1061 		comment = "unknown RR type";
   1062 		goto hexify;
   1063 	}
   1064 	_DIAGASSERT(__type_fit(int, buf - obuf));
   1065 	return (int)(buf - obuf);
   1066  formerr:
   1067 	comment = "RR format error";
   1068  hexify: {
   1069 	int n, m;
   1070 	char *p;
   1071 
   1072 	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
   1073 		       rdlen != 0U ? " (" : "", comment));
   1074 	T(addstr(tmp, (size_t)len, &buf, &buflen));
   1075 	while (rdata < edata) {
   1076 		p = tmp;
   1077 		p += SPRINTF((p, "\n\t"));
   1078 		spaced = 0;
   1079 		n = MIN(16, (int)(edata - rdata));
   1080 		for (m = 0; m < n; m++)
   1081 			p += SPRINTF((p, "%02x ", rdata[m]));
   1082 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
   1083 		if (n < 16) {
   1084 			T(addstr(")", (size_t)1, &buf, &buflen));
   1085 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
   1086 		}
   1087 		p = tmp;
   1088 		p += SPRINTF((p, "; "));
   1089 		for (m = 0; m < n; m++)
   1090 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
   1091 				? rdata[m]
   1092 				: '.';
   1093 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
   1094 		rdata += n;
   1095 	}
   1096 	_DIAGASSERT(__type_fit(int, buf - obuf));
   1097 	return (int)(buf - obuf);
   1098     }
   1099 }
   1100 
   1101 /* Private. */
   1102 
   1103 /*
   1104  * size_t
   1105  * prune_origin(name, origin)
   1106  *	Find out if the name is at or under the current origin.
   1107  * return:
   1108  *	Number of characters in name before start of origin,
   1109  *	or length of name if origin does not match.
   1110  * notes:
   1111  *	This function should share code with samedomain().
   1112  */
   1113 static size_t
   1114 prune_origin(const char *name, const char *origin) {
   1115 	const char *oname = name;
   1116 
   1117 	while (*name != '\0') {
   1118 		if (origin != NULL && ns_samename(name, origin) == 1)
   1119 			return (name - oname - (name > oname));
   1120 		while (*name != '\0') {
   1121 			if (*name == '\\') {
   1122 				name++;
   1123 				/* XXX need to handle \nnn form. */
   1124 				if (*name == '\0')
   1125 					break;
   1126 			} else if (*name == '.') {
   1127 				name++;
   1128 				break;
   1129 			}
   1130 			name++;
   1131 		}
   1132 	}
   1133 	return (name - oname);
   1134 }
   1135 
   1136 /*
   1137  * int
   1138  * charstr(rdata, edata, buf, buflen)
   1139  *	Format a <character-string> into the presentation buffer.
   1140  * return:
   1141  *	Number of rdata octets consumed
   1142  *	0 for protocol format error
   1143  *	-1 for output buffer error
   1144  * side effects:
   1145  *	buffer is advanced on success.
   1146  */
   1147 static int
   1148 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
   1149 	const u_char *odata = rdata;
   1150 	size_t save_buflen = *buflen;
   1151 	char *save_buf = *buf;
   1152 
   1153 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
   1154 		goto enospc;
   1155 	if (rdata < edata) {
   1156 		int n = *rdata;
   1157 
   1158 		if (rdata + 1 + n <= edata) {
   1159 			rdata++;
   1160 			while (n-- > 0) {
   1161 				if (strchr("\n\"\\", *rdata) != NULL)
   1162 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
   1163 						goto enospc;
   1164 				if (addstr((const char *)rdata, (size_t)1,
   1165 					   buf, buflen) < 0)
   1166 					goto enospc;
   1167 				rdata++;
   1168 			}
   1169 		}
   1170 	}
   1171 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
   1172 		goto enospc;
   1173 	_DIAGASSERT(__type_fit(int, rdata - odata));
   1174 	return (int)(rdata - odata);
   1175  enospc:
   1176 	errno = ENOSPC;
   1177 	*buf = save_buf;
   1178 	*buflen = save_buflen;
   1179 	return (-1);
   1180 }
   1181 
   1182 static int
   1183 addname(const u_char *msg, size_t msglen,
   1184 	const u_char **pp, const char *origin,
   1185 	char **buf, size_t *buflen)
   1186 {
   1187 	size_t newlen, save_buflen = *buflen;
   1188 	char *save_buf = *buf;
   1189 	int n;
   1190 
   1191 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
   1192 	if (n < 0)
   1193 		goto enospc;	/* Guess. */
   1194 	newlen = prune_origin(*buf, origin);
   1195 	if (**buf == '\0') {
   1196 		goto root;
   1197 	} else if (newlen == 0U) {
   1198 		/* Use "@" instead of name. */
   1199 		if (newlen + 2 > *buflen)
   1200 			goto enospc;        /* No room for "@\0". */
   1201 		(*buf)[newlen++] = '@';
   1202 		(*buf)[newlen] = '\0';
   1203 	} else {
   1204 		if (((origin == NULL || origin[0] == '\0') ||
   1205 		    (origin[0] != '.' && origin[1] != '\0' &&
   1206 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
   1207 			/* No trailing dot. */
   1208  root:
   1209 			if (newlen + 2 > *buflen)
   1210 				goto enospc;	/* No room for ".\0". */
   1211 			(*buf)[newlen++] = '.';
   1212 			(*buf)[newlen] = '\0';
   1213 		}
   1214 	}
   1215 	*pp += n;
   1216 	addlen(newlen, buf, buflen);
   1217 	**buf = '\0';
   1218 	_DIAGASSERT(__type_fit(int, newlen));
   1219 	return (int)newlen;
   1220  enospc:
   1221 	errno = ENOSPC;
   1222 	*buf = save_buf;
   1223 	*buflen = save_buflen;
   1224 	return (-1);
   1225 }
   1226 
   1227 static void
   1228 addlen(size_t len, char **buf, size_t *buflen) {
   1229 	assert(len <= *buflen);
   1230 	*buf += len;
   1231 	*buflen -= len;
   1232 }
   1233 
   1234 static int
   1235 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
   1236 	if (len >= *buflen) {
   1237 		errno = ENOSPC;
   1238 		return (-1);
   1239 	}
   1240 	memcpy(*buf, src, len);
   1241 	addlen(len, buf, buflen);
   1242 	**buf = '\0';
   1243 	return (0);
   1244 }
   1245 
   1246 static int
   1247 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
   1248 	size_t save_buflen = *buflen;
   1249 	char *save_buf = *buf;
   1250 	ptrdiff_t t;
   1251 
   1252 	if (spaced || len >= target - 1) {
   1253 		T(addstr("  ", (size_t)2, buf, buflen));
   1254 		spaced = 1;
   1255 	} else {
   1256 		for (t = (target - len - 1) / 8; t >= 0; t--)
   1257 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
   1258 				*buflen = save_buflen;
   1259 				*buf = save_buf;
   1260 				return (-1);
   1261 			}
   1262 		spaced = 0;
   1263 	}
   1264 	return (spaced);
   1265 }
   1266