1: /* print.c
2:
3: Turn data structures into printable text. */
4:
5: /*
6: * Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8: * Copyright (c) 1995-2003 by Internet Software Consortium
9: *
10: * Permission to use, copy, modify, and distribute this software for any
11: * purpose with or without fee is hereby granted, provided that the above
12: * copyright notice and this permission notice appear in all copies.
13: *
14: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21: *
22: * Internet Systems Consortium, Inc.
23: * 950 Charter Street
24: * Redwood City, CA 94063
25: * <info@isc.org>
26: * https://www.isc.org/
27: *
28: * This software has been written for Internet Systems Consortium
29: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30: * To learn more about Internet Systems Consortium, see
31: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33: * ``http://www.nominum.com''.
34: */
35:
36: #include "dhcpd.h"
37:
38: int db_time_format = DEFAULT_TIME_FORMAT;
39:
40: char *quotify_string (const char *s, const char *file, int line)
41: {
42: unsigned len = 0;
43: const char *sp;
44: char *buf, *nsp;
45:
46: for (sp = s; sp && *sp; sp++) {
47: if (*sp == ' ')
48: len++;
49: else if (!isascii ((int)*sp) || !isprint ((int)*sp))
50: len += 4;
51: else if (*sp == '"' || *sp == '\\')
52: len += 2;
53: else
54: len++;
55: }
56:
57: buf = dmalloc (len + 1, file, line);
58: if (buf) {
59: nsp = buf;
60: for (sp = s; sp && *sp; sp++) {
61: if (*sp == ' ')
62: *nsp++ = ' ';
63: else if (!isascii ((int)*sp) || !isprint ((int)*sp)) {
64: sprintf (nsp, "\\%03o",
65: *(const unsigned char *)sp);
66: nsp += 4;
67: } else if (*sp == '"' || *sp == '\\') {
68: *nsp++ = '\\';
69: *nsp++ = *sp;
70: } else
71: *nsp++ = *sp;
72: }
73: *nsp++ = 0;
74: }
75: return buf;
76: }
77:
78: char *quotify_buf (const unsigned char *s, unsigned len,
79: const char *file, int line)
80: {
81: unsigned nulen = 0;
82: char *buf, *nsp;
83: int i;
84:
85: for (i = 0; i < len; i++) {
86: if (s [i] == ' ')
87: nulen++;
88: else if (!isascii (s [i]) || !isprint (s [i]))
89: nulen += 4;
90: else if (s [i] == '"' || s [i] == '\\')
91: nulen += 2;
92: else
93: nulen++;
94: }
95:
96: buf = dmalloc (nulen + 1, MDL);
97: if (buf) {
98: nsp = buf;
99: for (i = 0; i < len; i++) {
100: if (s [i] == ' ')
101: *nsp++ = ' ';
102: else if (!isascii (s [i]) || !isprint (s [i])) {
103: sprintf (nsp, "\\%03o", s [i]);
104: nsp += 4;
105: } else if (s [i] == '"' || s [i] == '\\') {
106: *nsp++ = '\\';
107: *nsp++ = s [i];
108: } else
109: *nsp++ = s [i];
110: }
111: *nsp++ = 0;
112: }
113: return buf;
114: }
115:
116: char *print_base64 (const unsigned char *buf, unsigned len,
117: const char *file, int line)
118: {
119: char *s, *b;
120: unsigned bl;
121: int i;
122: unsigned val, extra;
123: static char to64 [] =
124: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
125:
126: bl = ((len * 4 + 2) / 3) + 1;
127: b = dmalloc (bl + 1, file, line);
128: if (!b)
129: return (char *)0;
130:
131: i = 0;
132: s = b;
133: while (i != len) {
134: val = buf [i++];
135: extra = val & 3;
136: val = val >> 2;
137: *s++ = to64 [val];
138: if (i == len) {
139: *s++ = to64 [extra << 4];
140: *s++ = '=';
141: break;
142: }
143: val = (extra << 8) + buf [i++];
144: extra = val & 15;
145: val = val >> 4;
146: *s++ = to64 [val];
147: if (i == len) {
148: *s++ = to64 [extra << 2];
149: *s++ = '=';
150: break;
151: }
152: val = (extra << 8) + buf [i++];
153: extra = val & 0x3f;
154: val = val >> 6;
155: *s++ = to64 [val];
156: *s++ = to64 [extra];
157: }
158: if (!len)
159: *s++ = '=';
160: *s++ = 0;
161: if (s > b + bl + 1)
162: abort ();
163: return b;
164: }
165:
166: char *print_hw_addr (htype, hlen, data)
167: int htype;
168: int hlen;
169: unsigned char *data;
170: {
171: static char habuf [49];
172: char *s;
173: int i;
174:
175: if (hlen <= 0)
176: habuf [0] = 0;
177: else {
178: s = habuf;
179: for (i = 0; i < hlen; i++) {
180: sprintf (s, "%02x", data [i]);
181: s += strlen (s);
182: *s++ = ':';
183: }
184: *--s = 0;
185: }
186: return habuf;
187: }
188:
189: void print_lease (lease)
190: struct lease *lease;
191: {
192: struct tm *t;
193: char tbuf [32];
194:
195: log_debug (" Lease %s",
196: piaddr (lease -> ip_addr));
197:
198: t = gmtime (&lease -> starts);
199: strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
200: log_debug (" start %s", tbuf);
201:
202: t = gmtime (&lease -> ends);
203: strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
204: log_debug (" end %s", tbuf);
205:
206: if (lease -> hardware_addr.hlen)
207: log_debug (" hardware addr = %s",
208: print_hw_addr (lease -> hardware_addr.hbuf [0],
209: lease -> hardware_addr.hlen - 1,
210: &lease -> hardware_addr.hbuf [1]));
211: log_debug (" host %s ",
212: lease -> host ? lease -> host -> name : "<none>");
213: }
214:
215: #if defined (DEBUG_PACKET)
216: void dump_packet_option (struct option_cache *oc,
217: struct packet *packet,
218: struct lease *lease,
219: struct client_state *client,
220: struct option_state *in_options,
221: struct option_state *cfg_options,
222: struct binding_scope **scope,
223: struct universe *u, void *foo)
224: {
225: const char *name, *dot;
226: struct data_string ds;
227: memset (&ds, 0, sizeof ds);
228:
229: if (u != &dhcp_universe) {
230: name = u -> name;
231: dot = ".";
232: } else {
233: name = "";
234: dot = "";
235: }
236: if (evaluate_option_cache (&ds, packet, lease, client,
237: in_options, cfg_options, scope, oc, MDL)) {
238: log_debug (" option %s%s%s %s;\n",
239: name, dot, oc -> option -> name,
240: pretty_print_option (oc -> option,
241: ds.data, ds.len, 1, 1));
242: data_string_forget (&ds, MDL);
243: }
244: }
245:
246: void dump_packet (tp)
247: struct packet *tp;
248: {
249: struct dhcp_packet *tdp = tp -> raw;
250:
251: log_debug ("packet length %d", tp -> packet_length);
252: log_debug ("op = %d htype = %d hlen = %d hops = %d",
253: tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
254: log_debug ("xid = %x secs = %ld flags = %x",
255: tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
256: log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
257: log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
258: log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
259: log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
260: log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
261: ((unsigned char *)(tdp -> chaddr)) [0],
262: ((unsigned char *)(tdp -> chaddr)) [1],
263: ((unsigned char *)(tdp -> chaddr)) [2],
264: ((unsigned char *)(tdp -> chaddr)) [3],
265: ((unsigned char *)(tdp -> chaddr)) [4],
266: ((unsigned char *)(tdp -> chaddr)) [5]);
267: log_debug ("filename = %s", tdp -> file);
268: log_debug ("server_name = %s", tdp -> sname);
269: if (tp -> options_valid) {
270: int i;
271:
272: for (i = 0; i < tp -> options -> universe_count; i++) {
273: if (tp -> options -> universes [i]) {
274: option_space_foreach (tp, (struct lease *)0,
275: (struct client_state *)0,
276: (struct option_state *)0,
277: tp -> options,
278: &global_scope,
279: universes [i], 0,
280: dump_packet_option);
281: }
282: }
283: }
284: log_debug ("%s", "");
285: }
286: #endif
287:
288: void dump_raw (buf, len)
289: const unsigned char *buf;
290: unsigned len;
291: {
292: int i;
293: char lbuf [80];
294: int lbix = 0;
295:
296: /*
297: 1 2 3 4 5 6 7
298: 01234567890123456789012345678901234567890123456789012345678901234567890123
299: 280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................
300: */
301:
302: memset(lbuf, ' ', 79);
303: lbuf [79] = 0;
304:
305: for (i = 0; i < len; i++) {
306: if ((i & 15) == 0) {
307: if (lbix) {
308: lbuf[53]=' ';
309: lbuf[54]=' ';
310: lbuf[55]=' ';
311: lbuf[73]='\0';
312: log_info ("%s", lbuf);
313: }
314: memset(lbuf, ' ', 79);
315: lbuf [79] = 0;
316: sprintf (lbuf, "%03x:", i);
317: lbix = 4;
318: } else if ((i & 7) == 0)
319: lbuf [lbix++] = ' ';
320:
321: if(isprint(buf[i])) {
322: lbuf[56+(i%16)]=buf[i];
323: } else {
324: lbuf[56+(i%16)]='.';
325: }
326:
327: sprintf (&lbuf [lbix], " %02x", buf [i]);
328: lbix += 3;
329: lbuf[lbix]=' ';
330:
331: }
332: lbuf[53]=' ';
333: lbuf[54]=' ';
334: lbuf[55]=' ';
335: lbuf[73]='\0';
336: log_info ("%s", lbuf);
337: }
338:
339: void hash_dump (table)
340: struct hash_table *table;
341: {
342: int i;
343: struct hash_bucket *bp;
344:
345: if (!table)
346: return;
347:
348: for (i = 0; i < table -> hash_count; i++) {
349: if (!table -> buckets [i])
350: continue;
351: log_info ("hash bucket %d:", i);
352: for (bp = table -> buckets [i]; bp; bp = bp -> next) {
353: if (bp -> len)
354: dump_raw (bp -> name, bp -> len);
355: else
356: log_info ("%s", (const char *)bp -> name);
357: }
358: }
359: }
360:
361: /*
362: * print a string as hex. This only outputs
363: * colon separated hex list no matter what
364: * the input looks like. See print_hex
365: * for a function that prints either cshl
366: * or a string if all bytes are printible
367: * It only uses limit characters from buf
368: * and doesn't do anything if buf == NULL
369: *
370: * len - length of data
371: * data - input data
372: * limit - length of buf to use
373: * buf - output buffer
374: */
375: void print_hex_only (len, data, limit, buf)
376: unsigned len;
377: const u_int8_t *data;
378: unsigned limit;
379: char *buf;
380: {
381: unsigned i;
382:
383: if ((buf == NULL) || (limit < 3))
384: return;
385:
386: for (i = 0; (i < limit / 3) && (i < len); i++) {
387: sprintf(&buf[i*3], "%02x:", data[i]);
388: }
389: buf[(i * 3) - 1] = 0;
390: return;
391: }
392:
393: /*
394: * print a string as either text if all the characters
395: * are printable or colon separated hex if they aren't
396: *
397: * len - length of data
398: * data - input data
399: * limit - length of buf to use
400: * buf - output buffer
401: */
402: void print_hex_or_string (len, data, limit, buf)
403: unsigned len;
404: const u_int8_t *data;
405: unsigned limit;
406: char *buf;
407: {
408: unsigned i;
409: if ((buf == NULL) || (limit < 3))
410: return;
411:
412: for (i = 0; (i < (limit - 3)) && (i < len); i++) {
413: if (!isascii(data[i]) || !isprint(data[i])) {
414: print_hex_only(len, data, limit, buf);
415: return;
416: }
417: }
418:
419: buf[0] = '"';
420: i = len;
421: if (i > (limit - 3))
422: i = limit - 3;
423: memcpy(&buf[1], data, i);
424: buf[i + 1] = '"';
425: buf[i + 2] = 0;
426: return;
427: }
428:
429: /*
430: * print a string as either hex or text
431: * using static buffers to hold the output
432: *
433: * len - length of data
434: * data - input data
435: * limit - length of buf
436: * buf_num - the output buffer to use
437: */
438: #define HBLEN 1024
439: char *print_hex(len, data, limit, buf_num)
440: unsigned len;
441: const u_int8_t *data;
442: unsigned limit;
443: unsigned buf_num;
444: {
445: static char hex_buf_1[HBLEN + 1];
446: static char hex_buf_2[HBLEN + 1];
447: static char hex_buf_3[HBLEN + 1];
448: char *hex_buf;
449:
450: switch(buf_num) {
451: case 0:
452: hex_buf = hex_buf_1;
453: if (limit >= sizeof(hex_buf_1))
454: limit = sizeof(hex_buf_1);
455: break;
456: case 1:
457: hex_buf = hex_buf_2;
458: if (limit >= sizeof(hex_buf_2))
459: limit = sizeof(hex_buf_2);
460: break;
461: case 2:
462: hex_buf = hex_buf_3;
463: if (limit >= sizeof(hex_buf_3))
464: limit = sizeof(hex_buf_3);
465: break;
466: default:
467: return(NULL);
468: }
469:
470: print_hex_or_string(len, data, limit, hex_buf);
471: return(hex_buf);
472: }
473:
474: #define DQLEN 80
475:
476: char *print_dotted_quads (len, data)
477: unsigned len;
478: const u_int8_t *data;
479: {
480: static char dq_buf [DQLEN + 1];
481: int i;
482: char *s;
483:
484: s = &dq_buf [0];
485:
486: i = 0;
487:
488: /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe%
489: * The sprintf can't exceed 18 bytes, and since the loop enforces
490: * 21 bytes of space per iteration at no time can we exit the
491: * loop without at least 3 bytes spare.
492: */
493: do {
494: sprintf (s, "%u.%u.%u.%u, ",
495: data [i], data [i + 1], data [i + 2], data [i + 3]);
496: s += strlen (s);
497: i += 4;
498: } while ((s - &dq_buf [0] > DQLEN - 21) &&
499: i + 3 < len);
500: if (i == len)
501: s [-2] = 0;
502: else
503: strcpy (s, "...");
504: return dq_buf;
505: }
506:
507: char *print_dec_1 (val)
508: unsigned long val;
509: {
510: static char vbuf [32];
511: sprintf (vbuf, "%lu", val);
512: return vbuf;
513: }
514:
515: char *print_dec_2 (val)
516: unsigned long val;
517: {
518: static char vbuf [32];
519: sprintf (vbuf, "%lu", val);
520: return vbuf;
521: }
522:
523: static unsigned print_subexpression (struct expression *, char *, unsigned);
524:
525: static unsigned print_subexpression (expr, buf, len)
526: struct expression *expr;
527: char *buf;
528: unsigned len;
529: {
530: unsigned rv, left;
531: const char *s;
532:
533: switch (expr -> op) {
534: case expr_none:
535: if (len > 3) {
536: strcpy (buf, "nil");
537: return 3;
538: }
539: break;
540:
541: case expr_match:
542: if (len > 7) {
543: strcpy (buf, "(match)");
544: return 7;
545: }
546: break;
547:
548: case expr_check:
549: rv = 10 + strlen (expr -> data.check -> name);
550: if (len > rv) {
551: sprintf (buf, "(check %s)",
552: expr -> data.check -> name);
553: return rv;
554: }
555: break;
556:
557: case expr_equal:
558: if (len > 6) {
559: rv = 4;
560: strcpy (buf, "(eq ");
561: rv += print_subexpression (expr -> data.equal [0],
562: buf + rv, len - rv - 2);
563: buf [rv++] = ' ';
564: rv += print_subexpression (expr -> data.equal [1],
565: buf + rv, len - rv - 1);
566: buf [rv++] = ')';
567: buf [rv] = 0;
568: return rv;
569: }
570: break;
571:
572: case expr_not_equal:
573: if (len > 7) {
574: rv = 5;
575: strcpy (buf, "(neq ");
576: rv += print_subexpression (expr -> data.equal [0],
577: buf + rv, len - rv - 2);
578: buf [rv++] = ' ';
579: rv += print_subexpression (expr -> data.equal [1],
580: buf + rv, len - rv - 1);
581: buf [rv++] = ')';
582: buf [rv] = 0;
583: return rv;
584: }
585: break;
586:
587: case expr_regex_match:
588: if (len > 10) {
589: rv = 4;
590: strcpy(buf, "(regex ");
591: rv += print_subexpression(expr->data.equal[0],
592: buf + rv, len - rv - 2);
593: buf[rv++] = ' ';
594: rv += print_subexpression(expr->data.equal[1],
595: buf + rv, len - rv - 1);
596: buf[rv++] = ')';
597: buf[rv] = 0;
598: return rv;
599: }
600: break;
601:
602: case expr_substring:
603: if (len > 11) {
604: rv = 8;
605: strcpy (buf, "(substr ");
606: rv += print_subexpression (expr -> data.substring.expr,
607: buf + rv, len - rv - 3);
608: buf [rv++] = ' ';
609: rv += print_subexpression
610: (expr -> data.substring.offset,
611: buf + rv, len - rv - 2);
612: buf [rv++] = ' ';
613: rv += print_subexpression (expr -> data.substring.len,
614: buf + rv, len - rv - 1);
615: buf [rv++] = ')';
616: buf [rv] = 0;
617: return rv;
618: }
619: break;
620:
621: case expr_suffix:
622: if (len > 10) {
623: rv = 8;
624: strcpy (buf, "(suffix ");
625: rv += print_subexpression (expr -> data.suffix.expr,
626: buf + rv, len - rv - 2);
627: if (len > rv)
628: buf [rv++] = ' ';
629: rv += print_subexpression (expr -> data.suffix.len,
630: buf + rv, len - rv - 1);
631: if (len > rv)
632: buf [rv++] = ')';
633: buf [rv] = 0;
634: return rv;
635: }
636: break;
637:
638: case expr_lcase:
639: if (len > 9) {
640: rv = 7;
641: strcpy(buf, "(lcase ");
642: rv += print_subexpression(expr->data.lcase,
643: buf + rv, len - rv - 1);
644: buf[rv++] = ')';
645: buf[rv] = 0;
646: return rv;
647: }
648: break;
649:
650: case expr_ucase:
651: if (len > 9) {
652: rv = 7;
653: strcpy(buf, "(ucase ");
654: rv += print_subexpression(expr->data.ucase,
655: buf + rv, len - rv - 1);
656: buf[rv++] = ')';
657: buf[rv] = 0;
658: return rv;
659: }
660: break;
661:
662: case expr_concat:
663: if (len > 10) {
664: rv = 8;
665: strcpy (buf, "(concat ");
666: rv += print_subexpression (expr -> data.concat [0],
667: buf + rv, len - rv - 2);
668: buf [rv++] = ' ';
669: rv += print_subexpression (expr -> data.concat [1],
670: buf + rv, len - rv - 1);
671: buf [rv++] = ')';
672: buf [rv] = 0;
673: return rv;
674: }
675: break;
676:
677: case expr_pick_first_value:
678: if (len > 8) {
679: rv = 6;
680: strcpy (buf, "(pick1st ");
681: rv += print_subexpression
682: (expr -> data.pick_first_value.car,
683: buf + rv, len - rv - 2);
684: buf [rv++] = ' ';
685: rv += print_subexpression
686: (expr -> data.pick_first_value.cdr,
687: buf + rv, len - rv - 1);
688: buf [rv++] = ')';
689: buf [rv] = 0;
690: return rv;
691: }
692: break;
693:
694: case expr_host_lookup:
695: rv = 15 + strlen (expr -> data.host_lookup -> hostname);
696: if (len > rv) {
697: sprintf (buf, "(dns-lookup %s)",
698: expr -> data.host_lookup -> hostname);
699: return rv;
700: }
701: break;
702:
703: case expr_and:
704: s = "and";
705: binop:
706: rv = strlen (s);
707: if (len > rv + 4) {
708: buf [0] = '(';
709: strcpy (&buf [1], s);
710: rv += 1;
711: buf [rv++] = ' ';
712: rv += print_subexpression (expr -> data.and [0],
713: buf + rv, len - rv - 2);
714: buf [rv++] = ' ';
715: rv += print_subexpression (expr -> data.and [1],
716: buf + rv, len - rv - 1);
717: buf [rv++] = ')';
718: buf [rv] = 0;
719: return rv;
720: }
721: break;
722:
723: case expr_or:
724: s = "or";
725: goto binop;
726:
727: case expr_add:
728: s = "+";
729: goto binop;
730:
731: case expr_subtract:
732: s = "-";
733: goto binop;
734:
735: case expr_multiply:
736: s = "*";
737: goto binop;
738:
739: case expr_divide:
740: s = "/";
741: goto binop;
742:
743: case expr_remainder:
744: s = "%";
745: goto binop;
746:
747: case expr_binary_and:
748: s = "&";
749: goto binop;
750:
751: case expr_binary_or:
752: s = "|";
753: goto binop;
754:
755: case expr_binary_xor:
756: s = "^";
757: goto binop;
758:
759: case expr_not:
760: if (len > 6) {
761: rv = 5;
762: strcpy (buf, "(not ");
763: rv += print_subexpression (expr -> data.not,
764: buf + rv, len - rv - 1);
765: buf [rv++] = ')';
766: buf [rv] = 0;
767: return rv;
768: }
769: break;
770:
771: case expr_config_option:
772: s = "cfg-option";
773: goto dooption;
774:
775: case expr_option:
776: s = "option";
777: dooption:
778: rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
779: strlen (expr -> data.option -> universe -> name));
780: if (len > rv) {
781: sprintf (buf, "(option %s.%s)",
782: expr -> data.option -> universe -> name,
783: expr -> data.option -> name);
784: return rv;
785: }
786: break;
787:
788: case expr_hardware:
789: if (len > 10) {
790: strcpy (buf, "(hardware)");
791: return 10;
792: }
793: break;
794:
795: case expr_packet:
796: if (len > 10) {
797: rv = 8;
798: strcpy (buf, "(substr ");
799: rv += print_subexpression (expr -> data.packet.offset,
800: buf + rv, len - rv - 2);
801: buf [rv++] = ' ';
802: rv += print_subexpression (expr -> data.packet.len,
803: buf + rv, len - rv - 1);
804: buf [rv++] = ')';
805: buf [rv] = 0;
806: return rv;
807: }
808: break;
809:
810: case expr_const_data:
811: s = print_hex_1 (expr -> data.const_data.len,
812: expr -> data.const_data.data, len);
813: rv = strlen (s);
814: if (rv >= len)
815: rv = len - 1;
816: strncpy (buf, s, rv);
817: buf [rv] = 0;
818: return rv;
819:
820: case expr_encapsulate:
821: rv = 13;
822: strcpy (buf, "(encapsulate ");
823: rv += expr -> data.encapsulate.len;
824: if (rv + 2 > len)
825: rv = len - 2;
826: strncpy (buf,
827: (const char *)expr -> data.encapsulate.data, rv - 13);
828: buf [rv++] = ')';
829: buf [rv++] = 0;
830: break;
831:
832: case expr_extract_int8:
833: if (len > 7) {
834: rv = 6;
835: strcpy (buf, "(int8 ");
836: rv += print_subexpression (expr -> data.extract_int,
837: buf + rv, len - rv - 1);
838: buf [rv++] = ')';
839: buf [rv] = 0;
840: return rv;
841: }
842: break;
843:
844: case expr_extract_int16:
845: if (len > 8) {
846: rv = 7;
847: strcpy (buf, "(int16 ");
848: rv += print_subexpression (expr -> data.extract_int,
849: buf + rv, len - rv - 1);
850: buf [rv++] = ')';
851: buf [rv] = 0;
852: return rv;
853: }
854: break;
855:
856: case expr_extract_int32:
857: if (len > 8) {
858: rv = 7;
859: strcpy (buf, "(int32 ");
860: rv += print_subexpression (expr -> data.extract_int,
861: buf + rv, len - rv - 1);
862: buf [rv++] = ')';
863: buf [rv] = 0;
864: return rv;
865: }
866: break;
867:
868: case expr_encode_int8:
869: if (len > 7) {
870: rv = 6;
871: strcpy (buf, "(to-int8 ");
872: rv += print_subexpression (expr -> data.encode_int,
873: buf + rv, len - rv - 1);
874: buf [rv++] = ')';
875: buf [rv] = 0;
876: return rv;
877: }
878: break;
879:
880: case expr_encode_int16:
881: if (len > 8) {
882: rv = 7;
883: strcpy (buf, "(to-int16 ");
884: rv += print_subexpression (expr -> data.encode_int,
885: buf + rv, len - rv - 1);
886: buf [rv++] = ')';
887: buf [rv] = 0;
888: return rv;
889: }
890: break;
891:
892: case expr_encode_int32:
893: if (len > 8) {
894: rv = 7;
895: strcpy (buf, "(to-int32 ");
896: rv += print_subexpression (expr -> data.encode_int,
897: buf + rv, len - rv - 1);
898: buf [rv++] = ')';
899: buf [rv] = 0;
900: return rv;
901: }
902: break;
903:
904: case expr_const_int:
905: s = print_dec_1 (expr -> data.const_int);
906: rv = strlen (s);
907: if (len > rv) {
908: strcpy (buf, s);
909: return rv;
910: }
911: break;
912:
913: case expr_exists:
914: rv = 10 + (strlen (expr -> data.option -> name) +
915: strlen (expr -> data.option -> universe -> name));
916: if (len > rv) {
917: sprintf (buf, "(exists %s.%s)",
918: expr -> data.option -> universe -> name,
919: expr -> data.option -> name);
920: return rv;
921: }
922: break;
923:
924: case expr_variable_exists:
925: rv = 10 + strlen (expr -> data.variable);
926: if (len > rv) {
927: sprintf (buf, "(defined %s)", expr -> data.variable);
928: return rv;
929: }
930: break;
931:
932: case expr_variable_reference:
933: rv = strlen (expr -> data.variable);
934: if (len > rv) {
935: sprintf (buf, "%s", expr -> data.variable);
936: return rv;
937: }
938: break;
939:
940: case expr_known:
941: s = "known";
942: astring:
943: rv = strlen (s);
944: if (len > rv) {
945: strcpy (buf, s);
946: return rv;
947: }
948: break;
949:
950: case expr_leased_address:
951: s = "leased-address";
952: goto astring;
953:
954: case expr_client_state:
955: s = "client-state";
956: goto astring;
957:
958: case expr_host_decl_name:
959: s = "host-decl-name";
960: goto astring;
961:
962: case expr_lease_time:
963: s = "lease-time";
964: goto astring;
965:
966: case expr_static:
967: s = "static";
968: goto astring;
969:
970: case expr_filename:
971: s = "filename";
972: goto astring;
973:
974: case expr_sname:
975: s = "server-name";
976: goto astring;
977:
978: case expr_reverse:
979: if (len > 11) {
980: rv = 13;
981: strcpy (buf, "(reverse ");
982: rv += print_subexpression (expr -> data.reverse.width,
983: buf + rv, len - rv - 2);
984: buf [rv++] = ' ';
985: rv += print_subexpression (expr -> data.reverse.buffer,
986: buf + rv, len - rv - 1);
987: buf [rv++] = ')';
988: buf [rv] = 0;
989: return rv;
990: }
991: break;
992:
993: case expr_binary_to_ascii:
994: if (len > 5) {
995: rv = 9;
996: strcpy (buf, "(b2a ");
997: rv += print_subexpression (expr -> data.b2a.base,
998: buf + rv, len - rv - 4);
999: buf [rv++] = ' ';
1000: rv += print_subexpression (expr -> data.b2a.width,
1001: buf + rv, len - rv - 3);
1002: buf [rv++] = ' ';
1003: rv += print_subexpression (expr -> data.b2a.separator,
1004: buf + rv, len - rv - 2);
1005: buf [rv++] = ' ';
1006: rv += print_subexpression (expr -> data.b2a.buffer,
1007: buf + rv, len - rv - 1);
1008: buf [rv++] = ')';
1009: buf [rv] = 0;
1010: return rv;
1011: }
1012: break;
1013:
1014: case expr_dns_transaction:
1015: rv = 10;
1016: if (len < rv + 2) {
1017: buf [0] = '(';
1018: strcpy (&buf [1], "ns-update ");
1019: while (len < rv + 2) {
1020: rv += print_subexpression
1021: (expr -> data.dns_transaction.car,
1022: buf + rv, len - rv - 2);
1023: buf [rv++] = ' ';
1024: expr = expr -> data.dns_transaction.cdr;
1025: }
1026: buf [rv - 1] = ')';
1027: buf [rv] = 0;
1028: return rv;
1029: }
1030: return 0;
1031:
1032: case expr_ns_delete:
1033: s = "delete";
1034: left = 4;
1035: goto dodnsupd;
1036: case expr_ns_exists:
1037: s = "exists";
1038: left = 4;
1039: goto dodnsupd;
1040: case expr_ns_not_exists:
1041: s = "not_exists";
1042: left = 4;
1043: goto dodnsupd;
1044: case expr_ns_add:
1045: s = "update";
1046: left = 5;
1047: dodnsupd:
1048: rv = strlen (s);
1049: if (len > strlen (s) + 1) {
1050: buf [0] = '(';
1051: strcpy (buf + 1, s);
1052: rv++;
1053: buf [rv++] = ' ';
1054: s = print_dec_1 (expr -> data.ns_add.rrclass);
1055: if (len > rv + strlen (s) + left) {
1056: strcpy (&buf [rv], s);
1057: rv += strlen (&buf [rv]);
1058: }
1059: buf [rv++] = ' ';
1060: left--;
1061: s = print_dec_1 (expr -> data.ns_add.rrtype);
1062: if (len > rv + strlen (s) + left) {
1063: strcpy (&buf [rv], s);
1064: rv += strlen (&buf [rv]);
1065: }
1066: buf [rv++] = ' ';
1067: left--;
1068: rv += print_subexpression
1069: (expr -> data.ns_add.rrname,
1070: buf + rv, len - rv - left);
1071: buf [rv++] = ' ';
1072: left--;
1073: rv += print_subexpression
1074: (expr -> data.ns_add.rrdata,
1075: buf + rv, len - rv - left);
1076: buf [rv++] = ' ';
1077: left--;
1078: rv += print_subexpression
1079: (expr -> data.ns_add.ttl,
1080: buf + rv, len - rv - left);
1081: buf [rv++] = ')';
1082: buf [rv] = 0;
1083: return rv;
1084: }
1085: break;
1086:
1087: case expr_null:
1088: if (len > 6) {
1089: strcpy (buf, "(null)");
1090: return 6;
1091: }
1092: break;
1093: case expr_funcall:
1094: rv = 12 + strlen (expr -> data.funcall.name);
1095: if (len > rv + 1) {
1096: strcpy (buf, "(funcall ");
1097: strcpy (buf + 9, expr -> data.funcall.name);
1098: buf [rv++] = ' ';
1099: rv += print_subexpression
1100: (expr -> data.funcall.arglist, buf + rv,
1101: len - rv - 1);
1102: buf [rv++] = ')';
1103: buf [rv] = 0;
1104: return rv;
1105: }
1106: break;
1107:
1108: case expr_arg:
1109: rv = print_subexpression (expr -> data.arg.val, buf, len);
1110: if (expr -> data.arg.next && rv + 2 < len) {
1111: buf [rv++] = ' ';
1112: rv += print_subexpression (expr -> data.arg.next,
1113: buf, len);
1114: if (rv + 1 < len)
1115: buf [rv++] = 0;
1116: return rv;
1117: }
1118: break;
1119:
1120: case expr_function:
1121: rv = 9;
1122: if (len > rv + 1) {
1123: struct string_list *foo;
1124: strcpy (buf, "(function");
1125: for (foo = expr -> data.func -> args;
1126: foo; foo = foo -> next) {
1127: if (len > rv + 2 + strlen (foo -> string)) {
1128: buf [rv - 1] = ' ';
1129: strcpy (&buf [rv], foo -> string);
1130: rv += strlen (foo -> string);
1131: }
1132: }
1133: buf [rv++] = ')';
1134: buf [rv] = 0;
1135: return rv;
1136: }
1137:
1138: default:
1139: log_fatal("Impossible case at %s:%d (undefined expression "
1140: "%d).", MDL, expr->op);
1141: break;
1142: }
1143: return 0;
1144: }
1145:
1146: void print_expression (name, expr)
1147: const char *name;
1148: struct expression *expr;
1149: {
1150: char buf [1024];
1151:
1152: print_subexpression (expr, buf, sizeof buf);
1153: log_info ("%s: %s", name, buf);
1154: }
1155:
1156: int token_print_indent_concat (FILE *file, int col, int indent,
1157: const char *prefix,
1158: const char *suffix, ...)
1159: {
1160: va_list list;
1161: unsigned len;
1162: char *s, *t, *u;
1163:
1164: va_start (list, suffix);
1165: s = va_arg (list, char *);
1166: len = 0;
1167: while (s) {
1168: len += strlen (s);
1169: s = va_arg (list, char *);
1170: }
1171: va_end (list);
1172:
1173: t = dmalloc (len + 1, MDL);
1174: if (!t)
1175: log_fatal ("token_print_indent: no memory for copy buffer");
1176:
1177: va_start (list, suffix);
1178: s = va_arg (list, char *);
1179: u = t;
1180: while (s) {
1181: len = strlen (s);
1182: strcpy (u, s);
1183: u += len;
1184: s = va_arg (list, char *);
1185: }
1186: va_end (list);
1187:
1188: len = token_print_indent (file, col, indent,
1189: prefix, suffix, t);
1190: dfree (t, MDL);
1191: return col;
1192: }
1193:
1194: int token_indent_data_string (FILE *file, int col, int indent,
1195: const char *prefix, const char *suffix,
1196: struct data_string *data)
1197: {
1198: int i;
1199: char *buf;
1200: char obuf [3];
1201:
1202: /* See if this is just ASCII. */
1203: for (i = 0; i < data -> len; i++)
1204: if (!isascii (data -> data [i]) ||
1205: !isprint (data -> data [i]))
1206: break;
1207:
1208: /* If we have a purely ASCII string, output it as text. */
1209: if (i == data -> len) {
1210: buf = dmalloc (data -> len + 3, MDL);
1211: if (buf) {
1212: buf [0] = '"';
1213: memcpy (buf + 1, data -> data, data -> len);
1214: buf [data -> len + 1] = '"';
1215: buf [data -> len + 2] = 0;
1216: i = token_print_indent (file, col, indent,
1217: prefix, suffix, buf);
1218: dfree (buf, MDL);
1219: return i;
1220: }
1221: }
1222:
1223: for (i = 0; i < data -> len; i++) {
1224: sprintf (obuf, "%2.2x", data -> data [i]);
1225: col = token_print_indent (file, col, indent,
1226: i == 0 ? prefix : "",
1227: (i + 1 == data -> len
1228: ? suffix
1229: : ""), obuf);
1230: if (i + 1 != data -> len)
1231: col = token_print_indent (file, col, indent,
1232: prefix, suffix, ":");
1233: }
1234: return col;
1235: }
1236:
1237: int token_print_indent (FILE *file, int col, int indent,
1238: const char *prefix,
1239: const char *suffix, const char *buf)
1240: {
1241: int len = strlen (buf) + strlen (prefix);
1242: if (col + len > 79) {
1243: if (indent + len < 79) {
1244: indent_spaces (file, indent);
1245: col = indent;
1246: } else {
1247: indent_spaces (file, col);
1248: col = len > 79 ? 0 : 79 - len - 1;
1249: }
1250: } else if (prefix && *prefix) {
1251: fputs (prefix, file);
1252: col += strlen (prefix);
1253: }
1254: fputs (buf, file);
1255: col += len;
1256: if (suffix && *suffix) {
1257: if (col + strlen (suffix) > 79) {
1258: indent_spaces (file, indent);
1259: col = indent;
1260: } else {
1261: fputs (suffix, file);
1262: col += strlen (suffix);
1263: }
1264: }
1265: return col;
1266: }
1267:
1268: void indent_spaces (FILE *file, int indent)
1269: {
1270: int i;
1271: fputc ('\n', file);
1272: for (i = 0; i < indent; i++)
1273: fputc (' ', file);
1274: }
1275:
1276: #if defined (NSUPDATE)
1277: void print_dns_status (int status, ns_updque *uq)
1278: {
1279: char obuf [1024];
1280: char *s = &obuf [0], *end = &obuf [1022];
1281: ns_updrec *u;
1282: int position;
1283: int ttlp;
1284: const char *predicate = "if", *en, *op;
1285: int errorp;
1286:
1287: for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) {
1288: ttlp = 0;
1289:
1290: switch (u -> r_opcode)
1291: {
1292: case NXRRSET:
1293: op = "rrset doesn't exist";
1294: position = 1;
1295: break;
1296: case YXRRSET:
1297: op = "rrset exists";
1298: position = 1;
1299: break;
1300: case NXDOMAIN:
1301: op = "domain doesn't exist";
1302: position = 1;
1303: break;
1304: case YXDOMAIN:
1305: op = "domain exists";
1306: position = 1;
1307: break;
1308: case ADD:
1309: op = "add";
1310: position = 0;
1311: ttlp = 1;
1312: break;
1313: case DELETE:
1314: op = "delete";
1315: position = 0;
1316: break;
1317: default:
1318: op = "unknown";
1319: position = 0;
1320: break;
1321: }
1322: if (!position) {
1323: if (s != &obuf [0] && s + 1 < end)
1324: *s++ = ' ';
1325: if (s + strlen (op) < end) {
1326: strcpy (s, op);
1327: s += strlen (s);
1328: }
1329: } else {
1330: if (s != &obuf [0] && s + 1 < end)
1331: *s++ = ' ';
1332: if (s + strlen (predicate) < end) {
1333: strcpy (s, predicate);
1334: s += strlen (s);
1335: }
1336: predicate = "and";
1337: }
1338: if (u -> r_dname) {
1339: if (s + 1 < end)
1340: *s++ = ' ';
1341: if (s + strlen (u -> r_dname) < end) {
1342: strcpy (s, u -> r_dname);
1343: s += strlen (s);
1344: }
1345: }
1346: if (ttlp) {
1347: if (s + 1 < end)
1348: *s++ = ' ';
1349: /* 27 is as big as a ttl can get. */
1350: if (s + 27 < end) {
1351: sprintf (s, "%lu",
1352: (unsigned long)(u -> r_ttl));
1353: s += strlen (s);
1354: }
1355: }
1356: switch (u -> r_class) {
1357: case C_IN:
1358: en = "IN";
1359: break;
1360: case C_CHAOS:
1361: en = "CHAOS";
1362: break;
1363: case C_HS:
1364: en = "HS";
1365: break;
1366: default:
1367: en = "UNKNOWN";
1368: break;
1369: }
1370: if (s + strlen (en) < end) {
1371: if (s + 1 < end)
1372: *s++ = ' ';
1373: strcpy (s, en);
1374: s += strlen (en);
1375: }
1376: switch (u -> r_type) {
1377: case T_A:
1378: en = "A";
1379: break;
1380: case T_AAAA:
1381: en = "AAAA";
1382: break;
1383: case T_PTR:
1384: en = "PTR";
1385: break;
1386: case T_MX:
1387: en = "MX";
1388: break;
1389: case T_TXT:
1390: en = "TXT";
1391: break;
1392: case T_KEY:
1393: en = "KEY";
1394: break;
1395: case T_CNAME:
1396: en = "CNAME";
1397: break;
1398: default:
1399: en = "UNKNOWN";
1400: break;
1401: }
1402: if (s + strlen (en) < end) {
1403: if (s + 1 < end)
1404: *s++ = ' ';
1405: strcpy (s, en);
1406: s += strlen (en);
1407: }
1408: if (u -> r_data) {
1409: if (s + 1 < end)
1410: *s++ = ' ';
1411: if (u -> r_type == T_TXT) {
1412: if (s + 1 < end)
1413: *s++ = '"';
1414: }
1415: if(u->r_type == T_KEY) {
1416: strcat(s, "<keydata>");
1417: s+=strlen("<keydata>");
1418: }
1419: else {
1420: if (s + u -> r_size < end) {
1421: memcpy (s, u -> r_data, u -> r_size);
1422: s += u -> r_size;
1423: if (u -> r_type == T_TXT) {
1424: if (s + 1 < end)
1425: *s++ = '"';
1426: }
1427: }
1428: }
1429: }
1430: if (position) {
1431: if (s + 1 < end)
1432: *s++ = ' ';
1433: if (s + strlen (op) < end) {
1434: strcpy (s, op);
1435: s += strlen (s);
1436: }
1437: }
1438: if (u == ISC_LIST_TAIL (*uq))
1439: break;
1440: }
1441: if (s == &obuf [0]) {
1442: strcpy (s, "empty update");
1443: s += strlen (s);
1444: }
1445: if (status == NOERROR)
1446: errorp = 0;
1447: else
1448: errorp = 1;
1449: en = isc_result_totext (status);
1450: #if 0
1451: switch (status) {
1452: case -1:
1453: en = "resolver failed";
1454: break;
1455:
1456: case FORMERR:
1457: en = "format error";
1458: break;
1459:
1460: case NOERROR:
1461: en = "succeeded";
1462: errorp = 0;
1463: break;
1464:
1465: case NOTAUTH:
1466: en = "not authorized";
1467: break;
1468:
1469: case NOTIMP:
1470: en = "not implemented";
1471: break;
1472:
1473: case NOTZONE:
1474: en = "not a single valid zone";
1475: break;
1476:
1477: case NXDOMAIN:
1478: en = "no such domain";
1479: break;
1480:
1481: case NXRRSET:
1482: en = "no such record";
1483: break;
1484:
1485: case REFUSED:
1486: en = "refused";
1487: break;
1488:
1489: case SERVFAIL:
1490: en = "server failed";
1491: break;
1492:
1493: case YXDOMAIN:
1494: en = "domain exists";
1495: break;
1496:
1497: case YXRRSET:
1498: en = "record exists";
1499: break;
1500:
1501: default:
1502: en = "unknown error";
1503: break;
1504: }
1505: #endif
1506:
1507: if (s + 2 < end) {
1508: *s++ = ':';
1509: *s++ = ' ';
1510: }
1511: if (s + strlen (en) < end) {
1512: strcpy (s, en);
1513: s += strlen (en);
1514: }
1515: if (s + 1 < end)
1516: *s++ = '.';
1517: *s++ = 0;
1518: if (errorp)
1519: log_error ("%s", obuf);
1520: else
1521: log_info ("%s", obuf);
1522: }
1523: #endif /* NSUPDATE */
1524:
1525: /* Format the given time as "A; # B", where A is the format
1526: * used by the parser, and B is the local time, for humans.
1527: */
1528: const char *
1529: print_time(TIME t)
1530: {
1531: static char buf[sizeof("epoch 9223372036854775807; "
1532: "# Wed Jun 30 21:49:08 2147483647")];
1533: static char buf1[sizeof("# Wed Jun 30 21:49:08 2147483647")];
1534: time_t since_epoch;
1535: /* The string: "6 2147483647/12/31 23:59:60;"
1536: * is smaller than the other, used to declare the buffer size, so
1537: * we can use one buffer for both.
1538: */
1539:
1540: if (t == MAX_TIME)
1541: return "never;";
1542:
1543: if (t < 0)
1544: return NULL;
1545:
1546: /* For those lucky enough to have a 128-bit time_t, ensure that
1547: * whatever (corrupt) value we're given doesn't exceed the static
1548: * buffer.
1549: */
1550: #if (MAX_TIME > 0x7fffffffffffffff)
1551: if (t > 0x7fffffffffffffff)
1552: return NULL;
1553: #endif
1554:
1555: if (db_time_format == LOCAL_TIME_FORMAT) {
1556: since_epoch = mktime(localtime(&t));
1557: if ((strftime(buf1, sizeof(buf1),
1558: "# %a %b %d %H:%M:%S %Y",
1559: localtime(&t)) == 0) ||
1560: (snprintf(buf, sizeof(buf), "epoch %lu; %s",
1561: (unsigned long)since_epoch, buf1) >= sizeof(buf)))
1562: return NULL;
1563:
1564: } else {
1565: /* No bounds check for the year is necessary - in this case,
1566: * strftime() will run out of space and assert an error.
1567: */
1568: if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;",
1569: gmtime(&t)) == 0)
1570: return NULL;
1571: }
1572:
1573: return buf;
1574: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>