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