"Inital commit to Gerrit"
[profile/ivi/dhcp.git] / server / db.c
1 /* db.c
2
3    Persistent database management routines for DHCPD... */
4
5 /*
6  * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1995-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   https://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 #include "dhcpd.h"
36 #include <ctype.h>
37 #include <errno.h>
38
39 static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd,
40                                         char *prepend);
41
42 FILE *db_file;
43
44 static int counting = 0;
45 static int count = 0;
46 TIME write_time;
47 int lease_file_is_corrupt = 0;
48
49 /* Write a single binding scope value in parsable format.
50  */
51
52 static isc_result_t
53 write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) {
54         char *s;
55
56         if ((db_file == NULL) || (bnd == NULL) || (prepend == NULL))
57                 return DHCP_R_INVALIDARG;
58
59         if (bnd->value->type == binding_data) {
60                 if (bnd->value->value.data.data != NULL) {
61                         s = quotify_buf(bnd->value->value.data.data,
62                                         bnd->value->value.data.len, MDL);
63                         if (s != NULL) {
64                                 errno = 0;
65                                 fprintf(db_file, "%sset %s = \"%s\";",
66                                         prepend, bnd->name, s);
67                                 if (errno)
68                                         return ISC_R_FAILURE;
69
70                                 dfree(s, MDL);
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
103 int write_lease (lease)
104         struct lease *lease;
105 {
106         int errors = 0;
107         struct binding *b;
108         char *s;
109         const char *tval;
110
111         /* If the lease file is corrupt, don't try to write any more leases
112            until we've written a good lease file. */
113         if (lease_file_is_corrupt)
114                 if (!new_lease_file ())
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 = quotify_buf (lease -> uid, lease -> uid_len, MDL);
215                 if (s) {
216                         errno = 0;
217                         fprintf (db_file, "\n  uid \"%s\";", s);
218                         if (errno)
219                                 ++errors;
220                         dfree (s, MDL);
221                 } else
222                         ++errors;
223         }
224
225         if (lease->scope != NULL) {
226             for (b = lease->scope->bindings; b; b = b->next) {
227                 if (!b->value)
228                         continue;
229
230                 if (write_binding_scope(db_file, b, "\n  ") != ISC_R_SUCCESS)
231                         ++errors;
232             }
233         }
234
235         if (lease -> agent_options) {
236             struct option_cache *oc;
237             struct data_string ds;
238             pair p;
239
240             memset (&ds, 0, sizeof ds);
241             for (p = lease -> agent_options -> first; p; p = p -> cdr) {
242                 oc = (struct option_cache *)p -> car;
243                 if (oc -> data.len) {
244                 errno = 0;
245                 fprintf (db_file, "\n  option agent.%s %s;",
246                          oc -> option -> name,
247                          pretty_print_option (oc -> option, oc -> data.data,
248                                                 oc -> data.len, 1, 1));
249                 if (errno)
250                     ++errors;
251                 }
252             }
253         }
254         if (lease -> client_hostname &&
255             db_printable((unsigned char *)lease->client_hostname)) {
256                 s = quotify_string (lease -> client_hostname, MDL);
257                 if (s) {
258                         errno = 0;
259                         fprintf (db_file, "\n  client-hostname \"%s\";", s);
260                         if (errno)
261                                 ++errors;
262                         dfree (s, MDL);
263                 } else
264                         ++errors;
265         }
266         if (lease -> on_expiry) {
267                 errno = 0;
268                 fprintf (db_file, "\n  on expiry%s {",
269                          lease -> on_expiry == lease -> on_release
270                          ? " or release" : "");
271                 write_statements (db_file, lease -> on_expiry, 4);
272                 /* XXX */
273                 fprintf (db_file, "\n  }");
274                 if (errno)
275                         ++errors;
276         }
277         if (lease -> on_release && lease -> on_release != lease -> on_expiry) {
278                 errno = 0;
279                 fprintf (db_file, "\n  on release {");
280                 write_statements (db_file, lease -> on_release, 4);
281                 /* XXX */
282                 fprintf (db_file, "\n  }");
283                 if (errno)
284                         ++errors;
285         }
286
287         errno = 0;
288         fputs ("\n}\n", db_file);
289         if (errno)
290                 ++errors;
291
292         if (errors) {
293                 log_info ("write_lease: unable to write lease %s",
294                       piaddr (lease -> ip_addr));
295                 lease_file_is_corrupt = 1;
296         }
297
298         return !errors;
299 }
300
301 int write_host (host)
302         struct host_decl *host;
303 {
304         int errors = 0;
305         int i;
306         struct data_string ip_addrs;
307
308         /* If the lease file is corrupt, don't try to write any more leases
309            until we've written a good lease file. */
310         if (lease_file_is_corrupt)
311                 if (!new_lease_file ())
312                         return 0;
313
314         if (!db_printable((unsigned char *)host->name))
315                 return 0;
316
317         if (counting)
318                 ++count;
319
320         errno = 0;
321         fprintf (db_file, "host %s {", host -> name);
322         if (errno)
323                 ++errors;
324
325         if (host -> flags & HOST_DECL_DYNAMIC) {
326                 errno = 0;
327                 fprintf (db_file, "\n  dynamic;");
328                 if (errno)
329                         ++errors;
330         }
331
332         if (host -> flags & HOST_DECL_DELETED) {
333                 errno = 0;
334                 fprintf (db_file, "\n  deleted;");
335                 if (errno)
336                         ++errors;
337         } else {
338                 if (host -> interface.hlen) {
339                         errno = 0;
340                         fprintf (db_file, "\n  hardware %s %s;",
341                                  hardware_types [host -> interface.hbuf [0]],
342                                  print_hw_addr (host -> interface.hbuf [0],
343                                                 host -> interface.hlen - 1,
344                                                 &host -> interface.hbuf [1]));
345                         if (errno)
346                                 ++errors;
347                 }
348                 if (host -> client_identifier.len) {
349                         int i;
350                         errno = 0;
351                         if (db_printable_len (host -> client_identifier.data,
352                                               host -> client_identifier.len)) {
353                                 fprintf (db_file, "\n  uid \"%.*s\";",
354                                          (int)host -> client_identifier.len,
355                                          host -> client_identifier.data);
356                                 if (errno)
357                                         ++errors;
358                         } else {
359                                 fprintf (db_file,
360                                          "\n  uid %2.2x",
361                                          host -> client_identifier.data [0]);
362                                 if (errno)
363                                         ++errors;
364                                 for (i = 1;
365                                      i < host -> client_identifier.len; i++) {
366                                         errno = 0;
367                                         fprintf (db_file, ":%2.2x",
368                                                  host ->
369                                                  client_identifier.data [i]);
370                                         if (errno)
371                                                 ++errors;
372                                 }
373
374                                 errno = 0;
375                                 fputc (';', db_file);
376                                 if (errno)
377                                         ++errors;
378                         }
379                 }
380                 
381                 memset (&ip_addrs, 0, sizeof ip_addrs);
382                 if (host -> fixed_addr &&
383                     evaluate_option_cache (&ip_addrs, (struct packet *)0,
384                                            (struct lease *)0,
385                                            (struct client_state *)0,
386                                            (struct option_state *)0,
387                                            (struct option_state *)0,
388                                            &global_scope,
389                                            host -> fixed_addr, MDL)) {
390                 
391                         errno = 0;
392                         fprintf (db_file, "\n  fixed-address ");
393                         if (errno)
394                                 ++errors;
395                         for (i = 0; i < ip_addrs.len - 3; i += 4) {
396
397                                 errno = 0;
398                                 fprintf (db_file, "%u.%u.%u.%u%s",
399                                          ip_addrs.data [i] & 0xff,
400                                          ip_addrs.data [i + 1] & 0xff,
401                                          ip_addrs.data [i + 2] & 0xff,
402                                          ip_addrs.data [i + 3] & 0xff,
403                                          i + 7 < ip_addrs.len ? "," : "");
404                                 if (errno)
405                                         ++errors;
406                         }
407
408                         errno = 0;
409                         fputc (';', db_file);
410                         if (errno)
411                                 ++errors;
412                 }
413
414                 if (host -> named_group) {
415                         errno = 0;
416                         fprintf (db_file, "\n  group \"%s\";",
417                                  host -> named_group -> name);
418                         if (errno)
419                                 ++errors;
420                 }
421
422                 if (host -> group &&
423                     (!host -> named_group ||
424                      host -> group != host -> named_group -> group) &&
425                     host -> group != root_group) {
426                         errno = 0;
427                         write_statements (db_file,
428                                           host -> group -> statements, 8);
429                         if (errno)
430                                 ++errors;
431                 }
432         }
433
434         errno = 0;
435         fputs ("\n}\n", db_file);
436         if (errno)
437                 ++errors;
438
439         if (errors) {
440                 log_info ("write_host: unable to write host %s",
441                           host -> name);
442                 lease_file_is_corrupt = 1;
443         }
444
445         return !errors;
446 }
447
448 int write_group (group)
449         struct group_object *group;
450 {
451         int errors = 0;
452
453         /* If the lease file is corrupt, don't try to write any more leases
454            until we've written a good lease file. */
455         if (lease_file_is_corrupt)
456                 if (!new_lease_file ())
457                         return 0;
458
459         if (!db_printable((unsigned char *)group->name))
460                 return 0;
461
462         if (counting)
463                 ++count;
464
465         errno = 0;
466         fprintf (db_file, "group %s {", group -> name);
467         if (errno)
468                 ++errors;
469
470         if (group -> flags & GROUP_OBJECT_DYNAMIC) {
471                 errno = 0;
472                 fprintf (db_file, "\n  dynamic;");
473                 if (errno)
474                         ++errors;
475         }
476
477         if (group -> flags & GROUP_OBJECT_STATIC) {
478                 errno = 0;
479                 fprintf (db_file, "\n  static;");
480                 if (errno)
481                         ++errors;
482         }
483
484         if (group -> flags & GROUP_OBJECT_DELETED) {
485                 errno = 0;
486                 fprintf (db_file, "\n  deleted;");
487                 if (errno)
488                         ++errors;
489         } else {
490                 if (group -> group) {
491                         errno = 0;
492                         write_statements (db_file,
493                                           group -> group -> statements, 8);
494                         if (errno)
495                                 ++errors;
496                 }
497         }
498
499         errno = 0;
500         fputs ("\n}\n", db_file);
501         if (errno)
502                 ++errors;
503
504         if (errors) {
505                 log_info ("write_group: unable to write group %s",
506                           group -> name);
507                 lease_file_is_corrupt = 1;
508         }
509
510         return !errors;
511 }
512
513 /*
514  * Write an IA and the options it has.
515  */
516 int
517 write_ia(const struct ia_xx *ia) {
518         struct iasubopt *iasubopt;
519         struct binding *bnd;
520         int i;
521         char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
522         const char *binding_state;
523         const char *tval;
524         char *s;
525         int fprintf_ret;
526
527         /* 
528          * If the lease file is corrupt, don't try to write any more 
529          * leases until we've written a good lease file. 
530          */
531         if (lease_file_is_corrupt) {
532                 if (!new_lease_file()) {
533                         return 0;
534                 }
535         }
536
537         if (counting) {
538                 ++count;
539         }
540
541         
542         s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL);
543         if (s == NULL) {
544                 goto error_exit;
545         }
546         switch (ia->ia_type) {
547         case D6O_IA_NA:
548                 fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s);
549                 break;
550         case D6O_IA_TA:
551                 fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s);
552                 break;
553         case D6O_IA_PD:
554                 fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s);
555                 break;
556         default:
557                 log_error("Unknown ia type %u for \"%s\" at %s:%d",
558                           (unsigned)ia->ia_type, s, MDL);
559                 fprintf_ret = -1;
560         }
561         dfree(s, MDL);
562         if (fprintf_ret < 0) {
563                 goto error_exit;
564         }
565         if (ia->cltt != MIN_TIME) {
566                 tval = print_time(ia->cltt);
567                 if (tval == NULL) {
568                         goto error_exit;
569                 }
570                 if (fprintf(db_file, "  cltt %s\n", tval) < 0) {
571                         goto error_exit;
572                 }
573         }
574         for (i=0; i<ia->num_iasubopt; i++) {
575                 iasubopt = ia->iasubopt[i];
576
577                 inet_ntop(AF_INET6, &iasubopt->addr,
578                           addr_buf, sizeof(addr_buf));
579                 if ((ia->ia_type != D6O_IA_PD) &&
580                     (fprintf(db_file, "  iaaddr %s {\n", addr_buf) < 0)) {
581                         goto error_exit;
582                 }
583                 if ((ia->ia_type == D6O_IA_PD) &&
584                     (fprintf(db_file, "  iaprefix %s/%d {\n",
585                              addr_buf, (int)iasubopt->plen) < 0)) {
586                         goto error_exit;
587                 }
588                 if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) {
589                         log_fatal("Unknown iasubopt state %d at %s:%d", 
590                                   iasubopt->state, MDL);
591                 }
592                 binding_state = binding_state_names[iasubopt->state-1];
593                 if (fprintf(db_file, "    binding state %s;\n", 
594                             binding_state) < 0) {
595                         goto error_exit;
596                 }
597                 if (fprintf(db_file, "    preferred-life %u;\n",
598                             (unsigned)iasubopt->prefer) < 0) {
599                         goto error_exit;
600                 }
601                 if (fprintf(db_file, "    max-life %u;\n",
602                             (unsigned)iasubopt->valid) < 0) {
603                         goto error_exit;
604                 }
605
606                 /* Note that from here on out, the \n is prepended to the
607                  * next write, rather than appended to the current write.
608                  */
609                 if ((iasubopt->state == FTS_ACTIVE) ||
610                     (iasubopt->state == FTS_ABANDONED) ||
611                     (iasubopt->hard_lifetime_end_time != 0)) {
612                         tval = print_time(iasubopt->hard_lifetime_end_time);
613                 } else {
614                         tval = print_time(iasubopt->soft_lifetime_end_time);
615                 }
616                 if (tval == NULL) {
617                         goto error_exit;
618                 }
619                 if (fprintf(db_file, "    ends %s", tval) < 0) {
620                         goto error_exit;
621                 }
622
623                 /* Write out any binding scopes: note that 'ends' above does
624                  * not have \n on the end!  We want that.
625                  */
626                 if (iasubopt->scope != NULL)
627                         bnd = iasubopt->scope->bindings;
628                 else
629                         bnd = NULL;
630
631                 for (; bnd != NULL ; bnd = bnd->next) {
632                         if (bnd->value == NULL)
633                                 continue;
634
635                         /* We don't do a regular error_exit because the
636                          * lease db is not corrupt in this case.
637                          */
638                         if (write_binding_scope(db_file, bnd,
639                                                 "\n    ") != ISC_R_SUCCESS)
640                                 goto error_exit;
641                                 
642                 }
643
644                 if (fprintf(db_file, "\n  }\n") < 0)
645                         goto error_exit;
646         }
647         if (fprintf(db_file, "}\n\n") < 0)
648                 goto error_exit;
649
650         fflush(db_file);
651         return 1;
652
653 error_exit:
654         log_info("write_ia: unable to write ia");
655         lease_file_is_corrupt = 1;
656         return 0;
657 }
658
659 #ifdef DHCPv6
660 /*
661  * Put a copy of the server DUID in the leases file.
662  */
663 int
664 write_server_duid(void) {
665         struct data_string server_duid;
666         char *s;
667         int fprintf_ret;
668
669         /*
670          * Only write the DUID if it's been set.
671          */
672         if (!server_duid_isset()) {
673                 return 1;
674         }
675
676         /* 
677          * If the lease file is corrupt, don't try to write any more 
678          * leases until we've written a good lease file. 
679          */
680         if (lease_file_is_corrupt) {
681                 if (!new_lease_file()) {
682                         return 0;
683                 }
684         }
685
686         /*
687          * Get a copy of our server DUID and convert to a quoted string.
688          */
689         memset(&server_duid, 0, sizeof(server_duid));
690         copy_server_duid(&server_duid, MDL);
691         s = quotify_buf(server_duid.data, server_duid.len, MDL);
692         data_string_forget(&server_duid, MDL);
693         if (s == NULL) {
694                 goto error_exit;
695         }
696
697         /*
698          * Write to the leases file.
699          */
700         fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s);
701         dfree(s, MDL);
702         if (fprintf_ret < 0) {
703                 goto error_exit;
704         }
705
706         /*
707          * Check if we actually managed to write.
708          */
709         fflush(db_file);
710         return 1;
711
712 error_exit:
713         log_info("write_server_duid: unable to write server-duid");
714         lease_file_is_corrupt = 1;
715         return 0;
716 }
717 #endif /* DHCPv6 */
718
719 #if defined (FAILOVER_PROTOCOL)
720 int write_failover_state (dhcp_failover_state_t *state)
721 {
722         int errors = 0;
723         const char *tval;
724
725         if (lease_file_is_corrupt)
726                 if (!new_lease_file ())
727                         return 0;
728
729         errno = 0;
730         fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
731         if (errno)
732                 ++errors;
733
734         tval = print_time(state->me.stos);
735         if (tval == NULL ||
736             fprintf(db_file, "\n  my state %s at %s",
737                     (state->me.state == startup) ?
738                     dhcp_failover_state_name_print(state->saved_state) :
739                     dhcp_failover_state_name_print(state->me.state),
740                     tval) < 0)
741                 ++errors;
742
743         tval = print_time(state->partner.stos);
744         if (tval == NULL ||
745             fprintf(db_file, "\n  partner state %s at %s",
746                     dhcp_failover_state_name_print(state->partner.state),
747                     tval) < 0)
748                 ++errors;
749
750         if (state -> i_am == secondary) {
751                 errno = 0;
752                 fprintf (db_file, "\n  mclt %ld;",
753                          (unsigned long)state -> mclt);
754                 if (errno)
755                         ++errors;
756         }
757
758         errno = 0;
759         fprintf (db_file, "\n}\n");
760         if (errno)
761                 ++errors;
762
763         if (errors) {
764                 log_info ("write_failover_state: unable to write state %s",
765                           state -> name);
766                 lease_file_is_corrupt = 1;
767                 return 0;
768         }
769
770         return 1;
771
772 }
773 #endif
774
775 int db_printable (s)
776         const unsigned char *s;
777 {
778         int i;
779         for (i = 0; s [i]; i++)
780                 if (!isascii (s [i]) || !isprint (s [i])
781                     || s [i] == '"' || s [i] == '\\')
782                         return 0;
783         return 1;
784 }
785
786 int db_printable_len (s, len)
787         const unsigned char *s;
788         unsigned len;
789 {
790         int i;
791
792         for (i = 0; i < len; i++)
793                 if (!isascii (s [i]) || !isprint (s [i]) ||
794                     s [i] == '"' || s [i] == '\\')
795                         return 0;
796         return 1;
797 }
798
799 static int print_hash_string(FILE *fp, struct class *class)
800 {
801         int i;
802
803         for (i = 0 ; i < class->hash_string.len ; i++)
804                 if (!isascii(class->hash_string.data[i]) ||
805                     !isprint(class->hash_string.data[i]))
806                         break;
807
808         if (i == class->hash_string.len) {
809                 if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
810                             class->hash_string.data) <= 0) {
811                         log_error("Failure writing hash string: %m");
812                         return 0;
813                 }
814         } else {
815                 if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
816                         log_error("Failure writing hash string: %m");
817                         return 0;
818                 }
819                 for (i = 1 ; i < class->hash_string.len ; i++) {
820                         if (fprintf(fp, ":%2.2x",
821                                     class->hash_string.data[i]) <= 0) {
822                                 log_error("Failure writing hash string: %m");
823                                 return 0;
824                         }
825                 }
826         }
827
828         return 1;
829 }
830
831
832 isc_result_t
833 write_named_billing_class(const void *key, unsigned len, void *object)
834 {
835         const unsigned char *name = key;
836         struct class *class = object;
837
838         if (class->flags & CLASS_DECL_DYNAMIC) {
839                 numclasseswritten++;
840                 if (class->superclass == 0) {
841                         if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
842                                 return ISC_R_IOERROR;
843                 } else {
844                         if (fprintf(db_file, "subclass \"%s\"",
845                                     class->superclass->name) <= 0)
846                                 return ISC_R_IOERROR;
847                         if (!print_hash_string(db_file, class))
848                                 return ISC_R_IOERROR;
849                         if (fprintf(db_file, " {\n") <= 0)
850                                 return ISC_R_IOERROR;
851                 }
852
853                 if ((class->flags & CLASS_DECL_DELETED) != 0) {
854                         if (fprintf(db_file, "  deleted;\n") <= 0)
855                                 return ISC_R_IOERROR;
856                 } else {
857                         if (fprintf(db_file, "  dynamic;\n") <= 0)
858                                 return ISC_R_IOERROR;
859                 }
860         
861                 if (class->lease_limit > 0) {
862                         if (fprintf(db_file, "  lease limit %d;\n",
863                                     class->lease_limit) <= 0)
864                                 return ISC_R_IOERROR;
865                 }
866
867                 if (class->expr != 0) {
868                         if (fprintf(db_file, "  match if ") <= 0)
869                                 return ISC_R_IOERROR;
870
871                         errno = 0;                                       
872                         write_expression(db_file, class->expr, 5, 5, 0);
873                         if (errno)
874                                 return ISC_R_IOERROR;
875
876                         if (fprintf(db_file, ";\n") <= 0)
877                                 return ISC_R_IOERROR;
878                 }
879
880                 if (class->submatch != 0) {
881                         if (class->spawning) {
882                                 if (fprintf(db_file, "  spawn ") <= 0)
883                                         return ISC_R_IOERROR;
884                         } else {
885                                 if (fprintf(db_file, "  match ") <= 0)
886                                         return ISC_R_IOERROR;
887                         }
888
889                         errno = 0;
890                         write_expression(db_file, class->submatch, 5, 5, 0);
891                         if (errno)
892                                 return ISC_R_IOERROR;
893
894                         if (fprintf(db_file, ";\n") <= 0)
895                                 return ISC_R_IOERROR;
896                 }
897         
898                 if (class->statements != 0) {
899                         errno = 0;
900                         write_statements(db_file, class->statements, 8);
901                         if (errno)
902                                 return ISC_R_IOERROR;
903                 }
904
905                 /* XXXJAB this isn't right, but classes read in off the
906                    leases file don't get the root group assigned to them
907                    (due to clone_group() call). */
908                 if (class->group != 0 && class->group->authoritative != 0) {
909                         errno = 0;
910                         write_statements(db_file, class->group->statements, 8);
911                         if (errno)
912                                 return ISC_R_IOERROR;
913                 }
914
915                 if (fprintf(db_file, "}\n\n") <= 0)
916                         return ISC_R_IOERROR;
917         }
918
919         if (class->hash != NULL) {      /* yep. recursive. god help us. */
920                 /* XXX - cannot check error status of this...
921                  * foo_hash_foreach returns a count of operations completed.
922                  */
923                 class_hash_foreach(class->hash, write_named_billing_class);
924         }
925
926         return ISC_R_SUCCESS;
927 }
928
929 void write_billing_classes ()
930 {
931         struct collection *lp;
932         struct class *cp;
933
934         for (lp = collections; lp; lp = lp -> next) {
935             for (cp = lp -> classes; cp; cp = cp -> nic) {
936                 if (cp -> spawning && cp -> hash) {
937                     class_hash_foreach (cp -> hash, write_named_billing_class);
938                 }
939             }
940         }
941 }
942
943 /* Write a spawned class to the database file. */
944
945 int write_billing_class (class)
946         struct class *class;
947 {
948         int errors = 0;
949
950         if (lease_file_is_corrupt)
951                 if (!new_lease_file ())
952                         return 0;
953
954         if (!class -> superclass) {
955                 errno = 0;
956                 fprintf (db_file, "\n  billing class \"%s\";", class -> name);
957                 return !errno;
958         }
959
960         if (fprintf(db_file, "\n  billing subclass \"%s\"",
961                     class -> superclass -> name) < 0)
962                 ++errors;
963
964         if (!print_hash_string(db_file, class))
965                 ++errors;
966
967         if (fprintf(db_file, ";") < 0)
968                 ++errors;
969
970         class -> dirty = !errors;
971         if (errors)
972                 lease_file_is_corrupt = 1;
973
974         return !errors;
975 }
976
977 /* Commit leases after a timeout. */
978 void commit_leases_timeout (void *foo)
979 {
980         commit_leases ();
981 }
982
983 /* Commit any leases that have been written out... */
984
985 int commit_leases ()
986 {
987         /* Commit any outstanding writes to the lease database file.
988            We need to do this even if we're rewriting the file below,
989            just in case the rewrite fails. */
990         if (fflush (db_file) == EOF) {
991                 log_info ("commit_leases: unable to commit: %m");
992                 return 0;
993         }
994         if (fsync (fileno (db_file)) < 0) {
995                 log_info ("commit_leases: unable to commit: %m");
996                 return 0;
997         }
998
999         /* send out all deferred ACKs now */
1000         flush_ackqueue(NULL);
1001
1002         /* If we haven't rewritten the lease database in over an
1003            hour, rewrite it now.  (The length of time should probably
1004            be configurable. */
1005         if (count && cur_time - write_time > 3600) {
1006                 count = 0;
1007                 write_time = cur_time;
1008                 new_lease_file ();
1009         }
1010         return 1;
1011 }
1012
1013 void db_startup (testp)
1014         int testp;
1015 {
1016         isc_result_t status;
1017
1018 #if defined (TRACING)
1019         if (!trace_playback ()) {
1020 #endif
1021                 /* Read in the existing lease file... */
1022                 status = read_conf_file (path_dhcpd_db,
1023                                          (struct group *)0, 0, 1);
1024                 /* XXX ignore status? */
1025 #if defined (TRACING)
1026         }
1027 #endif
1028
1029 #if defined (TRACING)
1030         /* If we're playing back, there is no lease file, so we can't
1031            append it, so we create one immediately (maybe this isn't
1032            the best solution... */
1033         if (trace_playback ()) {
1034                 new_lease_file ();
1035         }
1036 #endif
1037         if (!testp) {
1038                 db_file = fopen (path_dhcpd_db, "a");
1039                 if (!db_file)
1040                         log_fatal ("Can't open %s for append.", path_dhcpd_db);
1041                 expire_all_pools ();
1042 #if defined (TRACING)
1043                 if (trace_playback ())
1044                         write_time = cur_time;
1045                 else
1046 #endif
1047                         time(&write_time);
1048                 new_lease_file ();
1049         }
1050
1051 #if defined(REPORT_HASH_PERFORMANCE)
1052         log_info("Host HW hash:   %s", host_hash_report(host_hw_addr_hash));
1053         log_info("Host UID hash:  %s", host_hash_report(host_uid_hash));
1054         log_info("Lease IP hash:  %s",
1055                  lease_ip_hash_report(lease_ip_addr_hash));
1056         log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
1057         log_info("Lease HW hash:  %s",
1058                  lease_id_hash_report(lease_hw_addr_hash));
1059 #endif
1060 }
1061
1062 int new_lease_file ()
1063 {
1064         char newfname [512];
1065         char backfname [512];
1066         TIME t;
1067         int db_fd;
1068         int db_validity;
1069         FILE *new_db_file;
1070
1071         /* Make a temporary lease file... */
1072         time(&t);
1073
1074         db_validity = lease_file_is_corrupt;
1075
1076         /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
1077          * This should never happen since the path is a configuration
1078          * variable from build-time or command-line.  But if it should,
1079          * either by malice or ignorance, we panic, since the potential
1080          * for havoc is high.
1081          */
1082         if (snprintf (newfname, sizeof newfname, "%s.%d",
1083                      path_dhcpd_db, (int)t) >= sizeof newfname)
1084                 log_fatal("new_lease_file: lease file path too long");
1085
1086         db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
1087         if (db_fd < 0) {
1088                 log_error ("Can't create new lease file: %m");
1089                 return 0;
1090         }
1091         if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
1092                 log_error("Can't fdopen new lease file: %m");
1093                 close(db_fd);
1094                 goto fdfail;
1095         }
1096
1097         /* Close previous database, if any. */
1098         if (db_file)
1099                 fclose(db_file);
1100         db_file = new_db_file;
1101
1102         errno = 0;
1103         fprintf (db_file, "# The format of this file is documented in the %s",
1104                  "dhcpd.leases(5) manual page.\n");
1105         if (errno)
1106                 goto fail;
1107
1108         fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
1109                  PACKAGE_VERSION);
1110         if (errno)
1111                 goto fail;
1112
1113         /* At this point we have a new lease file that, so far, could not
1114          * be described as either corrupt nor valid.
1115          */
1116         lease_file_is_corrupt = 0;
1117
1118         /* Write out all the leases that we know of... */
1119         counting = 0;
1120         if (!write_leases ())
1121                 goto fail;
1122
1123 #if defined (TRACING)
1124         if (!trace_playback ()) {
1125 #endif
1126             /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
1127              * This should never happen since the path is a configuration
1128              * variable from build-time or command-line.  But if it should,
1129              * either by malice or ignorance, we panic, since the potential
1130              * for havoc is too high.
1131              */
1132             if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
1133                         >= sizeof backfname)
1134                 log_fatal("new_lease_file: backup lease file path too long");
1135
1136             /* Get the old database out of the way... */
1137             if (unlink (backfname) < 0 && errno != ENOENT) {
1138                 log_error ("Can't remove old lease database backup %s: %m",
1139                            backfname);
1140                 goto fail;
1141             }
1142             if (link(path_dhcpd_db, backfname) < 0) {
1143                 if (errno == ENOENT) {
1144                         log_error("%s is missing - no lease db to backup.",
1145                                   path_dhcpd_db);
1146                 } else {
1147                         log_error("Can't backup lease database %s to %s: %m",
1148                                   path_dhcpd_db, backfname);
1149                         goto fail;
1150                 }
1151             }
1152 #if defined (TRACING)
1153         }
1154 #endif
1155         
1156         /* Move in the new file... */
1157         if (rename (newfname, path_dhcpd_db) < 0) {
1158                 log_error ("Can't install new lease database %s to %s: %m",
1159                            newfname, path_dhcpd_db);
1160                 goto fail;
1161         }
1162
1163         counting = 1;
1164         return 1;
1165
1166       fail:
1167         lease_file_is_corrupt = db_validity;
1168       fdfail:
1169         unlink (newfname);
1170         return 0;
1171 }
1172
1173 int group_writer (struct group_object *group)
1174 {
1175         if (!write_group (group))
1176                 return 0;
1177         if (!commit_leases ())
1178                 return 0;
1179         return 1;
1180 }