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 40static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd, 41 char *prepend); 42 43FILE *db_file; 44 45static int counting = 0; 46static int count = 0; 47TIME write_time; 48int lease_file_is_corrupt = 0; 49 50/* Write a single binding scope value in parsable format. 51 */ 52 53static isc_result_t 54write_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 103int 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 303int 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 454int 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 */ 522int 523write_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 703error_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 */ 713int 714write_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 763error_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) 771int 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 826int 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 837int 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 850static 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 883isc_result_t 884write_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 980void 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 996int 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. */ 1029void commit_leases_timeout (void *foo) 1030{ 1031 commit_leases (); 1032} 1033 1034/* Commit any leases that have been written out... */ 1035 1036int 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 */ 1069int 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 1077void 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 1138int 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 1285int 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