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