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