1 /** $MirOS: src/usr.sbin/dhcpd/memory.c,v 1.3 2006/09/20 20:03:33 tg Exp $ */
2 /* $OpenBSD: memory.c,v 1.14 2006/08/09 22:23:53 cloder Exp $ */
3
4 /*
5 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of The Internet Software Consortium nor the names
18 * of its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * This software has been written for the Internet Software Consortium
36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37 * Enterprises. To learn more about the Internet Software Consortium,
38 * see ``http://www.vix.com/isc''. To learn more about Vixie
39 * Enterprises, see ``http://www.vix.com''.
40 */
41
42 #include "dhcpd.h"
43
44 __RCSID("$MirOS: src/usr.sbin/dhcpd/memory.c,v 1.3 2006/09/20 20:03:33 tg Exp $");
45
46 struct subnet *subnets;
47 static struct shared_network *shared_networks;
48 static struct hash_table *host_hw_addr_hash;
49 static struct hash_table *host_uid_hash;
50 static struct hash_table *lease_uid_hash;
51 static struct hash_table *lease_ip_addr_hash;
52 static struct hash_table *lease_hw_addr_hash;
53 static struct lease *dangling_leases;
54
55 static struct hash_table *vendor_class_hash;
56 static struct hash_table *user_class_hash;
57
58 void
enter_host(struct host_decl * hd)59 enter_host(struct host_decl *hd)
60 {
61 struct host_decl *hp = NULL, *np = NULL;
62
63 hd->n_ipaddr = NULL;
64 if (hd->interface.hlen) {
65 if (!host_hw_addr_hash)
66 host_hw_addr_hash = new_hash();
67 else
68 hp = (struct host_decl *)hash_lookup(host_hw_addr_hash,
69 hd->interface.haddr, hd->interface.hlen);
70
71 /*
72 * If there isn't already a host decl matching this
73 * address, add it to the hash table.
74 */
75 if (!hp)
76 add_hash(host_hw_addr_hash, hd->interface.haddr,
77 hd->interface.hlen, (unsigned char *)hd);
78 }
79
80 /*
81 * If there was already a host declaration for this hardware
82 * address, add this one to the end of the list.
83 */
84 if (hp) {
85 for (np = hp; np->n_ipaddr; np = np->n_ipaddr)
86 ;
87 np->n_ipaddr = hd;
88 }
89
90 if (hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]) {
91 if (!tree_evaluate(hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]))
92 return;
93
94 /* If there's no uid hash, make one; otherwise, see if
95 there's already an entry in the hash for this host. */
96 if (!host_uid_hash) {
97 host_uid_hash = new_hash();
98 hp = NULL;
99 } else
100 hp = (struct host_decl *)hash_lookup(host_uid_hash,
101 hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->value,
102 hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->len);
103
104 /*
105 * If there's already a host declaration for this
106 * client identifier, add this one to the end of the
107 * list. Otherwise, add it to the hash table.
108 */
109 if (hp) {
110 /* Don't link it in twice... */
111 if (!np) {
112 for (np = hp; np->n_ipaddr;
113 np = np->n_ipaddr)
114 ;
115 np->n_ipaddr = hd;
116 }
117 } else {
118 add_hash(host_uid_hash,
119 hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->value,
120 hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->len,
121 (unsigned char *)hd);
122 }
123 }
124 }
125
126 struct host_decl *
find_hosts_by_haddr(int htype,unsigned char * haddr,int hlen)127 find_hosts_by_haddr(int htype, unsigned char *haddr, int hlen)
128 {
129 return (struct host_decl *)hash_lookup(host_hw_addr_hash,
130 haddr, hlen);
131 }
132
133 struct host_decl *
find_hosts_by_uid(unsigned char * data,int len)134 find_hosts_by_uid(unsigned char *data, int len)
135 {
136 return (struct host_decl *)hash_lookup(host_uid_hash, data, len);
137 }
138
139 /*
140 * More than one host_decl can be returned by find_hosts_by_haddr or
141 * find_hosts_by_uid, and each host_decl can have multiple addresses.
142 * Loop through the list of hosts, and then for each host, through the
143 * list of addresses, looking for an address that's in the same shared
144 * network as the one specified. Store the matching address through
145 * the addr pointer, update the host pointer to point at the host_decl
146 * that matched, and return the subnet that matched.
147 */
148 struct subnet *
find_host_for_network(struct host_decl ** host,struct iaddr * addr,struct shared_network * share)149 find_host_for_network(struct host_decl **host, struct iaddr *addr,
150 struct shared_network *share)
151 {
152 struct subnet *subnet;
153 struct iaddr ip_address;
154 struct host_decl *hp;
155 int i;
156
157 for (hp = *host; hp; hp = hp->n_ipaddr) {
158 if (!hp->fixed_addr || !tree_evaluate(hp->fixed_addr))
159 continue;
160 for (i = 0; i < hp->fixed_addr->len; i += 4) {
161 ip_address.len = 4;
162 memcpy(ip_address.iabuf, hp->fixed_addr->value + i, 4);
163 subnet = find_grouped_subnet(share, ip_address);
164 if (subnet) {
165 *addr = ip_address;
166 *host = hp;
167 return subnet;
168 }
169 }
170 }
171 return NULL;
172 }
173
174 void
new_address_range(struct iaddr low,struct iaddr high,struct subnet * subnet,int dynamic)175 new_address_range(struct iaddr low, struct iaddr high, struct subnet *subnet,
176 int dynamic)
177 {
178 struct lease *address_range, *lp, *plp;
179 struct iaddr net;
180 int min, max, i;
181 char lowbuf[16], highbuf[16], netbuf[16];
182 struct shared_network *share = subnet->shared_network;
183 struct hostent *h;
184 struct in_addr ia;
185
186 /* All subnets should have attached shared network structures. */
187 if (!share) {
188 strlcpy(netbuf, piaddr(subnet->net), sizeof(netbuf));
189 error("No shared network for network %s (%s)",
190 netbuf, piaddr(subnet->netmask));
191 }
192
193 /* Initialize the hash table if it hasn't been done yet. */
194 if (!lease_uid_hash)
195 lease_uid_hash = new_hash();
196 if (!lease_ip_addr_hash)
197 lease_ip_addr_hash = new_hash();
198 if (!lease_hw_addr_hash)
199 lease_hw_addr_hash = new_hash();
200
201 /* Make sure that high and low addresses are in same subnet. */
202 net = subnet_number(low, subnet->netmask);
203 if (!addr_eq(net, subnet_number(high, subnet->netmask))) {
204 strlcpy(lowbuf, piaddr(low), sizeof(lowbuf));
205 strlcpy(highbuf, piaddr(high), sizeof(highbuf));
206 strlcpy(netbuf, piaddr(subnet->netmask), sizeof(netbuf));
207 error("Address range %s to %s, netmask %s spans %s!",
208 lowbuf, highbuf, netbuf, "multiple subnets");
209 }
210
211 /* Make sure that the addresses are on the correct subnet. */
212 if (!addr_eq(net, subnet->net)) {
213 strlcpy(lowbuf, piaddr(low), sizeof(lowbuf));
214 strlcpy(highbuf, piaddr(high), sizeof(highbuf));
215 strlcpy(netbuf, piaddr(subnet->netmask), sizeof(netbuf));
216 error("Address range %s to %s not on net %s/%s!",
217 lowbuf, highbuf, piaddr(subnet->net), netbuf);
218 }
219
220 /* Get the high and low host addresses... */
221 max = host_addr(high, subnet->netmask);
222 min = host_addr(low, subnet->netmask);
223
224 /* Allow range to be specified high-to-low as well as low-to-high. */
225 if (min > max) {
226 max = min;
227 min = host_addr(high, subnet->netmask);
228 }
229
230 /* Get a lease structure for each address in the range. */
231 address_range = new_leases(max - min + 1, "new_address_range");
232 if (!address_range) {
233 strlcpy(lowbuf, piaddr(low), sizeof(lowbuf));
234 strlcpy(highbuf, piaddr(high), sizeof(highbuf));
235 error("No memory for address range %s-%s.", lowbuf, highbuf);
236 }
237 memset(address_range, 0, (sizeof *address_range) * (max - min + 1));
238
239 /* Fill in the last lease if it hasn't been already... */
240 if (!share->last_lease)
241 share->last_lease = &address_range[0];
242
243 /* Fill out the lease structures with some minimal information. */
244 for (i = 0; i < max - min + 1; i++) {
245 address_range[i].ip_addr = ip_addr(subnet->net,
246 subnet->netmask, i + min);
247 address_range[i].starts = address_range[i].timestamp = MIN_TIME;
248 address_range[i].ends = MIN_TIME;
249 address_range[i].subnet = subnet;
250 address_range[i].shared_network = share;
251 address_range[i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0;
252
253 memcpy(&ia, address_range[i].ip_addr.iabuf, 4);
254
255 if (subnet->group->get_lease_hostnames) {
256 h = gethostbyaddr((char *)&ia, sizeof ia, AF_INET);
257 if (!h)
258 warning("No hostname for %s", inet_ntoa(ia));
259 else {
260 int len = strlen(h->h_name) + 1;
261
262 address_range[i].hostname = malloc(len);
263 if (!address_range[i].hostname)
264 error("no memory for hostname %s.",
265 h->h_name);
266 strlcpy(address_range[i].hostname,
267 h->h_name, len);
268 }
269 }
270
271 /* Link this entry into the list. */
272 address_range[i].next = share->leases;
273 address_range[i].prev = NULL;
274 share->leases = &address_range[i];
275 if (address_range[i].next)
276 address_range[i].next->prev = share->leases;
277 add_hash(lease_ip_addr_hash, address_range[i].ip_addr.iabuf,
278 address_range[i].ip_addr.len,
279 (unsigned char *)&address_range[i]);
280 }
281
282 /* Find out if any dangling leases are in range... */
283 plp = NULL;
284 for (lp = dangling_leases; lp; lp = lp->next) {
285 struct iaddr lnet;
286 int lhost;
287
288 lnet = subnet_number(lp->ip_addr, subnet->netmask);
289 lhost = host_addr(lp->ip_addr, subnet->netmask);
290
291 /* If it's in range, fill in the real lease structure with
292 the dangling lease's values, and remove the lease from
293 the list of dangling leases. */
294 if (addr_eq(lnet, subnet->net) && lhost >= i && lhost <= max) {
295 if (plp) {
296 plp->next = lp->next;
297 } else {
298 dangling_leases = lp->next;
299 }
300 lp->next = NULL;
301 address_range[lhost - i].hostname = lp->hostname;
302 address_range[lhost - i].client_hostname =
303 lp->client_hostname;
304 supersede_lease(&address_range[lhost - i], lp, 0);
305 free_lease(lp, "new_address_range");
306 } else
307 plp = lp;
308 }
309 }
310
311 struct subnet *
find_subnet(struct iaddr addr)312 find_subnet(struct iaddr addr)
313 {
314 struct subnet *rv;
315
316 for (rv = subnets; rv; rv = rv->next_subnet) {
317 if (addr_eq(subnet_number(addr, rv->netmask), rv->net))
318 return rv;
319 }
320 return NULL;
321 }
322
323 struct subnet *
find_grouped_subnet(struct shared_network * share,struct iaddr addr)324 find_grouped_subnet(struct shared_network *share, struct iaddr addr)
325 {
326 struct subnet *rv;
327
328 for (rv = share->subnets; rv; rv = rv->next_sibling) {
329 if (addr_eq(subnet_number(addr, rv->netmask), rv->net))
330 return rv;
331 }
332 return NULL;
333 }
334
335 int
subnet_inner_than(struct subnet * subnet,struct subnet * scan,int warnp)336 subnet_inner_than(struct subnet *subnet, struct subnet *scan, int warnp)
337 {
338 if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) ||
339 addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) {
340 char n1buf[16];
341 int i, j;
342
343 for (i = 0; i < 32; i++)
344 if (subnet->netmask.iabuf[3 - (i >> 3)] &
345 (1 << (i & 7)))
346 break;
347 for (j = 0; j < 32; j++)
348 if (scan->netmask.iabuf[3 - (j >> 3)] &
349 (1 << (j & 7)))
350 break;
351 strlcpy(n1buf, piaddr(subnet->net), sizeof(n1buf));
352 if (warnp)
353 warning("%ssubnet %s/%d conflicts with subnet %s/%d",
354 "Warning: ", n1buf, 32 - i,
355 piaddr(scan->net), 32 - j);
356 if (i < j)
357 return 1;
358 }
359 return 0;
360 }
361
362 /* Enter a new subnet into the subnet list. */
363 void
enter_subnet(struct subnet * subnet)364 enter_subnet(struct subnet *subnet)
365 {
366 struct subnet *scan, *prev = NULL;
367
368 /* Check for duplicates... */
369 for (scan = subnets; scan; scan = scan->next_subnet) {
370 /*
371 * When we find a conflict, make sure that the
372 * subnet with the narrowest subnet mask comes
373 * first.
374 */
375 if (subnet_inner_than(subnet, scan, 1)) {
376 if (prev) {
377 prev->next_subnet = subnet;
378 } else
379 subnets = subnet;
380 subnet->next_subnet = scan;
381 return;
382 }
383 prev = scan;
384 }
385
386 /* XXX use the BSD radix tree code instead of a linked list. */
387 subnet->next_subnet = subnets;
388 subnets = subnet;
389 }
390
391 /* Enter a new shared network into the shared network list. */
392 void
enter_shared_network(struct shared_network * share)393 enter_shared_network(struct shared_network *share)
394 {
395 /* XXX Sort the nets into a balanced tree to make searching quicker. */
396 share->next = shared_networks;
397 shared_networks = share;
398 }
399
400 /*
401 * Enter a lease into the system. This is called by the parser each
402 * time it reads in a new lease. If the subnet for that lease has
403 * already been read in (usually the case), just update that lease;
404 * otherwise, allocate temporary storage for the lease and keep it around
405 * until we're done reading in the config file.
406 */
407 void
enter_lease(struct lease * lease)408 enter_lease(struct lease *lease)
409 {
410 struct lease *comp = find_lease_by_ip_addr(lease->ip_addr);
411
412 /* If we don't have a place for this lease yet, save it for later. */
413 if (!comp) {
414 comp = new_lease("enter_lease");
415 if (!comp)
416 error("No memory for lease %s\n",
417 piaddr(lease->ip_addr));
418 *comp = *lease;
419 comp->next = dangling_leases;
420 comp->prev = NULL;
421 dangling_leases = comp;
422 } else {
423 /* Record the hostname information in the lease. */
424 comp->hostname = lease->hostname;
425 comp->client_hostname = lease->client_hostname;
426 supersede_lease(comp, lease, 0);
427 }
428 }
429
430 /*
431 * Replace the data in an existing lease with the data in a new lease;
432 * adjust hash tables to suit, and insertion sort the lease into the
433 * list of leases by expiry time so that we can always find the oldest
434 * lease.
435 */
436 int
supersede_lease(struct lease * comp,struct lease * lease,int commit)437 supersede_lease(struct lease *comp, struct lease *lease, int commit)
438 {
439 int enter_uid = 0;
440 int enter_hwaddr = 0;
441 int do_pftable = 0;
442 struct lease *lp;
443
444 /* Static leases are not currently kept in the database... */
445 if (lease->flags & STATIC_LEASE)
446 return 1;
447
448 /*
449 * If the existing lease hasn't expired and has a different
450 * unique identifier or, if it doesn't have a unique
451 * identifier, a different hardware address, then the two
452 * leases are in conflict. If the existing lease has a uid
453 * and the new one doesn't, but they both have the same
454 * hardware address, and dynamic bootp is allowed on this
455 * lease, then we allow that, in case a dynamic BOOTP lease is
456 * requested *after* a DHCP lease has been assigned.
457 */
458 if (!(lease->flags & ABANDONED_LEASE) &&
459 comp->ends > cur_time &&
460 (((comp->uid && lease->uid) &&
461 (comp->uid_len != lease->uid_len ||
462 memcmp (comp->uid, lease->uid, comp->uid_len))) ||
463 (!comp->uid &&
464 ((comp->hardware_addr.htype !=
465 lease->hardware_addr.htype) ||
466 (comp->hardware_addr.hlen !=
467 lease->hardware_addr.hlen) ||
468 memcmp(comp->hardware_addr.haddr, lease->hardware_addr.haddr,
469 comp->hardware_addr.hlen))))) {
470 warning("Lease conflict at %s", piaddr(comp->ip_addr));
471 return 0;
472 } else {
473 /* If there's a Unique ID, dissociate it from the hash
474 table and free it if necessary. */
475 if (comp->uid) {
476 uid_hash_delete(comp);
477 enter_uid = 1;
478 if (comp->uid != &comp->uid_buf[0]) {
479 free(comp->uid);
480 comp->uid_max = 0;
481 comp->uid_len = 0;
482 }
483 comp->uid = NULL;
484 } else
485 enter_uid = 1;
486
487 if (comp->hardware_addr.htype &&
488 ((comp->hardware_addr.hlen !=
489 lease->hardware_addr.hlen) ||
490 (comp->hardware_addr.htype !=
491 lease->hardware_addr.htype) ||
492 memcmp(comp->hardware_addr.haddr, lease->hardware_addr.haddr,
493 comp->hardware_addr.hlen))) {
494 hw_hash_delete(comp);
495 enter_hwaddr = 1;
496 do_pftable = 1;
497 } else if (!comp->hardware_addr.htype) {
498 enter_hwaddr = 1;
499 do_pftable = 1;
500 }
501
502 /* Copy the data files, but not the linkages. */
503 comp->starts = lease->starts;
504 if (lease->uid) {
505 if (lease->uid_len <= sizeof (lease->uid_buf)) {
506 memcpy(comp->uid_buf, lease->uid, lease->uid_len);
507 comp->uid = &comp->uid_buf[0];
508 comp->uid_max = sizeof comp->uid_buf;
509 } else if (lease->uid != &lease->uid_buf[0]) {
510 comp->uid = lease->uid;
511 comp->uid_max = lease->uid_max;
512 lease->uid = NULL;
513 lease->uid_max = 0;
514 } else {
515 error("corrupt lease uid."); /* XXX */
516 }
517 } else {
518 comp->uid = NULL;
519 comp->uid_max = 0;
520 }
521 comp->uid_len = lease->uid_len;
522 comp->host = lease->host;
523 comp->hardware_addr = lease->hardware_addr;
524 comp->flags = ((lease->flags & ~PERSISTENT_FLAGS) |
525 (comp->flags & ~EPHEMERAL_FLAGS));
526
527 /* Record the lease in the uid hash if necessary. */
528 if (enter_uid && lease->uid)
529 uid_hash_add(comp);
530
531 /* Record it in the hardware address hash if necessary. */
532 if (enter_hwaddr && lease->hardware_addr.htype)
533 hw_hash_add(comp);
534
535 /* Remove the lease from its current place in the
536 timeout sequence. */
537 if (comp->prev)
538 comp->prev->next = comp->next;
539 else
540 comp->shared_network->leases = comp->next;
541 if (comp->next)
542 comp->next->prev = comp->prev;
543 if (comp->shared_network->last_lease == comp)
544 comp->shared_network->last_lease = comp->prev;
545
546 /* Find the last insertion point... */
547 if (comp == comp->shared_network->insertion_point ||
548 !comp->shared_network->insertion_point)
549 lp = comp->shared_network->leases;
550 else
551 lp = comp->shared_network->insertion_point;
552
553 if (!lp) {
554 /* Nothing on the list yet? Just make comp the
555 head of the list. */
556 comp->shared_network->leases = comp;
557 comp->shared_network->last_lease = comp;
558 } else if (lp->ends > lease->ends) {
559 /* Skip down the list until we run out of list
560 or find a place for comp. */
561 while (lp->next && lp->ends > lease->ends) {
562 lp = lp->next;
563 }
564 if (lp->ends > lease->ends) {
565 /* If we ran out of list, put comp
566 at the end. */
567 lp->next = comp;
568 comp->prev = lp;
569 comp->next = NULL;
570 comp->shared_network->last_lease = comp;
571 } else {
572 /* If we didn't, put it between lp and
573 the previous item on the list. */
574 if ((comp->prev = lp->prev))
575 comp->prev->next = comp;
576 comp->next = lp;
577 lp->prev = comp;
578 }
579 } else {
580 /* Skip up the list until we run out of list
581 or find a place for comp. */
582 while (lp->prev && lp->ends < lease->ends) {
583 lp = lp->prev;
584 }
585 if (lp->ends < lease->ends) {
586 /* If we ran out of list, put comp
587 at the beginning. */
588 lp->prev = comp;
589 comp->next = lp;
590 comp->prev = NULL;
591 comp->shared_network->leases = comp;
592 } else {
593 /* If we didn't, put it between lp and
594 the next item on the list. */
595 if ((comp->next = lp->next))
596 comp->next->prev = comp;
597 comp->prev = lp;
598 lp->next = comp;
599 }
600 }
601 comp->shared_network->insertion_point = comp;
602 comp->ends = lease->ends;
603 }
604
605 pfmsg('L', lease); /* address is leased. remove from purgatory */
606 if (do_pftable) /* address changed hwaddr. remove from overload */
607 pfmsg('C', lease);
608
609 /* Return zero if we didn't commit the lease to permanent storage;
610 nonzero if we did. */
611 return commit && write_lease(comp) && commit_leases();
612 }
613
614 /* Release the specified lease and re-hash it as appropriate. */
615
616 void
release_lease(struct lease * lease)617 release_lease(struct lease *lease)
618 {
619 struct lease lt;
620
621 lt = *lease;
622 if (lt.ends > cur_time) {
623 lt.ends = cur_time;
624 supersede_lease(lease, <, 1);
625 note("Released lease for IP address %s",
626 piaddr(lease->ip_addr));
627 }
628 }
629
630
631 /*
632 * Abandon the specified lease for the specified time. sets it's
633 * particulars to zero, the end time appropriately and re-hash it as
634 * appropriate. abandons permanently if abtime is 0
635 */
636 void
abandon_lease(struct lease * lease,char * message)637 abandon_lease(struct lease *lease, char *message)
638 {
639 struct lease lt;
640 time_t abtime;
641
642 abtime = lease->subnet->group->default_lease_time;
643 lease->flags |= ABANDONED_LEASE;
644 lt = *lease;
645 lt.ends = cur_time + abtime;
646 warning("Abandoning IP address %s for %lld seconds: %s",
647 piaddr(lease->ip_addr), (int64_t)abtime, message);
648 lt.hardware_addr.htype = 0;
649 lt.hardware_addr.hlen = 0;
650 lt.uid = NULL;
651 lt.uid_len = 0;
652 supersede_lease(lease, <, 1);
653
654 pfmsg('A', lease); /* address is abandoned. send to purgatory */
655 return;
656 }
657
658 /* Locate the lease associated with a given IP address... */
659 struct lease *
find_lease_by_ip_addr(struct iaddr addr)660 find_lease_by_ip_addr(struct iaddr addr)
661 {
662 return (struct lease *)hash_lookup(lease_ip_addr_hash,
663 addr.iabuf, addr.len);
664 }
665
find_lease_by_uid(unsigned char * uid,int len)666 struct lease *find_lease_by_uid(unsigned char *uid, int len)
667 {
668 return (struct lease *)hash_lookup(lease_uid_hash, uid, len);
669 }
670
671 struct lease *
find_lease_by_hw_addr(unsigned char * hwaddr,int hwlen)672 find_lease_by_hw_addr(unsigned char *hwaddr, int hwlen)
673 {
674 return (struct lease *)hash_lookup(lease_hw_addr_hash, hwaddr, hwlen);
675 }
676
677 /* Add the specified lease to the uid hash. */
678 void
uid_hash_add(struct lease * lease)679 uid_hash_add(struct lease *lease)
680 {
681 struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len);
682 struct lease *scan;
683
684 /* If it's not in the hash, just add it. */
685 if (!head)
686 add_hash(lease_uid_hash, lease->uid,
687 lease->uid_len, (unsigned char *)lease);
688 else {
689 /* Otherwise, attach it to the end of the list. */
690 for (scan = head; scan->n_uid; scan = scan->n_uid)
691 ;
692 scan->n_uid = lease;
693 }
694 }
695
696 /* Delete the specified lease from the uid hash. */
697 void
uid_hash_delete(struct lease * lease)698 uid_hash_delete(struct lease *lease)
699 {
700 struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len);
701 struct lease *scan;
702
703 /* If it's not in the hash, we have no work to do. */
704 if (!head) {
705 lease->n_uid = NULL;
706 return;
707 }
708
709 /* If the lease we're freeing is at the head of the list,
710 remove the hash table entry and add a new one with the
711 next lease on the list (if there is one). */
712 if (head == lease) {
713 delete_hash_entry(lease_uid_hash, lease->uid, lease->uid_len);
714 if (lease->n_uid)
715 add_hash(lease_uid_hash, lease->n_uid->uid,
716 lease->n_uid->uid_len,
717 (unsigned char *)(lease->n_uid));
718 } else {
719 /* Otherwise, look for the lease in the list of leases
720 attached to the hash table entry, and remove it if
721 we find it. */
722 for (scan = head; scan->n_uid; scan = scan->n_uid) {
723 if (scan->n_uid == lease) {
724 scan->n_uid = scan->n_uid->n_uid;
725 break;
726 }
727 }
728 }
729 lease->n_uid = NULL;
730 }
731
732 /* Add the specified lease to the hardware address hash. */
733 void
hw_hash_add(struct lease * lease)734 hw_hash_add(struct lease *lease)
735 {
736 struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr,
737 lease->hardware_addr.hlen);
738 struct lease *scan;
739
740 /* If it's not in the hash, just add it. */
741 if (!head)
742 add_hash(lease_hw_addr_hash, lease->hardware_addr.haddr,
743 lease->hardware_addr.hlen, (unsigned char *)lease);
744 else {
745 /* Otherwise, attach it to the end of the list. */
746 for (scan = head; scan->n_hw; scan = scan->n_hw)
747 ;
748 scan->n_hw = lease;
749 }
750 }
751
752 /* Delete the specified lease from the hardware address hash. */
753 void
hw_hash_delete(struct lease * lease)754 hw_hash_delete(struct lease *lease)
755 {
756 struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr,
757 lease->hardware_addr.hlen);
758 struct lease *scan;
759
760 /* If it's not in the hash, we have no work to do. */
761 if (!head) {
762 lease->n_hw = NULL;
763 return;
764 }
765
766 /* If the lease we're freeing is at the head of the list,
767 remove the hash table entry and add a new one with the
768 next lease on the list (if there is one). */
769 if (head == lease) {
770 delete_hash_entry(lease_hw_addr_hash,
771 lease->hardware_addr.haddr, lease->hardware_addr.hlen);
772 if (lease->n_hw)
773 add_hash(lease_hw_addr_hash,
774 lease->n_hw->hardware_addr.haddr,
775 lease->n_hw->hardware_addr.hlen,
776 (unsigned char *)(lease->n_hw));
777 } else {
778 /*
779 * Otherwise, look for the lease in the list of leases
780 * attached to the hash table entry, and remove it if
781 * we find it.
782 */
783 for (scan = head; scan->n_hw; scan = scan->n_hw) {
784 if (scan->n_hw == lease) {
785 scan->n_hw = scan->n_hw->n_hw;
786 break;
787 }
788 }
789 }
790 lease->n_hw = NULL;
791 }
792
793
794 struct class *
add_class(int type,char * name)795 add_class(int type, char *name)
796 {
797 struct class *class = new_class("add_class");
798 char *tname = malloc(strlen(name) + 1);
799
800 if (!vendor_class_hash)
801 vendor_class_hash = new_hash();
802 if (!user_class_hash)
803 user_class_hash = new_hash();
804
805 if (!tname || !class || !vendor_class_hash || !user_class_hash)
806 return NULL;
807
808 memset(class, 0, sizeof *class);
809 strlcpy(tname, name, strlen(name) + 1);
810 class->name = tname;
811
812 if (type)
813 add_hash(user_class_hash, (unsigned char *)tname,
814 strlen(tname), (unsigned char *)class);
815 else
816 add_hash(vendor_class_hash, (unsigned char *)tname,
817 strlen(tname), (unsigned char *)class);
818 return class;
819 }
820
821 struct class *
find_class(int type,unsigned char * name,int len)822 find_class(int type, unsigned char *name, int len)
823 {
824 return (struct class *)hash_lookup(type ? user_class_hash :
825 vendor_class_hash, name, len);
826 }
827
828 struct group *
clone_group(struct group * group,char * caller)829 clone_group(struct group *group, char *caller)
830 {
831 struct group *g = new_group(caller);
832 if (!g)
833 error("%s: can't allocate new group", caller);
834 *g = *group;
835 return g;
836 }
837
838 /* Write all interesting leases to permanent storage. */
839
840 void
write_leases(void)841 write_leases(void)
842 {
843 struct lease *l;
844 struct shared_network *s;
845
846 for (s = shared_networks; s; s = s->next) {
847 for (l = s->leases; l; l = l->next) {
848 if (l->hardware_addr.hlen || l->uid_len ||
849 (l->flags & ABANDONED_LEASE))
850 if (!write_lease(l))
851 error("Can't rewrite lease database");
852 }
853 }
854 if (!commit_leases())
855 error("Can't commit leases to new database: %m");
856 }
857