server/db.c

Go to the documentation of this file.
00001 /* db.c
00002 
00003    Persistent database management routines for DHCPD... */
00004 
00005 /*
00006  * Copyright (c) 2012-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1995-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
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 /* PARANOIA */
00049 
00050 /* Write a single binding scope value in parsable format.
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 /* Write the specified lease to the current lease database file. */
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         /* If the lease file is corrupt, don't try to write any more leases
00112            until we've written a good lease file. */
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          * In this case, if the rewind state is not present in the lease file,
00173          * the reader will use the current binding state as the most
00174          * conservative (safest) state.  So if the in-memory rewind state is
00175          * for some reason invalid, the best thing to do is not to write a
00176          * state and let the reader take on a safe state.
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         /* If this lease is billed to a class and is still valid,
00194            write it out. */
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                 /* XXX */
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                 /* XXX */
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         /* If the lease file is corrupt, don't try to write any more leases
00310            until we've written a good lease file. */
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         /* If the lease file is corrupt, don't try to write any more leases
00456            until we've written a good lease file. */
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  * Write an IA and the options it has.
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          * If the lease file is corrupt, don't try to write any more 
00531          * leases until we've written a good lease file. 
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                 /* Note that from here on out, the \n is prepended to the
00609                  * next write, rather than appended to the current write.
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                 /* Write out any binding scopes: note that 'ends' above does
00626                  * not have \n on the end!  We want that.
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                         /* We don't do a regular error_exit because the
00638                          * lease db is not corrupt in this case.
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  * Put a copy of the server DUID in the leases file.
00687  */
00688 int
00689 write_server_duid(void) {
00690         struct data_string server_duid;
00691         char *s;
00692         int fprintf_ret;
00693 
00694         /*
00695          * Only write the DUID if it's been set.
00696          */
00697         if (!server_duid_isset()) {
00698                 return 1;
00699         }
00700 
00701         /* 
00702          * If the lease file is corrupt, don't try to write any more 
00703          * leases until we've written a good lease file. 
00704          */
00705         if (lease_file_is_corrupt) {
00706                 if (!new_lease_file()) {
00707                         return 0;
00708                 }
00709         }
00710 
00711         /*
00712          * Get a copy of our server DUID and convert to a quoted string.
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          * Write to the leases file.
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          * Check if we actually managed to write.
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 /* DHCPv6 */
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                 /* XXXJAB this isn't right, but classes read in off the
00931                    leases file don't get the root group assigned to them
00932                    (due to clone_group() call). */
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) {      /* yep. recursive. god help us. */
00945                 /* XXX - cannot check error status of this...
00946                  * foo_hash_foreach returns a count of operations completed.
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 /* Write a spawned class to the database file. */
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 /* Commit leases after a timeout. */
01003 void commit_leases_timeout (void *foo)
01004 {
01005         commit_leases ();
01006 }
01007 
01008 /* Commit any leases that have been written out... */
01009 
01010 int commit_leases ()
01011 {
01012         /* Commit any outstanding writes to the lease database file.
01013            We need to do this even if we're rewriting the file below,
01014            just in case the rewrite fails. */
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         /* send out all deferred ACKs now */
01026         flush_ackqueue(NULL);
01027 
01028         /* If we haven't rewritten the lease database in over an
01029            hour, rewrite it now.  (The length of time should probably
01030            be configurable. */
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  * rewrite the lease file about once an hour
01041  * This is meant as a quick patch for ticket 24887.  It allows
01042  * us to rotate the v6 lease file without adding too many fsync()
01043  * calls.  In the future wes should revisit this area and add
01044  * something similar to the delayed ack code for v4.
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 /* PARANOIA */
01059 {
01060         isc_result_t status;
01061 
01062 #if defined (TRACING)
01063         if (!trace_playback ()) {
01064 #endif
01065                 /* Read in the existing lease file... */
01066                 status = read_conf_file (path_dhcpd_db,
01067                                          (struct group *)0, 0, 1);
01068                 if (status != ISC_R_SUCCESS) {
01069                         /* XXX ignore status? */
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 /* PARANOIA */
01081 
01082 #if defined (TRACING)
01083         /* If we're playing back, there is no lease file, so we can't
01084            append it, so we create one immediately (maybe this isn't
01085            the best solution... */
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         /* Make a temporary lease file... */
01125         time(&t);
01126 
01127         db_validity = lease_file_is_corrupt;
01128 
01129         /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
01130          * This should never happen since the path is a configuration
01131          * variable from build-time or command-line.  But if it should,
01132          * either by malice or ignorance, we panic, since the potential
01133          * for havoc is high.
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 /* PARANOIA */
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         /* Close previous database, if any. */
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         /* At this point we have a new lease file that, so far, could not
01178          * be described as either corrupt nor valid.
01179          */
01180         lease_file_is_corrupt = 0;
01181 
01182         /* Write out all the leases that we know of... */
01183         counting = 0;
01184         if (!write_leases ())
01185                 goto fail;
01186 
01187 #if defined (TRACING)
01188         if (!trace_playback ()) {
01189 #endif
01190             /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
01191              * This should never happen since the path is a configuration
01192              * variable from build-time or command-line.  But if it should,
01193              * either by malice or ignorance, we panic, since the potential
01194              * for havoc is too high.
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             /* Get the old database out of the way... */
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         /* Move in the new file... */
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 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1