]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/db.c
Pulled up rt16929
[thirdparty/dhcp.git] / server / db.c
1 /* db.c
2
3 Persistent database management routines for DHCPD... */
4
5 /*
6 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35 #ifndef lint
36 static char copyright[] =
37 "$Id: db.c,v 1.80 2007/06/05 23:28:43 each Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
39
40 #include "dhcpd.h"
41 #include <ctype.h>
42 #include <errno.h>
43
44 FILE *db_file;
45
46 static int counting = 0;
47 static int count = 0;
48 TIME write_time;
49 int lease_file_is_corrupt = 0;
50
51 /* Write the specified lease to the current lease database file. */
52
53 int write_lease (lease)
54 struct lease *lease;
55 {
56 int errors = 0;
57 int i;
58 struct binding *b;
59 char *s;
60 const char *tval;
61
62 /* If the lease file is corrupt, don't try to write any more leases
63 until we've written a good lease file. */
64 if (lease_file_is_corrupt)
65 if (!new_lease_file ())
66 return 0;
67
68 if (counting)
69 ++count;
70 errno = 0;
71 fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
72 if (errno) {
73 ++errors;
74 }
75
76 if (lease->starts &&
77 ((tval = print_time(lease->starts)) == NULL ||
78 fprintf(db_file, "\n starts %s", tval) < 0))
79 ++errors;
80
81 if (lease->ends &&
82 ((tval = print_time(lease->ends)) == NULL ||
83 fprintf(db_file, "\n ends %s", tval) < 0))
84 ++errors;
85
86 if (lease->tstp &&
87 ((tval = print_time(lease->tstp)) == NULL ||
88 fprintf(db_file, "\n tstp %s", tval) < 0))
89 ++errors;
90
91 if (lease->tsfp &&
92 ((tval = print_time(lease->tsfp)) == NULL ||
93 fprintf(db_file, "\n tsfp %s", tval) < 0))
94 ++errors;
95
96 if (lease->atsfp &&
97 ((tval = print_time(lease->atsfp)) == NULL ||
98 fprintf(db_file, "\n atsfp %s", tval) < 0))
99 ++errors;
100
101 if (lease->cltt &&
102 ((tval = print_time(lease->cltt)) == NULL ||
103 fprintf(db_file, "\n cltt %s", tval) < 0))
104 ++errors;
105
106 fprintf (db_file, "\n binding state %s;",
107 ((lease -> binding_state > 0 &&
108 lease -> binding_state <= FTS_LAST)
109 ? binding_state_names [lease -> binding_state - 1]
110 : "abandoned"));
111
112 if (lease -> binding_state != lease -> next_binding_state)
113 fprintf (db_file, "\n next binding state %s;",
114 ((lease -> next_binding_state > 0 &&
115 lease -> next_binding_state <= FTS_LAST)
116 ? (binding_state_names
117 [lease -> next_binding_state - 1])
118 : "abandoned"));
119
120 if (lease->flags & RESERVED_LEASE)
121 fprintf(db_file, "\n reserved;");
122 if (lease->flags & BOOTP_LEASE)
123 fprintf(db_file, "\n dynamic-bootp;");
124
125 /* If this lease is billed to a class and is still valid,
126 write it out. */
127 if (lease -> billing_class && lease -> ends > cur_time) {
128 if (!write_billing_class (lease -> billing_class)) {
129 log_error ("unable to write class %s",
130 lease -> billing_class -> name);
131 ++errors;
132 }
133 }
134
135 if (lease -> hardware_addr.hlen) {
136 errno = 0;
137 fprintf (db_file, "\n hardware %s %s;",
138 hardware_types [lease -> hardware_addr.hbuf [0]],
139 print_hw_addr (lease -> hardware_addr.hbuf [0],
140 lease -> hardware_addr.hlen - 1,
141 &lease -> hardware_addr.hbuf [1]));
142 if (errno) {
143 ++errors;
144 }
145 }
146 if (lease -> uid_len) {
147 int i;
148 s = quotify_buf (lease -> uid, lease -> uid_len, MDL);
149 if (s) {
150 errno = 0;
151 fprintf (db_file, "\n uid \"%s\";", s);
152 if (errno)
153 ++errors;
154 dfree (s, MDL);
155 } else
156 ++errors;
157 }
158 if (lease -> scope) {
159 for (b = lease -> scope -> bindings; b; b = b -> next) {
160 if (!b -> value)
161 continue;
162 if (b -> value -> type == binding_data) {
163 if (b -> value -> value.data.data) {
164 s = quotify_buf (b -> value -> value.data.data,
165 b -> value -> value.data.len, MDL);
166 if (s) {
167 errno = 0;
168 fprintf (db_file, "\n set %s = \"%s\";",
169 b -> name, s);
170 if (errno)
171 ++errors;
172 dfree (s, MDL);
173 } else
174 ++errors;
175 }
176 } else if (b -> value -> type == binding_numeric) {
177 errno = 0;
178 fprintf (db_file, "\n set %s = %%%ld;",
179 b -> name, b -> value -> value.intval);
180 if (errno)
181 ++errors;
182 } else if (b -> value -> type == binding_boolean) {
183 errno = 0;
184 fprintf (db_file, "\n set %s = %s;",
185 b -> name,
186 b -> value -> value.intval ? "true" : "false");
187 if (errno)
188 ++errors;
189 } else if (b -> value -> type == binding_dns) {
190 log_error ("%s: persistent dns values not supported.",
191 b -> name);
192 } else if (b -> value -> type == binding_function) {
193 log_error ("%s: persistent functions not supported.",
194 b -> name);
195 } else {
196 log_error ("%s: unknown binding type %d",
197 b -> name, b -> value -> type);
198 }
199 }
200 }
201 if (lease -> agent_options) {
202 struct option_cache *oc;
203 struct data_string ds;
204 pair p;
205
206 memset (&ds, 0, sizeof ds);
207 for (p = lease -> agent_options -> first; p; p = p -> cdr) {
208 oc = (struct option_cache *)p -> car;
209 if (oc -> data.len) {
210 errno = 0;
211 fprintf (db_file, "\n option agent.%s %s;",
212 oc -> option -> name,
213 pretty_print_option (oc -> option, oc -> data.data,
214 oc -> data.len, 1, 1));
215 if (errno)
216 ++errors;
217 }
218 }
219 }
220 if (lease -> client_hostname &&
221 db_printable (lease -> client_hostname)) {
222 s = quotify_string (lease -> client_hostname, MDL);
223 if (s) {
224 errno = 0;
225 fprintf (db_file, "\n client-hostname \"%s\";", s);
226 if (errno)
227 ++errors;
228 dfree (s, MDL);
229 } else
230 ++errors;
231 }
232 if (lease -> on_expiry) {
233 errno = 0;
234 fprintf (db_file, "\n on expiry%s {",
235 lease -> on_expiry == lease -> on_release
236 ? " or release" : "");
237 if (errno)
238 ++errors;
239 write_statements (db_file, lease -> on_expiry, 4);
240 /* XXX */
241 fprintf (db_file, "\n }");
242 }
243 if (lease -> on_release && lease -> on_release != lease -> on_expiry) {
244 errno = 0;
245 fprintf (db_file, "\n on release {");
246 if (errno)
247 ++errors;
248 write_statements (db_file, lease -> on_release, 4);
249 /* XXX */
250 fprintf (db_file, "\n }");
251 }
252 errno = 0;
253 fputs ("\n}\n", db_file);
254 if (errno) {
255 ++errors;
256 }
257 if (errors)
258 log_info ("write_lease: unable to write lease %s",
259 piaddr (lease -> ip_addr));
260 if (errors)
261 lease_file_is_corrupt = 1;
262 return !errors;
263 }
264
265 int write_host (host)
266 struct host_decl *host;
267 {
268 int errors = 0;
269 int i;
270 struct data_string ip_addrs;
271
272 /* If the lease file is corrupt, don't try to write any more leases
273 until we've written a good lease file. */
274 if (lease_file_is_corrupt)
275 if (!new_lease_file ())
276 return 0;
277
278 if (!db_printable (host -> name))
279 return 0;
280
281 if (counting)
282 ++count;
283 errno = 0;
284
285 fprintf (db_file, "host %s {", host -> name);
286 if (errno) {
287 ++errors;
288 }
289
290 if (host -> flags & HOST_DECL_DYNAMIC) {
291 errno = 0;
292 fprintf (db_file, "\n dynamic;");
293 if (errno)
294 ++errors;
295 }
296
297 if (host -> flags & HOST_DECL_DELETED) {
298 errno = 0;
299 fprintf (db_file, "\n deleted;");
300 if (errno)
301 ++errors;
302 } else {
303 if (host -> interface.hlen) {
304 errno = 0;
305 fprintf (db_file, "\n hardware %s %s;",
306 hardware_types [host -> interface.hbuf [0]],
307 print_hw_addr (host -> interface.hbuf [0],
308 host -> interface.hlen - 1,
309 &host -> interface.hbuf [1]));
310 if (errno) {
311 ++errors;
312 }
313 }
314 if (host -> client_identifier.len) {
315 int i;
316 errno = 0;
317 if (db_printable_len (host -> client_identifier.data,
318 host -> client_identifier.len)) {
319 fprintf (db_file, "\n uid \"%.*s\";",
320 (int)host -> client_identifier.len,
321 host -> client_identifier.data);
322 } else {
323 fprintf (db_file,
324 "\n uid %2.2x",
325 host -> client_identifier.data [0]);
326 if (errno) {
327 ++errors;
328 }
329 for (i = 1;
330 i < host -> client_identifier.len; i++) {
331 errno = 0;
332 fprintf (db_file, ":%2.2x",
333 host ->
334 client_identifier.data [i]);
335 if (errno) {
336 ++errors;
337 }
338 }
339 putc (';', db_file);
340 }
341 }
342
343 memset (&ip_addrs, 0, sizeof ip_addrs);
344 if (host -> fixed_addr &&
345 evaluate_option_cache (&ip_addrs, (struct packet *)0,
346 (struct lease *)0,
347 (struct client_state *)0,
348 (struct option_state *)0,
349 (struct option_state *)0,
350 &global_scope,
351 host -> fixed_addr, MDL)) {
352
353 errno = 0;
354 fprintf (db_file, "\n fixed-address ");
355 if (errno) {
356 ++errors;
357 }
358 for (i = 0; i < ip_addrs.len - 3; i += 4) {
359 errno = 0;
360 fprintf (db_file, "%u.%u.%u.%u%s",
361 ip_addrs.data [i] & 0xff,
362 ip_addrs.data [i + 1] & 0xff,
363 ip_addrs.data [i + 2] & 0xff,
364 ip_addrs.data [i + 3] & 0xff,
365 i + 7 < ip_addrs.len ? "," : "");
366 if (errno) {
367 ++errors;
368 }
369 }
370 errno = 0;
371 fputc (';', db_file);
372 if (errno) {
373 ++errors;
374 }
375 }
376
377 if (host -> named_group) {
378 errno = 0;
379 fprintf (db_file, "\n group \"%s\";",
380 host -> named_group -> name);
381 if (errno) {
382 ++errors;
383 }
384 }
385
386 if (host -> group &&
387 (!host -> named_group ||
388 host -> group != host -> named_group -> group) &&
389 host -> group != root_group) {
390 errno = 0;
391 write_statements (db_file,
392 host -> group -> statements, 8);
393 if (errno) {
394 ++errors;
395 }
396 }
397 }
398
399 errno = 0;
400 fputs ("\n}\n", db_file);
401 if (errno) {
402 ++errors;
403 }
404 if (errors) {
405 log_info ("write_host: unable to write host %s",
406 host -> name);
407 lease_file_is_corrupt = 1;
408 }
409 return !errors;
410 }
411
412 int write_group (group)
413 struct group_object *group;
414 {
415 int errors = 0;
416 int i;
417
418 /* If the lease file is corrupt, don't try to write any more leases
419 until we've written a good lease file. */
420 if (lease_file_is_corrupt)
421 if (!new_lease_file ())
422 return 0;
423
424 if (!db_printable (group -> name))
425 return 0;
426
427 if (counting)
428 ++count;
429 errno = 0;
430
431 fprintf (db_file, "group %s {", group -> name);
432 if (errno) {
433 ++errors;
434 }
435
436 if (group -> flags & GROUP_OBJECT_DYNAMIC) {
437 errno = 0;
438 fprintf (db_file, "\n dynamic;");
439 if (errno)
440 ++errors;
441 }
442
443 if (group -> flags & GROUP_OBJECT_STATIC) {
444 errno = 0;
445 fprintf (db_file, "\n static;");
446 if (errno)
447 ++errors;
448 }
449
450 if (group -> flags & GROUP_OBJECT_DELETED) {
451 errno = 0;
452 fprintf (db_file, "\n deleted;");
453 if (errno)
454 ++errors;
455 } else {
456 if (group -> group) {
457 errno = 0;
458 write_statements (db_file,
459 group -> group -> statements, 8);
460 if (errno) {
461 ++errors;
462 }
463 }
464 }
465
466 errno = 0;
467 fputs ("\n}\n", db_file);
468 if (errno) {
469 ++errors;
470 }
471 if (errors) {
472 log_info ("write_group: unable to write group %s",
473 group -> name);
474 lease_file_is_corrupt = 1;
475 }
476 return !errors;
477 }
478
479 /*
480 * Write an IA_NA and the options it has.
481 */
482 int
483 write_ia_na(const struct ia_na *ia_na) {
484 struct iaaddr *iaaddr;
485 int i;
486 char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
487 const char *binding_state;
488 const char *tval;
489 char *s;
490 int fprintf_ret;
491
492 /*
493 * If the lease file is corrupt, don't try to write any more
494 * leases until we've written a good lease file.
495 */
496 if (lease_file_is_corrupt) {
497 if (!new_lease_file()) {
498 return 0;
499 }
500 }
501
502 if (counting) {
503 ++count;
504 }
505
506
507 s = quotify_buf(ia_na->iaid_duid.data, ia_na->iaid_duid.len, MDL);
508 if (s == NULL) {
509 goto error_exit;
510 }
511 fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s);
512 dfree(s, MDL);
513 if (fprintf_ret < 0) {
514 goto error_exit;
515 }
516 for (i=0; i<ia_na->num_iaaddr; i++) {
517 iaaddr = ia_na->iaaddr[i];
518
519 inet_ntop(AF_INET6, &iaaddr->addr, addr_buf, sizeof(addr_buf));
520 if (fprintf(db_file, " iaaddr %s {\n", addr_buf) < 0) {
521 goto error_exit;
522 }
523 if ((iaaddr->state <= 0) || (iaaddr->state > FTS_LAST)) {
524 log_fatal("Unknown ia_na state %d at %s:%d",
525 iaaddr->state, MDL);
526 }
527 binding_state = binding_state_names[iaaddr->state-1];
528 if (fprintf(db_file, " binding state %s;\n",
529 binding_state) < 0) {
530 goto error_exit;
531 }
532 tval = print_time(iaaddr->valid_lifetime_end_time);
533 if (tval == NULL) {
534 goto error_exit;
535 }
536 if (fprintf(db_file, " ends %s", tval) < 0) {
537 goto error_exit;
538 }
539 if (fprintf(db_file, "\n }\n") < 0) goto error_exit;
540 }
541 if (fprintf(db_file, "}\n\n") < 0) goto error_exit;
542
543 fflush(db_file);
544 return 1;
545
546 error_exit:
547 log_info("write_ia_na: unable to write ia-na");
548 lease_file_is_corrupt = 1;
549 return 0;
550 }
551
552 #ifdef DHCPv6
553 /*
554 * Put a copy of the server DUID in the leases file.
555 */
556 int
557 write_server_duid(void) {
558 struct data_string server_duid;
559 char *s;
560 int fprintf_ret;
561
562 /*
563 * Only write the DUID if it's been set.
564 */
565 if (!server_duid_isset()) {
566 return 1;
567 }
568
569 /*
570 * If the lease file is corrupt, don't try to write any more
571 * leases until we've written a good lease file.
572 */
573 if (lease_file_is_corrupt) {
574 if (!new_lease_file()) {
575 return 0;
576 }
577 }
578
579 /*
580 * Get a copy of our server DUID and convert to a quoted string.
581 */
582 memset(&server_duid, 0, sizeof(server_duid));
583 copy_server_duid(&server_duid, MDL);
584 s = quotify_buf(server_duid.data, server_duid.len, MDL);
585 data_string_forget(&server_duid, MDL);
586 if (s == NULL) {
587 goto error_exit;
588 }
589
590 /*
591 * Write to the leases file.
592 */
593 fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s);
594 dfree(s, MDL);
595 if (fprintf_ret < 0) {
596 goto error_exit;
597 }
598
599 /*
600 * Check if we actually managed to write.
601 */
602 fflush(db_file);
603 return 1;
604
605 error_exit:
606 log_info("write_server_duid: unable to write server-duid");
607 lease_file_is_corrupt = 1;
608 return 0;
609 }
610 #endif /* DHCPv6 */
611
612 #if defined (FAILOVER_PROTOCOL)
613 int write_failover_state (dhcp_failover_state_t *state)
614 {
615 struct tm *t;
616 int errors = 0;
617 const char *tval;
618
619 if (lease_file_is_corrupt)
620 if (!new_lease_file ())
621 return 0;
622
623 errno = 0;
624 fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
625 if (errno)
626 ++errors;
627
628 tval = print_time(state->me.stos);
629 if (tval == NULL ||
630 fprintf(db_file, "\n my state %s at %s",
631 (state->me.state == startup) ?
632 dhcp_failover_state_name_print(state->saved_state) :
633 dhcp_failover_state_name_print(state->me.state),
634 tval) < 0)
635 ++errors;
636
637 tval = print_time(state->partner.stos);
638 if (tval == NULL ||
639 fprintf(db_file, "\n partner state %s at %s",
640 dhcp_failover_state_name_print(state->partner.state),
641 tval) < 0)
642 ++errors;
643
644 if (state -> i_am == secondary) {
645 errno = 0;
646 fprintf (db_file, "\n mclt %ld;",
647 (unsigned long)state -> mclt);
648 if (errno)
649 ++errors;
650 }
651 fprintf (db_file, "\n}\n");
652 if (errno)
653 ++errors;
654
655 if (errors) {
656 log_info ("write_failover_state: unable to write state %s",
657 state -> name);
658 lease_file_is_corrupt = 1;
659 return 0;
660 }
661 return 1;
662
663 }
664 #endif
665
666 int db_printable (s)
667 const unsigned char *s;
668 {
669 int i;
670 for (i = 0; s [i]; i++)
671 if (!isascii (s [i]) || !isprint (s [i])
672 || s [i] == '"' || s [i] == '\\')
673 return 0;
674 return 1;
675 }
676
677 int db_printable_len (s, len)
678 const unsigned char *s;
679 unsigned len;
680 {
681 int i;
682
683 for (i = 0; i < len; i++)
684 if (!isascii (s [i]) || !isprint (s [i]) ||
685 s [i] == '"' || s [i] == '\\')
686 return 0;
687 return 1;
688 }
689
690 static int print_hash_string(FILE *fp, struct class *class)
691 {
692 int i;
693
694 for (i = 0 ; i < class->hash_string.len ; i++)
695 if (!isascii(class->hash_string.data[i]) ||
696 !isprint(class->hash_string.data[i]))
697 break;
698
699 if (i == class->hash_string.len) {
700 if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
701 class->hash_string.data) <= 0) {
702 log_error("Failure writing hash string: %m");
703 return 0;
704 }
705 } else {
706 if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
707 log_error("Failure writing hash string: %m");
708 return 0;
709 }
710 for (i = 1 ; i < class->hash_string.len ; i++) {
711 if (fprintf(fp, ":%2.2x",
712 class->hash_string.data[i]) <= 0) {
713 log_error("Failure writing hash string: %m");
714 return 0;
715 }
716 }
717 }
718
719 return 1;
720 }
721
722
723 isc_result_t
724 write_named_billing_class(const void *key, unsigned len, void *object)
725 {
726 const unsigned char *name = key;
727 struct class *class = object;
728
729 if (class->flags & CLASS_DECL_DYNAMIC) {
730 numclasseswritten++;
731 if (class->superclass == 0) {
732 if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
733 return ISC_R_IOERROR;
734 } else {
735 if (fprintf(db_file, "subclass \"%s\"",
736 class->superclass->name) <= 0)
737 return ISC_R_IOERROR;
738 if (!print_hash_string(db_file, class))
739 return ISC_R_IOERROR;
740 if (fprintf(db_file, " {\n") <= 0)
741 return ISC_R_IOERROR;
742 }
743
744 if ((class->flags & CLASS_DECL_DELETED) != 0) {
745 if (fprintf(db_file, " deleted;\n") <= 0)
746 return ISC_R_IOERROR;
747 } else {
748 if (fprintf(db_file, " dynamic;\n") <= 0)
749 return ISC_R_IOERROR;
750 }
751
752 if (class->lease_limit > 0) {
753 if (fprintf(db_file, " lease limit %d;\n",
754 class->lease_limit) <= 0)
755 return ISC_R_IOERROR;
756 }
757
758 if (class->expr != 0) {
759 if (fprintf(db_file, " match if ") <= 0)
760 return ISC_R_IOERROR;
761 write_expression(db_file, class->expr, 5, 5, 0);
762 if (fprintf(db_file, ";\n") <= 0)
763 return ISC_R_IOERROR;
764 }
765
766 if (class->submatch != 0) {
767 if (class->spawning) {
768 if (fprintf(db_file, " spawn ") <= 0)
769 return ISC_R_IOERROR;
770 } else {
771 if (fprintf(db_file, " match ") <= 0)
772 return ISC_R_IOERROR;
773 }
774
775 write_expression(db_file, class->submatch, 5, 5, 0);
776 if (fprintf(db_file, ";\n") <= 0)
777 return ISC_R_IOERROR;
778 }
779
780 if (class->statements != 0) {
781 write_statements(db_file, class->statements, 8);
782 }
783
784 /* XXXJAB this isn't right, but classes read in off the
785 leases file don't get the root group assigned to them
786 (due to clone_group() call). */
787 if (class->group != 0 && class->group->authoritative != 0)
788 write_statements(db_file, class->group->statements, 8);
789
790 if (fprintf(db_file, "}\n\n") <= 0)
791 return ISC_R_IOERROR;
792 }
793
794 if (class->hash != NULL) { /* yep. recursive. god help us. */
795 /* XXX - cannot check error status of this...
796 * foo_hash_foreach returns a count of operations completed.
797 */
798 class_hash_foreach(class->hash, write_named_billing_class);
799 }
800
801 return ISC_R_SUCCESS;
802 }
803
804 void write_billing_classes ()
805 {
806 struct collection *lp;
807 struct class *cp;
808 struct hash_bucket *bp;
809 int i;
810
811 for (lp = collections; lp; lp = lp -> next) {
812 for (cp = lp -> classes; cp; cp = cp -> nic) {
813 if (cp -> spawning && cp -> hash) {
814 class_hash_foreach (cp -> hash, write_named_billing_class);
815 }
816 }
817 }
818 }
819
820 /* Write a spawned class to the database file. */
821
822 int write_billing_class (class)
823 struct class *class;
824 {
825 int errors = 0;
826 int i;
827
828 if (lease_file_is_corrupt)
829 if (!new_lease_file ())
830 return 0;
831
832 if (!class -> superclass) {
833 errno = 0;
834 fprintf (db_file, "\n billing class \"%s\";", class -> name);
835 return !errno;
836 }
837
838 errno = 0;
839 fprintf (db_file, "\n billing subclass \"%s\"",
840 class -> superclass -> name);
841 if (errno)
842 ++errors;
843
844 print_hash_string(db_file, class);
845 fprintf(db_file, ";");
846
847 class -> dirty = !errors;
848 if (errors)
849 lease_file_is_corrupt = 1;
850 return !errors;
851 }
852
853 /* Commit leases after a timeout. */
854 void commit_leases_timeout (void *foo)
855 {
856 commit_leases ();
857 }
858
859 /* Commit any leases that have been written out... */
860
861 int commit_leases ()
862 {
863 /* Commit any outstanding writes to the lease database file.
864 We need to do this even if we're rewriting the file below,
865 just in case the rewrite fails. */
866 if (fflush (db_file) == EOF) {
867 log_info ("commit_leases: unable to commit: %m");
868 return 0;
869 }
870 if (fsync (fileno (db_file)) < 0) {
871 log_info ("commit_leases: unable to commit: %m");
872 return 0;
873 }
874
875 /* If we haven't rewritten the lease database in over an
876 hour, rewrite it now. (The length of time should probably
877 be configurable. */
878 if (count && cur_time - write_time > 3600) {
879 count = 0;
880 write_time = cur_time;
881 new_lease_file ();
882 }
883 return 1;
884 }
885
886 void db_startup (testp)
887 int testp;
888 {
889 isc_result_t status;
890
891 #if defined (TRACING)
892 if (!trace_playback ()) {
893 #endif
894 /* Read in the existing lease file... */
895 status = read_conf_file (path_dhcpd_db,
896 (struct group *)0, 0, 1);
897 /* XXX ignore status? */
898 #if defined (TRACING)
899 }
900 #endif
901
902 #if defined (TRACING)
903 /* If we're playing back, there is no lease file, so we can't
904 append it, so we create one immediately (maybe this isn't
905 the best solution... */
906 if (trace_playback ()) {
907 new_lease_file ();
908 }
909 #endif
910 if (!testp) {
911 db_file = fopen (path_dhcpd_db, "a");
912 if (!db_file)
913 log_fatal ("Can't open %s for append.", path_dhcpd_db);
914 expire_all_pools ();
915 #if defined (TRACING)
916 if (trace_playback ())
917 write_time = cur_time;
918 else
919 #endif
920 time(&write_time);
921 new_lease_file ();
922 }
923
924 #if defined(REPORT_HASH_PERFORMANCE)
925 log_info("Host HW hash: %s", host_hash_report(host_hw_addr_hash));
926 log_info("Host UID hash: %s", host_hash_report(host_uid_hash));
927 log_info("Lease IP hash: %s",
928 lease_ip_hash_report(lease_ip_addr_hash));
929 log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
930 log_info("Lease HW hash: %s",
931 lease_id_hash_report(lease_hw_addr_hash));
932 #endif
933 }
934
935 int new_lease_file ()
936 {
937 char newfname [512];
938 char backfname [512];
939 TIME t;
940 int db_fd;
941 int db_validity;
942 FILE *new_db_file;
943
944 /* Make a temporary lease file... */
945 time(&t);
946
947 db_validity = lease_file_is_corrupt;
948
949 /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
950 * This should never happen since the path is a configuration
951 * variable from build-time or command-line. But if it should,
952 * either by malice or ignorance, we panic, since the potential
953 * for havoc is high.
954 */
955 if (snprintf (newfname, sizeof newfname, "%s.%d",
956 path_dhcpd_db, (int)t) >= sizeof newfname)
957 log_fatal("new_lease_file: lease file path too long");
958
959 db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
960 if (db_fd < 0) {
961 log_error ("Can't create new lease file: %m");
962 return 0;
963 }
964 if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
965 log_error("Can't fdopen new lease file: %m");
966 close(db_fd);
967 goto fdfail;
968 }
969
970 /* Close previous database, if any. */
971 if (db_file)
972 fclose(db_file);
973 db_file = new_db_file;
974
975 errno = 0;
976 fprintf (db_file, "# The format of this file is documented in the %s",
977 "dhcpd.leases(5) manual page.\n");
978 if (errno != 0)
979 goto fail;
980 fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
981 PACKAGE_VERSION);
982 if (errno != 0)
983 goto fail;
984
985 /* At this point we have a new lease file that, so far, could not
986 * be described as either corrupt nor valid.
987 */
988 lease_file_is_corrupt = 0;
989
990 /* Write out all the leases that we know of... */
991 counting = 0;
992 if (!write_leases ())
993 goto fail;
994
995 #if defined (TRACING)
996 if (!trace_playback ()) {
997 #endif
998 /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
999 * This should never happen since the path is a configuration
1000 * variable from build-time or command-line. But if it should,
1001 * either by malice or ignorance, we panic, since the potential
1002 * for havoc is too high.
1003 */
1004 if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
1005 >= sizeof backfname)
1006 log_fatal("new_lease_file: backup lease file path too long");
1007
1008 /* Get the old database out of the way... */
1009 if (unlink (backfname) < 0 && errno != ENOENT) {
1010 log_error ("Can't remove old lease database backup %s: %m",
1011 backfname);
1012 goto fail;
1013 }
1014 if (link(path_dhcpd_db, backfname) < 0) {
1015 if (errno == ENOENT) {
1016 log_error("%s is missing - no lease db to backup.",
1017 path_dhcpd_db);
1018 } else {
1019 log_error("Can't backup lease database %s to %s: %m",
1020 path_dhcpd_db, backfname);
1021 goto fail;
1022 }
1023 }
1024 #if defined (TRACING)
1025 }
1026 #endif
1027
1028 /* Move in the new file... */
1029 if (rename (newfname, path_dhcpd_db) < 0) {
1030 log_error ("Can't install new lease database %s to %s: %m",
1031 newfname, path_dhcpd_db);
1032 goto fail;
1033 }
1034
1035 counting = 1;
1036 return 1;
1037
1038 fail:
1039 lease_file_is_corrupt = db_validity;
1040 fdfail:
1041 unlink (newfname);
1042 return 0;
1043 }
1044
1045 int group_writer (struct group_object *group)
1046 {
1047 if (!write_group (group))
1048 return 0;
1049 if (!commit_leases ())
1050 return 0;
1051 return 1;
1052 }