xref: /netbsd/external/mpl/dhcp/dist/server/db.c (revision 13df4856)
1 /*	$NetBSD: db.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2 
3 /* db.c
4 
5    Persistent database management routines for DHCPD... */
6 
7 /*
8  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1995-2003 by Internet Software Consortium
10  *
11  * This Source Code Form is subject to the terms of the Mozilla Public
12  * License, v. 2.0. If a copy of the MPL was not distributed with this
13  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   PO Box 360
25  *   Newmarket, NH 03857 USA
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: db.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
33 
34 #include "dhcpd.h"
35 #include <ctype.h>
36 #include <errno.h>
37 
38 #define LEASE_REWRITE_PERIOD 3600
39 
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
write_binding_scope(FILE * db_file,struct binding * bnd,char * prepend)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 
write_lease(lease)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 
write_host(host)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 
write_group(group)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
write_ia(const struct ia_xx * ia)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
write_server_duid(void)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)
write_failover_state(dhcp_failover_state_t * state)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 
db_printable(s)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 
db_printable_len(s,len)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 
print_hash_string(FILE * fp,struct class * class)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
write_named_billing_class(const void * key,unsigned len,void * object)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 
write_billing_classes()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 
write_billing_class(class)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. */
commit_leases_timeout(void * foo)1029 void commit_leases_timeout (void *foo)
1030 {
1031 	commit_leases ();
1032 }
1033 
1034 /* Commit any leases that have been written out... */
1035 
commit_leases()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  */
commit_leases_timed()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 
db_startup(int test_mode)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 
new_lease_file(int test_mode)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 
group_writer(struct group_object * group)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