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
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
write_binding_scope(FILE * db_file,struct binding * bnd,char * prepend)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
write_lease(lease)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 (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
write_host(host)303 int 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
write_group(group)454 int 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 */
522 int
write_ia(const struct ia_xx * ia)523 write_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
703 error_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 */
713 int
write_server_duid(void)714 write_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
763 error_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)
write_failover_state(dhcp_failover_state_t * state)771 int 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
db_printable(s)826 int 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
db_printable_len(s,len)837 int 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
print_hash_string(FILE * fp,struct class * class)850 static 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
883 isc_result_t
write_named_billing_class(const void * key,unsigned len,void * object)884 write_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
write_billing_classes()980 void 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
write_billing_class(class)996 int 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. */
commit_leases_timeout(void * foo)1029 void commit_leases_timeout (void *foo)
1030 {
1031 commit_leases ();
1032 }
1033
1034 /* Commit any leases that have been written out... */
1035
commit_leases()1036 int 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 */
commit_leases_timed()1069 int 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
db_startup(int test_mode)1077 void 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
new_lease_file(int test_mode)1138 int 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
group_writer(struct group_object * group)1285 int 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