ns_print.c revision d7ce700605e1af0e455e31ec11f19ff21d26b525
1/*
2 * Copyright (c) 1996, 1998 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18/*
19 * Portions copyright (c) 1999, 2000
20 * Intel Corporation.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 *    notice, this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright
31 *    notice, this list of conditions and the following disclaimer in the
32 *    documentation and/or other materials provided with the distribution.
33 *
34 * 3. All advertising materials mentioning features or use of this software
35 *    must display the following acknowledgement:
36 *
37 *    This product includes software developed by Intel Corporation and
38 *    its contributors.
39 *
40 * 4. Neither the name of Intel Corporation or its contributors may be
41 *    used to endorse or promote products derived from this software
42 *    without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
45 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
48 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 */
57
58#ifndef lint
59static char rcsid[] = "$Id: ns_print.c,v 1.1.1.1 2003/11/19 01:51:34 kyu3 Exp $";
60#endif
61
62/* Import. */
63
64#include <sys/types.h>
65#include <sys/socket.h>
66
67#include <netinet/in.h>
68#include <arpa/nameser.h>
69#include <arpa/inet.h>
70
71#include <assert.h>
72#include <errno.h>
73#include <resolv.h>
74#include <string.h>
75#include <ctype.h>
76
77#define SPRINTF(x) (sprintf x)
78
79/* Forward. */
80
81static size_t	prune_origin(const char *name, const char *origin);
82static int	charstr(const u_char *rdata, const u_char *edata,
83			char **buf, size_t *buflen);
84static int	addname(const u_char *msg, size_t msglen,
85			const u_char **p, const char *origin,
86			char **buf, size_t *buflen);
87static void	addlen(size_t len, char **buf, size_t *buflen);
88static int	addstr(const char *src, size_t len,
89		       char **buf, size_t *buflen);
90static int	addtab(size_t len, size_t target, int spaced,
91		       char **buf, size_t *buflen);
92
93/* Macros. */
94
95#define	T(x) \
96	do { \
97		if ((ssize_t)(x) < 0) \
98			return (-1); \
99	} while (0)
100
101/* Public. */
102
103/*
104 * int
105 * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
106 *	Convert an RR to presentation format.
107 * return:
108 *	Number of characters written to buf, or -1 (check errno).
109 */
110int
111ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
112	    const char *name_ctx, const char *origin,
113	    char *buf, size_t buflen)
114{
115	int n;
116
117	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
118			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
119			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
120			 name_ctx, origin, buf, buflen);
121	return (n);
122}
123
124/*
125 * int
126 * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
127 *	       name_ctx, origin, buf, buflen)
128 *	Convert the fields of an RR into presentation format.
129 * return:
130 *	Number of characters written to buf, or -1 (check errno).
131 */
132int
133ns_sprintrrf(const u_char *msg, size_t msglen,
134	    const char *name, ns_class class, ns_type type,
135	    u_long ttl, const u_char *rdata, size_t rdlen,
136	    const char *name_ctx, const char *origin,
137	    char *buf, size_t buflen)
138{
139	const char *obuf = buf;
140	const u_char *edata = rdata + rdlen;
141	int spaced = 0;
142
143	const char *comment;
144	char tmp[100];
145	int x;
146	size_t len;
147
148	static	char base64_key[NS_MD5RSA_MAX_BASE64];
149	static	char t[255*3];
150
151	/*
152	 * Owner.
153	 */
154	if (name_ctx != NULL && strcasecmp(name_ctx, name) == 0) {
155		T(addstr("\t\t\t", 3, &buf, &buflen));
156	} else {
157		len = prune_origin(name, origin);
158		if (len == 0) {
159			T(addstr("@\t\t\t", 4, &buf, &buflen));
160		} else {
161			T(addstr(name, len, &buf, &buflen));
162			/* Origin not used and no trailing dot? */
163			if ((!origin || !origin[0] || name[len] == '\0') &&
164			    name[len - 1] != '.') {
165				T(addstr(".", 1, &buf, &buflen));
166				len++;
167			}
168			T(spaced = addtab(len, 24, spaced, &buf, &buflen));
169		}
170	}
171
172	/*
173	 * TTL, Class, Type.
174	 */
175	T(x = ns_format_ttl(ttl, buf, buflen));
176	addlen(x, &buf, &buflen);
177	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
178	T(addstr(tmp, len, &buf, &buflen));
179	T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
180
181	/*
182	 * RData.
183	 */
184	switch (type) {
185	case ns_t_a:
186		if (rdlen != NS_INADDRSZ)
187			goto formerr;
188		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
189		addlen(strlen(buf), &buf, &buflen);
190		break;
191
192	case ns_t_cname:
193	case ns_t_mb:
194	case ns_t_mg:
195	case ns_t_mr:
196	case ns_t_ns:
197	case ns_t_ptr:
198		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
199		break;
200
201	case ns_t_hinfo:
202	case ns_t_isdn:
203		/* First word. */
204		T(len = charstr(rdata, edata, &buf, &buflen));
205		if (len == 0)
206			goto formerr;
207		rdata += len;
208		T(addstr(" ", 1, &buf, &buflen));
209
210		/* Second word. */
211		T(len = charstr(rdata, edata, &buf, &buflen));
212		if (len == 0)
213			goto formerr;
214		rdata += len;
215		break;
216
217	case ns_t_soa: {
218		u_long t;
219
220		/* Server name. */
221		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
222		T(addstr(" ", 1, &buf, &buflen));
223
224		/* Administrator name. */
225		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
226		T(addstr(" (\n", 3, &buf, &buflen));
227		spaced = 0;
228
229		if ((edata - rdata) != 5*NS_INT32SZ)
230			goto formerr;
231
232		/* Serial number. */
233		t = ns_get32(rdata);  rdata += NS_INT32SZ;
234		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
235		len = SPRINTF((tmp, "%lu", t));
236		T(addstr(tmp, len, &buf, &buflen));
237		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
238		T(addstr("; serial\n", 9, &buf, &buflen));
239		spaced = 0;
240
241		/* Refresh interval. */
242		t = ns_get32(rdata);  rdata += NS_INT32SZ;
243		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
244		T(len = ns_format_ttl(t, buf, buflen));
245		addlen(len, &buf, &buflen);
246		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
247		T(addstr("; refresh\n", 10, &buf, &buflen));
248		spaced = 0;
249
250		/* Retry interval. */
251		t = ns_get32(rdata);  rdata += NS_INT32SZ;
252		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
253		T(len = ns_format_ttl(t, buf, buflen));
254		addlen(len, &buf, &buflen);
255		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
256		T(addstr("; retry\n", 8, &buf, &buflen));
257		spaced = 0;
258
259		/* Expiry. */
260		t = ns_get32(rdata);  rdata += NS_INT32SZ;
261		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
262		T(len = ns_format_ttl(t, buf, buflen));
263		addlen(len, &buf, &buflen);
264		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
265		T(addstr("; expiry\n", 9, &buf, &buflen));
266		spaced = 0;
267
268		/* Minimum TTL. */
269		t = ns_get32(rdata);  rdata += NS_INT32SZ;
270		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
271		T(len = ns_format_ttl(t, buf, buflen));
272		addlen(len, &buf, &buflen);
273		T(addstr(" )", 2, &buf, &buflen));
274		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
275		T(addstr("; minimum\n", 10, &buf, &buflen));
276
277		break;
278	    }
279
280	case ns_t_mx:
281	case ns_t_afsdb:
282	case ns_t_rt: {
283		u_int t;
284
285		if (rdlen < NS_INT16SZ)
286			goto formerr;
287
288		/* Priority. */
289		t = ns_get16(rdata);
290		rdata += NS_INT16SZ;
291		len = SPRINTF((tmp, "%u ", t));
292		T(addstr(tmp, len, &buf, &buflen));
293
294		/* Target. */
295		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
296
297		break;
298	    }
299
300	case ns_t_px: {
301		u_int t;
302
303		if (rdlen < NS_INT16SZ)
304			goto formerr;
305
306		/* Priority. */
307		t = ns_get16(rdata);
308		rdata += NS_INT16SZ;
309		len = SPRINTF((tmp, "%u ", t));
310		T(addstr(tmp, len, &buf, &buflen));
311
312		/* Name1. */
313		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
314		T(addstr(" ", 1, &buf, &buflen));
315
316		/* Name2. */
317		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
318
319		break;
320	    }
321
322	case ns_t_x25:
323		T(len = charstr(rdata, edata, &buf, &buflen));
324		if (len == 0)
325			goto formerr;
326		rdata += len;
327		break;
328
329	case ns_t_txt:
330		while (rdata < edata) {
331			T(len = charstr(rdata, edata, &buf, &buflen));
332			if (len == 0)
333				goto formerr;
334			rdata += len;
335			if (rdata < edata)
336				T(addstr(" ", 1, &buf, &buflen));
337		}
338		break;
339
340	case ns_t_nsap: {
341
342		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
343		T(addstr(t, strlen(t), &buf, &buflen));
344		break;
345	    }
346
347	case ns_t_aaaa:
348		if (rdlen != NS_IN6ADDRSZ)
349			goto formerr;
350		(void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
351		addlen(strlen(buf), &buf, &buflen);
352		break;
353
354	case ns_t_loc: {
355		/* XXX protocol format checking? */
356		(void) loc_ntoa(rdata, t);
357		T(addstr(t, strlen(t), &buf, &buflen));
358		break;
359	    }
360
361	case ns_t_naptr: {
362		u_int order, preference;
363
364		if (rdlen < 2*NS_INT16SZ)
365			goto formerr;
366
367		/* Order, Precedence. */
368		order = ns_get16(rdata);	rdata += NS_INT16SZ;
369		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
370		len = SPRINTF((t, "%u %u ", order, preference));
371		T(addstr(t, len, &buf, &buflen));
372
373		/* Flags. */
374		T(len = charstr(rdata, edata, &buf, &buflen));
375		if (len == 0)
376			goto formerr;
377		rdata += len;
378		T(addstr(" ", 1, &buf, &buflen));
379
380		/* Service. */
381		T(len = charstr(rdata, edata, &buf, &buflen));
382		if (len == 0)
383			goto formerr;
384		rdata += len;
385		T(addstr(" ", 1, &buf, &buflen));
386
387		/* Regexp. */
388		T(len = charstr(rdata, edata, &buf, &buflen));
389		if ((ssize_t)len < 0)
390			return (-1);
391		if (len == 0)
392			goto formerr;
393		rdata += len;
394		T(addstr(" ", 1, &buf, &buflen));
395
396		/* Server. */
397		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
398		break;
399	    }
400
401	case ns_t_srv: {
402		u_int priority, weight, port;
403
404		if (rdlen < NS_INT16SZ*3)
405			goto formerr;
406
407		/* Priority, Weight, Port. */
408		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
409		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
410		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
411		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
412		T(addstr(t, len, &buf, &buflen));
413
414		/* Server. */
415		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
416		break;
417	    }
418
419	case ns_t_minfo:
420	case ns_t_rp:
421		/* Name1. */
422		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
423		T(addstr(" ", 1, &buf, &buflen));
424
425		/* Name2. */
426		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
427
428		break;
429
430	case ns_t_wks: {
431		int n, lcnt;
432
433		if (rdlen < NS_INT32SZ + 1)
434			goto formerr;
435
436		/* Address. */
437		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
438		addlen(strlen(buf), &buf, &buflen);
439		rdata += NS_INADDRSZ;
440
441		/* Protocol. */
442		len = SPRINTF((tmp, " %u ( ", *rdata));
443		T(addstr(tmp, len, &buf, &buflen));
444		rdata += NS_INT8SZ;
445
446		/* Bit map. */
447		n = 0;
448		lcnt = 0;
449		while (rdata < edata) {
450			u_int c = *rdata++;
451			do {
452				if (c & 0200) {
453					if (lcnt == 0) {
454						T(addstr("\n\t\t\t\t", 5,
455							 &buf, &buflen));
456						lcnt = 10;
457						spaced = 0;
458					}
459					len = SPRINTF((tmp, "%d ", n));
460					T(addstr(tmp, len, &buf, &buflen));
461					lcnt--;
462				}
463				c <<= 1;
464			} while (++n & 07);
465		}
466		T(addstr(")", 1, &buf, &buflen));
467
468		break;
469	    }
470
471	case ns_t_key: {
472		u_int keyflags, protocol, algorithm;
473		const char *leader;
474		int n;
475
476		if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
477			goto formerr;
478
479		/* Key flags, Protocol, Algorithm. */
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, len, &buf, &buflen));
486
487		/* Public key data. */
488		len = b64_ntop(rdata, edata - rdata,
489			       base64_key, sizeof base64_key);
490		if ((ssize_t)len < 0)
491			goto formerr;
492		if (len > 15) {
493			T(addstr(" (", 2, &buf, &buflen));
494			leader = "\n\t\t";
495			spaced = 0;
496		} else
497			leader = " ";
498		for (n = 0; n < (int)len; n += 48) {
499			T(addstr(leader, strlen(leader), &buf, &buflen));
500			T(addstr(base64_key + n, MIN(len - n, 48),
501				 &buf, &buflen));
502		}
503		if (len > 15)
504			T(addstr(" )", 2, &buf, &buflen));
505
506		break;
507	    }
508
509	case ns_t_sig: {
510		u_int type, algorithm, labels, footprint;
511		const char *leader;
512		u_long t;
513		int n;
514
515		if (rdlen < 22)
516			goto formerr;
517
518		/* Type covered, Algorithm, Label count, Original TTL. */
519	        type = ns_get16(rdata);  rdata += NS_INT16SZ;
520		algorithm = *rdata++;
521		labels = *rdata++;
522		t = ns_get32(rdata);  rdata += NS_INT32SZ;
523		len = SPRINTF((tmp, " %s %d %lu ",
524			       p_type((int)type), algorithm, t));
525		T(addstr(tmp, len, &buf, &buflen));
526		if (labels != (u_int)dn_count_labels(name))
527			goto formerr;
528
529		/* Signature expiry. */
530		t = ns_get32(rdata);  rdata += NS_INT32SZ;
531		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
532		T(addstr(tmp, len, &buf, &buflen));
533
534		/* Time signed. */
535		t = ns_get32(rdata);  rdata += NS_INT32SZ;
536		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
537		T(addstr(tmp, len, &buf, &buflen));
538
539		/* Signature Footprint. */
540		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
541		len = SPRINTF((tmp, "%u ", footprint));
542		T(addstr(tmp, len, &buf, &buflen));
543
544		/* Signer's name. */
545		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
546
547		/* Signature. */
548		len = b64_ntop(rdata, edata - rdata,
549			       base64_key, sizeof base64_key);
550		if (len > 15) {
551			T(addstr(" (", 2, &buf, &buflen));
552			leader = "\n\t\t";
553			spaced = 0;
554		} else
555			leader = " ";
556		if ((ssize_t)len < 0)
557			goto formerr;
558		for (n = 0; n < (int)len; n += 48) {
559			T(addstr(leader, strlen(leader), &buf, &buflen));
560			T(addstr(base64_key + n, MIN(len - n, 48),
561				 &buf, &buflen));
562		}
563		if (len > 15)
564			T(addstr(" )", 2, &buf, &buflen));
565
566		break;
567	    }
568
569	case ns_t_nxt: {
570		int n, c;
571
572		/* Next domain name. */
573		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
574
575		/* Type bit map. */
576		n = (int)(edata - rdata);
577		for (c = 0; c < n*8; c++)
578			if (NS_NXT_BIT_ISSET(c, rdata)) {
579				len = SPRINTF((tmp, " %s", p_type(c)));
580				T(addstr(tmp, len, &buf, &buflen));
581			}
582		break;
583	    }
584
585	default:
586		comment = "unknown RR type";
587		goto hexify;
588	}
589	return ((int)(buf - obuf));
590 formerr:
591	comment = "RR format error";
592 hexify: {
593	int n, m;
594	char *p;
595
596	len = SPRINTF((tmp, "\\#(\t\t; %s", comment));
597	T(addstr(tmp, len, &buf, &buflen));
598	while (rdata < edata) {
599		p = tmp;
600		p += SPRINTF((p, "\n\t"));
601		spaced = 0;
602		n = MIN(16, (int)(edata - rdata));
603		for (m = 0; m < n; m++)
604			p += SPRINTF((p, "%02x ", rdata[m]));
605		T(addstr(tmp, (u_int)(p - tmp), &buf, &buflen));
606		if (n < 16) {
607			T(addstr(")", 1, &buf, &buflen));
608			T(addtab((u_int)(p - tmp) + 1, 48, spaced, &buf, &buflen));
609		}
610		p = tmp;
611		p += SPRINTF((p, "; "));
612		for (m = 0; m < n; m++)
613			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
614				? rdata[m]
615				: '.';
616		T(addstr(tmp, (u_int)(p - tmp), &buf, &buflen));
617		rdata += n;
618	}
619	return ((int)(buf - obuf));
620    }
621}
622
623/* Private. */
624
625/*
626 * size_t
627 * prune_origin(name, origin)
628 *	Find out if the name is at or under the current origin.
629 * return:
630 *	Number of characters in name before start of origin,
631 *	or length of name if origin does not match.
632 * notes:
633 *	This function should share code with samedomain().
634 */
635static size_t
636prune_origin(const char *name, const char *origin) {
637	const char *oname = name;
638
639	while (*name != '\0') {
640		if (origin != NULL && strcasecmp(name, origin) == 0)
641			return ((size_t)(name - oname) - (name > oname));
642		while (*name != '\0') {
643			if (*name == '\\') {
644				name++;
645				/* XXX need to handle \nnn form. */
646				if (*name == '\0')
647					break;
648			} else if (*name == '.') {
649				name++;
650				break;
651			}
652			name++;
653		}
654	}
655	return ((size_t)(name - oname));
656}
657
658/*
659 * int
660 * charstr(rdata, edata, buf, buflen)
661 *	Format a <character-string> into the presentation buffer.
662 * return:
663 *	Number of rdata octets consumed
664 *	0 for protocol format error
665 *	-1 for output buffer error
666 * side effects:
667 *	buffer is advanced on success.
668 */
669static int
670charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
671	const u_char *odata = rdata;
672	size_t save_buflen = *buflen;
673	char *save_buf = *buf;
674
675	if (addstr("\"", 1, buf, buflen) < 0)
676		goto enospc;
677	if (rdata < edata) {
678		int n = *rdata;
679
680		if (rdata + 1 + n <= edata) {
681			rdata++;
682			while (n-- > 0) {
683				if (strchr("\n\"\\", *rdata) != NULL)
684					if (addstr("\\", 1, buf, buflen) < 0)
685						goto enospc;
686				if (addstr((const char *)rdata, 1,
687					   buf, buflen) < 0)
688					goto enospc;
689				rdata++;
690			}
691		}
692	}
693	if (addstr("\"", 1, buf, buflen) < 0)
694		goto enospc;
695	return ((int)(rdata - odata));
696 enospc:
697	errno = ENOSPC;
698	*buf = save_buf;
699	*buflen = save_buflen;
700	return (-1);
701}
702
703static int
704addname(const u_char *msg, size_t msglen,
705	const u_char **pp, const char *origin,
706	char **buf, size_t *buflen)
707{
708	size_t newlen, save_buflen = *buflen;
709	char *save_buf = *buf;
710	int n;
711
712	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)(*buflen));
713	if (n < 0)
714		goto enospc;	/* Guess. */
715	newlen = prune_origin(*buf, origin);
716	if ((origin == NULL || origin[0] == '\0' || (*buf)[newlen] == '\0') &&
717	    (newlen == 0 || (*buf)[newlen - 1] != '.')) {
718		/* No trailing dot. */
719		if (newlen + 2 > *buflen)
720			goto enospc;	/* No room for ".\0". */
721		(*buf)[newlen++] = '.';
722		(*buf)[newlen] = '\0';
723	}
724	if (newlen == 0) {
725		/* Use "@" instead of name. */
726		if (newlen + 2 > *buflen)
727			goto enospc;        /* No room for "@\0". */
728		(*buf)[newlen++] = '@';
729		(*buf)[newlen] = '\0';
730	}
731	*pp += n;
732	addlen(newlen, buf, buflen);
733	**buf = '\0';
734	return ((int)newlen);
735 enospc:
736	errno = ENOSPC;
737	*buf = save_buf;
738	*buflen = save_buflen;
739	return (-1);
740}
741
742static void
743addlen(size_t len, char **buf, size_t *buflen) {
744	assert(len <= *buflen);
745	*buf += len;
746	*buflen -= len;
747}
748
749static int
750addstr(const char *src, size_t len, char **buf, size_t *buflen) {
751	if (len > *buflen) {
752		errno = ENOSPC;
753		return (-1);
754	}
755	memcpy(*buf, src, len);
756	addlen(len, buf, buflen);
757	**buf = '\0';
758	return (0);
759}
760
761static int
762addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
763	size_t save_buflen = *buflen;
764	char *save_buf = *buf;
765	int t;
766
767	if (spaced || len >= target - 1) {
768		T(addstr("  ", 2, buf, buflen));
769		spaced = 1;
770	} else {
771		for (t = (int)(target - len - 1) / 8; t >= 0; t--)
772			if (addstr("\t", 1, buf, buflen) < 0) {
773				*buflen = save_buflen;
774				*buf = save_buf;
775				return (-1);
776			}
777		spaced = 0;
778	}
779	return (spaced);
780}
781