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