xref: /netbsd/external/mpl/dhcp/dist/server/mdb.c (revision 13df4856)
1 /*	$NetBSD: mdb.c,v 1.4 2022/04/03 01:10:59 christos Exp $	*/
2 
3 /* mdb.c
4 
5    Server-specific in-memory database support. */
6 
7 /*
8  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1996-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: mdb.c,v 1.4 2022/04/03 01:10:59 christos Exp $");
33 
34 #include "dhcpd.h"
35 #include "omapip/hash.h"
36 
37 struct subnet *subnets;
38 struct shared_network *shared_networks;
39 host_hash_t *host_hw_addr_hash;
40 host_hash_t *host_uid_hash;
41 host_hash_t *host_name_hash;
42 lease_id_hash_t *lease_uid_hash;
43 lease_ip_hash_t *lease_ip_addr_hash;
44 lease_id_hash_t *lease_hw_addr_hash;
45 
46 /*
47  * We allow users to specify any option as a host identifier.
48  *
49  * Any host is uniquely identified by the combination of
50  * option type & option data.
51  *
52  * We expect people will only use a few types of options as host
53  * identifier. Because of this, we store a list with an entry for
54  * each option type. Each of these has a hash table, which contains
55  * hash of the option data.
56  *
57  * For v6 we also include a relay count - this specifies which
58  * relay to check for the requested option.  As each different
59  * value of relays creates a new instance admins should use the
60  * same value across each option for all host-identifers.
61  * A value of 0 indicates that we aren't doing relay options
62  * and should simply look in the current option list.
63  */
64 typedef struct host_id_info {
65 	struct option *option;
66 	host_hash_t *values_hash;
67 	int relays;
68 	struct host_id_info *next;
69 } host_id_info_t;
70 
71 static host_id_info_t *host_id_info = NULL;
72 
73 int numclasseswritten;
74 
75 extern omapi_object_type_t *dhcp_type_host;
76 
enter_class(cd,dynamicp,commit)77 isc_result_t enter_class(cd, dynamicp, commit)
78 	struct class *cd;
79 	int dynamicp;
80 	int commit;
81 {
82 	if (!collections -> classes) {
83 		/* A subclass with no parent is invalid. */
84 		if (cd->name == NULL)
85 			return DHCP_R_INVALIDARG;
86 
87 		class_reference (&collections -> classes, cd, MDL);
88 	} else if (cd->name != NULL) {	/* regular class */
89 		struct class *c = 0;
90 
91 		if (find_class(&c, cd->name, MDL) != ISC_R_NOTFOUND) {
92 			class_dereference(&c, MDL);
93 			return ISC_R_EXISTS;
94 		}
95 
96 		/* Find the tail. */
97 		for (c = collections -> classes;
98 		     c -> nic; c = c -> nic)
99 			/* nothing */ ;
100 		class_reference (&c -> nic, cd, MDL);
101 	}
102 
103 	if (dynamicp && commit) {
104 		const char *name = cd->name;
105 
106 		if (name == NULL) {
107 			name = cd->superclass->name;
108 		}
109 
110 		write_named_billing_class ((const unsigned char *)name, 0, cd);
111 		if (!commit_leases ())
112 			return ISC_R_IOERROR;
113 	}
114 
115 	return ISC_R_SUCCESS;
116 }
117 
118 
119 /* Variable to check if we're starting the server.  The server will init as
120  * starting - but just to be safe start out as false to avoid triggering new
121  * special-case code
122  * XXX: There is actually a server_startup state...which is never entered...
123  */
124 #define SS_NOSYNC	1
125 #define SS_QFOLLOW	2
126 static int server_starting = 0;
127 
find_uid_statement(struct executable_statement * esp,void * vp,int condp)128 static int find_uid_statement (struct executable_statement *esp,
129 			       void *vp, int condp)
130 {
131 	struct executable_statement **evp = vp;
132 
133 	if (esp -> op == supersede_option_statement &&
134 	    esp -> data.option &&
135 	    (esp -> data.option -> option -> universe ==
136 	     &dhcp_universe) &&
137 	    (esp -> data.option -> option -> code ==
138 	     DHO_DHCP_CLIENT_IDENTIFIER)) {
139 		if (condp) {
140 			log_error ("dhcp client identifier may not be %s",
141 				   "specified conditionally.");
142 		} else if (!(*evp)) {
143 			executable_statement_reference (evp, esp, MDL);
144 			return 1;
145 		} else {
146 			log_error ("only one dhcp client identifier may be %s",
147 				   "specified");
148 		}
149 	}
150 	return 0;
151 }
152 
153 
154 static host_id_info_t *
find_host_id_info(unsigned int option_code,int relays)155 find_host_id_info(unsigned int option_code, int relays) {
156 	host_id_info_t *p;
157 
158 	for (p = host_id_info; p != NULL; p = p->next) {
159 		if ((p->option->code == option_code) &&
160 		    (p->relays == relays)) {
161 			break;
162 		}
163 	}
164 	return p;
165 }
166 
167 /* Debugging code */
168 #if 0
169 isc_result_t
170 print_host(const void *name, unsigned len, void *value) {
171 	struct host_decl *h;
172 	printf("--------------\n");
173 	printf("name:'%s'\n", print_hex_1(len, name, 60));
174 	printf("len:%d\n", len);
175 	h = (struct host_decl *)value;
176 	printf("host @%p is '%s'\n", h, h->name);
177 	return ISC_R_SUCCESS;
178 }
179 
180 void
181 hash_print_hosts(struct hash_table *h) {
182 	hash_foreach(h, print_host);
183 	printf("--------------\n");
184 }
185 #endif /* 0 */
186 
187 void
change_host_uid(struct host_decl * host,const char * uid,int len)188 change_host_uid(struct host_decl *host, const char *uid, int len) {
189 	/* XXX: should consolidate this type of code throughout */
190 	if (host_uid_hash == NULL) {
191 		if (!host_new_hash(&host_uid_hash, HOST_HASH_SIZE, MDL)) {
192 			log_fatal("Can't allocate host/uid hash");
193 		}
194 	}
195 
196 	/*
197 	 * Remove the old entry, if one exists.
198 	 */
199 	if (host->client_identifier.data != NULL) {
200 		host_hash_delete(host_uid_hash,
201 				 host->client_identifier.data,
202 				 host->client_identifier.len,
203 				 MDL);
204 		data_string_forget(&host->client_identifier, MDL);
205 	}
206 
207 	/*
208 	 * Set our new value.
209 	 */
210 	memset(&host->client_identifier, 0, sizeof(host->client_identifier));
211 	host->client_identifier.len = len;
212 	if (!buffer_allocate(&host->client_identifier.buffer, len, MDL)) {
213 		log_fatal("Can't allocate uid buffer");
214 	}
215 	host->client_identifier.data = host->client_identifier.buffer->data;
216 	memcpy((char *)host->client_identifier.data, uid, len);
217 
218 	/*
219 	 * And add to hash.
220 	 */
221 	host_hash_add(host_uid_hash, host->client_identifier.data,
222 		      host->client_identifier.len, host, MDL);
223 }
224 
enter_host(hd,dynamicp,commit)225 isc_result_t enter_host (hd, dynamicp, commit)
226 	struct host_decl *hd;
227 	int dynamicp;
228 	int commit;
229 {
230 	struct host_decl *hp = (struct host_decl *)0;
231 	struct host_decl *np = (struct host_decl *)0;
232 	struct executable_statement *esp;
233 	host_id_info_t *h_id_info;
234 
235 	if (!host_name_hash) {
236 		if (!host_new_hash(&host_name_hash, HOST_HASH_SIZE, MDL))
237 			log_fatal ("Can't allocate host name hash");
238 		host_hash_add (host_name_hash,
239 			       (unsigned char *)hd -> name,
240 			       strlen (hd -> name), hd, MDL);
241 	} else {
242 		host_hash_lookup (&hp, host_name_hash,
243 				  (unsigned char *)hd -> name,
244 				  strlen (hd -> name), MDL);
245 
246 		/* If it's deleted, we can supersede it. */
247 		if (hp && (hp -> flags & HOST_DECL_DELETED)) {
248 			host_hash_delete (host_name_hash,
249 					  (unsigned char *)hd -> name,
250 					  strlen (hd -> name), MDL);
251 			/* If the old entry wasn't dynamic, then we
252 			   always have to keep the deletion. */
253 			if (hp -> flags & HOST_DECL_STATIC) {
254 				hd -> flags |= HOST_DECL_STATIC;
255 			}
256 			host_dereference (&hp, MDL);
257 		}
258 
259 		/* If we are updating an existing host declaration, we
260 		   can just delete it and add it again. */
261 		if (hp && hp == hd) {
262 			host_dereference (&hp, MDL);
263 			delete_host (hd, 0);
264 			if (!write_host (hd))
265 				return ISC_R_IOERROR;
266 			hd -> flags &= ~HOST_DECL_DELETED;
267 		}
268 
269 		/* If there isn't already a host decl matching this
270 		   address, add it to the hash table. */
271 		if (!hp) {
272 			host_hash_add (host_name_hash,
273 				       (unsigned char *)hd -> name,
274 				       strlen (hd -> name), hd, MDL);
275 		} else {
276 			/* XXX actually, we have to delete the old one
277 			   XXX carefully and replace it.   Not done yet. */
278 			host_dereference (&hp, MDL);
279 			return ISC_R_EXISTS;
280 		}
281 	}
282 
283 	if (hd -> n_ipaddr)
284 		host_dereference (&hd -> n_ipaddr, MDL);
285 
286 	if (!hd -> type)
287 		hd -> type = dhcp_type_host;
288 
289 	if (hd -> interface.hlen) {
290 		if (!host_hw_addr_hash) {
291 			if (!host_new_hash(&host_hw_addr_hash,
292 					   HOST_HASH_SIZE, MDL))
293 				log_fatal ("Can't allocate host/hw hash");
294 		} else {
295 			/* If there isn't already a host decl matching this
296 			   address, add it to the hash table. */
297 			host_hash_lookup (&hp, host_hw_addr_hash,
298 					  hd -> interface.hbuf,
299 					  hd -> interface.hlen, MDL);
300 		}
301 		if (!hp)
302 			host_hash_add (host_hw_addr_hash, hd -> interface.hbuf,
303 				       hd -> interface.hlen, hd, MDL);
304 		else {
305 			/* If there was already a host declaration for
306 			   this hardware address, add this one to the
307 			   end of the list. */
308 			for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr)
309 				;
310 			host_reference (&np -> n_ipaddr, hd, MDL);
311 			host_dereference (&hp, MDL);
312 		}
313 	}
314 
315 	/* See if there's a statement that sets the client identifier.
316 	   This is a kludge - the client identifier really shouldn't be
317 	   set with an executable statement. */
318 	esp = NULL;
319 	if (executable_statement_foreach (hd->group->statements,
320 					  find_uid_statement, &esp, 0)) {
321 		struct data_string cid;
322 		memset(&cid, 0, sizeof(cid));
323 		(void) evaluate_option_cache (&cid,
324 					      NULL, NULL, NULL, NULL, NULL,
325 					      &global_scope,
326 					      esp->data.option, MDL);
327 
328 		if (hd->client_identifier.len > 0 && cid.len > 0) {
329 			char uid_buf[256];
330 			char cid_buf[256];
331 			print_hex_or_string(hd->client_identifier.len,
332 					    hd->client_identifier.data,
333 					    sizeof(uid_buf) - 1, uid_buf);
334 
335 			print_hex_or_string(cid.len, cid.data,
336 					    sizeof(cid_buf) - 1, cid_buf);
337 
338 			log_error ("Warning, host declaration '%s'"
339 				   " already has uid '%s',"
340 				   " ignoring dhcp-client-identifier '%s'",
341 				   hd->name, uid_buf, cid_buf);
342 
343 			data_string_forget(&cid, MDL);
344 		} else {
345 			memcpy(&hd->client_identifier, &cid, sizeof(cid));
346 		}
347 	}
348 
349 	/* If we got a client identifier, hash this entry by
350 	   client identifier. */
351 	if (hd -> client_identifier.len) {
352 		/* If there's no uid hash, make one; otherwise, see if
353 		   there's already an entry in the hash for this host. */
354 		if (!host_uid_hash) {
355 			if (!host_new_hash(&host_uid_hash,
356 					   HOST_HASH_SIZE, MDL))
357 				log_fatal ("Can't allocate host/uid hash");
358 
359 			host_hash_add (host_uid_hash,
360 				       hd -> client_identifier.data,
361 				       hd -> client_identifier.len,
362 				       hd, MDL);
363 		} else {
364 			/* If there's already a host declaration for this
365 			   client identifier, add this one to the end of the
366 			   list.  Otherwise, add it to the hash table. */
367 			if (host_hash_lookup (&hp, host_uid_hash,
368 					      hd -> client_identifier.data,
369 					      hd -> client_identifier.len,
370 					      MDL)) {
371 				/* Don't link it in twice... */
372 				if (!np) {
373 					for (np = hp; np -> n_ipaddr;
374 					     np = np -> n_ipaddr) {
375 						if (hd == np)
376 						    break;
377 					}
378 					if (hd != np)
379 					    host_reference (&np -> n_ipaddr,
380 							    hd, MDL);
381 				}
382 				host_dereference (&hp, MDL);
383 			} else {
384 				host_hash_add (host_uid_hash,
385 					       hd -> client_identifier.data,
386 					       hd -> client_identifier.len,
387 					       hd, MDL);
388 			}
389 		}
390 	}
391 
392 
393 	/*
394 	 * If we use an option as our host identifier, record it here.
395 	 */
396 	if (hd->host_id_option != NULL) {
397 		/*
398 		 * Look for the host identifier information for this option,
399 		 * and create a new entry if there is none.
400 		 */
401 		h_id_info = find_host_id_info(hd->host_id_option->code,
402 					      hd->relays);
403 		if (h_id_info == NULL) {
404 			h_id_info = dmalloc(sizeof(*h_id_info), MDL);
405 			if (h_id_info == NULL) {
406 				log_fatal("No memory for host-identifier "
407 					  "option information.");
408 			}
409 			option_reference(&h_id_info->option,
410 					 hd->host_id_option, MDL);
411 			if (!host_new_hash(&h_id_info->values_hash,
412 					   HOST_HASH_SIZE, MDL)) {
413 				log_fatal("No memory for host-identifier "
414 					  "option hash.");
415 			}
416 			h_id_info->relays = hd->relays;
417 			h_id_info->next = host_id_info;
418 			host_id_info = h_id_info;
419 		}
420 
421 		if (host_hash_lookup(&hp, h_id_info->values_hash,
422 				     hd->host_id.data, hd->host_id.len, MDL)) {
423 			/*
424 			 * If this option is already present, then add
425 			 * this host to the list in n_ipaddr, unless
426 			 * we have already done so previously.
427 			 *
428 			 * XXXSK: This seems scary to me, but I don't
429 			 *        fully understand how these are used.
430 			 *        Shouldn't there be multiple lists, or
431 			 *        maybe we should just forbid duplicates?
432 			 */
433 			if (np == NULL) {
434 				np = hp;
435 				while (np->n_ipaddr != NULL) {
436 					np = np->n_ipaddr;
437 				}
438 				if (hd != np) {
439 					host_reference(&np->n_ipaddr, hd, MDL);
440 				}
441 			}
442 			host_dereference(&hp, MDL);
443 		} else {
444 			host_hash_add(h_id_info->values_hash,
445 				      hd->host_id.data,
446 				      hd->host_id.len,
447 				      hd, MDL);
448 		}
449 	}
450 
451 	if (dynamicp && commit) {
452 		if (!write_host (hd))
453 			return ISC_R_IOERROR;
454 		if (!commit_leases ())
455 			return ISC_R_IOERROR;
456 	}
457 
458 	return ISC_R_SUCCESS;
459 }
460 
461 
delete_class(cp,commit)462 isc_result_t delete_class (cp, commit)
463 	struct class *cp;
464 	int commit;
465 {
466 	cp->flags |= CLASS_DECL_DELETED;
467 
468 	/* do the write first as we won't be leaving it in any data
469 	   structures, unlike the host objects */
470 
471 	if (commit) {
472 		write_named_billing_class ((unsigned char *)cp->name, 0, cp);
473 		if (!commit_leases ())
474 			return ISC_R_IOERROR;
475 	}
476 
477 	/*
478 	 * If this is a subclass remove it from the class's hash table
479 	 */
480 	if (cp->superclass) {
481 		class_hash_delete(cp->superclass->hash,
482 				  (const char *)cp->hash_string.data,
483 				  cp->hash_string.len,
484 				  MDL);
485 	}
486 
487 	/* remove from collections */
488 	unlink_class(&cp);
489 
490 	return ISC_R_SUCCESS;
491 }
492 
493 
delete_host(hd,commit)494 isc_result_t delete_host (hd, commit)
495 	struct host_decl *hd;
496 	int commit;
497 {
498 	struct host_decl *hp = (struct host_decl *)0;
499 	struct host_decl *np = (struct host_decl *)0;
500 	struct host_decl *foo;
501 	int hw_head = 0, uid_head = 1;
502 
503 	/* Don't need to do it twice. */
504 	if (hd -> flags & HOST_DECL_DELETED)
505 		return ISC_R_SUCCESS;
506 
507 	/* But we do need to do it once!   :') */
508 	hd -> flags |= HOST_DECL_DELETED;
509 
510 	if (hd -> interface.hlen) {
511 	    if (host_hw_addr_hash) {
512 		if (host_hash_lookup (&hp, host_hw_addr_hash,
513 				      hd -> interface.hbuf,
514 				      hd -> interface.hlen, MDL)) {
515 		    if (hp == hd) {
516 			host_hash_delete (host_hw_addr_hash,
517 					  hd -> interface.hbuf,
518 					  hd -> interface.hlen, MDL);
519 			hw_head = 1;
520 		    } else {
521 			np = (struct host_decl *)0;
522 			foo = (struct host_decl *)0;
523 			host_reference (&foo, hp, MDL);
524 			while (foo) {
525 			    if (foo == hd)
526 				    break;
527 			    if (np)
528 				    host_dereference (&np, MDL);
529 			    host_reference (&np, foo, MDL);
530 			    host_dereference (&foo, MDL);
531 			    if (np -> n_ipaddr)
532 				    host_reference (&foo, np -> n_ipaddr, MDL);
533 			}
534 
535 			if (foo) {
536 			    host_dereference (&np -> n_ipaddr, MDL);
537 			    if (hd -> n_ipaddr)
538 				host_reference (&np -> n_ipaddr,
539 						hd -> n_ipaddr, MDL);
540 			    host_dereference (&foo, MDL);
541 			}
542 			if (np)
543 				host_dereference (&np, MDL);
544 		    }
545 		    host_dereference (&hp, MDL);
546 		}
547 	    }
548 	}
549 
550 	/* If we got a client identifier, hash this entry by
551 	   client identifier. */
552 	if (hd -> client_identifier.len) {
553 	    if (host_uid_hash) {
554 		if (host_hash_lookup (&hp, host_uid_hash,
555 				      hd -> client_identifier.data,
556 				      hd -> client_identifier.len, MDL)) {
557 		    if (hp == hd) {
558 			host_hash_delete (host_uid_hash,
559 					  hd -> client_identifier.data,
560 					  hd -> client_identifier.len, MDL);
561 			uid_head = 1;
562 		    } else {
563 			np = (struct host_decl *)0;
564 			foo = (struct host_decl *)0;
565 			host_reference (&foo, hp, MDL);
566 			while (foo) {
567 			    if (foo == hd)
568 				    break;
569 			    if (np)
570 				host_dereference (&np, MDL);
571 			    host_reference (&np, foo, MDL);
572 			    host_dereference (&foo, MDL);
573 			    if (np -> n_ipaddr)
574 				    host_reference (&foo, np -> n_ipaddr, MDL);
575 			}
576 
577 			if (foo) {
578 			    host_dereference (&np -> n_ipaddr, MDL);
579 			    if (hd -> n_ipaddr)
580 				host_reference (&np -> n_ipaddr,
581 						hd -> n_ipaddr, MDL);
582 			    host_dereference (&foo, MDL);
583 			}
584 			if (np)
585 				host_dereference (&np, MDL);
586 		    }
587 		    host_dereference (&hp, MDL);
588 		}
589 	    }
590 	}
591 
592 	if (hd->host_id_option != NULL) {
593 		option_dereference(&hd->host_id_option, MDL);
594 		data_string_forget(&hd->host_id, MDL);
595 	}
596 
597 	if (hd -> n_ipaddr) {
598 		if (uid_head && hd -> n_ipaddr -> client_identifier.len) {
599 			host_hash_add
600 				(host_uid_hash,
601 				 hd -> n_ipaddr -> client_identifier.data,
602 				 hd -> n_ipaddr -> client_identifier.len,
603 				 hd -> n_ipaddr, MDL);
604 		}
605 		if (hw_head && hd -> n_ipaddr -> interface.hlen) {
606 			host_hash_add (host_hw_addr_hash,
607 				       hd -> n_ipaddr -> interface.hbuf,
608 				       hd -> n_ipaddr -> interface.hlen,
609 				       hd -> n_ipaddr, MDL);
610 		}
611 		host_dereference (&hd -> n_ipaddr, MDL);
612 	}
613 
614 	if (host_name_hash) {
615 		if (host_hash_lookup (&hp, host_name_hash,
616 				      (unsigned char *)hd -> name,
617 				      strlen (hd -> name), MDL)) {
618 			if (hp == hd && !(hp -> flags & HOST_DECL_STATIC)) {
619 				host_hash_delete (host_name_hash,
620 						  (unsigned char *)hd -> name,
621 						  strlen (hd -> name), MDL);
622 			}
623 			host_dereference (&hp, MDL);
624 		}
625 	}
626 
627 	if (commit) {
628 		if (!write_host (hd))
629 			return ISC_R_IOERROR;
630 		if (!commit_leases ())
631 			return ISC_R_IOERROR;
632 	}
633 	return ISC_R_SUCCESS;
634 }
635 
find_hosts_by_haddr(struct host_decl ** hp,int htype,const unsigned char * haddr,unsigned hlen,const char * file,int line)636 int find_hosts_by_haddr (struct host_decl **hp, int htype,
637 			 const unsigned char *haddr, unsigned hlen,
638 			 const char *file, int line)
639 {
640 	struct hardware h;
641 #if defined(LDAP_CONFIGURATION)
642 	int ret;
643 
644 	if ((ret = find_haddr_in_ldap (hp, htype, hlen, haddr, file, line)))
645 		return ret;
646 #endif
647 
648 	h.hlen = hlen + 1;
649 	h.hbuf [0] = htype;
650 	memcpy (&h.hbuf [1], haddr, hlen);
651 
652 	return host_hash_lookup (hp, host_hw_addr_hash,
653 				 h.hbuf, h.hlen, file, line);
654 }
655 
find_hosts_by_uid(struct host_decl ** hp,const unsigned char * data,unsigned len,const char * file,int line)656 int find_hosts_by_uid (struct host_decl **hp,
657 		       const unsigned char *data, unsigned len,
658 		       const char *file, int line)
659 {
660 	return host_hash_lookup (hp, host_uid_hash, data, len, file, line);
661 }
662 
663 int
find_hosts_by_option(struct host_decl ** hp,struct packet * packet,struct option_state * opt_state,const char * file,int line)664 find_hosts_by_option(struct host_decl **hp,
665 		     struct packet *packet,
666 		     struct option_state *opt_state,
667 		     const char *file, int line) {
668 	host_id_info_t *p;
669 	struct option_cache *oc;
670 	struct data_string data;
671 	int found;
672 	struct packet *relay_packet;
673 	struct option_state *relay_state;
674 
675 #if defined(LDAP_CONFIGURATION)
676 	if ((found = find_client_in_ldap (hp, packet, opt_state, file, line)))
677 		return found;
678 #endif
679 
680 	for (p = host_id_info; p != NULL; p = p->next) {
681 		relay_packet = packet;
682 		relay_state = opt_state;
683 
684 		/* If this option block is for a relay (relays != 0)
685 		 * and we are processing the main options and not
686 		 * options from the IA (packet->options == opt_state)
687 		 * try to find the proper relay
688 		 */
689 		if ((p->relays != 0) && (packet->options == opt_state)) {
690 			int i = p->relays;
691 			while ((i != 0) &&
692 			       (relay_packet->dhcpv6_container_packet != NULL)) {
693 				relay_packet =
694 					relay_packet->dhcpv6_container_packet;
695 				i--;
696 			}
697 			/* We wanted a specific relay but were
698 			 * unable to find it */
699 			if ((p->relays <= MAX_V6RELAY_HOPS) && (i != 0))
700 				continue;
701 
702 			relay_state = relay_packet->options;
703 		}
704 
705 		oc = lookup_option(p->option->universe,
706 				   relay_state, p->option->code);
707 		if (oc != NULL) {
708 			memset(&data, 0, sizeof(data));
709 
710 			if (!evaluate_option_cache(&data, relay_packet, NULL,
711 						   NULL, relay_state, NULL,
712 						   &global_scope, oc,
713 						   MDL)) {
714 				log_error("Error evaluating option cache");
715 				return 0;
716 			}
717 
718 			found = host_hash_lookup(hp, p->values_hash,
719 						 data.data, data.len,
720 						 file, line);
721 
722 			data_string_forget(&data, MDL);
723 
724 			if (found) {
725 				return 1;
726 			}
727 		}
728 	}
729 	return 0;
730 }
731 
732 /* More than one host_decl can be returned by find_hosts_by_haddr or
733    find_hosts_by_uid, and each host_decl can have multiple addresses.
734    Loop through the list of hosts, and then for each host, through the
735    list of addresses, looking for an address that's in the same shared
736    network as the one specified.    Store the matching address through
737    the addr pointer, update the host pointer to point at the host_decl
738    that matched, and return the subnet that matched. */
739 
find_host_for_network(struct subnet ** sp,struct host_decl ** host,struct iaddr * addr,struct shared_network * share)740 int find_host_for_network (struct subnet **sp, struct host_decl **host,
741 			   struct iaddr *addr, struct shared_network *share)
742 {
743 	int i;
744 	struct iaddr ip_address;
745 	struct host_decl *hp;
746 	struct data_string fixed_addr;
747 
748 	memset (&fixed_addr, 0, sizeof fixed_addr);
749 
750 	for (hp = *host; hp; hp = hp -> n_ipaddr) {
751 		if (!hp -> fixed_addr)
752 			continue;
753 		if (!evaluate_option_cache (&fixed_addr, (struct packet *)0,
754 					    (struct lease *)0,
755 					    (struct client_state *)0,
756 					    (struct option_state *)0,
757 					    (struct option_state *)0,
758 					    &global_scope,
759 					    hp -> fixed_addr, MDL))
760 			continue;
761 		for (i = 0; i < fixed_addr.len; i += 4) {
762 			ip_address.len = 4;
763 			memcpy (ip_address.iabuf,
764 				fixed_addr.data + i, 4);
765 			if (find_grouped_subnet (sp, share, ip_address, MDL)) {
766 				struct host_decl *tmp = (struct host_decl *)0;
767 				*addr = ip_address;
768 				/* This is probably not necessary, but
769 				   just in case *host is the only reference
770 				   to that host declaration, make a temporary
771 				   reference so that dereferencing it doesn't
772 				   dereference hp out from under us. */
773 				host_reference (&tmp, *host, MDL);
774 				host_dereference (host, MDL);
775 				host_reference (host, hp, MDL);
776 				host_dereference (&tmp, MDL);
777 				data_string_forget (&fixed_addr, MDL);
778 				return 1;
779 			}
780 		}
781 		data_string_forget (&fixed_addr, MDL);
782 	}
783 	return 0;
784 }
785 
new_address_range(cfile,low,high,subnet,pool,lpchain)786 void new_address_range (cfile, low, high, subnet, pool, lpchain)
787 	struct parse *cfile;
788 	struct iaddr low, high;
789 	struct subnet *subnet;
790 	struct pool *pool;
791 	struct lease **lpchain;
792 {
793 #if defined(COMPACT_LEASES)
794 	struct lease *address_range;
795 	unsigned s;
796 #endif
797 	unsigned min, max, i, num_addrs;
798 	char lowbuf [16], highbuf [16], netbuf [16];
799 	struct shared_network *share = subnet -> shared_network;
800 	struct lease *lt = (struct lease *)0;
801 #if !defined(COMPACT_LEASES)
802 	isc_result_t status;
803 #endif
804 
805 	/* All subnets should have attached shared network structures. */
806 	if (!share) {
807 		strcpy (netbuf, piaddr (subnet -> net));
808 		log_fatal ("No shared network for network %s (%s)",
809 		       netbuf, piaddr (subnet -> netmask));
810 	}
811 
812 	/* Initialize the hash table if it hasn't been done yet. */
813 	if (!lease_uid_hash) {
814 		if (!lease_id_new_hash(&lease_uid_hash, LEASE_HASH_SIZE, MDL))
815 			log_fatal ("Can't allocate lease/uid hash");
816 	}
817 	if (!lease_ip_addr_hash) {
818 		if (!lease_ip_new_hash(&lease_ip_addr_hash, LEASE_HASH_SIZE,
819 				       MDL))
820 			log_fatal ("Can't allocate lease/ip hash");
821 	}
822 	if (!lease_hw_addr_hash) {
823 		if (!lease_id_new_hash(&lease_hw_addr_hash, LEASE_HASH_SIZE,
824 				       MDL))
825 			log_fatal ("Can't allocate lease/hw hash");
826 	}
827 
828 	/* Make sure that high and low addresses are in this subnet. */
829 	if (!addr_eq(subnet->net, subnet_number(low, subnet->netmask))) {
830 		strcpy(lowbuf, piaddr(low));
831 		strcpy(netbuf, piaddr(subnet->net));
832 		log_fatal("bad range, address %s not in subnet %s netmask %s",
833 			  lowbuf, netbuf, piaddr(subnet->netmask));
834 	}
835 
836 	if (!addr_eq(subnet->net, subnet_number(high, subnet->netmask))) {
837 		strcpy(highbuf, piaddr(high));
838 		strcpy(netbuf, piaddr(subnet->net));
839 		log_fatal("bad range, address %s not in subnet %s netmask %s",
840 			  highbuf, netbuf, piaddr(subnet->netmask));
841 	}
842 
843 	/* Get the high and low host addresses... */
844 	max = host_addr (high, subnet -> netmask);
845 	min = host_addr (low, subnet -> netmask);
846 
847 	/* Allow range to be specified high-to-low as well as low-to-high. */
848 	if (min > max) {
849 		max = min;
850 		min = host_addr (high, subnet -> netmask);
851 	}
852 
853 	/* get the number of addresses we want, and add it to the pool info
854 	 * this value is only for use when setting up lease chains and will
855 	 * be overwritten when expire_all_pools is run
856 	 */
857 	num_addrs = max - min + 1;
858 #if defined (BINARY_LEASES)
859 	pool->lease_count += num_addrs;
860 #endif
861 
862 	/* Get a lease structure for each address in the range. */
863 #if defined (COMPACT_LEASES)
864 	s = (num_addrs + 1) * sizeof (struct lease);
865 	/* Check unsigned overflow in new_leases().
866 	   With 304 byte lease structure (x64_86), this happens at
867 	   range 10.0.0.0 10.215.148.52; */
868 	if (((s % sizeof (struct lease)) != 0) ||
869 	    ((s / sizeof (struct lease)) != (num_addrs + 1))) {
870 		strcpy (lowbuf, piaddr (low));
871 		strcpy (highbuf, piaddr (high));
872 		parse_warn (cfile, "%s-%s is an overly large address range.",
873 			   lowbuf, highbuf);
874 		log_fatal ("Memory overflow.");
875 	}
876 	address_range = new_leases (num_addrs, MDL);
877 	if (!address_range) {
878 		strcpy (lowbuf, piaddr (low));
879 		strcpy (highbuf, piaddr (high));
880 		log_fatal ("No memory for address range %s-%s.",
881 			   lowbuf, highbuf);
882 	}
883 #endif
884 
885 	/* Fill out the lease structures with some minimal information. */
886 	for (i = 0; i < num_addrs; i++) {
887 		struct lease *lp = (struct lease *)0;
888 #if defined (COMPACT_LEASES)
889 		omapi_object_initialize ((omapi_object_t *)&address_range [i],
890 					 dhcp_type_lease,
891 					 0, sizeof (struct lease), MDL);
892 		lease_reference (&lp, &address_range [i], MDL);
893 #else
894 		status = lease_allocate (&lp, MDL);
895 		if (status != ISC_R_SUCCESS)
896 			log_fatal ("No memory for lease %s: %s",
897 				   piaddr (ip_addr (subnet -> net,
898 						    subnet -> netmask,
899 						    i + min)),
900 				   isc_result_totext (status));
901 #endif
902 		lp->ip_addr = ip_addr(subnet->net, subnet->netmask, i + min);
903 		lp->starts = MIN_TIME;
904 		lp->ends = MIN_TIME;
905 		subnet_reference(&lp->subnet, subnet, MDL);
906 		pool_reference(&lp->pool, pool, MDL);
907 		lp->binding_state = FTS_FREE;
908 		lp->next_binding_state = FTS_FREE;
909 		lp->rewind_binding_state = FTS_FREE;
910 		lp->flags = 0;
911 
912 		/* Remember the lease in the IP address hash. */
913 		if (find_lease_by_ip_addr (&lt, lp -> ip_addr, MDL)) {
914 			if (lt -> pool) {
915 				parse_warn (cfile,
916 					    "lease %s is declared twice!",
917 					    piaddr (lp -> ip_addr));
918 			} else
919 				pool_reference (&lt -> pool, pool, MDL);
920 			lease_dereference (&lt, MDL);
921 		} else
922 			lease_ip_hash_add(lease_ip_addr_hash,
923 					  lp->ip_addr.iabuf, lp->ip_addr.len,
924 					  lp, MDL);
925 		/* Put the lease on the chain for the caller. */
926 		if (lpchain) {
927 			if (*lpchain) {
928 				lease_reference (&lp -> next, *lpchain, MDL);
929 				lease_dereference (lpchain, MDL);
930 			}
931 			lease_reference (lpchain, lp, MDL);
932 		}
933 		lease_dereference (&lp, MDL);
934 	}
935 }
936 
find_subnet(struct subnet ** sp,struct iaddr addr,const char * file,int line)937 int find_subnet (struct subnet **sp,
938 		 struct iaddr addr, const char *file, int line)
939 {
940 	struct subnet *rv;
941 
942 	for (rv = subnets; rv; rv = rv -> next_subnet) {
943 #if defined(DHCP4o6)
944 		if (addr.len != rv->netmask.len)
945 			continue;
946 #endif
947 		if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
948 			if (subnet_reference (sp, rv,
949 					      file, line) != ISC_R_SUCCESS)
950 				return 0;
951 			return 1;
952 		}
953 	}
954 	return 0;
955 }
956 
find_grouped_subnet(struct subnet ** sp,struct shared_network * share,struct iaddr addr,const char * file,int line)957 int find_grouped_subnet (struct subnet **sp,
958 			 struct shared_network *share, struct iaddr addr,
959 			 const char *file, int line)
960 {
961 	struct subnet *rv;
962 
963 	for (rv = share -> subnets; rv; rv = rv -> next_sibling) {
964 #if defined(DHCP4o6)
965 		if (addr.len != rv->netmask.len)
966 			continue;
967 #endif
968 		if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
969 			if (subnet_reference (sp, rv,
970 					      file, line) != ISC_R_SUCCESS)
971 				return 0;
972 			return 1;
973 		}
974 	}
975 	return 0;
976 }
977 
978 /* XXX: could speed up if everyone had a prefix length */
979 int
subnet_inner_than(const struct subnet * subnet,const struct subnet * scan,int warnp)980 subnet_inner_than(const struct subnet *subnet,
981 		  const struct subnet *scan,
982 		  int warnp) {
983 #if defined(DHCP4o6)
984 	if (subnet->net.len != scan->net.len)
985 		return 0;
986 #endif
987 	if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) ||
988 	    addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) {
989 		char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")];
990 		int i, j;
991 		for (i = 0; i < 128; i++)
992 			if (subnet->netmask.iabuf[3 - (i >> 3)]
993 			    & (1 << (i & 7)))
994 				break;
995 		for (j = 0; j < 128; j++)
996 			if (scan->netmask.iabuf[3 - (j >> 3)] &
997 			    (1 << (j & 7)))
998 				break;
999 		if (warnp) {
1000 			strcpy(n1buf, piaddr(subnet->net));
1001 			log_error("Warning: subnet %s/%d overlaps subnet %s/%d",
1002 			      n1buf, 32 - i,
1003 			      piaddr(scan->net), 32 - j);
1004 		}
1005 		if (i < j)
1006 			return 1;
1007 	}
1008 	return 0;
1009 }
1010 
1011 /* Enter a new subnet into the subnet list. */
enter_subnet(subnet)1012 void enter_subnet (subnet)
1013 	struct subnet *subnet;
1014 {
1015 	struct subnet *scan = (struct subnet *)0;
1016 	struct subnet *next = (struct subnet *)0;
1017 	struct subnet *prev = (struct subnet *)0;
1018 
1019 	/* Check for duplicates... */
1020 	if (subnets)
1021 	    subnet_reference (&next, subnets, MDL);
1022 	while (next) {
1023 	    subnet_reference (&scan, next, MDL);
1024 	    subnet_dereference (&next, MDL);
1025 
1026 	    /* When we find a conflict, make sure that the
1027 	       subnet with the narrowest subnet mask comes
1028 	       first. */
1029 	    if (subnet_inner_than (subnet, scan, 1)) {
1030 		if (prev) {
1031 		    if (prev -> next_subnet)
1032 			subnet_dereference (&prev -> next_subnet, MDL);
1033 		    subnet_reference (&prev -> next_subnet, subnet, MDL);
1034 		    subnet_dereference (&prev, MDL);
1035 		} else {
1036 		    subnet_dereference (&subnets, MDL);
1037 		    subnet_reference (&subnets, subnet, MDL);
1038 		}
1039 		subnet_reference (&subnet -> next_subnet, scan, MDL);
1040 		subnet_dereference (&scan, MDL);
1041 		return;
1042 	    }
1043 	    subnet_reference (&prev, scan, MDL);
1044 	    subnet_dereference (&scan, MDL);
1045 	}
1046 	if (prev)
1047 		subnet_dereference (&prev, MDL);
1048 
1049 	/* XXX use the BSD radix tree code instead of a linked list. */
1050 	if (subnets) {
1051 		subnet_reference (&subnet -> next_subnet, subnets, MDL);
1052 		subnet_dereference (&subnets, MDL);
1053 	}
1054 	subnet_reference (&subnets, subnet, MDL);
1055 }
1056 
1057 /* Enter a new shared network into the shared network list. */
1058 
enter_shared_network(share)1059 void enter_shared_network (share)
1060 	struct shared_network *share;
1061 {
1062 	if (shared_networks) {
1063 		shared_network_reference (&share -> next,
1064 					  shared_networks, MDL);
1065 		shared_network_dereference (&shared_networks, MDL);
1066 	}
1067 	shared_network_reference (&shared_networks, share, MDL);
1068 }
1069 
new_shared_network_interface(cfile,share,name)1070 void new_shared_network_interface (cfile, share, name)
1071 	struct parse *cfile;
1072 	struct shared_network *share;
1073 	const char *name;
1074 {
1075 	struct interface_info *ip;
1076 	isc_result_t status;
1077 
1078 	if (share -> interface) {
1079 		parse_warn (cfile,
1080 			    "A subnet or shared network can't be connected %s",
1081 			    "to two interfaces.");
1082 		return;
1083 	}
1084 
1085 	for (ip = interfaces; ip; ip = ip -> next)
1086 		if (!strcmp (ip -> name, name))
1087 			break;
1088 	if (!ip) {
1089 		status = interface_allocate (&ip, MDL);
1090 		if (status != ISC_R_SUCCESS)
1091 			log_fatal ("new_shared_network_interface %s: %s",
1092 				   name, isc_result_totext (status));
1093 		if (strlen (name) > sizeof ip -> name) {
1094 			memcpy (ip -> name, name, (sizeof ip -> name) - 1);
1095 			ip -> name [(sizeof ip -> name) - 1] = 0;
1096 		} else
1097 			strcpy (ip -> name, name);
1098 		if (interfaces) {
1099 			interface_reference (&ip -> next, interfaces, MDL);
1100 			interface_dereference (&interfaces, MDL);
1101 		}
1102 		interface_reference (&interfaces, ip, MDL);
1103 		ip -> flags = INTERFACE_REQUESTED;
1104 		/* XXX this is a reference loop. */
1105 		shared_network_reference (&ip -> shared_network, share, MDL);
1106 		interface_reference (&share -> interface, ip, MDL);
1107 	}
1108 }
1109 
1110 /* Enter a lease into the system.   This is called by the parser each
1111    time it reads in a new lease.   If the subnet for that lease has
1112    already been read in (usually the case), just update that lease;
1113    otherwise, allocate temporary storage for the lease and keep it around
1114    until we're done reading in the config file. */
1115 
enter_lease(lease)1116 void enter_lease (lease)
1117 	struct lease *lease;
1118 {
1119 	struct lease *comp = (struct lease *)0;
1120 
1121 	if (find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) {
1122 		if (!comp -> pool) {
1123 			log_error ("undeclared lease found in database: %s",
1124 				   piaddr (lease -> ip_addr));
1125 		} else
1126 			pool_reference (&lease -> pool, comp -> pool, MDL);
1127 
1128 		if (comp -> subnet)
1129 			subnet_reference (&lease -> subnet,
1130 					  comp -> subnet, MDL);
1131 		lease_ip_hash_delete(lease_ip_addr_hash,
1132 				     lease->ip_addr.iabuf, lease->ip_addr.len,
1133 				     MDL);
1134 		lease_dereference (&comp, MDL);
1135 	}
1136 
1137 	/* The only way a lease can get here without a subnet is if it's in
1138 	   the lease file, but not in the dhcpd.conf file.  In this case, we
1139 	   *should* keep it around until it's expired, but never reallocate it
1140 	   or renew it.  Currently, to maintain consistency, we are not doing
1141 	   this.
1142 	   XXX fix this so that the lease is kept around until it expires.
1143 	   XXX this will be important in IPv6 with addresses that become
1144 	   XXX non-renewable as a result of a renumbering event. */
1145 
1146 	if (!lease -> subnet) {
1147 		log_error ("lease %s: no subnet.", piaddr (lease -> ip_addr));
1148 		return;
1149 	}
1150 	lease_ip_hash_add(lease_ip_addr_hash, lease->ip_addr.iabuf,
1151 			  lease->ip_addr.len, lease, MDL);
1152 }
1153 
1154 /* Replace the data in an existing lease with the data in a new lease;
1155    adjust hash tables to suit, and insertion sort the lease into the
1156    list of leases by expiry time so that we can always find the oldest
1157    lease. */
1158 
supersede_lease(comp,lease,commit,propogate,pimmediate,from_pool)1159 int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
1160 	struct lease *comp, *lease;
1161 	int commit;
1162 	int propogate;
1163 	int pimmediate;
1164 	int from_pool;
1165 {
1166 	LEASE_STRUCT_PTR lq;
1167 	struct timeval tv;
1168 #if defined (FAILOVER_PROTOCOL)
1169 	int do_pool_check = 0;
1170 
1171 	/* We must commit leases before sending updates regarding them
1172 	   to failover peers.  It is, therefore, an error to set pimmediate
1173 	   and not commit. */
1174 	if (pimmediate && !commit)
1175 		return 0;
1176 #endif
1177 	/* If there is no sample lease, just do the move. */
1178 	if (!lease)
1179 		goto just_move_it;
1180 
1181 	/* Static leases are not currently kept in the database... */
1182 	if (lease -> flags & STATIC_LEASE)
1183 		return 1;
1184 
1185 	/* If the existing lease hasn't expired and has a different
1186 	   unique identifier or, if it doesn't have a unique
1187 	   identifier, a different hardware address, then the two
1188 	   leases are in conflict.  If the existing lease has a uid
1189 	   and the new one doesn't, but they both have the same
1190 	   hardware address, and dynamic bootp is allowed on this
1191 	   lease, then we allow that, in case a dynamic BOOTP lease is
1192 	   requested *after* a DHCP lease has been assigned. */
1193 
1194 	if (lease -> binding_state != FTS_ABANDONED &&
1195 	    lease -> next_binding_state != FTS_ABANDONED &&
1196 	    comp -> binding_state == FTS_ACTIVE &&
1197 	    (((comp -> uid && lease -> uid) &&
1198 	      (comp -> uid_len != lease -> uid_len ||
1199 	       memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
1200 	     (!comp -> uid &&
1201 	      ((comp -> hardware_addr.hlen !=
1202 		lease -> hardware_addr.hlen) ||
1203 	       memcmp (comp -> hardware_addr.hbuf,
1204 		       lease -> hardware_addr.hbuf,
1205 		       comp -> hardware_addr.hlen))))) {
1206 		log_error ("Lease conflict at %s",
1207 		      piaddr (comp -> ip_addr));
1208 	}
1209 
1210 	/* If there's a Unique ID, dissociate it from the hash
1211 	   table and free it if necessary. */
1212 	if (comp->uid) {
1213 		uid_hash_delete(comp);
1214 		if (comp->uid != comp->uid_buf) {
1215 			dfree(comp->uid, MDL);
1216 			comp->uid_max = 0;
1217 			comp->uid_len = 0;
1218 		}
1219 		comp -> uid = (unsigned char *)0;
1220 	}
1221 
1222 	/* If there's a hardware address, remove the lease from its
1223 	 * old position in the hash bucket's ordered list.
1224 	 */
1225 	if (comp->hardware_addr.hlen)
1226 		hw_hash_delete(comp);
1227 
1228 	/* If the lease has been billed to a class, remove the billing. */
1229 	if (comp -> billing_class != lease -> billing_class) {
1230 		if (comp->billing_class)
1231 			unbill_class(comp);
1232 		if (lease -> billing_class)
1233 			bill_class (comp, lease -> billing_class);
1234 	}
1235 
1236 	/* Copy the data files, but not the linkages. */
1237 	comp -> starts = lease -> starts;
1238 	if (lease -> uid) {
1239 		if (lease -> uid_len <= sizeof (lease -> uid_buf)) {
1240 			memcpy (comp -> uid_buf,
1241 				lease -> uid, lease -> uid_len);
1242 			comp -> uid = &comp -> uid_buf [0];
1243 			comp -> uid_max = sizeof comp -> uid_buf;
1244 			comp -> uid_len = lease -> uid_len;
1245 		} else if (lease -> uid != &lease -> uid_buf [0]) {
1246 			comp -> uid = lease -> uid;
1247 			comp -> uid_max = lease -> uid_max;
1248 			lease -> uid = (unsigned char *)0;
1249 			lease -> uid_max = 0;
1250 			comp -> uid_len = lease -> uid_len;
1251 			lease -> uid_len = 0;
1252 		} else {
1253 			log_fatal ("corrupt lease uid."); /* XXX */
1254 		}
1255 	} else {
1256 		comp -> uid = (unsigned char *)0;
1257 		comp -> uid_len = comp -> uid_max = 0;
1258 	}
1259 	if (comp -> host)
1260 		host_dereference (&comp -> host, MDL);
1261 	host_reference (&comp -> host, lease -> host, MDL);
1262 	comp -> hardware_addr = lease -> hardware_addr;
1263 	if (comp -> scope)
1264 		binding_scope_dereference (&comp -> scope, MDL);
1265 	if (lease -> scope) {
1266 		binding_scope_reference (&comp -> scope, lease -> scope, MDL);
1267 		binding_scope_dereference (&lease -> scope, MDL);
1268 	}
1269 
1270 	if (comp -> agent_options)
1271 		option_chain_head_dereference (&comp -> agent_options, MDL);
1272 	if (lease -> agent_options) {
1273 		/* Only retain the agent options if the lease is still
1274 		   affirmatively associated with a client. */
1275 		if (lease -> next_binding_state == FTS_ACTIVE ||
1276 		    lease -> next_binding_state == FTS_EXPIRED)
1277 			option_chain_head_reference (&comp -> agent_options,
1278 						     lease -> agent_options,
1279 						     MDL);
1280 		option_chain_head_dereference (&lease -> agent_options, MDL);
1281 	}
1282 
1283 	/* Record the hostname information in the lease. */
1284 	if (comp -> client_hostname)
1285 		dfree (comp -> client_hostname, MDL);
1286 	comp -> client_hostname = lease -> client_hostname;
1287 	lease -> client_hostname = (char *)0;
1288 
1289 	if (lease->on_star.on_expiry) {
1290 		if (comp->on_star.on_expiry)
1291 			executable_statement_dereference
1292 				(&comp->on_star.on_expiry, MDL);
1293 		executable_statement_reference (&comp->on_star.on_expiry,
1294 						lease->on_star.on_expiry,
1295 						MDL);
1296 	}
1297 	if (lease->on_star.on_commit) {
1298 		if (comp->on_star.on_commit)
1299 			executable_statement_dereference
1300 				(&comp->on_star.on_commit, MDL);
1301 		executable_statement_reference (&comp->on_star.on_commit,
1302 						lease->on_star.on_commit,
1303 						MDL);
1304 	}
1305 	if (lease->on_star.on_release) {
1306 		if (comp->on_star.on_release)
1307 			executable_statement_dereference
1308 				(&comp->on_star.on_release, MDL);
1309 		executable_statement_reference (&comp->on_star.on_release,
1310 						lease->on_star.on_release,
1311 						MDL);
1312 	}
1313 
1314 	/* Record the lease in the uid hash if necessary. */
1315 	if (comp->uid)
1316 		uid_hash_add(comp);
1317 
1318 	/* Record it in the hardware address hash if necessary. */
1319 	if (comp->hardware_addr.hlen)
1320 		hw_hash_add(comp);
1321 
1322 	comp->cltt = lease->cltt;
1323 #if defined (FAILOVER_PROTOCOL)
1324 	comp->tstp = lease->tstp;
1325 	comp->tsfp = lease->tsfp;
1326 	comp->atsfp = lease->atsfp;
1327 #endif /* FAILOVER_PROTOCOL */
1328 	comp->ends = lease->ends;
1329 	comp->next_binding_state = lease->next_binding_state;
1330 
1331 	/*
1332 	 * If we have a control block pointer copy it in.
1333 	 * We don't zero out an older ponter as it is still
1334 	 * in use.  We shouldn't need to overwrite an
1335 	 * old pointer with a new one as the old transaction
1336 	 * should have been cancelled before getting here.
1337 	 */
1338 	if (lease->ddns_cb != NULL)
1339 		comp->ddns_cb = lease->ddns_cb;
1340 
1341       just_move_it:
1342 #if defined (FAILOVER_PROTOCOL)
1343 	/*
1344 	 * Atsfp should be cleared upon any state change that implies
1345 	 * propagation whether supersede_lease was given a copy lease
1346 	 * structure or not (often from the pool_timer()).
1347 	 */
1348 	if (propogate)
1349 		comp->atsfp = 0;
1350 #endif /* FAILOVER_PROTOCOL */
1351 
1352 	if (!comp -> pool) {
1353 		log_error ("Supersede_lease: lease %s with no pool.",
1354 			   piaddr (comp -> ip_addr));
1355 		return 0;
1356 	}
1357 
1358 	/* Figure out which queue it's on. */
1359 	switch (comp -> binding_state) {
1360 	      case FTS_FREE:
1361 		if (comp->flags & RESERVED_LEASE)
1362 			lq = &comp->pool->reserved;
1363 		else {
1364 			lq = &comp->pool->free;
1365 			comp->pool->free_leases--;
1366 		}
1367 
1368 #if defined(FAILOVER_PROTOCOL)
1369 		do_pool_check = 1;
1370 #endif
1371 		break;
1372 
1373 	      case FTS_ACTIVE:
1374 		lq = &comp -> pool -> active;
1375 		break;
1376 
1377 	      case FTS_EXPIRED:
1378 	      case FTS_RELEASED:
1379 	      case FTS_RESET:
1380 		lq = &comp -> pool -> expired;
1381 		break;
1382 
1383 	      case FTS_ABANDONED:
1384 		lq = &comp -> pool -> abandoned;
1385 		break;
1386 
1387 	      case FTS_BACKUP:
1388 		if (comp->flags & RESERVED_LEASE)
1389 			lq = &comp->pool->reserved;
1390 		else {
1391 			lq = &comp->pool->backup;
1392 			comp->pool->backup_leases--;
1393 		}
1394 
1395 #if defined(FAILOVER_PROTOCOL)
1396 		do_pool_check = 1;
1397 #endif
1398 		break;
1399 
1400 	      default:
1401 		log_error ("Lease with bogus binding state: %d",
1402 			   comp -> binding_state);
1403 #if defined (BINDING_STATE_DEBUG)
1404 		abort ();
1405 #endif
1406 		return 0;
1407 	}
1408 
1409 	/* Remove the lease from its current place in its current
1410 	   timer sequence. */
1411 	LEASE_REMOVEP(lq, comp);
1412 
1413 	/* Now that we've done the flag-affected queue removal
1414 	 * we can update the new lease's flags, if there's an
1415 	 * existing lease */
1416 	if (lease) {
1417 		comp->flags = ((lease->flags & ~PERSISTENT_FLAGS) |
1418 				(comp->flags & ~EPHEMERAL_FLAGS));
1419 	}
1420 
1421 	/* Make the state transition. */
1422 	if (commit || !pimmediate)
1423 		make_binding_state_transition (comp);
1424 
1425 	/* Put the lease back on the appropriate queue.    If the lease
1426 	   is corrupt (as detected by lease_enqueue), don't go any farther. */
1427 	if (!lease_enqueue (comp))
1428 		return 0;
1429 
1430 	/* If this is the next lease that will timeout on the pool,
1431 	   zap the old timeout and set the timeout on this pool to the
1432 	   time that the lease's next event will happen.
1433 
1434 	   We do not actually set the timeout unless commit is true -
1435 	   we don't want to thrash the timer queue when reading the
1436 	   lease database.  Instead, the database code calls the
1437 	   expiry event on each pool after reading in the lease file,
1438 	   and the expiry code sets the timer if there's anything left
1439 	   to expire after it's run any outstanding expiry events on
1440 	   the pool. */
1441 	if ((commit || !pimmediate) &&
1442 	    comp -> sort_time != MIN_TIME &&
1443 	    comp -> sort_time > cur_time &&
1444 	    (comp -> sort_time < comp -> pool -> next_event_time ||
1445 	     comp -> pool -> next_event_time == MIN_TIME)) {
1446 		comp -> pool -> next_event_time = comp -> sort_time;
1447 		tv . tv_sec = comp -> pool -> next_event_time;
1448 		tv . tv_usec = 0;
1449 		add_timeout (&tv,
1450 			     pool_timer, comp -> pool,
1451 			     (tvref_t)pool_reference,
1452 			     (tvunref_t)pool_dereference);
1453 	}
1454 
1455 	if (commit) {
1456 #if defined(FAILOVER_PROTOCOL)
1457 		/*
1458 		 * If commit and propogate are set, then we can save a
1459 		 * possible fsync later in BNDUPD socket transmission by
1460 		 * stepping the rewind state forward to the new state, in
1461 		 * case it has changed.  This is only worth doing if the
1462 		 * failover connection is currently connected, as in this
1463 		 * case it is likely we will be transmitting to the peer very
1464 		 * shortly.
1465 		 */
1466 		if (propogate && (comp->pool->failover_peer != NULL) &&
1467 		    ((comp->pool->failover_peer->service_state ==
1468 							    cooperating) ||
1469 		     (comp->pool->failover_peer->service_state ==
1470 							    not_responding)))
1471 			comp->rewind_binding_state = comp->binding_state;
1472 #endif
1473 
1474 		if (!write_lease (comp))
1475 			return 0;
1476 		if ((server_starting & SS_NOSYNC) == 0) {
1477 			if (!commit_leases ())
1478 				return 0;
1479 		}
1480 	}
1481 
1482 #if defined (FAILOVER_PROTOCOL)
1483 	if (propogate) {
1484 		comp -> desired_binding_state = comp -> binding_state;
1485 		if (!dhcp_failover_queue_update (comp, pimmediate))
1486 			return 0;
1487 	}
1488 	if (do_pool_check && comp->pool->failover_peer)
1489 		dhcp_failover_pool_check(comp->pool);
1490 #endif
1491 
1492 	/* If the current binding state has already expired and we haven't
1493 	 * been called from pool_timer, do an expiry event right now.
1494 	 */
1495 	/* XXX At some point we should optimize this so that we don't
1496 	   XXX write the lease twice, but this is a safe way to fix the
1497 	   XXX problem for 3.0 (I hope!). */
1498 	if ((from_pool == 0) &&
1499 	    (commit || !pimmediate) &&
1500 	    (comp->sort_time < cur_time) &&
1501 	    (comp->next_binding_state != comp->binding_state))
1502 		pool_timer(comp->pool);
1503 
1504 	return 1;
1505 }
1506 
make_binding_state_transition(struct lease * lease)1507 void make_binding_state_transition (struct lease *lease)
1508 {
1509 
1510 #if defined (FAILOVER_PROTOCOL)
1511 	dhcp_failover_state_t *peer;
1512 
1513 	if (lease -> pool && lease -> pool -> failover_peer)
1514 		peer = lease -> pool -> failover_peer;
1515 	else
1516 		peer = (dhcp_failover_state_t *)0;
1517 #endif
1518 
1519 	/* If the lease was active and is now no longer active, but isn't
1520 	   released, then it just expired, so do the expiry event. */
1521 	if (lease -> next_binding_state != lease -> binding_state &&
1522 	    ((
1523 #if defined (FAILOVER_PROTOCOL)
1524 		    peer &&
1525 		    (lease->binding_state == FTS_EXPIRED ||
1526 		     lease->binding_state == FTS_ACTIVE) &&
1527 		    (lease->next_binding_state == FTS_FREE ||
1528 		     lease->next_binding_state == FTS_BACKUP)) ||
1529 	     (!peer &&
1530 #endif
1531 	      lease -> binding_state == FTS_ACTIVE &&
1532 	      lease -> next_binding_state != FTS_RELEASED))) {
1533 #if defined (NSUPDATE)
1534 		(void) ddns_removals(lease, NULL, NULL, ISC_TRUE);
1535 #endif
1536 		if (lease->on_star.on_expiry) {
1537 			execute_statements(NULL, NULL, lease,
1538 					   NULL, NULL, NULL,
1539 					   &lease->scope,
1540 					   lease->on_star.on_expiry,
1541 					   NULL);
1542 			if (lease->on_star.on_expiry)
1543 				executable_statement_dereference
1544 					(&lease->on_star.on_expiry, MDL);
1545 		}
1546 
1547 		/* No sense releasing a lease after it's expired. */
1548 		if (lease->on_star.on_release)
1549 			executable_statement_dereference
1550 				(&lease->on_star.on_release, MDL);
1551 		/* Get rid of client-specific bindings that are only
1552 		   correct when the lease is active. */
1553 		if (lease->billing_class)
1554 			unbill_class(lease);
1555 		if (lease -> agent_options)
1556 			option_chain_head_dereference (&lease -> agent_options,
1557 						       MDL);
1558 		if (lease -> client_hostname) {
1559 			dfree (lease -> client_hostname, MDL);
1560 			lease -> client_hostname = (char *)0;
1561 		}
1562 		if (lease -> host)
1563 			host_dereference (&lease -> host, MDL);
1564 
1565 		/* Send the expiry time to the peer. */
1566 		lease -> tstp = lease -> ends;
1567 	}
1568 
1569 	/* If the lease was active and is now released, do the release
1570 	   event. */
1571 	if (lease -> next_binding_state != lease -> binding_state &&
1572 	    ((
1573 #if defined (FAILOVER_PROTOCOL)
1574 		    peer &&
1575 		    lease -> binding_state == FTS_RELEASED &&
1576 		    (lease -> next_binding_state == FTS_FREE ||
1577 		     lease -> next_binding_state == FTS_BACKUP)) ||
1578 	     (!peer &&
1579 #endif
1580 	      lease -> binding_state == FTS_ACTIVE &&
1581 	      lease -> next_binding_state == FTS_RELEASED))) {
1582 #if defined (NSUPDATE)
1583 		/*
1584 		 * Note: ddns_removals() is also iterated when the lease
1585 		 * enters state 'released' in 'release_lease()'.  The below
1586 		 * is caught when a peer receives a BNDUPD from a failover
1587 		 * peer; it may not have received the client's release (it
1588 		 * may have been offline).
1589 		 *
1590 		 * We could remove the call from release_lease() because
1591 		 * it will also catch here on the originating server after the
1592 		 * peer acknowledges the state change.  However, there could
1593 		 * be many hours inbetween, and in this case we /know/ the
1594 		 * client is no longer using the lease when we receive the
1595 		 * release message.  This is not true of expiry, where the
1596 		 * peer may have extended the lease.
1597 		 */
1598 		(void) ddns_removals(lease, NULL, NULL, ISC_TRUE);
1599 #endif
1600 		if (lease->on_star.on_release) {
1601 			execute_statements(NULL, NULL, lease,
1602 					   NULL, NULL, NULL,
1603 					   &lease->scope,
1604 					   lease->on_star.on_release,
1605 					   NULL);
1606 			executable_statement_dereference
1607 				(&lease->on_star.on_release, MDL);
1608 		}
1609 
1610 		/* A released lease can't expire. */
1611 		if (lease->on_star.on_expiry)
1612 			executable_statement_dereference
1613 				(&lease->on_star.on_expiry, MDL);
1614 
1615 		/* Get rid of client-specific bindings that are only
1616 		   correct when the lease is active. */
1617 		if (lease->billing_class)
1618 			unbill_class(lease);
1619 		if (lease -> agent_options)
1620 			option_chain_head_dereference (&lease -> agent_options,
1621 						       MDL);
1622 		if (lease -> client_hostname) {
1623 			dfree (lease -> client_hostname, MDL);
1624 			lease -> client_hostname = (char *)0;
1625 		}
1626 		if (lease -> host)
1627 			host_dereference (&lease -> host, MDL);
1628 
1629 		/* Send the release time (should be == cur_time) to the
1630 		   peer. */
1631 		lease -> tstp = lease -> ends;
1632 	}
1633 
1634 #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
1635 	log_debug ("lease %s moves from %s to %s",
1636 		   piaddr (lease -> ip_addr),
1637 		   binding_state_print (lease -> binding_state),
1638 		   binding_state_print (lease -> next_binding_state));
1639 #endif
1640 
1641 	lease -> binding_state = lease -> next_binding_state;
1642 	switch (lease -> binding_state) {
1643 	      case FTS_ACTIVE:
1644 #if defined (FAILOVER_PROTOCOL)
1645 		if (lease -> pool && lease -> pool -> failover_peer)
1646 			lease -> next_binding_state = FTS_EXPIRED;
1647 		else
1648 #endif
1649 			lease -> next_binding_state = FTS_FREE;
1650 		break;
1651 
1652 	      case FTS_EXPIRED:
1653 	      case FTS_RELEASED:
1654 	      case FTS_ABANDONED:
1655 	      case FTS_RESET:
1656 		lease->next_binding_state = FTS_FREE;
1657 #if defined(FAILOVER_PROTOCOL)
1658 		/* If we are not in partner_down, leases don't go from
1659 		   EXPIRED to FREE on a timeout - only on an update.
1660 		   If we're in partner_down, they expire at mclt past
1661 		   the time we entered partner_down. */
1662 		if ((lease->pool != NULL) &&
1663 		    (lease->pool->failover_peer != NULL) &&
1664 		    (lease->pool->failover_peer->me.state == partner_down))
1665 			lease->tsfp =
1666 			    (lease->pool->failover_peer->me.stos +
1667 			     lease->pool->failover_peer->mclt);
1668 #endif /* FAILOVER_PROTOCOL */
1669 		break;
1670 
1671 	      case FTS_FREE:
1672 	      case FTS_BACKUP:
1673 		lease -> next_binding_state = lease -> binding_state;
1674 		break;
1675 	}
1676 #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
1677 	log_debug ("lease %s: next binding state %s",
1678 		   piaddr (lease -> ip_addr),
1679 		   binding_state_print (lease -> next_binding_state));
1680 #endif
1681 }
1682 
1683 /* Copy the contents of one lease into another, correctly maintaining
1684    reference counts. */
lease_copy(struct lease ** lp,struct lease * lease,const char * file,int line)1685 int lease_copy (struct lease **lp,
1686 		struct lease *lease, const char *file, int line)
1687 {
1688 	struct lease *lt = (struct lease *)0;
1689 	isc_result_t status;
1690 
1691 	status = lease_allocate (&lt, MDL);
1692 	if (status != ISC_R_SUCCESS)
1693 		return 0;
1694 
1695 	lt -> ip_addr = lease -> ip_addr;
1696 	lt -> starts = lease -> starts;
1697 	lt -> ends = lease -> ends;
1698 	lt -> uid_len = lease -> uid_len;
1699 	lt -> uid_max = lease -> uid_max;
1700 	if (lease -> uid == lease -> uid_buf) {
1701 		lt -> uid = lt -> uid_buf;
1702 		memcpy (lt -> uid_buf, lease -> uid_buf, sizeof lt -> uid_buf);
1703 	} else if (!lease -> uid_max) {
1704 		lt -> uid = (unsigned char *)0;
1705 	} else {
1706 		lt -> uid = dmalloc (lt -> uid_max, MDL);
1707 		if (!lt -> uid) {
1708 			lease_dereference (&lt, MDL);
1709 			return 0;
1710 		}
1711 		memcpy (lt -> uid, lease -> uid, lease -> uid_max);
1712 	}
1713 	if (lease -> client_hostname) {
1714 		lt -> client_hostname =
1715 			dmalloc (strlen (lease -> client_hostname) + 1, MDL);
1716 		if (!lt -> client_hostname) {
1717 			lease_dereference (&lt, MDL);
1718 			return 0;
1719 		}
1720 		strcpy (lt -> client_hostname, lease -> client_hostname);
1721 	}
1722 	if (lease -> scope)
1723 		binding_scope_reference (&lt -> scope, lease -> scope, MDL);
1724 	if (lease -> agent_options)
1725 		option_chain_head_reference (&lt -> agent_options,
1726 					     lease -> agent_options, MDL);
1727 	host_reference (&lt -> host, lease -> host, file, line);
1728 	subnet_reference (&lt -> subnet, lease -> subnet, file, line);
1729 	pool_reference (&lt -> pool, lease -> pool, file, line);
1730 	class_reference (&lt -> billing_class,
1731 			 lease -> billing_class, file, line);
1732 	lt -> hardware_addr = lease -> hardware_addr;
1733 	if (lease->on_star.on_expiry)
1734 		executable_statement_reference (&lt->on_star.on_expiry,
1735 						lease->on_star.on_expiry,
1736 						file, line);
1737 	if (lease->on_star.on_commit)
1738 		executable_statement_reference (&lt->on_star.on_commit,
1739 						lease->on_star.on_commit,
1740 						file, line);
1741 	if (lease->on_star.on_release)
1742 		executable_statement_reference (&lt->on_star.on_release,
1743 						lease->on_star.on_release,
1744 						file, line);
1745 	lt->flags = lease->flags;
1746 	lt->tstp = lease->tstp;
1747 	lt->tsfp = lease->tsfp;
1748 	lt->atsfp = lease->atsfp;
1749 	lt->cltt = lease -> cltt;
1750 	lt->binding_state = lease->binding_state;
1751 	lt->next_binding_state = lease->next_binding_state;
1752 	lt->rewind_binding_state = lease->rewind_binding_state;
1753 	status = lease_reference(lp, lt, file, line);
1754 	lease_dereference(&lt, MDL);
1755 	return status == ISC_R_SUCCESS;
1756 }
1757 
1758 /* Release the specified lease and re-hash it as appropriate. */
release_lease(lease,packet)1759 void release_lease (lease, packet)
1760 	struct lease *lease;
1761 	struct packet *packet;
1762 {
1763 	/* If there are statements to execute when the lease is
1764 	   released, execute them. */
1765 #if defined (NSUPDATE)
1766 	(void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
1767 #endif
1768 	if (lease->on_star.on_release) {
1769 		execute_statements (NULL, packet, lease,
1770 				    NULL, packet->options,
1771 				    NULL, &lease->scope,
1772 				    lease->on_star.on_release, NULL);
1773 		if (lease->on_star.on_release)
1774 			executable_statement_dereference
1775 				(&lease->on_star.on_release, MDL);
1776 	}
1777 
1778 	/* We do either the on_release or the on_expiry events, but
1779 	   not both (it's possible that they could be the same,
1780 	   in any case). */
1781 	if (lease->on_star.on_expiry)
1782 		executable_statement_dereference
1783 			(&lease->on_star.on_expiry, MDL);
1784 
1785 	if (lease -> binding_state != FTS_FREE &&
1786 	    lease -> binding_state != FTS_BACKUP &&
1787 	    lease -> binding_state != FTS_RELEASED &&
1788 	    lease -> binding_state != FTS_EXPIRED &&
1789 	    lease -> binding_state != FTS_RESET) {
1790 		if (lease->on_star.on_commit)
1791 			executable_statement_dereference
1792 				(&lease->on_star.on_commit, MDL);
1793 
1794 		/* Blow away any bindings. */
1795 		if (lease -> scope)
1796 			binding_scope_dereference (&lease -> scope, MDL);
1797 
1798 		/* Set sort times to the present. */
1799 		lease -> ends = cur_time;
1800 		/* Lower layers of muckery set tstp to ->ends.  But we send
1801 		 * protocol messages before this.  So it is best to set
1802 		 * tstp now anyway.
1803 		 */
1804 		lease->tstp = cur_time;
1805 #if defined (FAILOVER_PROTOCOL)
1806 		if (lease -> pool && lease -> pool -> failover_peer) {
1807 			dhcp_failover_state_t *peer = NULL;
1808 
1809 			if (lease->pool != NULL)
1810 				peer = lease->pool->failover_peer;
1811 
1812 			if ((peer->service_state == not_cooperating) &&
1813 			    (((peer->i_am == primary) &&
1814 			      (lease->rewind_binding_state == FTS_FREE)) ||
1815 			     ((peer->i_am == secondary) &&
1816 			      (lease->rewind_binding_state == FTS_BACKUP)))) {
1817 				lease->next_binding_state =
1818 						  lease->rewind_binding_state;
1819 			} else
1820 				lease -> next_binding_state = FTS_RELEASED;
1821 		} else {
1822 			lease -> next_binding_state = FTS_FREE;
1823 		}
1824 #else
1825 		lease -> next_binding_state = FTS_FREE;
1826 #endif
1827 		supersede_lease(lease, NULL, 1, 1, 1, 0);
1828 	}
1829 }
1830 
1831 /* Abandon the specified lease (set its timeout to infinity and its
1832    particulars to zero, and re-hash it as appropriate. */
1833 
abandon_lease(lease,message)1834 void abandon_lease (lease, message)
1835 	struct lease *lease;
1836 	const char *message;
1837 {
1838 	struct lease *lt = NULL;
1839 #if defined (NSUPDATE)
1840 	(void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
1841 #endif
1842 
1843 	if (!lease_copy(&lt, lease, MDL)) {
1844 		return;
1845 	}
1846 
1847 	if (lt->scope) {
1848 		binding_scope_dereference(&lt->scope, MDL);
1849 	}
1850 
1851 	/* Calculate the abandone expiry time.  If it wraps,
1852  	 * use the maximum expiry time. */
1853 	lt->ends = cur_time + abandon_lease_time;
1854 	if (lt->ends < cur_time || lt->ends > MAX_TIME) {
1855 		lt->ends = MAX_TIME;
1856 	}
1857 
1858 	lt->next_binding_state = FTS_ABANDONED;
1859 
1860 	log_error ("Abandoning IP address %s: %s", piaddr(lease->ip_addr),
1861                     message);
1862 	lt->hardware_addr.hlen = 0;
1863 	if (lt->uid && lt->uid != lt->uid_buf) {
1864 		dfree(lt->uid, MDL);
1865 	}
1866 
1867 	lt->uid = NULL;
1868 	lt->uid_len = 0;
1869 	lt->uid_max = 0;
1870 	supersede_lease(lease, lt, 1, 1, 1, 0);
1871 	lease_dereference(&lt, MDL);
1872 }
1873 
1874 #if 0
1875 /*
1876  * This doesn't appear to be in use for anything anymore.
1877  * I'm ifdeffing it now and if there are no complaints in
1878  * the future it will be removed.
1879  * SAR
1880  */
1881 
1882 /* Abandon the specified lease (set its timeout to infinity and its
1883    particulars to zero, and re-hash it as appropriate. */
1884 
1885 void dissociate_lease (lease)
1886 	struct lease *lease;
1887 {
1888 	struct lease *lt = (struct lease *)0;
1889 #if defined (NSUPDATE)
1890 	(void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
1891 #endif
1892 
1893 	if (!lease_copy (&lt, lease, MDL))
1894 		return;
1895 
1896 #if defined (FAILOVER_PROTOCOL)
1897 	if (lease -> pool && lease -> pool -> failover_peer) {
1898 		lt -> next_binding_state = FTS_RESET;
1899 	} else {
1900 		lt -> next_binding_state = FTS_FREE;
1901 	}
1902 #else
1903 	lt -> next_binding_state = FTS_FREE;
1904 #endif
1905 	lt -> ends = cur_time; /* XXX */
1906 	lt -> hardware_addr.hlen = 0;
1907 	if (lt -> uid && lt -> uid != lt -> uid_buf)
1908 		dfree (lt -> uid, MDL);
1909 	lt -> uid = (unsigned char *)0;
1910 	lt -> uid_len = 0;
1911 	lt -> uid_max = 0;
1912 	supersede_lease (lease, lt, 1, 1, 1, 0);
1913 	lease_dereference (&lt, MDL);
1914 }
1915 #endif
1916 
1917 /* Timer called when a lease in a particular pool expires. */
pool_timer(vpool)1918 void pool_timer (vpool)
1919 	void *vpool;
1920 {
1921 	struct pool *pool;
1922 	struct lease *next = NULL;
1923 	struct lease *lease = NULL;
1924 	struct lease *ltemp = NULL;
1925 #define FREE_LEASES 0
1926 #define ACTIVE_LEASES 1
1927 #define EXPIRED_LEASES 2
1928 #define ABANDONED_LEASES 3
1929 #define BACKUP_LEASES 4
1930 #define RESERVED_LEASES 5
1931 	LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
1932 	TIME next_expiry = MAX_TIME;
1933 	int i;
1934 	struct timeval tv;
1935 
1936 	pool = (struct pool *)vpool;
1937 
1938 	lptr[FREE_LEASES] = &pool->free;
1939 	lptr[ACTIVE_LEASES] = &pool->active;
1940 	lptr[EXPIRED_LEASES] = &pool->expired;
1941 	lptr[ABANDONED_LEASES] = &pool->abandoned;
1942 	lptr[BACKUP_LEASES] = &pool->backup;
1943 	lptr[RESERVED_LEASES] = &pool->reserved;
1944 
1945 	for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
1946 		/* If there's nothing on the queue, skip it. */
1947 		if (!(LEASE_NOT_EMPTYP(lptr[i])))
1948 			continue;
1949 
1950 #if defined (FAILOVER_PROTOCOL)
1951 		if (pool->failover_peer &&
1952 		    pool->failover_peer->me.state != partner_down) {
1953 			/*
1954 			 * Normally the secondary doesn't initiate expiration
1955 			 * events (unless in partner-down), but rather relies
1956 			 * on the primary to expire the lease.  However, when
1957 			 * disconnected from its peer, the server is allowed to
1958 			 * rewind a lease to the previous state that the peer
1959 			 * would have recorded it.  This means there may be
1960 			 * opportunities for active->free or active->backup
1961 			 * expirations while out of contact.
1962 			 *
1963 			 * Q: Should we limit this expiration to
1964 			 *    comms-interrupt rather than not-normal?
1965 			 */
1966 			if ((i == ACTIVE_LEASES) &&
1967 			    (pool->failover_peer->i_am == secondary) &&
1968 			    (pool->failover_peer->me.state == normal))
1969 				continue;
1970 
1971 			/* Leases in an expired state don't move to
1972 			   free because of a timeout unless we're in
1973 			   partner_down. */
1974 			if (i == EXPIRED_LEASES)
1975 				continue;
1976 		}
1977 #endif
1978 		lease_reference(&lease, LEASE_GET_FIRSTP(lptr[i]), MDL);
1979 
1980 		while (lease) {
1981 			/* Remember the next lease in the list. */
1982 			if (next)
1983 				lease_dereference(&next, MDL);
1984 			ltemp = LEASE_GET_NEXTP(lptr[i], lease);
1985 			if (ltemp)
1986 				lease_reference(&next, ltemp, MDL);
1987 
1988 			/* If we've run out of things to expire on this list,
1989 			   stop. */
1990 			if (lease->sort_time > cur_time) {
1991 				if (lease->sort_time < next_expiry)
1992 					next_expiry = lease->sort_time;
1993 				break;
1994 			}
1995 
1996 			/* If there is a pending state change, and
1997 			   this lease has gotten to the time when the
1998 			   state change should happen, just call
1999 			   supersede_lease on it to make the change
2000 			   happen. */
2001 			if (lease->next_binding_state != lease->binding_state)
2002 			{
2003 #if defined(FAILOVER_PROTOCOL)
2004 				dhcp_failover_state_t *peer = NULL;
2005 
2006 				if (lease->pool != NULL)
2007 					peer = lease->pool->failover_peer;
2008 
2009 				/* Can we rewind the lease to a free state? */
2010 				if (peer != NULL &&
2011 				    peer->service_state == not_cooperating &&
2012 				    lease->next_binding_state == FTS_EXPIRED &&
2013 				    ((peer->i_am == primary &&
2014 				      lease->rewind_binding_state == FTS_FREE)
2015 					||
2016 				     (peer->i_am == secondary &&
2017 				      lease->rewind_binding_state ==
2018 								FTS_BACKUP)))
2019 					lease->next_binding_state =
2020 						   lease->rewind_binding_state;
2021 #endif
2022 				supersede_lease(lease, NULL, 1, 1, 1, 1);
2023 			}
2024 
2025 			lease_dereference(&lease, MDL);
2026 			if (next)
2027 				lease_reference(&lease, next, MDL);
2028 		}
2029 		if (next)
2030 			lease_dereference(&next, MDL);
2031 		if (lease)
2032 			lease_dereference(&lease, MDL);
2033 	}
2034 
2035 	/* If we found something to expire and its expiration time
2036 	 * is either less than the current expiration time or the
2037 	 * current expiration time is already expired update the
2038 	 * timer.
2039 	 */
2040 	if ((next_expiry != MAX_TIME) &&
2041 	    ((pool->next_event_time > next_expiry) ||
2042 	     (pool->next_event_time <= cur_time))) {
2043 		pool->next_event_time = next_expiry;
2044 		tv.tv_sec = pool->next_event_time;
2045 		tv.tv_usec = 0;
2046 		add_timeout (&tv, pool_timer, pool,
2047 			     (tvref_t)pool_reference,
2048 			     (tvunref_t)pool_dereference);
2049 	} else
2050 		pool->next_event_time = MIN_TIME;
2051 
2052 }
2053 
2054 /* Locate the lease associated with a given IP address... */
2055 
find_lease_by_ip_addr(struct lease ** lp,struct iaddr addr,const char * file,int line)2056 int find_lease_by_ip_addr (struct lease **lp, struct iaddr addr,
2057 			   const char *file, int line)
2058 {
2059 	return lease_ip_hash_lookup(lp, lease_ip_addr_hash, addr.iabuf,
2060 				    addr.len, file, line);
2061 }
2062 
find_lease_by_uid(struct lease ** lp,const unsigned char * uid,unsigned len,const char * file,int line)2063 int find_lease_by_uid (struct lease **lp, const unsigned char *uid,
2064 		       unsigned len, const char *file, int line)
2065 {
2066 	if (len == 0)
2067 		return 0;
2068 	return lease_id_hash_lookup (lp, lease_uid_hash, uid, len, file, line);
2069 }
2070 
find_lease_by_hw_addr(struct lease ** lp,const unsigned char * hwaddr,unsigned hwlen,const char * file,int line)2071 int find_lease_by_hw_addr (struct lease **lp,
2072 			   const unsigned char *hwaddr, unsigned hwlen,
2073 			   const char *file, int line)
2074 {
2075 	if (hwlen == 0)
2076 		return (0);
2077 
2078 	/*
2079 	 * If it's an infiniband address don't bother
2080 	 * as we don't have a useful address to hash.
2081 	 */
2082 	if ((hwlen == 1) && (hwaddr[0] == HTYPE_INFINIBAND))
2083 		return (0);
2084 
2085 	return (lease_id_hash_lookup(lp, lease_hw_addr_hash, hwaddr, hwlen,
2086 				     file, line));
2087 }
2088 
2089 /* If the lease is preferred over the candidate, return truth.  The
2090  * 'cand' and 'lease' names are retained to read more clearly against
2091  * the 'uid_hash_add' and 'hw_hash_add' functions (this is common logic
2092  * to those two functions).
2093  *
2094  * 1) ACTIVE leases are preferred.  The active lease with
2095  *    the longest lifetime is preferred over shortest.
2096  * 2) "transitional states" are next, this time with the
2097  *    most recent CLTT.
2098  * 3) free/backup/etc states are next, again with CLTT.  In truth we
2099  *    should never see reset leases for this.
2100  * 4) Abandoned leases are always dead last.
2101  */
2102 static isc_boolean_t
client_lease_preferred(struct lease * cand,struct lease * lease)2103 client_lease_preferred(struct lease *cand, struct lease *lease)
2104 {
2105 	if (cand->binding_state == FTS_ACTIVE) {
2106 		if (lease->binding_state == FTS_ACTIVE &&
2107 		    lease->ends >= cand->ends)
2108 			return ISC_TRUE;
2109 	} else if (cand->binding_state == FTS_EXPIRED ||
2110 		   cand->binding_state == FTS_RELEASED) {
2111 		if (lease->binding_state == FTS_ACTIVE)
2112 			return ISC_TRUE;
2113 
2114 		if ((lease->binding_state == FTS_EXPIRED ||
2115 		     lease->binding_state == FTS_RELEASED) &&
2116 		    lease->cltt >= cand->cltt)
2117 			return ISC_TRUE;
2118 	} else if (cand->binding_state != FTS_ABANDONED) {
2119 		if (lease->binding_state == FTS_ACTIVE ||
2120 		    lease->binding_state == FTS_EXPIRED ||
2121 		    lease->binding_state == FTS_RELEASED)
2122 			return ISC_TRUE;
2123 
2124 		if (lease->binding_state != FTS_ABANDONED &&
2125 		    lease->cltt >= cand->cltt)
2126 			return ISC_TRUE;
2127 	} else /* (cand->binding_state == FTS_ABANDONED) */ {
2128 		if (lease->binding_state != FTS_ABANDONED ||
2129 		    lease->cltt >= cand->cltt)
2130 			return ISC_TRUE;
2131 	}
2132 
2133 	return ISC_FALSE;
2134 }
2135 
2136 /* Add the specified lease to the uid hash. */
2137 void
uid_hash_add(struct lease * lease)2138 uid_hash_add(struct lease *lease)
2139 {
2140 	struct lease *head = NULL;
2141 	struct lease *cand = NULL;
2142 	struct lease *prev = NULL;
2143 	struct lease *next = NULL;
2144 
2145 	/* If it's not in the hash, just add it. */
2146 	if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL))
2147 		lease_id_hash_add(lease_uid_hash, lease->uid, lease->uid_len,
2148 				  lease, MDL);
2149 	else {
2150 		/* Otherwise, insert it into the list in order of its
2151 		 * preference for "resuming allocation to the client."
2152 		 *
2153 		 * Because we don't have control of the hash bucket index
2154 		 * directly, we have to remove and re-insert the client
2155 		 * id into the hash if we're inserting onto the head.
2156 		 */
2157 		lease_reference(&cand, head, MDL);
2158 		while (cand != NULL) {
2159 			if (client_lease_preferred(cand, lease))
2160 				break;
2161 
2162 			if (prev != NULL)
2163 				lease_dereference(&prev, MDL);
2164 			lease_reference(&prev, cand, MDL);
2165 
2166 			if (cand->n_uid != NULL)
2167 				lease_reference(&next, cand->n_uid, MDL);
2168 
2169 			lease_dereference(&cand, MDL);
2170 
2171 			if (next != NULL) {
2172 				lease_reference(&cand, next, MDL);
2173 				lease_dereference(&next, MDL);
2174 			}
2175 		}
2176 
2177 		/* If we want to insert 'before cand', and prev is NULL,
2178 		 * then it was the head of the list.  Assume that position.
2179 		 */
2180 		if (prev == NULL) {
2181 			lease_reference(&lease->n_uid, head, MDL);
2182 			lease_id_hash_delete(lease_uid_hash, lease->uid,
2183 					     lease->uid_len, MDL);
2184 			lease_id_hash_add(lease_uid_hash, lease->uid,
2185 					  lease->uid_len, lease, MDL);
2186 		} else /* (prev != NULL) */ {
2187 			if(prev->n_uid != NULL) {
2188 				lease_reference(&lease->n_uid, prev->n_uid,
2189 						MDL);
2190 				lease_dereference(&prev->n_uid, MDL);
2191 			}
2192 			lease_reference(&prev->n_uid, lease, MDL);
2193 
2194 			lease_dereference(&prev, MDL);
2195 		}
2196 
2197 		if (cand != NULL)
2198 			lease_dereference(&cand, MDL);
2199 		lease_dereference(&head, MDL);
2200 	}
2201 }
2202 
2203 /* Delete the specified lease from the uid hash. */
2204 
uid_hash_delete(lease)2205 void uid_hash_delete (lease)
2206 	struct lease *lease;
2207 {
2208 	struct lease *head = (struct lease *)0;
2209 	struct lease *scan;
2210 
2211 	/* If it's not in the hash, we have no work to do. */
2212 	if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL)) {
2213 		if (lease -> n_uid)
2214 			lease_dereference (&lease -> n_uid, MDL);
2215 		return;
2216 	}
2217 
2218 	/* If the lease we're freeing is at the head of the list,
2219 	   remove the hash table entry and add a new one with the
2220 	   next lease on the list (if there is one). */
2221 	if (head == lease) {
2222 		lease_id_hash_delete(lease_uid_hash, lease->uid,
2223 				     lease->uid_len, MDL);
2224 		if (lease -> n_uid) {
2225 			lease_id_hash_add(lease_uid_hash, lease->n_uid->uid,
2226 					  lease->n_uid->uid_len, lease->n_uid,
2227 					  MDL);
2228 			lease_dereference (&lease -> n_uid, MDL);
2229 		}
2230 	} else {
2231 		/* Otherwise, look for the lease in the list of leases
2232 		   attached to the hash table entry, and remove it if
2233 		   we find it. */
2234 		for (scan = head; scan -> n_uid; scan = scan -> n_uid) {
2235 			if (scan -> n_uid == lease) {
2236 				lease_dereference (&scan -> n_uid, MDL);
2237 				if (lease -> n_uid) {
2238 					lease_reference (&scan -> n_uid,
2239 							 lease -> n_uid, MDL);
2240 					lease_dereference (&lease -> n_uid,
2241 							   MDL);
2242 				}
2243 				break;
2244 			}
2245 		}
2246 	}
2247 	lease_dereference (&head, MDL);
2248 }
2249 
2250 /* Add the specified lease to the hardware address hash. */
2251 /* We don't add leases with infiniband addresses to the
2252  * hash as there isn't any address to hash on. */
2253 
2254 void
hw_hash_add(struct lease * lease)2255 hw_hash_add(struct lease *lease)
2256 {
2257 	struct lease *head = NULL;
2258 	struct lease *cand = NULL;
2259 	struct lease *prev = NULL;
2260 	struct lease *next = NULL;
2261 
2262 	/*
2263 	 * If it's an infiniband address don't bother
2264 	 * as we don't have a useful address to hash.
2265 	 */
2266 	if ((lease->hardware_addr.hlen == 1) &&
2267 	    (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
2268 		return;
2269 
2270 	/* If it's not in the hash, just add it. */
2271 	if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
2272 				    lease -> hardware_addr.hlen, MDL))
2273 		lease_id_hash_add(lease_hw_addr_hash,
2274 				  lease->hardware_addr.hbuf,
2275 				  lease->hardware_addr.hlen, lease, MDL);
2276 	else {
2277 		/* Otherwise, insert it into the list in order of its
2278 		 * preference for "resuming allocation to the client."
2279 		 *
2280 		 * Because we don't have control of the hash bucket index
2281 		 * directly, we have to remove and re-insert the client
2282 		 * id into the hash if we're inserting onto the head.
2283 		 */
2284 		lease_reference(&cand, head, MDL);
2285 		while (cand != NULL) {
2286 			if (client_lease_preferred(cand, lease))
2287 				break;
2288 
2289 			if (prev != NULL)
2290 				lease_dereference(&prev, MDL);
2291 			lease_reference(&prev, cand, MDL);
2292 
2293 			if (cand->n_hw != NULL)
2294 				lease_reference(&next, cand->n_hw, MDL);
2295 
2296 			lease_dereference(&cand, MDL);
2297 
2298 			if (next != NULL) {
2299 				lease_reference(&cand, next, MDL);
2300 				lease_dereference(&next, MDL);
2301 			}
2302 		}
2303 
2304 		/* If we want to insert 'before cand', and prev is NULL,
2305 		 * then it was the head of the list.  Assume that position.
2306 		 */
2307 		if (prev == NULL) {
2308 			lease_reference(&lease->n_hw, head, MDL);
2309 			lease_id_hash_delete(lease_hw_addr_hash,
2310 					     lease->hardware_addr.hbuf,
2311 					     lease->hardware_addr.hlen, MDL);
2312 			lease_id_hash_add(lease_hw_addr_hash,
2313 					  lease->hardware_addr.hbuf,
2314 					  lease->hardware_addr.hlen,
2315 					  lease, MDL);
2316 		} else /* (prev != NULL) */ {
2317 			if(prev->n_hw != NULL) {
2318 				lease_reference(&lease->n_hw, prev->n_hw,
2319 						MDL);
2320 				lease_dereference(&prev->n_hw, MDL);
2321 			}
2322 			lease_reference(&prev->n_hw, lease, MDL);
2323 
2324 			lease_dereference(&prev, MDL);
2325 		}
2326 
2327 		if (cand != NULL)
2328 			lease_dereference(&cand, MDL);
2329 		lease_dereference(&head, MDL);
2330 	}
2331 }
2332 
2333 /* Delete the specified lease from the hardware address hash. */
2334 
hw_hash_delete(lease)2335 void hw_hash_delete (lease)
2336 	struct lease *lease;
2337 {
2338 	struct lease *head = (struct lease *)0;
2339 	struct lease *next = (struct lease *)0;
2340 
2341 	/*
2342 	 * If it's an infiniband address don't bother
2343 	 * as we don't have a useful address to hash.
2344 	 */
2345 	if ((lease->hardware_addr.hlen == 1) &&
2346 	    (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
2347 		return;
2348 
2349 	/* If it's not in the hash, we have no work to do. */
2350 	if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
2351 				    lease -> hardware_addr.hlen, MDL)) {
2352 		if (lease -> n_hw)
2353 			lease_dereference (&lease -> n_hw, MDL);
2354 		return;
2355 	}
2356 
2357 	/* If the lease we're freeing is at the head of the list,
2358 	   remove the hash table entry and add a new one with the
2359 	   next lease on the list (if there is one). */
2360 	if (head == lease) {
2361 		lease_id_hash_delete(lease_hw_addr_hash,
2362 				     lease->hardware_addr.hbuf,
2363 				     lease->hardware_addr.hlen, MDL);
2364 		if (lease->n_hw) {
2365 			lease_id_hash_add(lease_hw_addr_hash,
2366 					  lease->n_hw->hardware_addr.hbuf,
2367 					  lease->n_hw->hardware_addr.hlen,
2368 					  lease->n_hw, MDL);
2369 			lease_dereference(&lease->n_hw, MDL);
2370 		}
2371 	} else {
2372 		/* Otherwise, look for the lease in the list of leases
2373 		   attached to the hash table entry, and remove it if
2374 		   we find it. */
2375 		while (head -> n_hw) {
2376 			if (head -> n_hw == lease) {
2377 				lease_dereference (&head -> n_hw, MDL);
2378 				if (lease -> n_hw) {
2379 					lease_reference (&head -> n_hw,
2380 							 lease -> n_hw, MDL);
2381 					lease_dereference (&lease -> n_hw,
2382 							   MDL);
2383 				}
2384 				break;
2385 			}
2386 			lease_reference (&next, head -> n_hw, MDL);
2387 			lease_dereference (&head, MDL);
2388 			lease_reference (&head, next, MDL);
2389 			lease_dereference (&next, MDL);
2390 		}
2391 	}
2392 	if (head)
2393 		lease_dereference (&head, MDL);
2394 }
2395 
2396 /* Write v4 leases to permanent storage. */
write_leases4(void)2397 static int write_leases4(void) {
2398 	struct lease *l;
2399 	struct shared_network *s;
2400 	struct pool *p;
2401 	LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
2402 	int num_written = 0, i;
2403 
2404 	/* Write all the leases. */
2405 	for (s = shared_networks; s; s = s->next) {
2406 	    for (p = s->pools; p; p = p->next) {
2407 		lptr[FREE_LEASES] = &p->free;
2408 		lptr[ACTIVE_LEASES] = &p->active;
2409 		lptr[EXPIRED_LEASES] = &p->expired;
2410 		lptr[ABANDONED_LEASES] = &p->abandoned;
2411 		lptr[BACKUP_LEASES] = &p->backup;
2412 		lptr[RESERVED_LEASES] = &p->reserved;
2413 
2414 		for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
2415 		    for (l = LEASE_GET_FIRSTP(lptr[i]);
2416 			 l != NULL;
2417 			 l = LEASE_GET_NEXTP(lptr[i], l)) {
2418 #if !defined (DEBUG_DUMP_ALL_LEASES)
2419 			if (l->hardware_addr.hlen != 0 || l->uid_len != 0 ||
2420 			    l->tsfp != 0 || l->binding_state != FTS_FREE)
2421 #endif
2422 			{
2423 			    if (write_lease(l) == 0)
2424 				    return (0);
2425 			    num_written++;
2426 			}
2427 		    }
2428 		}
2429 	    }
2430 	}
2431 
2432 	log_info ("Wrote %d leases to leases file.", num_written);
2433 	return (1);
2434 }
2435 
2436 /* Write all interesting leases to permanent storage. */
2437 
write_leases()2438 int write_leases ()
2439 {
2440 	struct host_decl *hp;
2441 	struct group_object *gp;
2442 	struct hash_bucket *hb;
2443 	struct class *cp;
2444 	struct collection *colp;
2445 	int i;
2446 	int num_written;
2447 
2448 	/* write all the dynamically-created class declarations. */
2449 	if (collections->classes) {
2450 		numclasseswritten = 0;
2451 		for (colp = collections ; colp ; colp = colp->next) {
2452 			for (cp = colp->classes ; cp ; cp = cp->nic) {
2453 				write_named_billing_class(
2454 						(unsigned char *)cp->name,
2455 							  0, cp);
2456 			}
2457 		}
2458 
2459 		/* XXXJAB this number doesn't include subclasses... */
2460 		log_info ("Wrote %d class decls to leases file.",
2461 			  numclasseswritten);
2462 	}
2463 
2464 
2465 	/* Write all the dynamically-created group declarations. */
2466 	if (group_name_hash) {
2467 	    num_written = 0;
2468 	    for (i = 0; i < group_name_hash -> hash_count; i++) {
2469 		for (hb = group_name_hash -> buckets [i];
2470 		     hb; hb = hb -> next) {
2471 			gp = (struct group_object *)hb -> value;
2472 			if ((gp -> flags & GROUP_OBJECT_DYNAMIC) ||
2473 			    ((gp -> flags & GROUP_OBJECT_STATIC) &&
2474 			     (gp -> flags & GROUP_OBJECT_DELETED))) {
2475 				if (!write_group (gp))
2476 					return 0;
2477 				++num_written;
2478 			}
2479 		}
2480 	    }
2481 	    log_info ("Wrote %d group decls to leases file.", num_written);
2482 	}
2483 
2484 	/* Write all the deleted host declarations. */
2485 	if (host_name_hash) {
2486 	    num_written = 0;
2487 	    for (i = 0; i < host_name_hash -> hash_count; i++) {
2488 		for (hb = host_name_hash -> buckets [i];
2489 		     hb; hb = hb -> next) {
2490 			hp = (struct host_decl *)hb -> value;
2491 			if (((hp -> flags & HOST_DECL_STATIC) &&
2492 			     (hp -> flags & HOST_DECL_DELETED))) {
2493 				if (!write_host (hp))
2494 					return 0;
2495 				++num_written;
2496 			}
2497 		}
2498 	    }
2499 	    log_info ("Wrote %d deleted host decls to leases file.",
2500 		      num_written);
2501 	}
2502 
2503 	/* Write all the new, dynamic host declarations. */
2504 	if (host_name_hash) {
2505 	    num_written = 0;
2506 	    for (i = 0; i < host_name_hash -> hash_count; i++) {
2507 		for (hb = host_name_hash -> buckets [i];
2508 		     hb; hb = hb -> next) {
2509 			hp = (struct host_decl *)hb -> value;
2510 			if ((hp -> flags & HOST_DECL_DYNAMIC)) {
2511 				if (!write_host (hp))
2512 					++num_written;
2513 			}
2514 		}
2515 	    }
2516 	    log_info ("Wrote %d new dynamic host decls to leases file.",
2517 		      num_written);
2518 	}
2519 
2520 #if defined (FAILOVER_PROTOCOL)
2521 	/* Write all the failover states. */
2522 	if (!dhcp_failover_write_all_states ())
2523 		return 0;
2524 #endif
2525 
2526 	switch (local_family) {
2527 	      case AF_INET:
2528 		if (write_leases4() == 0)
2529 			return (0);
2530 		break;
2531 #ifdef DHCPv6
2532 	      case AF_INET6:
2533 		if (write_leases6() == 0)
2534 			return (0);
2535 		break;
2536 #endif /* DHCPv6 */
2537 	}
2538 
2539 	if (commit_leases() == 0)
2540 		return (0);
2541 	return (1);
2542 }
2543 
2544 #if !defined (BINARY_LEASES)
2545 /* Unlink all the leases in the queue. */
lease_remove_all(struct lease ** lq)2546 void lease_remove_all(struct lease **lq) {
2547 	struct lease *lp, *ln = NULL;
2548 
2549 	/* nothing to do */
2550 	if (*lq == NULL)
2551 		return;
2552 
2553 	/* We simply derefernce the first item in the list.  When
2554 	 * it's reference counter goes to zero it will be cleaned
2555 	 * and the reference counter
2556 	 *
2557 	 * Get a pointer to the first item in the list and then
2558 	 * drop the reference from the queue pointer
2559 	 */
2560 	lease_reference(&lp, *lq, MDL);
2561 	lease_dereference(lq, MDL);
2562 
2563 	do {
2564 		/* if we have a next save a pointer to it and unlink it */
2565 		if (lp->next) {
2566 			lease_reference(&ln, lp->next, MDL);
2567 			lease_dereference(&lp->next, MDL);
2568 		}
2569 
2570 		/* get rid of what we currently have */
2571 		lease_dereference(&lp, MDL);
2572 
2573 		/* move the next to the current and loop */
2574 		lp = ln;
2575 		ln = NULL;
2576 	} while (lp != NULL);
2577 }
2578 
2579 /*
2580  * This routine walks through a given lease queue (lq) looking
2581  * for comp.  If it doesn't find the lease it is a fatal error
2582  * as it should be on the given queue.  Once we find the lease
2583  * we can remove it from this list.
2584  */
lease_remove(struct lease ** lq,struct lease * comp)2585 void lease_remove(struct lease **lq, struct lease *comp)
2586 {
2587 	struct lease *prev, *lp;
2588 
2589 	prev = NULL;
2590 	for (lp = *lq; lp != NULL; lp = lp->next) {
2591 		if (lp == comp)
2592 			break;
2593 		prev = lp;
2594 	}
2595 
2596 	if (!lp) {
2597 		log_fatal("Lease with binding state %s not on its queue.",
2598 			  (comp->binding_state < 1 ||
2599 			   comp->binding_state > FTS_LAST)
2600 			  ? "unknown"
2601 			  : binding_state_names[comp->binding_state - 1]);
2602 	}
2603 
2604 	if (prev) {
2605 		lease_dereference(&prev->next, MDL);
2606 		if (comp->next) {
2607 			lease_reference(&prev->next, comp->next, MDL);
2608 			lease_dereference (&comp->next, MDL);
2609 		}
2610 	} else {
2611 		lease_dereference(lq, MDL);
2612 		if (comp->next) {
2613 			lease_reference(lq, comp->next, MDL);
2614 			lease_dereference(&comp->next, MDL);
2615 		}
2616 	}
2617 }
2618 
2619 /* This routine inserts comp into lq in a sorted fashion.
2620  * The sort key is comp->sort_time, smaller values are
2621  * placed earlier in the list.
2622  */
lease_insert(struct lease ** lq,struct lease * comp)2623 void lease_insert(struct lease **lq, struct lease *comp)
2624 {
2625 	struct lease *prev, *lp;
2626 	static struct lease **last_lq = NULL;
2627 	static struct lease *last_insert_point = NULL;
2628 
2629 	/* This only works during server startup: during runtime, the last
2630 	 * lease may be dequeued in between calls.  If the queue is the same
2631 	 * as was used previously, and the lease structure isn't (this is not
2632 	 * a re-queue), use that as a starting point for the insertion-sort.
2633 	 */
2634 	if ((server_starting & SS_QFOLLOW) && (lq == last_lq) &&
2635 	    (comp != last_insert_point) &&
2636 	    (last_insert_point->sort_time <= comp->sort_time)) {
2637 		prev = last_insert_point;
2638 		lp = prev->next;
2639 	} else {
2640 		prev = NULL;
2641 		lp = *lq;
2642 	}
2643 
2644 	/* Insertion sort the lease onto the appropriate queue. */
2645 	for (; lp != NULL ; lp = lp->next) {
2646 		if (lp->sort_time >= comp->sort_time)
2647 			break;
2648 		prev = lp;
2649 	}
2650 
2651 	if (prev) {
2652 		if (prev->next) {
2653 			lease_reference(&comp->next, prev->next, MDL);
2654 			lease_dereference(&prev->next, MDL);
2655 		}
2656 		lease_reference(&prev->next, comp, MDL);
2657 	} else {
2658 		if (*lq) {
2659 			lease_reference (&comp->next, *lq, MDL);
2660 			lease_dereference(lq, MDL);
2661 		}
2662 		lease_reference(lq, comp, MDL);
2663 	}
2664 	last_insert_point = comp;
2665 	last_lq = lq;
2666 
2667 	return;
2668 }
2669 #endif
2670 
2671 /* In addition to placing this lease upon a lease queue depending on its
2672  * state, it also keeps track of the number of FREE and BACKUP leases in
2673  * existence, and sets the sort_time on the lease.
2674  *
2675  * Sort_time is used in pool_timer() to determine when the lease will
2676  * bubble to the top of the list and be supersede_lease()'d into its next
2677  * state (possibly, if all goes well).  Example, ACTIVE leases move to
2678  * EXPIRED state when the 'ends' value is reached, so that is its sort
2679  * time.  Most queues are sorted by 'ends', since it is generally best
2680  * practice to re-use the oldest lease, to reduce address collision
2681  * chances.
2682  */
lease_enqueue(struct lease * comp)2683 int lease_enqueue (struct lease *comp)
2684 {
2685 	LEASE_STRUCT_PTR lq;
2686 
2687 	/* No queue to put it on? */
2688 	if (!comp -> pool)
2689 		return 0;
2690 
2691 	/* Figure out which queue it's going to. */
2692 	switch (comp -> binding_state) {
2693 	      case FTS_FREE:
2694 		if (comp->flags & RESERVED_LEASE) {
2695 			lq = &comp->pool->reserved;
2696 		} else {
2697 			lq = &comp->pool->free;
2698 			comp->pool->free_leases++;
2699 		}
2700 		comp -> sort_time = comp -> ends;
2701 		break;
2702 
2703 	      case FTS_ACTIVE:
2704 		lq = &comp -> pool -> active;
2705 		comp -> sort_time = comp -> ends;
2706 		break;
2707 
2708 	      case FTS_EXPIRED:
2709 	      case FTS_RELEASED:
2710 	      case FTS_RESET:
2711 		lq = &comp -> pool -> expired;
2712 #if defined(FAILOVER_PROTOCOL)
2713 		/* In partner_down, tsfp is the time at which the lease
2714 		 * may be reallocated (stos+mclt).  We can do that with
2715 		 * lease_mine_to_reallocate() anywhere between tsfp and
2716 		 * ends.  But we prefer to wait until ends before doing it
2717 		 * automatically (choose the greater of the two).  Note
2718 		 * that 'ends' is usually a historic timestamp in the
2719 		 * case of expired leases, is really only in the future
2720 		 * on released leases, and if we know a lease to be released
2721 		 * the peer might still know it to be active...in which case
2722 		 * it's possible the peer has renewed this lease, so avoid
2723 		 * doing that.
2724 		 */
2725 		if (comp->pool->failover_peer &&
2726 		    comp->pool->failover_peer->me.state == partner_down)
2727 			comp->sort_time = (comp->tsfp > comp->ends) ?
2728 					  comp->tsfp : comp->ends;
2729 		else
2730 #endif
2731 			comp->sort_time = comp->ends;
2732 
2733 		break;
2734 
2735 	      case FTS_ABANDONED:
2736 		lq = &comp -> pool -> abandoned;
2737 		comp -> sort_time = comp -> ends;
2738 		break;
2739 
2740 	      case FTS_BACKUP:
2741 		if (comp->flags & RESERVED_LEASE) {
2742 			lq = &comp->pool->reserved;
2743 		} else {
2744 			lq = &comp->pool->backup;
2745 			comp->pool->backup_leases++;
2746 		}
2747 		comp -> sort_time = comp -> ends;
2748 		break;
2749 
2750 	      default:
2751 		log_error ("Lease with bogus binding state: %d",
2752 			   comp -> binding_state);
2753 #if defined (BINDING_STATE_DEBUG)
2754 		abort ();
2755 #endif
2756 		return 0;
2757 	}
2758 
2759 	LEASE_INSERTP(lq, comp);
2760 
2761 	return 1;
2762 }
2763 
2764 /* For a given lease, sort it onto the right list in its pool and put it
2765    in each appropriate hash, understanding that it's already by definition
2766    in lease_ip_addr_hash. */
2767 
2768 isc_result_t
lease_instantiate(const void * key,unsigned len,void * object)2769 lease_instantiate(const void *key, unsigned len, void *object)
2770 {
2771 	struct lease *lease = object;
2772 	struct class *class;
2773 	/* XXX If the lease doesn't have a pool at this point, it's an
2774 	   XXX orphan, which we *should* keep around until it expires,
2775 	   XXX but which right now we just forget. */
2776 	if (!lease -> pool) {
2777 		lease_ip_hash_delete(lease_ip_addr_hash, lease->ip_addr.iabuf,
2778 				     lease->ip_addr.len, MDL);
2779 		return ISC_R_SUCCESS;
2780 	}
2781 
2782 #if defined (FAILOVER_PROTOCOL)
2783 	/* If the lease is in FTS_BACKUP but there is no peer, then the
2784  	 * pool must have been formerly configured for failover and
2785  	 * is now configured as standalone. This means we need to
2786  	 * move the lease to FTS_FREE to make it available. */
2787 	if ((lease->binding_state == FTS_BACKUP) &&
2788 	    (lease->pool->failover_peer == NULL)) {
2789 #else
2790 	/* We aren't compiled for failover, so just move to FTS_FREE */
2791 	if (lease->binding_state == FTS_BACKUP) {
2792 #endif
2793 		lease->binding_state = FTS_FREE;
2794 		lease->next_binding_state = FTS_FREE;
2795 		lease->rewind_binding_state = FTS_FREE;
2796 	}
2797 
2798 	/* Put the lease on the right queue.  Failure to queue is probably
2799 	 * due to a bogus binding state.  In such a case, we claim success,
2800 	 * so that later leases in a hash_foreach are processed, but we
2801 	 * return early as we really don't want hw address hash entries or
2802 	 * other cruft to surround such a bogus entry.
2803 	 */
2804 	if (!lease_enqueue(lease))
2805 		return ISC_R_SUCCESS;
2806 
2807 	/* Record the lease in the uid hash if possible. */
2808 	if (lease -> uid) {
2809 		uid_hash_add (lease);
2810 	}
2811 
2812 	/* Record it in the hardware address hash if possible. */
2813 	if (lease -> hardware_addr.hlen) {
2814 		hw_hash_add (lease);
2815 	}
2816 
2817 	/* If the lease has a billing class, set up the billing. */
2818 	if (lease -> billing_class) {
2819 		class = (struct class *)0;
2820 		class_reference (&class, lease -> billing_class, MDL);
2821 		class_dereference (&lease -> billing_class, MDL);
2822 		/* If the lease is available for allocation, the billing
2823 		   is invalid, so we don't keep it. */
2824 		if (lease -> binding_state == FTS_ACTIVE ||
2825 		    lease -> binding_state == FTS_EXPIRED ||
2826 		    lease -> binding_state == FTS_RELEASED ||
2827 		    lease -> binding_state == FTS_RESET)
2828 			bill_class (lease, class);
2829 		class_dereference (&class, MDL);
2830 	}
2831 	return ISC_R_SUCCESS;
2832 }
2833 
2834 /* Run expiry events on every pool.   This is called on startup so that
2835    any expiry events that occurred after the server stopped and before it
2836    was restarted can be run.   At the same time, if failover support is
2837    compiled in, we compute the balance of leases for the pool. */
2838 
2839 void expire_all_pools ()
2840 {
2841 	struct shared_network *s;
2842 	struct pool *p;
2843 	int i;
2844 	struct lease *l;
2845 	LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
2846 
2847 	/* Indicate that we are in the startup phase */
2848 	server_starting = SS_NOSYNC | SS_QFOLLOW;
2849 
2850 #if defined (BINARY_LEASES)
2851 	/* set up the growth factors for the binary leases.
2852 	 * We use 100% for free, 50% for active and backup
2853 	 * 20% for expired, abandoned and reserved
2854 	 * but no less than 100, 50, and 20.
2855 	 */
2856 	for (s = shared_networks; s; s = s -> next) {
2857 	    for (p = s -> pools; p != NULL; p = p -> next) {
2858 		size_t num_f = 100, num_a = 50, num_e = 20;
2859 		if (p->lease_count > 100) {
2860 		    num_f = p->lease_count;
2861 		    num_a = num_f / 2;
2862 		    num_e = num_f / 5;
2863 		}
2864 		lc_init_growth(&p->free, num_f);
2865 		lc_init_growth(&p->active, num_a);
2866 		lc_init_growth(&p->expired, num_a);
2867 		lc_init_growth(&p->abandoned, num_e);
2868 		lc_init_growth(&p->backup, num_e);
2869 		lc_init_growth(&p->reserved, num_e);
2870 	    }
2871 	}
2872 #endif
2873 
2874 	/* First, go over the hash list and actually put all the leases
2875 	   on the appropriate lists. */
2876 	lease_ip_hash_foreach(lease_ip_addr_hash, lease_instantiate);
2877 
2878 	/* Loop through each pool in each shared network and call the
2879 	 * expiry routine on the pool.  It is no longer safe to follow
2880 	 * the queue insertion point, as expiration of a lease can move
2881 	 * it between queues (and this may be the lease that function
2882 	 * points at).
2883 	 */
2884 	server_starting &= ~SS_QFOLLOW;
2885 	for (s = shared_networks; s; s = s -> next) {
2886 	    for (p = s -> pools; p; p = p -> next) {
2887 		pool_timer (p);
2888 
2889 		p -> lease_count = 0;
2890 		p -> free_leases = 0;
2891 		p -> backup_leases = 0;
2892 
2893 		lptr [FREE_LEASES] = &p -> free;
2894 		lptr [ACTIVE_LEASES] = &p -> active;
2895 		lptr [EXPIRED_LEASES] = &p -> expired;
2896 		lptr [ABANDONED_LEASES] = &p -> abandoned;
2897 		lptr [BACKUP_LEASES] = &p -> backup;
2898 		lptr [RESERVED_LEASES] = &p->reserved;
2899 
2900 		for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
2901 		    for (l = LEASE_GET_FIRSTP(lptr[i]);
2902 			 l != NULL;
2903 			 l = LEASE_GET_NEXTP(lptr[i], l)) {
2904 			p -> lease_count++;
2905 			if (l -> ends <= cur_time) {
2906 				if (l->binding_state == FTS_FREE) {
2907 					if (i == FREE_LEASES)
2908 						p->free_leases++;
2909 					else if (i != RESERVED_LEASES)
2910 						log_fatal("Impossible case "
2911 							  "at %s:%d.", MDL);
2912 				} else if (l->binding_state == FTS_BACKUP) {
2913 					if (i == BACKUP_LEASES)
2914 						p->backup_leases++;
2915 					else if (i != RESERVED_LEASES)
2916 						log_fatal("Impossible case "
2917 							  "at %s:%d.", MDL);
2918 				}
2919 			}
2920 #if defined (FAILOVER_PROTOCOL)
2921 			if (p -> failover_peer &&
2922 			    l -> tstp > l -> atsfp &&
2923 			    !(l -> flags & ON_UPDATE_QUEUE)) {
2924 				l -> desired_binding_state = l -> binding_state;
2925 				dhcp_failover_queue_update (l, 1);
2926 			}
2927 #endif
2928 		    }
2929 		}
2930 	    }
2931 	}
2932 
2933 	/* turn off startup phase */
2934 	server_starting = 0;
2935 }
2936 
2937 void dump_subnets ()
2938 {
2939 	struct lease *l;
2940 	struct shared_network *s;
2941 	struct subnet *n;
2942 	struct pool *p;
2943 	LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
2944 	int i;
2945 
2946 	log_info ("Subnets:");
2947 	for (n = subnets; n; n = n -> next_subnet) {
2948 		log_debug ("  Subnet %s", piaddr (n -> net));
2949 		log_debug ("     netmask %s",
2950 		       piaddr (n -> netmask));
2951 	}
2952 	log_info ("Shared networks:");
2953 	for (s = shared_networks; s; s = s -> next) {
2954 	    log_info ("  %s", s -> name);
2955 	    for (p = s -> pools; p; p = p -> next) {
2956 		lptr [FREE_LEASES] = &p -> free;
2957 		lptr [ACTIVE_LEASES] = &p -> active;
2958 		lptr [EXPIRED_LEASES] = &p -> expired;
2959 		lptr [ABANDONED_LEASES] = &p -> abandoned;
2960 		lptr [BACKUP_LEASES] = &p -> backup;
2961 		lptr [RESERVED_LEASES] = &p->reserved;
2962 
2963 		for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
2964 		    for (l = LEASE_GET_FIRSTP(lptr[i]);
2965 			 l != NULL;
2966 			 l = LEASE_GET_NEXTP(lptr[i], l)) {
2967 			    print_lease (l);
2968 		    }
2969 		}
2970 	    }
2971 	}
2972 }
2973 
2974 HASH_FUNCTIONS(lease_ip, const unsigned char *, struct lease, lease_ip_hash_t,
2975 	       lease_reference, lease_dereference, do_ip4_hash)
2976 HASH_FUNCTIONS(lease_id, const unsigned char *, struct lease, lease_id_hash_t,
2977 	       lease_reference, lease_dereference, do_id_hash)
2978 HASH_FUNCTIONS (host, const unsigned char *, struct host_decl, host_hash_t,
2979 		host_reference, host_dereference, do_string_hash)
2980 HASH_FUNCTIONS (class, const char *, struct class, class_hash_t,
2981 		class_reference, class_dereference, do_string_hash)
2982 
2983 #if defined (DEBUG_MEMORY_LEAKAGE) && \
2984 		defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
2985 extern struct hash_table *dns_zone_hash;
2986 extern struct interface_info **interface_vector;
2987 extern int interface_count;
2988 dhcp_control_object_t *dhcp_control_object;
2989 extern struct hash_table *auth_key_hash;
2990 struct hash_table *universe_hash;
2991 struct universe **universes;
2992 int universe_count, universe_max;
2993 #if 0
2994 extern int end;
2995 #endif
2996 
2997 #if defined (COMPACT_LEASES)
2998 extern struct lease *lease_hunks;
2999 #endif
3000 
3001 void free_everything(void)
3002 {
3003 	struct subnet *sc = (struct subnet *)0, *sn = (struct subnet *)0;
3004 	struct shared_network *nc = (struct shared_network *)0,
3005 		*nn = (struct shared_network *)0;
3006 	struct pool *pc = (struct pool *)0, *pn = (struct pool *)0;
3007 	struct lease *lc = NULL, *ln = NULL,  *ltemp = NULL;
3008 	struct interface_info *ic = (struct interface_info *)0,
3009 		*in = (struct interface_info *)0;
3010 	struct class *cc = (struct class *)0, *cn = (struct class *)0;
3011 	struct collection *lp;
3012 	int i;
3013 
3014 	/* Get rid of all the hash tables. */
3015 	if (host_hw_addr_hash)
3016 		host_free_hash_table (&host_hw_addr_hash, MDL);
3017 	host_hw_addr_hash = 0;
3018 	if (host_uid_hash)
3019 		host_free_hash_table (&host_uid_hash, MDL);
3020 	host_uid_hash = 0;
3021 	if (lease_uid_hash)
3022 		lease_id_free_hash_table (&lease_uid_hash, MDL);
3023 	lease_uid_hash = 0;
3024 	if (lease_ip_addr_hash)
3025 		lease_ip_free_hash_table (&lease_ip_addr_hash, MDL);
3026 	lease_ip_addr_hash = 0;
3027 	if (lease_hw_addr_hash)
3028 		lease_id_free_hash_table (&lease_hw_addr_hash, MDL);
3029 	lease_hw_addr_hash = 0;
3030 	if (host_name_hash)
3031 		host_free_hash_table (&host_name_hash, MDL);
3032 	host_name_hash = 0;
3033 	if (dns_zone_hash)
3034 		dns_zone_free_hash_table (&dns_zone_hash, MDL);
3035 	dns_zone_hash = 0;
3036 
3037 	while (host_id_info != NULL) {
3038 		host_id_info_t *tmp;
3039 		option_dereference(&host_id_info->option, MDL);
3040 		host_free_hash_table(&host_id_info->values_hash, MDL);
3041 		tmp = host_id_info->next;
3042 		dfree(host_id_info, MDL);
3043 		host_id_info = tmp;
3044 	}
3045 #if 0
3046 	if (auth_key_hash)
3047 		auth_key_free_hash_table (&auth_key_hash, MDL);
3048 #endif
3049 	auth_key_hash = 0;
3050 
3051 	omapi_object_dereference ((omapi_object_t **)&dhcp_control_object,
3052 				  MDL);
3053 
3054 	for (lp = collections; lp; lp = lp -> next) {
3055 	    if (lp -> classes) {
3056 		class_reference (&cn, lp -> classes, MDL);
3057 		do {
3058 		    if (cn) {
3059 			class_reference (&cc, cn, MDL);
3060 			class_dereference (&cn, MDL);
3061 		    }
3062 		    if (cc -> nic) {
3063 			class_reference (&cn, cc -> nic, MDL);
3064 			class_dereference (&cc -> nic, MDL);
3065 		    }
3066 		    group_dereference (&cc -> group, MDL);
3067 		    if (cc -> hash) {
3068 			    class_free_hash_table (&cc -> hash, MDL);
3069 			    cc -> hash = (struct hash_table *)0;
3070 		    }
3071 		    class_dereference (&cc, MDL);
3072 		} while (cn);
3073 		class_dereference (&lp -> classes, MDL);
3074 	    }
3075 	}
3076 
3077 	if (interface_vector) {
3078 	    for (i = 0; i < interface_count; i++) {
3079 		if (interface_vector [i])
3080 		    interface_dereference (&interface_vector [i], MDL);
3081 	    }
3082 	    dfree (interface_vector, MDL);
3083 	    interface_vector = 0;
3084 	}
3085 
3086 	if (interfaces) {
3087 	    interface_reference (&in, interfaces, MDL);
3088 	    do {
3089 		if (in) {
3090 		    interface_reference (&ic, in, MDL);
3091 		    interface_dereference (&in, MDL);
3092 		}
3093 		if (ic -> next) {
3094 		    interface_reference (&in, ic -> next, MDL);
3095 		    interface_dereference (&ic -> next, MDL);
3096 		}
3097 		omapi_unregister_io_object ((omapi_object_t *)ic);
3098 		if (ic -> shared_network) {
3099 		    if (ic -> shared_network -> interface)
3100 			interface_dereference
3101 				(&ic -> shared_network -> interface, MDL);
3102 		    shared_network_dereference (&ic -> shared_network, MDL);
3103 		}
3104 		interface_dereference (&ic, MDL);
3105 	    } while (in);
3106 	    interface_dereference (&interfaces, MDL);
3107 	}
3108 
3109 	/* Subnets are complicated because of the extra links. */
3110 	if (subnets) {
3111 	    subnet_reference (&sn, subnets, MDL);
3112 	    do {
3113 		if (sn) {
3114 		    subnet_reference (&sc, sn, MDL);
3115 		    subnet_dereference (&sn, MDL);
3116 		}
3117 		if (sc -> next_subnet) {
3118 		    subnet_reference (&sn, sc -> next_subnet, MDL);
3119 		    subnet_dereference (&sc -> next_subnet, MDL);
3120 		}
3121 		if (sc -> next_sibling)
3122 		    subnet_dereference (&sc -> next_sibling, MDL);
3123 		if (sc -> shared_network)
3124 		    shared_network_dereference (&sc -> shared_network, MDL);
3125 		group_dereference (&sc -> group, MDL);
3126 		if (sc -> interface)
3127 		    interface_dereference (&sc -> interface, MDL);
3128 		subnet_dereference (&sc, MDL);
3129 	    } while (sn);
3130 	    subnet_dereference (&subnets, MDL);
3131 	}
3132 
3133 	/* So are shared networks. */
3134 	/* XXX: this doesn't work presently, but i'm ok just filtering
3135 	 * it out of the noise (you get a bigger spike on the real leaks).
3136 	 * It would be good to fix this, but it is not a "real bug," so not
3137 	 * today.  This hack is incomplete, it doesn't trim out sub-values.
3138 	 */
3139 	if (shared_networks) {
3140 		shared_network_dereference (&shared_networks, MDL);
3141 	/* This is the old method (tries to free memory twice, broken) */
3142 	} else if (0) {
3143 	    shared_network_reference (&nn, shared_networks, MDL);
3144 	    do {
3145 		if (nn) {
3146 		    shared_network_reference (&nc, nn, MDL);
3147 		    shared_network_dereference (&nn, MDL);
3148 		}
3149 		if (nc -> next) {
3150 		    shared_network_reference (&nn, nc -> next, MDL);
3151 		    shared_network_dereference (&nc -> next, MDL);
3152 		}
3153 
3154 		/* As are pools. */
3155 		if (nc -> pools) {
3156 		    pool_reference (&pn, nc -> pools, MDL);
3157 		    do {
3158 			LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
3159 
3160 			if (pn) {
3161 			    pool_reference (&pc, pn, MDL);
3162 			    pool_dereference (&pn, MDL);
3163 			}
3164 			if (pc -> next) {
3165 			    pool_reference (&pn, pc -> next, MDL);
3166 			    pool_dereference (&pc -> next, MDL);
3167 			}
3168 
3169 			lptr [FREE_LEASES] = &pc -> free;
3170 			lptr [ACTIVE_LEASES] = &pc -> active;
3171 			lptr [EXPIRED_LEASES] = &pc -> expired;
3172 			lptr [ABANDONED_LEASES] = &pc -> abandoned;
3173 			lptr [BACKUP_LEASES] = &pc -> backup;
3174 			lptr [RESERVED_LEASES] = &pc->reserved;
3175 
3176 			/* As (sigh) are leases. */
3177 			for (i = FREE_LEASES ; i <= RESERVED_LEASES ; i++) {
3178 			    if (LEASE_NOT_EMPTYP(lptr[i])) {
3179 			        lease_reference(&ln, LEASE_GET_FIRSTP(lptr[i]), MDL);
3180 				do {
3181 				    /* save a pointer to the current lease */
3182 				    lease_reference (&lc, ln, MDL);
3183 				    lease_dereference (&ln, MDL);
3184 
3185 				    /* get the next lease if there is one */
3186 				    ltemp = LEASE_GET_NEXTP(lptr[i], lc);
3187 				    if (ltemp != NULL) {
3188 					lease_reference(&ln, ltemp, MDL);
3189 				    }
3190 
3191 				    /* remove the current lease from the queue */
3192 				    LEASE_REMOVEP(lptr[i], lc);
3193 
3194 				    if (lc -> billing_class)
3195 				       class_dereference (&lc -> billing_class,
3196 							  MDL);
3197 				    if (lc -> state)
3198 					free_lease_state (lc -> state, MDL);
3199 				    lc -> state = (struct lease_state *)0;
3200 				    if (lc -> n_hw)
3201 					lease_dereference (&lc -> n_hw, MDL);
3202 				    if (lc -> n_uid)
3203 					lease_dereference (&lc -> n_uid, MDL);
3204 				    lease_dereference (&lc, MDL);
3205 				} while (ln);
3206 			    }
3207 			}
3208 			if (pc -> group)
3209 			    group_dereference (&pc -> group, MDL);
3210 			if (pc -> shared_network)
3211 			    shared_network_dereference (&pc -> shared_network,
3212 							MDL);
3213 			pool_dereference (&pc, MDL);
3214 		    } while (pn);
3215 		    pool_dereference (&nc -> pools, MDL);
3216 		}
3217 		/* Because of a circular reference, we need to nuke this
3218 		   manually. */
3219 		group_dereference (&nc -> group, MDL);
3220 		shared_network_dereference (&nc, MDL);
3221 	    } while (nn);
3222 	    shared_network_dereference (&shared_networks, MDL);
3223 	}
3224 
3225 	cancel_all_timeouts ();
3226 	relinquish_timeouts ();
3227 #if defined(DELAYED_ACK)
3228 	relinquish_ackqueue();
3229 #endif
3230 	trace_free_all ();
3231 	group_dereference (&root_group, MDL);
3232 	executable_statement_dereference (&default_classification_rules, MDL);
3233 
3234 	shutdown_state = shutdown_drop_omapi_connections;
3235 	omapi_io_state_foreach (dhcp_io_shutdown, 0);
3236 	shutdown_state = shutdown_listeners;
3237 	omapi_io_state_foreach (dhcp_io_shutdown, 0);
3238 	shutdown_state = shutdown_dhcp;
3239 	omapi_io_state_foreach (dhcp_io_shutdown, 0);
3240 
3241 	omapi_object_dereference ((omapi_object_t **)&icmp_state, MDL);
3242 
3243 	universe_free_hash_table (&universe_hash, MDL);
3244 	for (i = 0; i < universe_count; i++) {
3245 #if 0
3246 		union {
3247 			const char *c;
3248 			char *s;
3249 		} foo;
3250 #endif
3251 		if (universes [i]) {
3252 			if (universes[i]->name_hash)
3253 			    option_name_free_hash_table(
3254 						&universes[i]->name_hash,
3255 						MDL);
3256 			if (universes[i]->code_hash)
3257 			    option_code_free_hash_table(
3258 						&universes[i]->code_hash,
3259 						MDL);
3260 #if 0
3261 			if (universes [i] -> name > (char *)&end) {
3262 				foo.c = universes [i] -> name;
3263 				dfree (foo.s, MDL);
3264 			}
3265 			if (universes [i] > (struct universe *)&end)
3266 				dfree (universes [i], MDL);
3267 #endif
3268 		}
3269 	}
3270 	dfree (universes, MDL);
3271 
3272 	relinquish_free_lease_states ();
3273 	relinquish_free_pairs ();
3274 	relinquish_free_expressions ();
3275 	relinquish_free_binding_values ();
3276 	relinquish_free_option_caches ();
3277 	relinquish_free_packets ();
3278 #if defined(COMPACT_LEASES)
3279 	relinquish_lease_hunks ();
3280 #endif
3281 	relinquish_hash_bucket_hunks ();
3282 	omapi_type_relinquish ();
3283 }
3284 #endif /* DEBUG_MEMORY_LEAKAGE_ON_EXIT */
3285