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