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