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