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