00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "dhcpd.h"
00031 #include <ctype.h>
00032 #include <errno.h>
00033
00034 #define LEASE_REWRITE_PERIOD 3600
00035
00036 static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd,
00037 char *prepend);
00038
00039 FILE *db_file;
00040
00041 static int counting = 0;
00042 static int count = 0;
00043 TIME write_time;
00044 int lease_file_is_corrupt = 0;
00045 #if defined (PARANOIA)
00046 uid_t global_set_uid = 0;
00047 gid_t global_set_gid = 0;
00048 #endif
00049
00050
00051
00052
00053 static isc_result_t
00054 write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) {
00055 char *s;
00056
00057 if ((db_file == NULL) || (bnd == NULL) || (prepend == NULL))
00058 return DHCP_R_INVALIDARG;
00059
00060 if (bnd->value->type == binding_data) {
00061 if (bnd->value->value.data.data != NULL) {
00062 s = quotify_buf(bnd->value->value.data.data,
00063 bnd->value->value.data.len, MDL);
00064 if (s != NULL) {
00065 errno = 0;
00066 fprintf(db_file, "%sset %s = \"%s\";",
00067 prepend, bnd->name, s);
00068 dfree(s, MDL);
00069 if (errno)
00070 return ISC_R_FAILURE;
00071 } else {
00072 return ISC_R_FAILURE;
00073 }
00074 }
00075 } else if (bnd->value->type == binding_numeric) {
00076 errno = 0;
00077 fprintf(db_file, "%sset %s = %%%ld;", prepend,
00078 bnd->name, bnd->value->value.intval);
00079 if (errno)
00080 return ISC_R_FAILURE;
00081 } else if (bnd->value->type == binding_boolean) {
00082 errno = 0;
00083 fprintf(db_file, "%sset %s = %s;", prepend, bnd->name,
00084 bnd->value->value.intval ? "true" : "false");
00085 if (errno)
00086 return ISC_R_FAILURE;
00087 } else if (bnd->value->type == binding_dns) {
00088 log_error("%s: persistent dns values not supported.",
00089 bnd->name);
00090 } else if (bnd->value->type == binding_function) {
00091 log_error("%s: persistent functions not supported.",
00092 bnd->name);
00093 } else {
00094 log_fatal("%s: unknown binding type %d", bnd->name,
00095 bnd->value->type);
00096 }
00097
00098 return ISC_R_SUCCESS;
00099 }
00100
00101
00102
00103 int write_lease (lease)
00104 struct lease *lease;
00105 {
00106 int errors = 0;
00107 struct binding *b;
00108 char *s;
00109 const char *tval;
00110
00111
00112
00113 if (lease_file_is_corrupt)
00114 if (!new_lease_file ())
00115 return 0;
00116
00117 if (counting)
00118 ++count;
00119 errno = 0;
00120 fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
00121 if (errno) {
00122 ++errors;
00123 }
00124
00125 if (lease->starts &&
00126 ((tval = print_time(lease->starts)) == NULL ||
00127 fprintf(db_file, "\n starts %s", tval) < 0))
00128 ++errors;
00129
00130 if (lease->ends &&
00131 ((tval = print_time(lease->ends)) == NULL ||
00132 fprintf(db_file, "\n ends %s", tval) < 0))
00133 ++errors;
00134
00135 if (lease->tstp &&
00136 ((tval = print_time(lease->tstp)) == NULL ||
00137 fprintf(db_file, "\n tstp %s", tval) < 0))
00138 ++errors;
00139
00140 if (lease->tsfp &&
00141 ((tval = print_time(lease->tsfp)) == NULL ||
00142 fprintf(db_file, "\n tsfp %s", tval) < 0))
00143 ++errors;
00144
00145 if (lease->atsfp &&
00146 ((tval = print_time(lease->atsfp)) == NULL ||
00147 fprintf(db_file, "\n atsfp %s", tval) < 0))
00148 ++errors;
00149
00150 if (lease->cltt &&
00151 ((tval = print_time(lease->cltt)) == NULL ||
00152 fprintf(db_file, "\n cltt %s", tval) < 0))
00153 ++errors;
00154
00155 if (fprintf (db_file, "\n binding state %s;",
00156 ((lease -> binding_state > 0 &&
00157 lease -> binding_state <= FTS_LAST)
00158 ? binding_state_names [lease -> binding_state - 1]
00159 : "abandoned")) < 0)
00160 ++errors;
00161
00162 if (lease -> binding_state != lease -> next_binding_state)
00163 if (fprintf (db_file, "\n next binding state %s;",
00164 ((lease -> next_binding_state > 0 &&
00165 lease -> next_binding_state <= FTS_LAST)
00166 ? (binding_state_names
00167 [lease -> next_binding_state - 1])
00168 : "abandoned")) < 0)
00169 ++errors;
00170
00171
00172
00173
00174
00175
00176
00177
00178 if ((lease->binding_state != lease->rewind_binding_state) &&
00179 (lease->rewind_binding_state > 0) &&
00180 (lease->rewind_binding_state <= FTS_LAST) &&
00181 (fprintf(db_file, "\n rewind binding state %s;",
00182 binding_state_names[lease->rewind_binding_state-1])) < 0)
00183 ++errors;
00184
00185 if (lease->flags & RESERVED_LEASE)
00186 if (fprintf(db_file, "\n reserved;") < 0)
00187 ++errors;
00188
00189 if (lease->flags & BOOTP_LEASE)
00190 if (fprintf(db_file, "\n dynamic-bootp;") < 0)
00191 ++errors;
00192
00193
00194
00195 if (lease -> billing_class && lease -> ends > cur_time) {
00196 if (!write_billing_class (lease -> billing_class)) {
00197 log_error ("unable to write class %s",
00198 lease -> billing_class -> name);
00199 ++errors;
00200 }
00201 }
00202
00203 if (lease -> hardware_addr.hlen) {
00204 errno = 0;
00205 fprintf (db_file, "\n hardware %s %s;",
00206 hardware_types [lease -> hardware_addr.hbuf [0]],
00207 print_hw_addr (lease -> hardware_addr.hbuf [0],
00208 lease -> hardware_addr.hlen - 1,
00209 &lease -> hardware_addr.hbuf [1]));
00210 if (errno)
00211 ++errors;
00212 }
00213 if (lease -> uid_len) {
00214 s = quotify_buf (lease -> uid, lease -> uid_len, MDL);
00215 if (s) {
00216 errno = 0;
00217 fprintf (db_file, "\n uid \"%s\";", s);
00218 if (errno)
00219 ++errors;
00220 dfree (s, MDL);
00221 } else
00222 ++errors;
00223 }
00224
00225 if (lease->scope != NULL) {
00226 for (b = lease->scope->bindings; b; b = b->next) {
00227 if (!b->value)
00228 continue;
00229
00230 if (write_binding_scope(db_file, b, "\n ") != ISC_R_SUCCESS)
00231 ++errors;
00232 }
00233 }
00234
00235 if (lease -> agent_options) {
00236 struct option_cache *oc;
00237 struct data_string ds;
00238 pair p;
00239
00240 memset (&ds, 0, sizeof ds);
00241 for (p = lease -> agent_options -> first; p; p = p -> cdr) {
00242 oc = (struct option_cache *)p -> car;
00243 if (oc -> data.len) {
00244 errno = 0;
00245 fprintf (db_file, "\n option agent.%s %s;",
00246 oc -> option -> name,
00247 pretty_print_option (oc -> option, oc -> data.data,
00248 oc -> data.len, 1, 1));
00249 if (errno)
00250 ++errors;
00251 }
00252 }
00253 }
00254 if (lease -> client_hostname &&
00255 db_printable((unsigned char *)lease->client_hostname)) {
00256 s = quotify_string (lease -> client_hostname, MDL);
00257 if (s) {
00258 errno = 0;
00259 fprintf (db_file, "\n client-hostname \"%s\";", s);
00260 if (errno)
00261 ++errors;
00262 dfree (s, MDL);
00263 } else
00264 ++errors;
00265 }
00266 if (lease->on_star.on_expiry) {
00267 errno = 0;
00268 fprintf (db_file, "\n on expiry%s {",
00269 lease->on_star.on_expiry == lease->on_star.on_release
00270 ? " or release" : "");
00271 write_statements (db_file, lease->on_star.on_expiry, 4);
00272
00273 fprintf (db_file, "\n }");
00274 if (errno)
00275 ++errors;
00276 }
00277 if (lease->on_star.on_release &&
00278 lease->on_star.on_release != lease->on_star.on_expiry) {
00279 errno = 0;
00280 fprintf (db_file, "\n on release {");
00281 write_statements (db_file, lease->on_star.on_release, 4);
00282
00283 fprintf (db_file, "\n }");
00284 if (errno)
00285 ++errors;
00286 }
00287
00288 errno = 0;
00289 fputs ("\n}\n", db_file);
00290 if (errno)
00291 ++errors;
00292
00293 if (errors) {
00294 log_info ("write_lease: unable to write lease %s",
00295 piaddr (lease -> ip_addr));
00296 lease_file_is_corrupt = 1;
00297 }
00298
00299 return !errors;
00300 }
00301
00302 int write_host (host)
00303 struct host_decl *host;
00304 {
00305 int errors = 0;
00306 int i;
00307 struct data_string ip_addrs;
00308
00309
00310
00311 if (lease_file_is_corrupt)
00312 if (!new_lease_file ())
00313 return 0;
00314
00315 if (!db_printable((unsigned char *)host->name))
00316 return 0;
00317
00318 if (counting)
00319 ++count;
00320
00321 errno = 0;
00322 fprintf (db_file, "host %s {", host -> name);
00323 if (errno)
00324 ++errors;
00325
00326 if (host -> flags & HOST_DECL_DYNAMIC) {
00327 errno = 0;
00328 fprintf (db_file, "\n dynamic;");
00329 if (errno)
00330 ++errors;
00331 }
00332
00333 if (host -> flags & HOST_DECL_DELETED) {
00334 errno = 0;
00335 fprintf (db_file, "\n deleted;");
00336 if (errno)
00337 ++errors;
00338 } else {
00339 if (host -> interface.hlen) {
00340 errno = 0;
00341 fprintf (db_file, "\n hardware %s %s;",
00342 hardware_types [host -> interface.hbuf [0]],
00343 print_hw_addr (host -> interface.hbuf [0],
00344 host -> interface.hlen - 1,
00345 &host -> interface.hbuf [1]));
00346 if (errno)
00347 ++errors;
00348 }
00349 if (host -> client_identifier.len) {
00350 int i;
00351 errno = 0;
00352 if (db_printable_len (host -> client_identifier.data,
00353 host -> client_identifier.len)) {
00354 fprintf (db_file, "\n uid \"%.*s\";",
00355 (int)host -> client_identifier.len,
00356 host -> client_identifier.data);
00357 if (errno)
00358 ++errors;
00359 } else {
00360 fprintf (db_file,
00361 "\n uid %2.2x",
00362 host -> client_identifier.data [0]);
00363 if (errno)
00364 ++errors;
00365 for (i = 1;
00366 i < host -> client_identifier.len; i++) {
00367 errno = 0;
00368 fprintf (db_file, ":%2.2x",
00369 host ->
00370 client_identifier.data [i]);
00371 if (errno)
00372 ++errors;
00373 }
00374
00375 errno = 0;
00376 fputc (';', db_file);
00377 if (errno)
00378 ++errors;
00379 }
00380 }
00381
00382 memset (&ip_addrs, 0, sizeof ip_addrs);
00383 if (host -> fixed_addr &&
00384 evaluate_option_cache (&ip_addrs, (struct packet *)0,
00385 (struct lease *)0,
00386 (struct client_state *)0,
00387 (struct option_state *)0,
00388 (struct option_state *)0,
00389 &global_scope,
00390 host -> fixed_addr, MDL)) {
00391
00392 errno = 0;
00393 fprintf (db_file, "\n fixed-address ");
00394 if (errno)
00395 ++errors;
00396 for (i = 0; i < ip_addrs.len - 3; i += 4) {
00397
00398 errno = 0;
00399 fprintf (db_file, "%u.%u.%u.%u%s",
00400 ip_addrs.data [i] & 0xff,
00401 ip_addrs.data [i + 1] & 0xff,
00402 ip_addrs.data [i + 2] & 0xff,
00403 ip_addrs.data [i + 3] & 0xff,
00404 i + 7 < ip_addrs.len ? "," : "");
00405 if (errno)
00406 ++errors;
00407 }
00408
00409 errno = 0;
00410 fputc (';', db_file);
00411 if (errno)
00412 ++errors;
00413 data_string_forget (&ip_addrs, MDL);
00414 }
00415
00416 if (host -> named_group) {
00417 errno = 0;
00418 fprintf (db_file, "\n group \"%s\";",
00419 host -> named_group -> name);
00420 if (errno)
00421 ++errors;
00422 }
00423
00424 if (host -> group &&
00425 (!host -> named_group ||
00426 host -> group != host -> named_group -> group) &&
00427 host -> group != root_group) {
00428 errno = 0;
00429 write_statements (db_file,
00430 host -> group -> statements, 8);
00431 if (errno)
00432 ++errors;
00433 }
00434 }
00435
00436 errno = 0;
00437 fputs ("\n}\n", db_file);
00438 if (errno)
00439 ++errors;
00440
00441 if (errors) {
00442 log_info ("write_host: unable to write host %s",
00443 host -> name);
00444 lease_file_is_corrupt = 1;
00445 }
00446
00447 return !errors;
00448 }
00449
00450 int write_group (group)
00451 struct group_object *group;
00452 {
00453 int errors = 0;
00454
00455
00456
00457 if (lease_file_is_corrupt)
00458 if (!new_lease_file ())
00459 return 0;
00460
00461 if (!db_printable((unsigned char *)group->name))
00462 return 0;
00463
00464 if (counting)
00465 ++count;
00466
00467 errno = 0;
00468 fprintf (db_file, "group %s {", group -> name);
00469 if (errno)
00470 ++errors;
00471
00472 if (group -> flags & GROUP_OBJECT_DYNAMIC) {
00473 errno = 0;
00474 fprintf (db_file, "\n dynamic;");
00475 if (errno)
00476 ++errors;
00477 }
00478
00479 if (group -> flags & GROUP_OBJECT_STATIC) {
00480 errno = 0;
00481 fprintf (db_file, "\n static;");
00482 if (errno)
00483 ++errors;
00484 }
00485
00486 if (group -> flags & GROUP_OBJECT_DELETED) {
00487 errno = 0;
00488 fprintf (db_file, "\n deleted;");
00489 if (errno)
00490 ++errors;
00491 } else {
00492 if (group -> group) {
00493 errno = 0;
00494 write_statements (db_file,
00495 group -> group -> statements, 8);
00496 if (errno)
00497 ++errors;
00498 }
00499 }
00500
00501 errno = 0;
00502 fputs ("\n}\n", db_file);
00503 if (errno)
00504 ++errors;
00505
00506 if (errors) {
00507 log_info ("write_group: unable to write group %s",
00508 group -> name);
00509 lease_file_is_corrupt = 1;
00510 }
00511
00512 return !errors;
00513 }
00514
00515
00516
00517
00518 int
00519 write_ia(const struct ia_xx *ia) {
00520 struct iasubopt *iasubopt;
00521 struct binding *bnd;
00522 int i;
00523 char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
00524 const char *binding_state;
00525 const char *tval;
00526 char *s;
00527 int fprintf_ret;
00528
00529
00530
00531
00532
00533 if (lease_file_is_corrupt) {
00534 if (!new_lease_file()) {
00535 return 0;
00536 }
00537 }
00538
00539 if (counting) {
00540 ++count;
00541 }
00542
00543
00544 s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL);
00545 if (s == NULL) {
00546 goto error_exit;
00547 }
00548 switch (ia->ia_type) {
00549 case D6O_IA_NA:
00550 fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s);
00551 break;
00552 case D6O_IA_TA:
00553 fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s);
00554 break;
00555 case D6O_IA_PD:
00556 fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s);
00557 break;
00558 default:
00559 log_error("Unknown ia type %u for \"%s\" at %s:%d",
00560 (unsigned)ia->ia_type, s, MDL);
00561 fprintf_ret = -1;
00562 }
00563 dfree(s, MDL);
00564 if (fprintf_ret < 0) {
00565 goto error_exit;
00566 }
00567 if (ia->cltt != MIN_TIME) {
00568 tval = print_time(ia->cltt);
00569 if (tval == NULL) {
00570 goto error_exit;
00571 }
00572 if (fprintf(db_file, " cltt %s\n", tval) < 0) {
00573 goto error_exit;
00574 }
00575 }
00576 for (i=0; i<ia->num_iasubopt; i++) {
00577 iasubopt = ia->iasubopt[i];
00578
00579 inet_ntop(AF_INET6, &iasubopt->addr,
00580 addr_buf, sizeof(addr_buf));
00581 if ((ia->ia_type != D6O_IA_PD) &&
00582 (fprintf(db_file, " iaaddr %s {\n", addr_buf) < 0)) {
00583 goto error_exit;
00584 }
00585 if ((ia->ia_type == D6O_IA_PD) &&
00586 (fprintf(db_file, " iaprefix %s/%d {\n",
00587 addr_buf, (int)iasubopt->plen) < 0)) {
00588 goto error_exit;
00589 }
00590 if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) {
00591 log_fatal("Unknown iasubopt state %d at %s:%d",
00592 iasubopt->state, MDL);
00593 }
00594 binding_state = binding_state_names[iasubopt->state-1];
00595 if (fprintf(db_file, " binding state %s;\n",
00596 binding_state) < 0) {
00597 goto error_exit;
00598 }
00599 if (fprintf(db_file, " preferred-life %u;\n",
00600 (unsigned)iasubopt->prefer) < 0) {
00601 goto error_exit;
00602 }
00603 if (fprintf(db_file, " max-life %u;\n",
00604 (unsigned)iasubopt->valid) < 0) {
00605 goto error_exit;
00606 }
00607
00608
00609
00610
00611 if ((iasubopt->state == FTS_ACTIVE) ||
00612 (iasubopt->state == FTS_ABANDONED) ||
00613 (iasubopt->hard_lifetime_end_time != 0)) {
00614 tval = print_time(iasubopt->hard_lifetime_end_time);
00615 } else {
00616 tval = print_time(iasubopt->soft_lifetime_end_time);
00617 }
00618 if (tval == NULL) {
00619 goto error_exit;
00620 }
00621 if (fprintf(db_file, " ends %s", tval) < 0) {
00622 goto error_exit;
00623 }
00624
00625
00626
00627
00628 if (iasubopt->scope != NULL)
00629 bnd = iasubopt->scope->bindings;
00630 else
00631 bnd = NULL;
00632
00633 for (; bnd != NULL ; bnd = bnd->next) {
00634 if (bnd->value == NULL)
00635 continue;
00636
00637
00638
00639
00640 if (write_binding_scope(db_file, bnd,
00641 "\n ") != ISC_R_SUCCESS)
00642 goto error_exit;
00643
00644 }
00645
00646 if (iasubopt->on_star.on_expiry) {
00647 if (fprintf(db_file, "\n on expiry%s {",
00648 iasubopt->on_star.on_expiry ==
00649 iasubopt->on_star.on_release
00650 ? " or release" : "") < 0)
00651 goto error_exit;
00652 write_statements(db_file,
00653 iasubopt->on_star.on_expiry, 6);
00654 if (fprintf(db_file, "\n }") < 0)
00655 goto error_exit;
00656 }
00657
00658 if (iasubopt->on_star.on_release &&
00659 iasubopt->on_star.on_release !=
00660 iasubopt->on_star.on_expiry) {
00661 if (fprintf(db_file, "\n on release {") < 0)
00662 goto error_exit;
00663 write_statements(db_file,
00664 iasubopt->on_star.on_release, 6);
00665 if (fprintf(db_file, "\n }") < 0)
00666 goto error_exit;
00667 }
00668
00669 if (fprintf(db_file, "\n }\n") < 0)
00670 goto error_exit;
00671 }
00672 if (fprintf(db_file, "}\n\n") < 0)
00673 goto error_exit;
00674
00675 fflush(db_file);
00676 return 1;
00677
00678 error_exit:
00679 log_info("write_ia: unable to write ia");
00680 lease_file_is_corrupt = 1;
00681 return 0;
00682 }
00683
00684 #ifdef DHCPv6
00685
00686
00687
00688 int
00689 write_server_duid(void) {
00690 struct data_string server_duid;
00691 char *s;
00692 int fprintf_ret;
00693
00694
00695
00696
00697 if (!server_duid_isset()) {
00698 return 1;
00699 }
00700
00701
00702
00703
00704
00705 if (lease_file_is_corrupt) {
00706 if (!new_lease_file()) {
00707 return 0;
00708 }
00709 }
00710
00711
00712
00713
00714 memset(&server_duid, 0, sizeof(server_duid));
00715 copy_server_duid(&server_duid, MDL);
00716 s = quotify_buf(server_duid.data, server_duid.len, MDL);
00717 data_string_forget(&server_duid, MDL);
00718 if (s == NULL) {
00719 goto error_exit;
00720 }
00721
00722
00723
00724
00725 fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s);
00726 dfree(s, MDL);
00727 if (fprintf_ret < 0) {
00728 goto error_exit;
00729 }
00730
00731
00732
00733
00734 fflush(db_file);
00735 return 1;
00736
00737 error_exit:
00738 log_info("write_server_duid: unable to write server-duid");
00739 lease_file_is_corrupt = 1;
00740 return 0;
00741 }
00742 #endif
00743
00744 #if defined (FAILOVER_PROTOCOL)
00745 int write_failover_state (dhcp_failover_state_t *state)
00746 {
00747 int errors = 0;
00748 const char *tval;
00749
00750 if (lease_file_is_corrupt)
00751 if (!new_lease_file ())
00752 return 0;
00753
00754 errno = 0;
00755 fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
00756 if (errno)
00757 ++errors;
00758
00759 tval = print_time(state->me.stos);
00760 if (tval == NULL ||
00761 fprintf(db_file, "\n my state %s at %s",
00762 (state->me.state == startup) ?
00763 dhcp_failover_state_name_print(state->saved_state) :
00764 dhcp_failover_state_name_print(state->me.state),
00765 tval) < 0)
00766 ++errors;
00767
00768 tval = print_time(state->partner.stos);
00769 if (tval == NULL ||
00770 fprintf(db_file, "\n partner state %s at %s",
00771 dhcp_failover_state_name_print(state->partner.state),
00772 tval) < 0)
00773 ++errors;
00774
00775 if (state -> i_am == secondary) {
00776 errno = 0;
00777 fprintf (db_file, "\n mclt %ld;",
00778 (unsigned long)state -> mclt);
00779 if (errno)
00780 ++errors;
00781 }
00782
00783 errno = 0;
00784 fprintf (db_file, "\n}\n");
00785 if (errno)
00786 ++errors;
00787
00788 if (errors) {
00789 log_info ("write_failover_state: unable to write state %s",
00790 state -> name);
00791 lease_file_is_corrupt = 1;
00792 return 0;
00793 }
00794
00795 return 1;
00796
00797 }
00798 #endif
00799
00800 int db_printable (s)
00801 const unsigned char *s;
00802 {
00803 int i;
00804 for (i = 0; s [i]; i++)
00805 if (!isascii (s [i]) || !isprint (s [i])
00806 || s [i] == '"' || s [i] == '\\')
00807 return 0;
00808 return 1;
00809 }
00810
00811 int db_printable_len (s, len)
00812 const unsigned char *s;
00813 unsigned len;
00814 {
00815 int i;
00816
00817 for (i = 0; i < len; i++)
00818 if (!isascii (s [i]) || !isprint (s [i]) ||
00819 s [i] == '"' || s [i] == '\\')
00820 return 0;
00821 return 1;
00822 }
00823
00824 static int print_hash_string(FILE *fp, struct class *class)
00825 {
00826 int i;
00827
00828 for (i = 0 ; i < class->hash_string.len ; i++)
00829 if (!isascii(class->hash_string.data[i]) ||
00830 !isprint(class->hash_string.data[i]))
00831 break;
00832
00833 if (i == class->hash_string.len) {
00834 if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
00835 class->hash_string.data) <= 0) {
00836 log_error("Failure writing hash string: %m");
00837 return 0;
00838 }
00839 } else {
00840 if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
00841 log_error("Failure writing hash string: %m");
00842 return 0;
00843 }
00844 for (i = 1 ; i < class->hash_string.len ; i++) {
00845 if (fprintf(fp, ":%2.2x",
00846 class->hash_string.data[i]) <= 0) {
00847 log_error("Failure writing hash string: %m");
00848 return 0;
00849 }
00850 }
00851 }
00852
00853 return 1;
00854 }
00855
00856
00857 isc_result_t
00858 write_named_billing_class(const void *key, unsigned len, void *object)
00859 {
00860 const unsigned char *name = key;
00861 struct class *class = object;
00862
00863 if (class->flags & CLASS_DECL_DYNAMIC) {
00864 numclasseswritten++;
00865 if (class->superclass == 0) {
00866 if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
00867 return ISC_R_IOERROR;
00868 } else {
00869 if (fprintf(db_file, "subclass \"%s\"",
00870 class->superclass->name) <= 0)
00871 return ISC_R_IOERROR;
00872 if (!print_hash_string(db_file, class))
00873 return ISC_R_IOERROR;
00874 if (fprintf(db_file, " {\n") <= 0)
00875 return ISC_R_IOERROR;
00876 }
00877
00878 if ((class->flags & CLASS_DECL_DELETED) != 0) {
00879 if (fprintf(db_file, " deleted;\n") <= 0)
00880 return ISC_R_IOERROR;
00881 } else {
00882 if (fprintf(db_file, " dynamic;\n") <= 0)
00883 return ISC_R_IOERROR;
00884 }
00885
00886 if (class->lease_limit > 0) {
00887 if (fprintf(db_file, " lease limit %d;\n",
00888 class->lease_limit) <= 0)
00889 return ISC_R_IOERROR;
00890 }
00891
00892 if (class->expr != 0) {
00893 if (fprintf(db_file, " match if ") <= 0)
00894 return ISC_R_IOERROR;
00895
00896 errno = 0;
00897 write_expression(db_file, class->expr, 5, 5, 0);
00898 if (errno)
00899 return ISC_R_IOERROR;
00900
00901 if (fprintf(db_file, ";\n") <= 0)
00902 return ISC_R_IOERROR;
00903 }
00904
00905 if (class->submatch != 0) {
00906 if (class->spawning) {
00907 if (fprintf(db_file, " spawn ") <= 0)
00908 return ISC_R_IOERROR;
00909 } else {
00910 if (fprintf(db_file, " match ") <= 0)
00911 return ISC_R_IOERROR;
00912 }
00913
00914 errno = 0;
00915 write_expression(db_file, class->submatch, 5, 5, 0);
00916 if (errno)
00917 return ISC_R_IOERROR;
00918
00919 if (fprintf(db_file, ";\n") <= 0)
00920 return ISC_R_IOERROR;
00921 }
00922
00923 if (class->statements != 0) {
00924 errno = 0;
00925 write_statements(db_file, class->statements, 8);
00926 if (errno)
00927 return ISC_R_IOERROR;
00928 }
00929
00930
00931
00932
00933 if (class->group != 0 && class->group->authoritative != 0) {
00934 errno = 0;
00935 write_statements(db_file, class->group->statements, 8);
00936 if (errno)
00937 return ISC_R_IOERROR;
00938 }
00939
00940 if (fprintf(db_file, "}\n\n") <= 0)
00941 return ISC_R_IOERROR;
00942 }
00943
00944 if (class->hash != NULL) {
00945
00946
00947
00948 class_hash_foreach(class->hash, write_named_billing_class);
00949 }
00950
00951 return ISC_R_SUCCESS;
00952 }
00953
00954 void write_billing_classes ()
00955 {
00956 struct collection *lp;
00957 struct class *cp;
00958
00959 for (lp = collections; lp; lp = lp -> next) {
00960 for (cp = lp -> classes; cp; cp = cp -> nic) {
00961 if (cp -> spawning && cp -> hash) {
00962 class_hash_foreach (cp -> hash, write_named_billing_class);
00963 }
00964 }
00965 }
00966 }
00967
00968
00969
00970 int write_billing_class (class)
00971 struct class *class;
00972 {
00973 int errors = 0;
00974
00975 if (lease_file_is_corrupt)
00976 if (!new_lease_file ())
00977 return 0;
00978
00979 if (!class -> superclass) {
00980 errno = 0;
00981 fprintf (db_file, "\n billing class \"%s\";", class -> name);
00982 return !errno;
00983 }
00984
00985 if (fprintf(db_file, "\n billing subclass \"%s\"",
00986 class -> superclass -> name) < 0)
00987 ++errors;
00988
00989 if (!print_hash_string(db_file, class))
00990 ++errors;
00991
00992 if (fprintf(db_file, ";") < 0)
00993 ++errors;
00994
00995 class -> dirty = !errors;
00996 if (errors)
00997 lease_file_is_corrupt = 1;
00998
00999 return !errors;
01000 }
01001
01002
01003 void commit_leases_timeout (void *foo)
01004 {
01005 commit_leases ();
01006 }
01007
01008
01009
01010 int commit_leases ()
01011 {
01012
01013
01014
01015 if (fflush (db_file) == EOF) {
01016 log_info("commit_leases: unable to commit, fflush(): %m");
01017 return (0);
01018 }
01019 if ((dont_use_fsync == 0) &&
01020 (fsync(fileno (db_file)) < 0)) {
01021 log_info ("commit_leases: unable to commit, fsync(): %m");
01022 return (0);
01023 }
01024
01025
01026 flush_ackqueue(NULL);
01027
01028
01029
01030
01031 if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) {
01032 count = 0;
01033 write_time = cur_time;
01034 new_lease_file();
01035 }
01036 return (1);
01037 }
01038
01039
01040
01041
01042
01043
01044
01045
01046 int commit_leases_timed()
01047 {
01048 if ((count != 0) && (cur_time - write_time > LEASE_REWRITE_PERIOD)) {
01049 return (commit_leases());
01050 }
01051 return (1);
01052 }
01053
01054 #if defined (PARANOIA)
01055 void db_startup (int testp, uid_t set_uid, gid_t set_gid)
01056 #else
01057 void db_startup (int testp)
01058 #endif
01059 {
01060 isc_result_t status;
01061
01062 #if defined (TRACING)
01063 if (!trace_playback ()) {
01064 #endif
01065
01066 status = read_conf_file (path_dhcpd_db,
01067 (struct group *)0, 0, 1);
01068 if (status != ISC_R_SUCCESS) {
01069
01070 ;
01071 }
01072
01073 #if defined (TRACING)
01074 }
01075 #endif
01076
01077 #if defined (PARANOIA)
01078 global_set_uid = set_uid;
01079 global_set_gid = set_gid;
01080 #endif
01081
01082 #if defined (TRACING)
01083
01084
01085
01086 if (trace_playback ()) {
01087 new_lease_file ();
01088 }
01089 #endif
01090 if (!testp) {
01091 db_file = fopen (path_dhcpd_db, "ae");
01092 if (!db_file)
01093 log_fatal ("Can't open %s for append.", path_dhcpd_db);
01094 expire_all_pools ();
01095 #if defined (TRACING)
01096 if (trace_playback ())
01097 write_time = cur_time;
01098 else
01099 #endif
01100 time(&write_time);
01101 new_lease_file ();
01102 }
01103
01104 #if defined(REPORT_HASH_PERFORMANCE)
01105 log_info("Host HW hash: %s", host_hash_report(host_hw_addr_hash));
01106 log_info("Host UID hash: %s", host_hash_report(host_uid_hash));
01107 log_info("Lease IP hash: %s",
01108 lease_ip_hash_report(lease_ip_addr_hash));
01109 log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
01110 log_info("Lease HW hash: %s",
01111 lease_id_hash_report(lease_hw_addr_hash));
01112 #endif
01113 }
01114
01115 int new_lease_file ()
01116 {
01117 char newfname [512];
01118 char backfname [512];
01119 TIME t;
01120 int db_fd;
01121 int db_validity;
01122 FILE *new_db_file;
01123
01124
01125 time(&t);
01126
01127 db_validity = lease_file_is_corrupt;
01128
01129
01130
01131
01132
01133
01134
01135 if (snprintf (newfname, sizeof newfname, "%s.%d",
01136 path_dhcpd_db, (int)t) >= sizeof newfname)
01137 log_fatal("new_lease_file: lease file path too long");
01138
01139 db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0664);
01140 if (db_fd < 0) {
01141 log_error ("Can't create new lease file: %m");
01142 return 0;
01143 }
01144
01145 #if defined (PARANOIA)
01146 if (global_set_uid && !geteuid() &&
01147 global_set_gid && !getegid())
01148 if (fchown(db_fd, global_set_uid, global_set_gid)) {
01149 log_fatal ("Can't chown new lease file: %m");
01150 close(db_fd);
01151 goto fdfail;
01152 }
01153 #endif
01154
01155 if ((new_db_file = fdopen(db_fd, "we")) == NULL) {
01156 log_error("Can't fdopen new lease file: %m");
01157 close(db_fd);
01158 goto fdfail;
01159 }
01160
01161
01162 if (db_file)
01163 fclose(db_file);
01164 db_file = new_db_file;
01165
01166 errno = 0;
01167 fprintf (db_file, "# The format of this file is documented in the %s",
01168 "dhcpd.leases(5) manual page.\n");
01169 if (errno)
01170 goto fail;
01171
01172 fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
01173 PACKAGE_VERSION);
01174 if (errno)
01175 goto fail;
01176
01177
01178
01179
01180 lease_file_is_corrupt = 0;
01181
01182
01183 counting = 0;
01184 if (!write_leases ())
01185 goto fail;
01186
01187 #if defined (TRACING)
01188 if (!trace_playback ()) {
01189 #endif
01190
01191
01192
01193
01194
01195
01196 if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
01197 >= sizeof backfname)
01198 log_fatal("new_lease_file: backup lease file path too long");
01199
01200
01201 if (unlink (backfname) < 0 && errno != ENOENT) {
01202 log_error ("Can't remove old lease database backup %s: %m",
01203 backfname);
01204 goto fail;
01205 }
01206 if (link(path_dhcpd_db, backfname) < 0) {
01207 if (errno == ENOENT) {
01208 log_error("%s is missing - no lease db to backup.",
01209 path_dhcpd_db);
01210 } else {
01211 log_error("Can't backup lease database %s to %s: %m",
01212 path_dhcpd_db, backfname);
01213 goto fail;
01214 }
01215 }
01216 #if defined (TRACING)
01217 }
01218 #endif
01219
01220
01221 if (rename (newfname, path_dhcpd_db) < 0) {
01222 log_error ("Can't install new lease database %s to %s: %m",
01223 newfname, path_dhcpd_db);
01224 goto fail;
01225 }
01226
01227 counting = 1;
01228 return 1;
01229
01230 fail:
01231 lease_file_is_corrupt = db_validity;
01232 fdfail:
01233 unlink (newfname);
01234 return 0;
01235 }
01236
01237 int group_writer (struct group_object *group)
01238 {
01239 if (!write_group (group))
01240 return 0;
01241 if (!commit_leases ())
01242 return 0;
01243 return 1;
01244 }