xref: /minix/external/bsd/dhcp/dist/server/db.c (revision fb9c64b2)
1 /*	$NetBSD: db.c,v 1.1.1.3 2014/07/12 11:58:05 spz Exp $	*/
2 /* db.c
3 
4    Persistent database management routines for DHCPD... */
5 
6 /*
7  * Copyright (c) 2012-2014 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1995-2003 by Internet Software Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
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  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: db.c,v 1.1.1.3 2014/07/12 11:58:05 spz Exp $");
33 
34 #include "dhcpd.h"
35 #include <ctype.h>
36 #include <errno.h>
37 
38 #define LEASE_REWRITE_PERIOD 3600
39 
40 static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd,
41 					char *prepend);
42 
43 FILE *db_file;
44 
45 static int counting = 0;
46 static int count = 0;
47 TIME write_time;
48 int lease_file_is_corrupt = 0;
49 
50 /* Write a single binding scope value in parsable format.
51  */
52 
53 static isc_result_t
54 write_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 
103 int 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 ())
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 = quotify_buf (lease -> uid, lease -> uid_len, MDL);
215 		if (s) {
216 			errno = 0;
217 			fprintf (db_file, "\n  uid \"%s\";", s);
218 			if (errno)
219 				++errors;
220 			dfree (s, MDL);
221 		} else
222 			++errors;
223 	}
224 
225 	if (lease->scope != NULL) {
226 	    for (b = lease->scope->bindings; b; b = b->next) {
227 		if (!b->value)
228 			continue;
229 
230 		if (write_binding_scope(db_file, b, "\n  ") != ISC_R_SUCCESS)
231 			++errors;
232 	    }
233 	}
234 
235 	if (lease -> agent_options) {
236 	    struct option_cache *oc;
237 	    struct data_string ds;
238 	    pair p;
239 
240 	    memset (&ds, 0, sizeof ds);
241 	    for (p = lease -> agent_options -> first; p; p = p -> cdr) {
242 	        oc = (struct option_cache *)p -> car;
243 	        if (oc -> data.len) {
244 	    	errno = 0;
245 	    	fprintf (db_file, "\n  option agent.%s %s;",
246 	    		 oc -> option -> name,
247 	    		 pretty_print_option (oc -> option, oc -> data.data,
248 				      		oc -> data.len, 1, 1));
249 	    	if (errno)
250 		    ++errors;
251 	        }
252 	    }
253 	}
254 	if (lease -> client_hostname &&
255 	    db_printable((unsigned char *)lease->client_hostname)) {
256 		s = quotify_string (lease -> client_hostname, MDL);
257 		if (s) {
258 			errno = 0;
259 			fprintf (db_file, "\n  client-hostname \"%s\";", s);
260 			if (errno)
261 				++errors;
262 			dfree (s, MDL);
263 		} else
264 			++errors;
265 	}
266 	if (lease->on_star.on_expiry) {
267 		errno = 0;
268 		fprintf (db_file, "\n  on expiry%s {",
269 			 lease->on_star.on_expiry == lease->on_star.on_release
270 			 ? " or release" : "");
271 		write_statements (db_file, lease->on_star.on_expiry, 4);
272 		/* XXX */
273 		fprintf (db_file, "\n  }");
274 		if (errno)
275 			++errors;
276 	}
277 	if (lease->on_star.on_release &&
278 	    lease->on_star.on_release != lease->on_star.on_expiry) {
279 		errno = 0;
280 		fprintf (db_file, "\n  on release {");
281 		write_statements (db_file, lease->on_star.on_release, 4);
282 		/* XXX */
283 		fprintf (db_file, "\n  }");
284 		if (errno)
285 			++errors;
286 	}
287 
288 	errno = 0;
289 	fputs ("\n}\n", db_file);
290 	if (errno)
291 		++errors;
292 
293 	if (errors) {
294 		log_info ("write_lease: unable to write lease %s",
295 		      piaddr (lease -> ip_addr));
296 		lease_file_is_corrupt = 1;
297         }
298 
299 	return !errors;
300 }
301 
302 int write_host (host)
303 	struct host_decl *host;
304 {
305 	int errors = 0;
306 	int i;
307 	struct data_string ip_addrs;
308 
309 	/* If the lease file is corrupt, don't try to write any more leases
310 	   until we've written a good lease file. */
311 	if (lease_file_is_corrupt)
312 		if (!new_lease_file ())
313 			return 0;
314 
315 	if (!db_printable((unsigned char *)host->name))
316 		return 0;
317 
318 	if (counting)
319 		++count;
320 
321 	errno = 0;
322 	fprintf (db_file, "host %s {", host -> name);
323 	if (errno)
324 		++errors;
325 
326 	if (host -> flags & HOST_DECL_DYNAMIC) {
327 		errno = 0;
328 		fprintf (db_file, "\n  dynamic;");
329 		if (errno)
330 			++errors;
331 	}
332 
333 	if (host -> flags & HOST_DECL_DELETED) {
334 		errno = 0;
335 		fprintf (db_file, "\n  deleted;");
336 		if (errno)
337 			++errors;
338 	} else {
339 		if (host -> interface.hlen) {
340 			errno = 0;
341 			fprintf (db_file, "\n  hardware %s %s;",
342 				 hardware_types [host -> interface.hbuf [0]],
343 				 print_hw_addr (host -> interface.hbuf [0],
344 						host -> interface.hlen - 1,
345 						&host -> interface.hbuf [1]));
346 			if (errno)
347 				++errors;
348 		}
349 		if (host -> client_identifier.len) {
350 			int i;
351 			errno = 0;
352 			if (db_printable_len (host -> client_identifier.data,
353 					      host -> client_identifier.len)) {
354 				fprintf (db_file, "\n  uid \"%.*s\";",
355 					 (int)host -> client_identifier.len,
356 					 host -> client_identifier.data);
357 				if (errno)
358 					++errors;
359 			} else {
360 				fprintf (db_file,
361 					 "\n  uid %2.2x",
362 					 host -> client_identifier.data [0]);
363 				if (errno)
364 					++errors;
365 				for (i = 1;
366 				     i < host -> client_identifier.len; i++) {
367 					errno = 0;
368 					fprintf (db_file, ":%2.2x",
369 						 host ->
370 						 client_identifier.data [i]);
371 					if (errno)
372 						++errors;
373 				}
374 
375                                 errno = 0;
376 				fputc (';', db_file);
377 				if (errno)
378 					++errors;
379 			}
380 		}
381 
382 		memset (&ip_addrs, 0, sizeof ip_addrs);
383 		if (host -> fixed_addr &&
384 		    evaluate_option_cache (&ip_addrs, (struct packet *)0,
385 					   (struct lease *)0,
386 					   (struct client_state *)0,
387 					   (struct option_state *)0,
388 					   (struct option_state *)0,
389 					   &global_scope,
390 					   host -> fixed_addr, MDL)) {
391 
392 			errno = 0;
393 			fprintf (db_file, "\n  fixed-address ");
394 			if (errno)
395 				++errors;
396 			for (i = 0; i < ip_addrs.len - 3; i += 4) {
397 
398 				errno = 0;
399 				fprintf (db_file, "%u.%u.%u.%u%s",
400 					 ip_addrs.data [i] & 0xff,
401 					 ip_addrs.data [i + 1] & 0xff,
402 					 ip_addrs.data [i + 2] & 0xff,
403 					 ip_addrs.data [i + 3] & 0xff,
404 					 i + 7 < ip_addrs.len ? "," : "");
405 				if (errno)
406 					++errors;
407 			}
408 
409 			errno = 0;
410 			fputc (';', db_file);
411 			if (errno)
412 				++errors;
413 		}
414 
415 		if (host -> named_group) {
416 			errno = 0;
417 			fprintf (db_file, "\n  group \"%s\";",
418 				 host -> named_group -> name);
419 			if (errno)
420 				++errors;
421 		}
422 
423 		if (host -> group &&
424 		    (!host -> named_group ||
425 		     host -> group != host -> named_group -> group) &&
426 		    host -> group != root_group) {
427 			errno = 0;
428 			write_statements (db_file,
429 					  host -> group -> statements, 8);
430 			if (errno)
431 				++errors;
432 		}
433 	}
434 
435 	errno = 0;
436 	fputs ("\n}\n", db_file);
437 	if (errno)
438 		++errors;
439 
440 	if (errors) {
441 		log_info ("write_host: unable to write host %s",
442 			  host -> name);
443 		lease_file_is_corrupt = 1;
444 	}
445 
446 	return !errors;
447 }
448 
449 int write_group (group)
450 	struct group_object *group;
451 {
452 	int errors = 0;
453 
454 	/* If the lease file is corrupt, don't try to write any more leases
455 	   until we've written a good lease file. */
456 	if (lease_file_is_corrupt)
457 		if (!new_lease_file ())
458 			return 0;
459 
460 	if (!db_printable((unsigned char *)group->name))
461 		return 0;
462 
463 	if (counting)
464 		++count;
465 
466 	errno = 0;
467 	fprintf (db_file, "group %s {", group -> name);
468 	if (errno)
469 		++errors;
470 
471 	if (group -> flags & GROUP_OBJECT_DYNAMIC) {
472 		errno = 0;
473 		fprintf (db_file, "\n  dynamic;");
474 		if (errno)
475 			++errors;
476 	}
477 
478 	if (group -> flags & GROUP_OBJECT_STATIC) {
479 		errno = 0;
480 		fprintf (db_file, "\n  static;");
481 		if (errno)
482 			++errors;
483 	}
484 
485 	if (group -> flags & GROUP_OBJECT_DELETED) {
486 		errno = 0;
487 		fprintf (db_file, "\n  deleted;");
488 		if (errno)
489 			++errors;
490 	} else {
491 		if (group -> group) {
492 			errno = 0;
493 			write_statements (db_file,
494 					  group -> group -> statements, 8);
495 			if (errno)
496 				++errors;
497 		}
498 	}
499 
500 	errno = 0;
501 	fputs ("\n}\n", db_file);
502 	if (errno)
503 		++errors;
504 
505 	if (errors) {
506 		log_info ("write_group: unable to write group %s",
507 			  group -> name);
508 		lease_file_is_corrupt = 1;
509 	}
510 
511 	return !errors;
512 }
513 
514 /*
515  * Write an IA and the options it has.
516  */
517 int
518 write_ia(const struct ia_xx *ia) {
519 	struct iasubopt *iasubopt;
520 	struct binding *bnd;
521 	int i;
522 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
523 	const char *binding_state;
524 	const char *tval;
525 	char *s;
526 	int fprintf_ret;
527 
528 	/*
529 	 * If the lease file is corrupt, don't try to write any more
530 	 * leases until we've written a good lease file.
531 	 */
532 	if (lease_file_is_corrupt) {
533 		if (!new_lease_file()) {
534 			return 0;
535 		}
536 	}
537 
538 	if (counting) {
539 		++count;
540 	}
541 
542 
543 	s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL);
544 	if (s == NULL) {
545 		goto error_exit;
546 	}
547 	switch (ia->ia_type) {
548 	case D6O_IA_NA:
549 		fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s);
550 		break;
551 	case D6O_IA_TA:
552 		fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s);
553 		break;
554 	case D6O_IA_PD:
555 		fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s);
556 		break;
557 	default:
558 		log_error("Unknown ia type %u for \"%s\" at %s:%d",
559 			  (unsigned)ia->ia_type, s, MDL);
560 		fprintf_ret = -1;
561 	}
562 	dfree(s, MDL);
563 	if (fprintf_ret < 0) {
564 		goto error_exit;
565 	}
566 	if (ia->cltt != MIN_TIME) {
567 		tval = print_time(ia->cltt);
568 		if (tval == NULL) {
569 			goto error_exit;
570 		}
571 		if (fprintf(db_file, "  cltt %s\n", tval) < 0) {
572 			goto error_exit;
573 		}
574 	}
575 	for (i=0; i<ia->num_iasubopt; i++) {
576 		iasubopt = ia->iasubopt[i];
577 
578 		inet_ntop(AF_INET6, &iasubopt->addr,
579 			  addr_buf, sizeof(addr_buf));
580 		if ((ia->ia_type != D6O_IA_PD) &&
581 		    (fprintf(db_file, "  iaaddr %s {\n", addr_buf) < 0)) {
582 			goto error_exit;
583 		}
584 		if ((ia->ia_type == D6O_IA_PD) &&
585 		    (fprintf(db_file, "  iaprefix %s/%d {\n",
586 			     addr_buf, (int)iasubopt->plen) < 0)) {
587 			goto error_exit;
588 		}
589 		if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) {
590 			log_fatal("Unknown iasubopt state %d at %s:%d",
591 				  iasubopt->state, MDL);
592 		}
593 		binding_state = binding_state_names[iasubopt->state-1];
594 		if (fprintf(db_file, "    binding state %s;\n",
595 			    binding_state) < 0) {
596 			goto error_exit;
597 		}
598 		if (fprintf(db_file, "    preferred-life %u;\n",
599 			    (unsigned)iasubopt->prefer) < 0) {
600 			goto error_exit;
601 		}
602 		if (fprintf(db_file, "    max-life %u;\n",
603 			    (unsigned)iasubopt->valid) < 0) {
604 			goto error_exit;
605 		}
606 
607 		/* Note that from here on out, the \n is prepended to the
608 		 * next write, rather than appended to the current write.
609 		 */
610 		if ((iasubopt->state == FTS_ACTIVE) ||
611 		    (iasubopt->state == FTS_ABANDONED) ||
612 		    (iasubopt->hard_lifetime_end_time != 0)) {
613 			tval = print_time(iasubopt->hard_lifetime_end_time);
614 		} else {
615 			tval = print_time(iasubopt->soft_lifetime_end_time);
616 		}
617 		if (tval == NULL) {
618 			goto error_exit;
619 		}
620 		if (fprintf(db_file, "    ends %s", tval) < 0) {
621 			goto error_exit;
622 		}
623 
624 		/* Write out any binding scopes: note that 'ends' above does
625 		 * not have \n on the end!  We want that.
626 		 */
627 		if (iasubopt->scope != NULL)
628 			bnd = iasubopt->scope->bindings;
629 		else
630 			bnd = NULL;
631 
632 		for (; bnd != NULL ; bnd = bnd->next) {
633 			if (bnd->value == NULL)
634 				continue;
635 
636 			/* We don't do a regular error_exit because the
637 			 * lease db is not corrupt in this case.
638 			 */
639 			if (write_binding_scope(db_file, bnd,
640 						"\n    ") != ISC_R_SUCCESS)
641 				goto error_exit;
642 
643 		}
644 
645 		if (iasubopt->on_star.on_expiry) {
646 			if (fprintf(db_file, "\n    on expiry%s {",
647 				    iasubopt->on_star.on_expiry ==
648 				    iasubopt->on_star.on_release
649 				    ? " or release" : "") < 0)
650 				goto error_exit;
651 			write_statements(db_file,
652 					 iasubopt->on_star.on_expiry, 6);
653 			if (fprintf(db_file, "\n    }") < 0)
654 				goto error_exit;
655 		}
656 
657 		if (iasubopt->on_star.on_release &&
658 		    iasubopt->on_star.on_release !=
659 		    iasubopt->on_star.on_expiry) {
660 			if (fprintf(db_file, "\n    on release {") < 0)
661 				goto error_exit;
662 			write_statements(db_file,
663 					 iasubopt->on_star.on_release, 6);
664 			if (fprintf(db_file, "\n    }") < 0)
665 				goto error_exit;
666 		}
667 
668 		if (fprintf(db_file, "\n  }\n") < 0)
669                         goto error_exit;
670 	}
671 	if (fprintf(db_file, "}\n\n") < 0)
672                 goto error_exit;
673 
674 	fflush(db_file);
675 	return 1;
676 
677 error_exit:
678 	log_info("write_ia: unable to write ia");
679 	lease_file_is_corrupt = 1;
680 	return 0;
681 }
682 
683 #ifdef DHCPv6
684 /*
685  * Put a copy of the server DUID in the leases file.
686  */
687 int
688 write_server_duid(void) {
689 	struct data_string server_duid;
690 	char *s;
691 	int fprintf_ret;
692 
693 	/*
694 	 * Only write the DUID if it's been set.
695 	 */
696 	if (!server_duid_isset()) {
697 		return 1;
698 	}
699 
700 	/*
701 	 * If the lease file is corrupt, don't try to write any more
702 	 * leases until we've written a good lease file.
703 	 */
704 	if (lease_file_is_corrupt) {
705 		if (!new_lease_file()) {
706 			return 0;
707 		}
708 	}
709 
710 	/*
711 	 * Get a copy of our server DUID and convert to a quoted string.
712 	 */
713 	memset(&server_duid, 0, sizeof(server_duid));
714 	copy_server_duid(&server_duid, MDL);
715 	s = quotify_buf(server_duid.data, server_duid.len, MDL);
716 	data_string_forget(&server_duid, MDL);
717 	if (s == NULL) {
718 		goto error_exit;
719 	}
720 
721 	/*
722 	 * Write to the leases file.
723 	 */
724 	fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s);
725 	dfree(s, MDL);
726 	if (fprintf_ret < 0) {
727 		goto error_exit;
728 	}
729 
730 	/*
731 	 * Check if we actually managed to write.
732 	 */
733 	fflush(db_file);
734 	return 1;
735 
736 error_exit:
737 	log_info("write_server_duid: unable to write server-duid");
738 	lease_file_is_corrupt = 1;
739 	return 0;
740 }
741 #endif /* DHCPv6 */
742 
743 #if defined (FAILOVER_PROTOCOL)
744 int write_failover_state (dhcp_failover_state_t *state)
745 {
746 	int errors = 0;
747 	const char *tval;
748 
749 	if (lease_file_is_corrupt)
750 		if (!new_lease_file ())
751 			return 0;
752 
753 	errno = 0;
754 	fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
755 	if (errno)
756 		++errors;
757 
758 	tval = print_time(state->me.stos);
759 	if (tval == NULL ||
760 	    fprintf(db_file, "\n  my state %s at %s",
761 		    (state->me.state == startup) ?
762 		    dhcp_failover_state_name_print(state->saved_state) :
763 		    dhcp_failover_state_name_print(state->me.state),
764 		    tval) < 0)
765 		++errors;
766 
767 	tval = print_time(state->partner.stos);
768 	if (tval == NULL ||
769 	    fprintf(db_file, "\n  partner state %s at %s",
770 		    dhcp_failover_state_name_print(state->partner.state),
771 		    tval) < 0)
772 		++errors;
773 
774 	if (state -> i_am == secondary) {
775 		errno = 0;
776 		fprintf (db_file, "\n  mclt %ld;",
777 			 (unsigned long)state -> mclt);
778 		if (errno)
779 			++errors;
780 	}
781 
782         errno = 0;
783 	fprintf (db_file, "\n}\n");
784 	if (errno)
785 		++errors;
786 
787 	if (errors) {
788 		log_info ("write_failover_state: unable to write state %s",
789 			  state -> name);
790 		lease_file_is_corrupt = 1;
791 		return 0;
792 	}
793 
794 	return 1;
795 
796 }
797 #endif
798 
799 int db_printable (s)
800 	const unsigned char *s;
801 {
802 	int i;
803 	for (i = 0; s [i]; i++)
804 		if (!isascii (s [i]) || !isprint (s [i])
805 		    || s [i] == '"' || s [i] == '\\')
806 			return 0;
807 	return 1;
808 }
809 
810 int db_printable_len (s, len)
811 	const unsigned char *s;
812 	unsigned len;
813 {
814 	int i;
815 
816 	for (i = 0; i < len; i++)
817 		if (!isascii (s [i]) || !isprint (s [i]) ||
818 		    s [i] == '"' || s [i] == '\\')
819 			return 0;
820 	return 1;
821 }
822 
823 static int print_hash_string(FILE *fp, struct class *class)
824 {
825 	int i;
826 
827 	for (i = 0 ; i < class->hash_string.len ; i++)
828 		if (!isascii(class->hash_string.data[i]) ||
829 		    !isprint(class->hash_string.data[i]))
830 			break;
831 
832 	if (i == class->hash_string.len) {
833 		if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
834 			    class->hash_string.data) <= 0) {
835 			log_error("Failure writing hash string: %m");
836 			return 0;
837 		}
838 	} else {
839 		if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
840 			log_error("Failure writing hash string: %m");
841 			return 0;
842 		}
843 		for (i = 1 ; i < class->hash_string.len ; i++) {
844 			if (fprintf(fp, ":%2.2x",
845 				    class->hash_string.data[i]) <= 0) {
846 				log_error("Failure writing hash string: %m");
847 				return 0;
848 			}
849 		}
850 	}
851 
852 	return 1;
853 }
854 
855 
856 isc_result_t
857 write_named_billing_class(const void *key, unsigned len, void *object)
858 {
859 	const unsigned char *name = key;
860 	struct class *class = object;
861 
862 	if (class->flags & CLASS_DECL_DYNAMIC) {
863 		numclasseswritten++;
864 		if (class->superclass == 0) {
865 			if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
866 				return ISC_R_IOERROR;
867 		} else {
868 			if (fprintf(db_file, "subclass \"%s\"",
869 				    class->superclass->name) <= 0)
870 				return ISC_R_IOERROR;
871 			if (!print_hash_string(db_file, class))
872 				return ISC_R_IOERROR;
873 			if (fprintf(db_file, " {\n") <= 0)
874 				return ISC_R_IOERROR;
875 		}
876 
877 		if ((class->flags & CLASS_DECL_DELETED) != 0) {
878 			if (fprintf(db_file, "  deleted;\n") <= 0)
879 				return ISC_R_IOERROR;
880 		} else {
881 			if (fprintf(db_file, "  dynamic;\n") <= 0)
882 				return ISC_R_IOERROR;
883 		}
884 
885 		if (class->lease_limit > 0) {
886 			if (fprintf(db_file, "  lease limit %d;\n",
887 				    class->lease_limit) <= 0)
888 				return ISC_R_IOERROR;
889 		}
890 
891 		if (class->expr != 0) {
892 			if (fprintf(db_file, "  match if ") <= 0)
893 				return ISC_R_IOERROR;
894 
895                         errno = 0;
896 			write_expression(db_file, class->expr, 5, 5, 0);
897                         if (errno)
898                                 return ISC_R_IOERROR;
899 
900 			if (fprintf(db_file, ";\n") <= 0)
901 				return ISC_R_IOERROR;
902 		}
903 
904 		if (class->submatch != 0) {
905 			if (class->spawning) {
906 				if (fprintf(db_file, "  spawn ") <= 0)
907 					return ISC_R_IOERROR;
908 			} else {
909 				if (fprintf(db_file, "  match ") <= 0)
910 					return ISC_R_IOERROR;
911 			}
912 
913                         errno = 0;
914 			write_expression(db_file, class->submatch, 5, 5, 0);
915                         if (errno)
916                                 return ISC_R_IOERROR;
917 
918 			if (fprintf(db_file, ";\n") <= 0)
919 				return ISC_R_IOERROR;
920 		}
921 
922 		if (class->statements != 0) {
923                         errno = 0;
924 			write_statements(db_file, class->statements, 8);
925                         if (errno)
926                                 return ISC_R_IOERROR;
927 		}
928 
929 		/* XXXJAB this isn't right, but classes read in off the
930 		   leases file don't get the root group assigned to them
931 		   (due to clone_group() call). */
932 		if (class->group != 0 && class->group->authoritative != 0) {
933                         errno = 0;
934 			write_statements(db_file, class->group->statements, 8);
935                         if (errno)
936                                 return ISC_R_IOERROR;
937                 }
938 
939 		if (fprintf(db_file, "}\n\n") <= 0)
940 			return ISC_R_IOERROR;
941 	}
942 
943 	if (class->hash != NULL) {	/* yep. recursive. god help us. */
944 		/* XXX - cannot check error status of this...
945 		 * foo_hash_foreach returns a count of operations completed.
946 		 */
947 		class_hash_foreach(class->hash, write_named_billing_class);
948 	}
949 
950 	return ISC_R_SUCCESS;
951 }
952 
953 void write_billing_classes ()
954 {
955 	struct collection *lp;
956 	struct class *cp;
957 
958 	for (lp = collections; lp; lp = lp -> next) {
959 	    for (cp = lp -> classes; cp; cp = cp -> nic) {
960 		if (cp -> spawning && cp -> hash) {
961 		    class_hash_foreach (cp -> hash, write_named_billing_class);
962 		}
963 	    }
964 	}
965 }
966 
967 /* Write a spawned class to the database file. */
968 
969 int write_billing_class (class)
970 	struct class *class;
971 {
972 	int errors = 0;
973 
974 	if (lease_file_is_corrupt)
975 		if (!new_lease_file ())
976 			return 0;
977 
978 	if (!class -> superclass) {
979 		errno = 0;
980 		fprintf (db_file, "\n  billing class \"%s\";", class -> name);
981 		return !errno;
982 	}
983 
984 	if (fprintf(db_file, "\n  billing subclass \"%s\"",
985 		    class -> superclass -> name) < 0)
986 		++errors;
987 
988 	if (!print_hash_string(db_file, class))
989                 ++errors;
990 
991 	if (fprintf(db_file, ";") < 0)
992                 ++errors;
993 
994 	class -> dirty = !errors;
995 	if (errors)
996 		lease_file_is_corrupt = 1;
997 
998 	return !errors;
999 }
1000 
1001 /* Commit leases after a timeout. */
1002 void commit_leases_timeout (void *foo)
1003 {
1004 	commit_leases ();
1005 }
1006 
1007 /* Commit any leases that have been written out... */
1008 
1009 int commit_leases ()
1010 {
1011 	/* Commit any outstanding writes to the lease database file.
1012 	   We need to do this even if we're rewriting the file below,
1013 	   just in case the rewrite fails. */
1014 	if (fflush (db_file) == EOF) {
1015 		log_info("commit_leases: unable to commit, fflush(): %m");
1016 		return (0);
1017 	}
1018 	if ((dont_use_fsync == 0) &&
1019 	    (fsync(fileno (db_file)) < 0)) {
1020 		log_info ("commit_leases: unable to commit, fsync(): %m");
1021 		return (0);
1022 	}
1023 
1024 	/* send out all deferred ACKs now */
1025 	flush_ackqueue(NULL);
1026 
1027 	/* If we haven't rewritten the lease database in over an
1028 	   hour, rewrite it now.  (The length of time should probably
1029 	   be configurable. */
1030 	if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) {
1031 		count = 0;
1032 		write_time = cur_time;
1033 		new_lease_file();
1034 	}
1035 	return (1);
1036 }
1037 
1038 /*
1039  * rewrite the lease file about once an hour
1040  * This is meant as a quick patch for ticket 24887.  It allows
1041  * us to rotate the v6 lease file without adding too many fsync()
1042  * calls.  In the future wes should revisit this area and add
1043  * something similar to the delayed ack code for v4.
1044  */
1045 int commit_leases_timed()
1046 {
1047 	if ((count != 0) && (cur_time - write_time > LEASE_REWRITE_PERIOD)) {
1048 		return (commit_leases());
1049 	}
1050 	return (1);
1051 }
1052 
1053 void db_startup (testp)
1054 	int testp;
1055 {
1056 	isc_result_t status;
1057 
1058 #if defined (TRACING)
1059 	if (!trace_playback ()) {
1060 #endif
1061 		/* Read in the existing lease file... */
1062 		status = read_conf_file (path_dhcpd_db,
1063 					 (struct group *)0, 0, 1);
1064 		if (status != ISC_R_SUCCESS) {
1065 			/* XXX ignore status? */
1066 			;
1067 		}
1068 
1069 #if defined (TRACING)
1070 	}
1071 #endif
1072 
1073 #if defined (TRACING)
1074 	/* If we're playing back, there is no lease file, so we can't
1075 	   append it, so we create one immediately (maybe this isn't
1076 	   the best solution... */
1077 	if (trace_playback ()) {
1078 		new_lease_file ();
1079 	}
1080 #endif
1081 	if (!testp) {
1082 		db_file = fopen (path_dhcpd_db, "a");
1083 		if (!db_file)
1084 			log_fatal ("Can't open %s for append.", path_dhcpd_db);
1085 		expire_all_pools ();
1086 #if defined (TRACING)
1087 		if (trace_playback ())
1088 			write_time = cur_time;
1089 		else
1090 #endif
1091 			time(&write_time);
1092 		new_lease_file ();
1093 	}
1094 
1095 #if defined(REPORT_HASH_PERFORMANCE)
1096 	log_info("Host HW hash:   %s", host_hash_report(host_hw_addr_hash));
1097 	log_info("Host UID hash:  %s", host_hash_report(host_uid_hash));
1098 	log_info("Lease IP hash:  %s",
1099 		 lease_ip_hash_report(lease_ip_addr_hash));
1100 	log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
1101 	log_info("Lease HW hash:  %s",
1102 		 lease_id_hash_report(lease_hw_addr_hash));
1103 #endif
1104 }
1105 
1106 int new_lease_file ()
1107 {
1108 	char newfname [512];
1109 	char backfname [512];
1110 	TIME t;
1111 	int db_fd;
1112 	int db_validity;
1113 	FILE *new_db_file;
1114 
1115 	/* Make a temporary lease file... */
1116 	time(&t);
1117 
1118 	db_validity = lease_file_is_corrupt;
1119 
1120 	/* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
1121 	 * This should never happen since the path is a configuration
1122 	 * variable from build-time or command-line.  But if it should,
1123 	 * either by malice or ignorance, we panic, since the potential
1124 	 * for havoc is high.
1125 	 */
1126 	if (snprintf (newfname, sizeof newfname, "%s.%d",
1127 		     path_dhcpd_db, (int)t) >= sizeof newfname)
1128 		log_fatal("new_lease_file: lease file path too long");
1129 
1130 	db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
1131 	if (db_fd < 0) {
1132 		log_error ("Can't create new lease file: %m");
1133 		return 0;
1134 	}
1135 	if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
1136 		log_error("Can't fdopen new lease file: %m");
1137 		close(db_fd);
1138 		goto fdfail;
1139 	}
1140 
1141 	/* Close previous database, if any. */
1142 	if (db_file)
1143 		fclose(db_file);
1144 	db_file = new_db_file;
1145 
1146 	errno = 0;
1147 	fprintf (db_file, "# The format of this file is documented in the %s",
1148 		 "dhcpd.leases(5) manual page.\n");
1149 	if (errno)
1150 		goto fail;
1151 
1152 	fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
1153 		 PACKAGE_VERSION);
1154 	if (errno)
1155 		goto fail;
1156 
1157 	/* At this point we have a new lease file that, so far, could not
1158 	 * be described as either corrupt nor valid.
1159 	 */
1160 	lease_file_is_corrupt = 0;
1161 
1162 	/* Write out all the leases that we know of... */
1163 	counting = 0;
1164 	if (!write_leases ())
1165 		goto fail;
1166 
1167 #if defined (TRACING)
1168 	if (!trace_playback ()) {
1169 #endif
1170 	    /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
1171 	     * This should never happen since the path is a configuration
1172 	     * variable from build-time or command-line.  But if it should,
1173 	     * either by malice or ignorance, we panic, since the potential
1174 	     * for havoc is too high.
1175 	     */
1176 	    if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
1177 			>= sizeof backfname)
1178 		log_fatal("new_lease_file: backup lease file path too long");
1179 
1180 	    /* Get the old database out of the way... */
1181 	    if (unlink (backfname) < 0 && errno != ENOENT) {
1182 		log_error ("Can't remove old lease database backup %s: %m",
1183 			   backfname);
1184 		goto fail;
1185 	    }
1186 	    if (link(path_dhcpd_db, backfname) < 0) {
1187 		if (errno == ENOENT) {
1188 			log_error("%s is missing - no lease db to backup.",
1189 				  path_dhcpd_db);
1190 		} else {
1191 			log_error("Can't backup lease database %s to %s: %m",
1192 				  path_dhcpd_db, backfname);
1193 			goto fail;
1194 		}
1195 	    }
1196 #if defined (TRACING)
1197 	}
1198 #endif
1199 
1200 	/* Move in the new file... */
1201 	if (rename (newfname, path_dhcpd_db) < 0) {
1202 		log_error ("Can't install new lease database %s to %s: %m",
1203 			   newfname, path_dhcpd_db);
1204 		goto fail;
1205 	}
1206 
1207 	counting = 1;
1208 	return 1;
1209 
1210       fail:
1211 	lease_file_is_corrupt = db_validity;
1212       fdfail:
1213 	unlink (newfname);
1214 	return 0;
1215 }
1216 
1217 int group_writer (struct group_object *group)
1218 {
1219 	if (!write_group (group))
1220 		return 0;
1221 	if (!commit_leases ())
1222 		return 0;
1223 	return 1;
1224 }
1225