1/*	$NetBSD: db.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2
3/* db.c
4
5   Persistent database management routines for DHCPD... */
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: db.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
33
34#include "dhcpd.h"
35#include <ctype.h>
36#include <errno.h>
37
38#define LEASE_REWRITE_PERIOD 3600
39
40static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd,
41					char *prepend);
42
43FILE *db_file;
44
45static int counting = 0;
46static int count = 0;
47TIME write_time;
48int lease_file_is_corrupt = 0;
49
50/* Write a single binding scope value in parsable format.
51 */
52
53static isc_result_t
54write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) {
55	char *s;
56
57	if ((db_file == NULL) || (bnd == NULL) || (prepend == NULL))
58		return DHCP_R_INVALIDARG;
59
60	if (bnd->value->type == binding_data) {
61		if (bnd->value->value.data.data != NULL) {
62			s = quotify_buf(bnd->value->value.data.data,
63					bnd->value->value.data.len, '"', MDL);
64			if (s != NULL) {
65				errno = 0;
66				fprintf(db_file, "%sset %s = %s;",
67					prepend, bnd->name, s);
68				dfree(s, MDL);
69				if (errno)
70					return ISC_R_FAILURE;
71			} else {
72			    return ISC_R_FAILURE;
73			}
74		}
75	} else if (bnd->value->type == binding_numeric) {
76		errno = 0;
77		fprintf(db_file, "%sset %s = %%%ld;", prepend,
78			bnd->name, bnd->value->value.intval);
79		if (errno)
80			return ISC_R_FAILURE;
81	} else if (bnd->value->type == binding_boolean) {
82		errno = 0;
83		fprintf(db_file, "%sset %s = %s;", prepend, bnd->name,
84			bnd->value->value.intval ? "true" : "false");
85		if (errno)
86			return ISC_R_FAILURE;
87	} else if (bnd->value->type == binding_dns) {
88		log_error("%s: persistent dns values not supported.",
89			  bnd->name);
90	} else if (bnd->value->type == binding_function) {
91		log_error("%s: persistent functions not supported.",
92			  bnd->name);
93	} else {
94		log_fatal("%s: unknown binding type %d", bnd->name,
95			  bnd->value->type);
96	}
97
98	return ISC_R_SUCCESS;
99}
100
101/* Write the specified lease to the current lease database file. */
102
103int write_lease (lease)
104	struct lease *lease;
105{
106	int errors = 0;
107	struct binding *b;
108	char *s;
109	const char *tval;
110
111	/* If the lease file is corrupt, don't try to write any more leases
112	   until we've written a good lease file. */
113	if (lease_file_is_corrupt)
114		if (!new_lease_file (0))
115			return 0;
116
117	if (counting)
118		++count;
119	errno = 0;
120	fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
121	if (errno) {
122		++errors;
123	}
124
125	if (lease->starts &&
126	    ((tval = print_time(lease->starts)) == NULL ||
127	     fprintf(db_file, "\n  starts %s", tval) < 0))
128		++errors;
129
130	if (lease->ends &&
131	    ((tval = print_time(lease->ends)) == NULL ||
132	     fprintf(db_file, "\n  ends %s", tval) < 0))
133		++errors;
134
135	if (lease->tstp &&
136	    ((tval = print_time(lease->tstp)) == NULL ||
137	     fprintf(db_file, "\n  tstp %s", tval) < 0))
138		++errors;
139
140	if (lease->tsfp &&
141	    ((tval = print_time(lease->tsfp)) == NULL ||
142	     fprintf(db_file, "\n  tsfp %s", tval) < 0))
143		++errors;
144
145	if (lease->atsfp &&
146	    ((tval = print_time(lease->atsfp)) == NULL ||
147	     fprintf(db_file, "\n  atsfp %s", tval) < 0))
148		++errors;
149
150	if (lease->cltt &&
151	    ((tval = print_time(lease->cltt)) == NULL ||
152	     fprintf(db_file, "\n  cltt %s", tval) < 0))
153		++errors;
154
155	if (fprintf (db_file, "\n  binding state %s;",
156		 ((lease -> binding_state > 0 &&
157		   lease -> binding_state <= FTS_LAST)
158		  ? binding_state_names [lease -> binding_state - 1]
159		  : "abandoned")) < 0)
160                ++errors;
161
162	if (lease -> binding_state != lease -> next_binding_state)
163		if (fprintf (db_file, "\n  next binding state %s;",
164			 ((lease -> next_binding_state > 0 &&
165			   lease -> next_binding_state <= FTS_LAST)
166			  ? (binding_state_names
167			     [lease -> next_binding_state - 1])
168			  : "abandoned")) < 0)
169                        ++errors;
170
171	/*
172	 * In this case, if the rewind state is not present in the lease file,
173	 * the reader will use the current binding state as the most
174	 * conservative (safest) state.  So if the in-memory rewind state is
175	 * for some reason invalid, the best thing to do is not to write a
176	 * state and let the reader take on a safe state.
177	 */
178	if ((lease->binding_state != lease->rewind_binding_state) &&
179	    (lease->rewind_binding_state > 0) &&
180	    (lease->rewind_binding_state <= FTS_LAST) &&
181	    (fprintf(db_file, "\n  rewind binding state %s;",
182		     binding_state_names[lease->rewind_binding_state-1])) < 0)
183			++errors;
184
185	if (lease->flags & RESERVED_LEASE)
186		if (fprintf(db_file, "\n  reserved;") < 0)
187                        ++errors;
188
189	if (lease->flags & BOOTP_LEASE)
190		if (fprintf(db_file, "\n  dynamic-bootp;") < 0)
191                        ++errors;
192
193	/* If this lease is billed to a class and is still valid,
194	   write it out. */
195	if (lease -> billing_class && lease -> ends > cur_time) {
196		if (!write_billing_class (lease -> billing_class)) {
197			log_error ("unable to write class %s",
198				   lease -> billing_class -> name);
199			++errors;
200		}
201	}
202
203	if (lease -> hardware_addr.hlen) {
204		errno = 0;
205		fprintf (db_file, "\n  hardware %s %s;",
206			 hardware_types [lease -> hardware_addr.hbuf [0]],
207			 print_hw_addr (lease -> hardware_addr.hbuf [0],
208					lease -> hardware_addr.hlen - 1,
209					&lease -> hardware_addr.hbuf [1]));
210		if (errno)
211			++errors;
212	}
213	if (lease -> uid_len) {
214		s = format_lease_id(lease->uid, lease->uid_len, lease_id_format,
215				    MDL);
216		if (s) {
217			errno = 0;
218			fprintf (db_file, "\n  uid %s;", s);
219			if (errno)
220				++errors;
221			dfree (s, MDL);
222		} else
223			++errors;
224	}
225
226	if (lease->scope != NULL) {
227	    for (b = lease->scope->bindings; b; b = b->next) {
228		if (!b->value)
229			continue;
230
231		if (write_binding_scope(db_file, b, "\n  ") != ISC_R_SUCCESS)
232			++errors;
233	    }
234	}
235
236	if (lease -> agent_options) {
237	    struct option_cache *oc;
238	    struct data_string ds;
239	    pair p;
240
241	    memset (&ds, 0, sizeof ds);
242	    for (p = lease -> agent_options -> first; p; p = p -> cdr) {
243	        oc = (struct option_cache *)p -> car;
244	        if (oc -> data.len) {
245	    	errno = 0;
246	    	fprintf (db_file, "\n  option agent.%s %s;",
247	    		 oc -> option -> name,
248	    		 pretty_print_option (oc -> option, oc -> data.data,
249				      		oc -> data.len, 1, 1));
250	    	if (errno)
251		    ++errors;
252	        }
253	    }
254	}
255	if (lease -> client_hostname &&
256	    db_printable((unsigned char *)lease->client_hostname)) {
257		s = quotify_string (lease -> client_hostname, MDL);
258		if (s) {
259			errno = 0;
260			fprintf (db_file, "\n  client-hostname \"%s\";", s);
261			if (errno)
262				++errors;
263			dfree (s, MDL);
264		} else
265			++errors;
266	}
267	if (lease->on_star.on_expiry) {
268		errno = 0;
269		fprintf (db_file, "\n  on expiry%s {",
270			 lease->on_star.on_expiry == lease->on_star.on_release
271			 ? " or release" : "");
272		write_statements (db_file, lease->on_star.on_expiry, 4);
273		/* XXX */
274		fprintf (db_file, "\n  }");
275		if (errno)
276			++errors;
277	}
278	if (lease->on_star.on_release &&
279	    lease->on_star.on_release != lease->on_star.on_expiry) {
280		errno = 0;
281		fprintf (db_file, "\n  on release {");
282		write_statements (db_file, lease->on_star.on_release, 4);
283		/* XXX */
284		fprintf (db_file, "\n  }");
285		if (errno)
286			++errors;
287	}
288
289	errno = 0;
290	fputs ("\n}\n", db_file);
291	if (errno)
292		++errors;
293
294	if (errors) {
295		log_info ("write_lease: unable to write lease %s",
296		      piaddr (lease -> ip_addr));
297		lease_file_is_corrupt = 1;
298        }
299
300	return !errors;
301}
302
303int write_host (host)
304	struct host_decl *host;
305{
306	int errors = 0;
307	int i;
308	struct data_string ip_addrs;
309
310	/* If the lease file is corrupt, don't try to write any more leases
311	   until we've written a good lease file. */
312	if (lease_file_is_corrupt)
313		if (!new_lease_file (0))
314			return 0;
315
316	if (!db_printable((unsigned char *)host->name))
317		return 0;
318
319	if (counting)
320		++count;
321
322	errno = 0;
323	fprintf (db_file, "host %s {", host -> name);
324	if (errno)
325		++errors;
326
327	if (host -> flags & HOST_DECL_DYNAMIC) {
328		errno = 0;
329		fprintf (db_file, "\n  dynamic;");
330		if (errno)
331			++errors;
332	}
333
334	if (host -> flags & HOST_DECL_DELETED) {
335		errno = 0;
336		fprintf (db_file, "\n  deleted;");
337		if (errno)
338			++errors;
339	} else {
340		if (host -> interface.hlen) {
341			errno = 0;
342			fprintf (db_file, "\n  hardware %s %s;",
343				 hardware_types [host -> interface.hbuf [0]],
344				 print_hw_addr (host -> interface.hbuf [0],
345						host -> interface.hlen - 1,
346						&host -> interface.hbuf [1]));
347			if (errno)
348				++errors;
349		}
350		if (host -> client_identifier.len) {
351			int i;
352			errno = 0;
353			if (db_printable_len (host -> client_identifier.data,
354					      host -> client_identifier.len)) {
355				fprintf (db_file, "\n  uid \"%.*s\";",
356					 (int)host -> client_identifier.len,
357					 host -> client_identifier.data);
358				if (errno)
359					++errors;
360			} else {
361				fprintf (db_file,
362					 "\n  uid %2.2x",
363					 host -> client_identifier.data [0]);
364				if (errno)
365					++errors;
366				for (i = 1;
367				     i < host -> client_identifier.len; i++) {
368					errno = 0;
369					fprintf (db_file, ":%2.2x",
370						 host ->
371						 client_identifier.data [i]);
372					if (errno)
373						++errors;
374				}
375
376                                errno = 0;
377				fputc (';', db_file);
378				if (errno)
379					++errors;
380			}
381		}
382
383		memset (&ip_addrs, 0, sizeof ip_addrs);
384		if (host -> fixed_addr &&
385		    evaluate_option_cache (&ip_addrs, (struct packet *)0,
386					   (struct lease *)0,
387					   (struct client_state *)0,
388					   (struct option_state *)0,
389					   (struct option_state *)0,
390					   &global_scope,
391					   host -> fixed_addr, MDL)) {
392
393			errno = 0;
394			fprintf (db_file, "\n  fixed-address ");
395			if (errno)
396				++errors;
397			for (i = 0; i < ip_addrs.len - 3; i += 4) {
398
399				errno = 0;
400				fprintf (db_file, "%u.%u.%u.%u%s",
401					 ip_addrs.data [i] & 0xff,
402					 ip_addrs.data [i + 1] & 0xff,
403					 ip_addrs.data [i + 2] & 0xff,
404					 ip_addrs.data [i + 3] & 0xff,
405					 i + 7 < ip_addrs.len ? "," : "");
406				if (errno)
407					++errors;
408			}
409
410			/* We're done with ip_addrs so pitch it */
411			data_string_forget (&ip_addrs, MDL);
412
413			errno = 0;
414			fputc (';', db_file);
415			if (errno)
416				++errors;
417
418		}
419
420		if (host -> named_group) {
421			errno = 0;
422			fprintf (db_file, "\n  group \"%s\";",
423				 host -> named_group -> name);
424			if (errno)
425				++errors;
426		}
427
428		if (host -> group &&
429		    (!host -> named_group ||
430		     host -> group != host -> named_group -> group) &&
431		    host -> group != root_group) {
432			errno = 0;
433			write_statements (db_file,
434					  host -> group -> statements, 8);
435			if (errno)
436				++errors;
437		}
438	}
439
440	errno = 0;
441	fputs ("\n}\n", db_file);
442	if (errno)
443		++errors;
444
445	if (errors) {
446		log_info ("write_host: unable to write host %s",
447			  host -> name);
448		lease_file_is_corrupt = 1;
449	}
450
451	return !errors;
452}
453
454int write_group (group)
455	struct group_object *group;
456{
457	int errors = 0;
458
459	/* If the lease file is corrupt, don't try to write any more leases
460	   until we've written a good lease file. */
461	if (lease_file_is_corrupt)
462		if (!new_lease_file (0))
463			return 0;
464
465	if (!db_printable((unsigned char *)group->name))
466		return 0;
467
468	if (counting)
469		++count;
470
471	errno = 0;
472	fprintf (db_file, "group %s {", group -> name);
473	if (errno)
474		++errors;
475
476	if (group -> flags & GROUP_OBJECT_DYNAMIC) {
477		errno = 0;
478		fprintf (db_file, "\n  dynamic;");
479		if (errno)
480			++errors;
481	}
482
483	if (group -> flags & GROUP_OBJECT_STATIC) {
484		errno = 0;
485		fprintf (db_file, "\n  static;");
486		if (errno)
487			++errors;
488	}
489
490	if (group -> flags & GROUP_OBJECT_DELETED) {
491		errno = 0;
492		fprintf (db_file, "\n  deleted;");
493		if (errno)
494			++errors;
495	} else {
496		if (group -> group) {
497			errno = 0;
498			write_statements (db_file,
499					  group -> group -> statements, 8);
500			if (errno)
501				++errors;
502		}
503	}
504
505	errno = 0;
506	fputs ("\n}\n", db_file);
507	if (errno)
508		++errors;
509
510	if (errors) {
511		log_info ("write_group: unable to write group %s",
512			  group -> name);
513		lease_file_is_corrupt = 1;
514	}
515
516	return !errors;
517}
518
519/*
520 * Write an IA and the options it has.
521 */
522int
523write_ia(const struct ia_xx *ia) {
524	struct iasubopt *iasubopt;
525	struct binding *bnd;
526	int i;
527	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
528	const char *binding_state;
529	const char *tval;
530	char *s;
531	int fprintf_ret;
532
533#ifdef EUI_64
534	/* If we're not writing EUI64 leases to the file, then
535	* we can skip writing this IA provided all of its leases
536	* are EUI64. (Not sure you can ever have a case where
537	* they aren't but doesn't hurt to check) */
538	if (ia->ia_type == D6O_IA_NA && !persist_eui64) {
539		int i;
540		for (i=0; i < ia->num_iasubopt; i++) {
541			if (!ia->iasubopt[i]->ipv6_pool->ipv6_pond->use_eui_64)
542			{
543				break;
544			}
545		}
546
547		if (i == ia->num_iasubopt) {
548			/* Their all EUI64 so we can skip it */
549			return(1);
550		}
551	}
552#endif
553
554	/*
555	 * If the lease file is corrupt, don't try to write any more
556	 * leases until we've written a good lease file.
557	 */
558	if (lease_file_is_corrupt) {
559		if (!new_lease_file(0)) {
560			return 0;
561		}
562	}
563
564	if (counting) {
565		++count;
566	}
567
568	s = format_lease_id(ia->iaid_duid.data, ia->iaid_duid.len,
569			    lease_id_format, MDL);
570	if (s == NULL) {
571		goto error_exit;
572	}
573	switch (ia->ia_type) {
574	case D6O_IA_NA:
575		fprintf_ret = fprintf(db_file, "ia-na %s {\n", s);
576		break;
577	case D6O_IA_TA:
578		fprintf_ret = fprintf(db_file, "ia-ta %s {\n", s);
579		break;
580	case D6O_IA_PD:
581		fprintf_ret = fprintf(db_file, "ia-pd %s {\n", s);
582		break;
583	default:
584		log_error("Unknown ia type %u for %s at %s:%d",
585			  (unsigned)ia->ia_type, s, MDL);
586		fprintf_ret = -1;
587	}
588	dfree(s, MDL);
589	if (fprintf_ret < 0) {
590		goto error_exit;
591	}
592	if (ia->cltt != MIN_TIME) {
593		tval = print_time(ia->cltt);
594		if (tval == NULL) {
595			goto error_exit;
596		}
597		if (fprintf(db_file, "  cltt %s\n", tval) < 0) {
598			goto error_exit;
599		}
600	}
601	for (i=0; i<ia->num_iasubopt; i++) {
602		iasubopt = ia->iasubopt[i];
603
604		inet_ntop(AF_INET6, &iasubopt->addr,
605			  addr_buf, sizeof(addr_buf));
606		if ((ia->ia_type != D6O_IA_PD) &&
607		    (fprintf(db_file, "  iaaddr %s {\n", addr_buf) < 0)) {
608			goto error_exit;
609		}
610		if ((ia->ia_type == D6O_IA_PD) &&
611		    (fprintf(db_file, "  iaprefix %s/%d {\n",
612			     addr_buf, (int)iasubopt->plen) < 0)) {
613			goto error_exit;
614		}
615		if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) {
616			log_fatal("Unknown iasubopt state %d at %s:%d",
617				  iasubopt->state, MDL);
618		}
619		binding_state = binding_state_names[iasubopt->state-1];
620		if (fprintf(db_file, "    binding state %s;\n",
621			    binding_state) < 0) {
622			goto error_exit;
623		}
624		if (fprintf(db_file, "    preferred-life %u;\n",
625			    (unsigned)iasubopt->prefer) < 0) {
626			goto error_exit;
627		}
628		if (fprintf(db_file, "    max-life %u;\n",
629			    (unsigned)iasubopt->valid) < 0) {
630			goto error_exit;
631		}
632
633		/* Note that from here on out, the \n is prepended to the
634		 * next write, rather than appended to the current write.
635		 */
636		if ((iasubopt->state == FTS_ACTIVE) ||
637		    (iasubopt->state == FTS_ABANDONED) ||
638		    (iasubopt->hard_lifetime_end_time != 0)) {
639			tval = print_time(iasubopt->hard_lifetime_end_time);
640		} else {
641			tval = print_time(iasubopt->soft_lifetime_end_time);
642		}
643		if (tval == NULL) {
644			goto error_exit;
645		}
646		if (fprintf(db_file, "    ends %s", tval) < 0) {
647			goto error_exit;
648		}
649
650		/* Write out any binding scopes: note that 'ends' above does
651		 * not have \n on the end!  We want that.
652		 */
653		if (iasubopt->scope != NULL)
654			bnd = iasubopt->scope->bindings;
655		else
656			bnd = NULL;
657
658		for (; bnd != NULL ; bnd = bnd->next) {
659			if (bnd->value == NULL)
660				continue;
661
662			/* We don't do a regular error_exit because the
663			 * lease db is not corrupt in this case.
664			 */
665			if (write_binding_scope(db_file, bnd,
666						"\n    ") != ISC_R_SUCCESS)
667				goto error_exit;
668
669		}
670
671		if (iasubopt->on_star.on_expiry) {
672			if (fprintf(db_file, "\n    on expiry%s {",
673				    iasubopt->on_star.on_expiry ==
674				    iasubopt->on_star.on_release
675				    ? " or release" : "") < 0)
676				goto error_exit;
677			write_statements(db_file,
678					 iasubopt->on_star.on_expiry, 6);
679			if (fprintf(db_file, "\n    }") < 0)
680				goto error_exit;
681		}
682
683		if (iasubopt->on_star.on_release &&
684		    iasubopt->on_star.on_release !=
685		    iasubopt->on_star.on_expiry) {
686			if (fprintf(db_file, "\n    on release {") < 0)
687				goto error_exit;
688			write_statements(db_file,
689					 iasubopt->on_star.on_release, 6);
690			if (fprintf(db_file, "\n    }") < 0)
691				goto error_exit;
692		}
693
694		if (fprintf(db_file, "\n  }\n") < 0)
695                        goto error_exit;
696	}
697	if (fprintf(db_file, "}\n\n") < 0)
698                goto error_exit;
699
700	fflush(db_file);
701	return 1;
702
703error_exit:
704	log_info("write_ia: unable to write ia");
705	lease_file_is_corrupt = 1;
706	return 0;
707}
708
709#ifdef DHCPv6
710/*
711 * Put a copy of the server DUID in the leases file.
712 */
713int
714write_server_duid(void) {
715	struct data_string server_duid;
716	char *s;
717	int fprintf_ret;
718
719	/*
720	 * Only write the DUID if it's been set.
721	 */
722	if (!server_duid_isset()) {
723		return 1;
724	}
725
726	/*
727	 * If the lease file is corrupt, don't try to write any more
728	 * leases until we've written a good lease file.
729	 */
730	if (lease_file_is_corrupt) {
731		if (!new_lease_file(0)) {
732			return 0;
733		}
734	}
735
736	/*
737	 * Get a copy of our server DUID and convert to a quoted string.
738	 */
739	memset(&server_duid, 0, sizeof(server_duid));
740	copy_server_duid(&server_duid, MDL);
741	s = format_lease_id(server_duid.data, server_duid.len, lease_id_format,
742			    MDL);
743	data_string_forget(&server_duid, MDL);
744	if (s == NULL) {
745		goto error_exit;
746	}
747
748	/*
749	 * Write to the leases file.
750	 */
751	fprintf_ret = fprintf(db_file, "server-duid %s;\n\n", s);
752	dfree(s, MDL);
753	if (fprintf_ret < 0) {
754		goto error_exit;
755	}
756
757	/*
758	 * Check if we actually managed to write.
759	 */
760	fflush(db_file);
761	return 1;
762
763error_exit:
764	log_info("write_server_duid: unable to write server-duid");
765	lease_file_is_corrupt = 1;
766	return 0;
767}
768#endif /* DHCPv6 */
769
770#if defined (FAILOVER_PROTOCOL)
771int write_failover_state (dhcp_failover_state_t *state)
772{
773	int errors = 0;
774	const char *tval;
775
776	if (lease_file_is_corrupt)
777		if (!new_lease_file (0))
778			return 0;
779
780	errno = 0;
781	fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
782	if (errno)
783		++errors;
784
785	tval = print_time(state->me.stos);
786	if (tval == NULL ||
787	    fprintf(db_file, "\n  my state %s at %s",
788		    (state->me.state == startup) ?
789		    dhcp_failover_state_name_print(state->saved_state) :
790		    dhcp_failover_state_name_print(state->me.state),
791		    tval) < 0)
792		++errors;
793
794	tval = print_time(state->partner.stos);
795	if (tval == NULL ||
796	    fprintf(db_file, "\n  partner state %s at %s",
797		    dhcp_failover_state_name_print(state->partner.state),
798		    tval) < 0)
799		++errors;
800
801	if (state -> i_am == secondary) {
802		errno = 0;
803		fprintf (db_file, "\n  mclt %ld;",
804			 (unsigned long)state -> mclt);
805		if (errno)
806			++errors;
807	}
808
809        errno = 0;
810	fprintf (db_file, "\n}\n");
811	if (errno)
812		++errors;
813
814	if (errors) {
815		log_info ("write_failover_state: unable to write state %s",
816			  state -> name);
817		lease_file_is_corrupt = 1;
818		return 0;
819	}
820
821	return 1;
822
823}
824#endif
825
826int db_printable (s)
827	const unsigned char *s;
828{
829	int i;
830	for (i = 0; s [i]; i++)
831		if (!isascii (s [i]) || !isprint (s [i])
832		    || s [i] == '"' || s [i] == '\\')
833			return 0;
834	return 1;
835}
836
837int db_printable_len (s, len)
838	const unsigned char *s;
839	unsigned len;
840{
841	int i;
842
843	for (i = 0; i < len; i++)
844		if (!isascii (s [i]) || !isprint (s [i]) ||
845		    s [i] == '"' || s [i] == '\\')
846			return 0;
847	return 1;
848}
849
850static int print_hash_string(FILE *fp, struct class *class)
851{
852	int i;
853
854	for (i = 0 ; i < class->hash_string.len ; i++)
855		if (!isascii(class->hash_string.data[i]) ||
856		    !isprint(class->hash_string.data[i]))
857			break;
858
859	if (i == class->hash_string.len) {
860		if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
861			    class->hash_string.data) <= 0) {
862			log_error("Failure writing hash string: %m");
863			return 0;
864		}
865	} else {
866		if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
867			log_error("Failure writing hash string: %m");
868			return 0;
869		}
870		for (i = 1 ; i < class->hash_string.len ; i++) {
871			if (fprintf(fp, ":%2.2x",
872				    class->hash_string.data[i]) <= 0) {
873				log_error("Failure writing hash string: %m");
874				return 0;
875			}
876		}
877	}
878
879	return 1;
880}
881
882
883isc_result_t
884write_named_billing_class(const void *key, unsigned len, void *object)
885{
886	const unsigned char *name = key;
887	struct class *class = object;
888
889	if (class->flags & CLASS_DECL_DYNAMIC) {
890		numclasseswritten++;
891		if (class->superclass == 0) {
892			if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
893				return ISC_R_IOERROR;
894		} else {
895			if (fprintf(db_file, "subclass \"%s\"",
896				    class->superclass->name) <= 0)
897				return ISC_R_IOERROR;
898			if (!print_hash_string(db_file, class))
899				return ISC_R_IOERROR;
900			if (fprintf(db_file, " {\n") <= 0)
901				return ISC_R_IOERROR;
902		}
903
904		if ((class->flags & CLASS_DECL_DELETED) != 0) {
905			if (fprintf(db_file, "  deleted;\n") <= 0)
906				return ISC_R_IOERROR;
907		} else {
908			if (fprintf(db_file, "  dynamic;\n") <= 0)
909				return ISC_R_IOERROR;
910		}
911
912		if (class->lease_limit > 0) {
913			if (fprintf(db_file, "  lease limit %d;\n",
914				    class->lease_limit) <= 0)
915				return ISC_R_IOERROR;
916		}
917
918		if (class->expr != 0) {
919			if (fprintf(db_file, "  match if ") <= 0)
920				return ISC_R_IOERROR;
921
922                        errno = 0;
923			write_expression(db_file, class->expr, 5, 5, 0);
924                        if (errno)
925                                return ISC_R_IOERROR;
926
927			if (fprintf(db_file, ";\n") <= 0)
928				return ISC_R_IOERROR;
929		}
930
931		if (class->submatch != 0) {
932			if (class->spawning) {
933				if (fprintf(db_file, "  spawn ") <= 0)
934					return ISC_R_IOERROR;
935			} else {
936				if (fprintf(db_file, "  match ") <= 0)
937					return ISC_R_IOERROR;
938			}
939
940                        errno = 0;
941			write_expression(db_file, class->submatch, 5, 5, 0);
942                        if (errno)
943                                return ISC_R_IOERROR;
944
945			if (fprintf(db_file, ";\n") <= 0)
946				return ISC_R_IOERROR;
947		}
948
949		if (class->statements != 0) {
950                        errno = 0;
951			write_statements(db_file, class->statements, 8);
952                        if (errno)
953                                return ISC_R_IOERROR;
954		}
955
956		/* XXXJAB this isn't right, but classes read in off the
957		   leases file don't get the root group assigned to them
958		   (due to clone_group() call). */
959		if (class->group != 0 && class->group->authoritative != 0) {
960                        errno = 0;
961			write_statements(db_file, class->group->statements, 8);
962                        if (errno)
963                                return ISC_R_IOERROR;
964                }
965
966		if (fprintf(db_file, "}\n\n") <= 0)
967			return ISC_R_IOERROR;
968	}
969
970	if (class->hash != NULL) {	/* yep. recursive. god help us. */
971		/* XXX - cannot check error status of this...
972		 * foo_hash_foreach returns a count of operations completed.
973		 */
974		class_hash_foreach(class->hash, write_named_billing_class);
975	}
976
977	return ISC_R_SUCCESS;
978}
979
980void write_billing_classes ()
981{
982	struct collection *lp;
983	struct class *cp;
984
985	for (lp = collections; lp; lp = lp -> next) {
986	    for (cp = lp -> classes; cp; cp = cp -> nic) {
987		if (cp -> spawning && cp -> hash) {
988		    class_hash_foreach (cp -> hash, write_named_billing_class);
989		}
990	    }
991	}
992}
993
994/* Write a spawned class to the database file. */
995
996int write_billing_class (class)
997	struct class *class;
998{
999	int errors = 0;
1000
1001	if (lease_file_is_corrupt)
1002		if (!new_lease_file (0))
1003			return 0;
1004
1005	if (!class -> superclass) {
1006		errno = 0;
1007		fprintf (db_file, "\n  billing class \"%s\";", class -> name);
1008		return !errno;
1009	}
1010
1011	if (fprintf(db_file, "\n  billing subclass \"%s\"",
1012		    class -> superclass -> name) < 0)
1013		++errors;
1014
1015	if (!print_hash_string(db_file, class))
1016                ++errors;
1017
1018	if (fprintf(db_file, ";") < 0)
1019                ++errors;
1020
1021	class -> dirty = !errors;
1022	if (errors)
1023		lease_file_is_corrupt = 1;
1024
1025	return !errors;
1026}
1027
1028/* Commit leases after a timeout. */
1029void commit_leases_timeout (void *foo)
1030{
1031	commit_leases ();
1032}
1033
1034/* Commit any leases that have been written out... */
1035
1036int commit_leases ()
1037{
1038	/* Commit any outstanding writes to the lease database file.
1039	   We need to do this even if we're rewriting the file below,
1040	   just in case the rewrite fails. */
1041	if (fflush (db_file) == EOF) {
1042		log_info("commit_leases: unable to commit, fflush(): %m");
1043		return (0);
1044	}
1045	if ((dont_use_fsync == 0) &&
1046	    (fsync(fileno (db_file)) < 0)) {
1047		log_info ("commit_leases: unable to commit, fsync(): %m");
1048		return (0);
1049	}
1050
1051	/* If we haven't rewritten the lease database in over an
1052	   hour, rewrite it now.  (The length of time should probably
1053	   be configurable. */
1054	if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) {
1055		count = 0;
1056		write_time = cur_time;
1057		new_lease_file(0);
1058	}
1059	return (1);
1060}
1061
1062/*
1063 * rewrite the lease file about once an hour
1064 * This is meant as a quick patch for ticket 24887.  It allows
1065 * us to rotate the v6 lease file without adding too many fsync()
1066 * calls.  In the future wes should revisit this area and add
1067 * something similar to the delayed ack code for v4.
1068 */
1069int commit_leases_timed()
1070{
1071	if ((count != 0) && (cur_time - write_time > LEASE_REWRITE_PERIOD)) {
1072		return (commit_leases());
1073	}
1074	return (1);
1075}
1076
1077void db_startup (int test_mode)
1078{
1079	const char *current_db_path;
1080	isc_result_t status;
1081
1082#if defined (TRACING)
1083	if (!trace_playback ()) {
1084#endif
1085		/* Unset authoring_byte_order so we'll know if it was specified
1086		   in the lease file or not. */
1087		authoring_byte_order = 0;
1088
1089		/* Read in the existing lease file... */
1090		status = read_conf_file (path_dhcpd_db,
1091					 (struct group *)0, 0, 1);
1092		if (status != ISC_R_SUCCESS) {
1093			/* XXX ignore status? */
1094			;
1095		}
1096
1097#if defined (TRACING)
1098	}
1099#endif
1100
1101#if defined (TRACING)
1102	/* If we're playing back, there is no lease file, so we can't
1103	   append it, so we create one immediately (maybe this isn't
1104	   the best solution... */
1105	if (trace_playback ()) {
1106		new_lease_file (0);
1107	}
1108#endif
1109	/* expire_all_pools will cause writes to the "current" lease file.
1110	* Therefore, in test mode we need to point db_file to a disposable
1111	* file to protect the original lease file. */
1112	current_db_path = (test_mode ? "/dev/null" : path_dhcpd_db);
1113	db_file = fopen (current_db_path, "a");
1114	if (!db_file) {
1115		log_fatal ("Can't open %s for append.", current_db_path);
1116	}
1117
1118	expire_all_pools ();
1119#if defined (TRACING)
1120	if (trace_playback ())
1121		write_time = cur_time;
1122	else
1123#endif
1124		time(&write_time);
1125	new_lease_file (test_mode);
1126
1127#if defined(REPORT_HASH_PERFORMANCE)
1128	log_info("Host HW hash:   %s", host_hash_report(host_hw_addr_hash));
1129	log_info("Host UID hash:  %s", host_hash_report(host_uid_hash));
1130	log_info("Lease IP hash:  %s",
1131		 lease_ip_hash_report(lease_ip_addr_hash));
1132	log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
1133	log_info("Lease HW hash:  %s",
1134		 lease_id_hash_report(lease_hw_addr_hash));
1135#endif
1136}
1137
1138int new_lease_file (int test_mode)
1139{
1140	char newfname [512];
1141	char backfname [512];
1142	TIME t;
1143	int db_fd;
1144	int db_validity;
1145	FILE *new_db_file;
1146
1147	/* Make a temporary lease file... */
1148	time(&t);
1149
1150	db_validity = lease_file_is_corrupt;
1151
1152	/* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
1153	 * This should never happen since the path is a configuration
1154	 * variable from build-time or command-line.  But if it should,
1155	 * either by malice or ignorance, we panic, since the potential
1156	 * for havoc is high.
1157	 */
1158	if (snprintf (newfname, sizeof newfname, "%s.%d",
1159		     path_dhcpd_db, (int)t) >= sizeof newfname)
1160		log_fatal("new_lease_file: lease file path too long");
1161
1162	db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
1163	if (db_fd < 0) {
1164		log_error ("Can't create new lease file: %m");
1165		return 0;
1166	}
1167
1168#if defined (PARANOIA)
1169	/*
1170	 * If we are currently root and plan to change the
1171	 * uid and gid change the file information so we
1172	 * can manipulate it later, after we've changed
1173	 * our group and user (that is dropped privileges.)
1174	 */
1175	if ((set_uid != 0) && (geteuid() == 0) &&
1176	    (set_gid != 0) && (getegid() == 0)) {
1177		if (fchown(db_fd, set_uid, set_gid)) {
1178			log_fatal ("Can't chown new lease file: %m");
1179		}
1180	}
1181#endif /* PARANOIA */
1182
1183	if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
1184		log_error("Can't fdopen new lease file: %m");
1185		close(db_fd);
1186		goto fdfail;
1187	}
1188
1189	/* Close previous database, if any. */
1190	if (db_file)
1191		fclose(db_file);
1192	db_file = new_db_file;
1193
1194	errno = 0;
1195	fprintf (db_file, "# The format of this file is documented in the %s",
1196		 "dhcpd.leases(5) manual page.\n");
1197
1198	if (errno)
1199		goto fail;
1200
1201	fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
1202		 PACKAGE_VERSION);
1203	if (errno)
1204		goto fail;
1205
1206	fprintf (db_file, "# authoring-byte-order entry is generated,"
1207                          " DO NOT DELETE\n");
1208	if (errno)
1209		goto fail;
1210
1211	fprintf (db_file, "authoring-byte-order %s;\n\n",
1212		 (DHCP_BYTE_ORDER == LITTLE_ENDIAN ?
1213		  "little-endian" : "big-endian"));
1214	if (errno)
1215		goto fail;
1216
1217	/* At this point we have a new lease file that, so far, could not
1218	 * be described as either corrupt nor valid.
1219	 */
1220	lease_file_is_corrupt = 0;
1221
1222	/* Write out all the leases that we know of... */
1223	counting = 0;
1224	if (!write_leases ())
1225		goto fail;
1226
1227	if (test_mode) {
1228		log_debug("Lease file test successful,"
1229			  " removing temp lease file: %s",
1230			  newfname);
1231		(void)unlink (newfname);
1232		return (1);
1233	}
1234
1235#if defined (TRACING)
1236	if (!trace_playback ()) {
1237#endif
1238	    /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
1239	     * This should never happen since the path is a configuration
1240	     * variable from build-time or command-line.  But if it should,
1241	     * either by malice or ignorance, we panic, since the potential
1242	     * for havoc is too high.
1243	     */
1244	    if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
1245			>= sizeof backfname)
1246		log_fatal("new_lease_file: backup lease file path too long");
1247
1248	    /* Get the old database out of the way... */
1249	    if (unlink (backfname) < 0 && errno != ENOENT) {
1250		log_error ("Can't remove old lease database backup %s: %m",
1251			   backfname);
1252		goto fail;
1253	    }
1254	    if (link(path_dhcpd_db, backfname) < 0) {
1255		if (errno == ENOENT) {
1256			log_error("%s is missing - no lease db to backup.",
1257				  path_dhcpd_db);
1258		} else {
1259			log_error("Can't backup lease database %s to %s: %m",
1260				  path_dhcpd_db, backfname);
1261			goto fail;
1262		}
1263	    }
1264#if defined (TRACING)
1265	}
1266#endif
1267
1268	/* Move in the new file... */
1269	if (rename (newfname, path_dhcpd_db) < 0) {
1270		log_error ("Can't install new lease database %s to %s: %m",
1271			   newfname, path_dhcpd_db);
1272		goto fail;
1273	}
1274
1275	counting = 1;
1276	return 1;
1277
1278      fail:
1279	lease_file_is_corrupt = db_validity;
1280      fdfail:
1281	(void)unlink (newfname);
1282	return 0;
1283}
1284
1285int group_writer (struct group_object *group)
1286{
1287	if (!write_group (group))
1288		return 0;
1289	if (!commit_leases ())
1290		return 0;
1291	return 1;
1292}
1293