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