1 /* $OpenBSD: memory.c,v 1.15 2008/05/07 12:19:20 beck 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 "dhcpd.h" 42 #include "sync.h" 43 44 struct subnet *subnets; 45 static struct shared_network *shared_networks; 46 static struct hash_table *host_hw_addr_hash; 47 static struct hash_table *host_uid_hash; 48 static struct hash_table *lease_uid_hash; 49 static struct hash_table *lease_ip_addr_hash; 50 static struct hash_table *lease_hw_addr_hash; 51 static struct lease *dangling_leases; 52 53 static struct hash_table *vendor_class_hash; 54 static struct hash_table *user_class_hash; 55 56 extern int syncsend; 57 58 void 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 * 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 * 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 * 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 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 * 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 * 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 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 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 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 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 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 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 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 %d seconds: %s", 647 piaddr(lease->ip_addr), 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 * 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 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 * 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 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 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 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 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 * 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 * 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 * 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 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 if (syncsend) 853 sync_lease(l); 854 } 855 } 856 } 857 if (!commit_leases()) 858 error("Can't commit leases to new database: %m"); 859 } 860