1 /* $OpenBSD: memory.c,v 1.22 2014/06/11 16:45:15 pelikan 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 = calloc(max - min + 1, sizeof(struct lease)); 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 address_range[i].hostname = strdup(h->h_name); 261 if (address_range[i].hostname == NULL) 262 error("no memory for hostname %s.", 263 h->h_name); 264 } 265 } 266 267 /* Link this entry into the list. */ 268 address_range[i].next = share->leases; 269 address_range[i].prev = NULL; 270 share->leases = &address_range[i]; 271 if (address_range[i].next) 272 address_range[i].next->prev = share->leases; 273 add_hash(lease_ip_addr_hash, address_range[i].ip_addr.iabuf, 274 address_range[i].ip_addr.len, 275 (unsigned char *)&address_range[i]); 276 } 277 278 /* Find out if any dangling leases are in range... */ 279 plp = NULL; 280 for (lp = dangling_leases; lp; lp = lp->next) { 281 struct iaddr lnet; 282 int lhost; 283 284 lnet = subnet_number(lp->ip_addr, subnet->netmask); 285 lhost = host_addr(lp->ip_addr, subnet->netmask); 286 287 /* If it's in range, fill in the real lease structure with 288 the dangling lease's values, and remove the lease from 289 the list of dangling leases. */ 290 if (addr_eq(lnet, subnet->net) && lhost >= i && lhost <= max) { 291 if (plp) { 292 plp->next = lp->next; 293 } else { 294 dangling_leases = lp->next; 295 } 296 lp->next = NULL; 297 address_range[lhost - i].hostname = lp->hostname; 298 address_range[lhost - i].client_hostname = 299 lp->client_hostname; 300 supersede_lease(&address_range[lhost - i], lp, 0); 301 free(lp); 302 } else 303 plp = lp; 304 } 305 } 306 307 struct subnet * 308 find_subnet(struct iaddr addr) 309 { 310 struct subnet *rv; 311 312 for (rv = subnets; rv; rv = rv->next_subnet) { 313 if (addr_eq(subnet_number(addr, rv->netmask), rv->net)) 314 return rv; 315 } 316 return NULL; 317 } 318 319 struct subnet * 320 find_grouped_subnet(struct shared_network *share, struct iaddr addr) 321 { 322 struct subnet *rv; 323 324 for (rv = share->subnets; rv; rv = rv->next_sibling) { 325 if (addr_eq(subnet_number(addr, rv->netmask), rv->net)) 326 return rv; 327 } 328 return NULL; 329 } 330 331 int 332 subnet_inner_than(struct subnet *subnet, struct subnet *scan, int warnp) 333 { 334 if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) || 335 addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) { 336 char n1buf[16]; 337 int i, j; 338 339 for (i = 0; i < 32; i++) 340 if (subnet->netmask.iabuf[3 - (i >> 3)] & 341 (1 << (i & 7))) 342 break; 343 for (j = 0; j < 32; j++) 344 if (scan->netmask.iabuf[3 - (j >> 3)] & 345 (1 << (j & 7))) 346 break; 347 strlcpy(n1buf, piaddr(subnet->net), sizeof(n1buf)); 348 if (warnp) 349 warning("%ssubnet %s/%d conflicts with subnet %s/%d", 350 "Warning: ", n1buf, 32 - i, 351 piaddr(scan->net), 32 - j); 352 if (i < j) 353 return 1; 354 } 355 return 0; 356 } 357 358 /* Enter a new subnet into the subnet list. */ 359 void 360 enter_subnet(struct subnet *subnet) 361 { 362 struct subnet *scan, *prev = NULL; 363 364 /* Check for duplicates... */ 365 for (scan = subnets; scan; scan = scan->next_subnet) { 366 /* 367 * When we find a conflict, make sure that the 368 * subnet with the narrowest subnet mask comes 369 * first. 370 */ 371 if (subnet_inner_than(subnet, scan, 1)) { 372 if (prev) { 373 prev->next_subnet = subnet; 374 } else 375 subnets = subnet; 376 subnet->next_subnet = scan; 377 return; 378 } 379 prev = scan; 380 } 381 382 /* XXX use the BSD radix tree code instead of a linked list. */ 383 subnet->next_subnet = subnets; 384 subnets = subnet; 385 } 386 387 /* Enter a new shared network into the shared network list. */ 388 void 389 enter_shared_network(struct shared_network *share) 390 { 391 /* XXX Sort the nets into a balanced tree to make searching quicker. */ 392 share->next = shared_networks; 393 shared_networks = share; 394 } 395 396 /* 397 * Enter a lease into the system. This is called by the parser each 398 * time it reads in a new lease. If the subnet for that lease has 399 * already been read in (usually the case), just update that lease; 400 * otherwise, allocate temporary storage for the lease and keep it around 401 * until we're done reading in the config file. 402 */ 403 void 404 enter_lease(struct lease *lease) 405 { 406 struct lease *comp = find_lease_by_ip_addr(lease->ip_addr); 407 408 /* If we don't have a place for this lease yet, save it for later. */ 409 if (!comp) { 410 comp = calloc(1, sizeof(struct lease)); 411 if (!comp) 412 error("No memory for lease %s\n", 413 piaddr(lease->ip_addr)); 414 *comp = *lease; 415 comp->next = dangling_leases; 416 comp->prev = NULL; 417 dangling_leases = comp; 418 } else { 419 /* Record the hostname information in the lease. */ 420 comp->hostname = lease->hostname; 421 comp->client_hostname = lease->client_hostname; 422 supersede_lease(comp, lease, 0); 423 } 424 } 425 426 static inline int 427 hwaddrcmp(struct hardware *a, struct hardware *b) 428 { 429 return ((a->htype != b->htype) || (a->hlen != b->hlen) || 430 memcmp(a->haddr, b->haddr, b->hlen)); 431 } 432 433 static inline int 434 uidcmp(struct lease *a, struct lease *b) 435 { 436 return (a->uid_len != b->uid_len || memcmp(a->uid, b->uid, b->uid_len)); 437 } 438 439 static inline int 440 uid_or_hwaddr_cmp(struct lease *a, struct lease *b) 441 { 442 if (a->uid && b->uid) 443 return uidcmp(a, b); 444 return hwaddrcmp(&a->hardware_addr, &b->hardware_addr); 445 } 446 447 /* 448 * Replace the data in an existing lease with the data in a new lease; 449 * adjust hash tables to suit, and insertion sort the lease into the 450 * list of leases by expiry time so that we can always find the oldest 451 * lease. 452 */ 453 int 454 supersede_lease(struct lease *comp, struct lease *lease, int commit) 455 { 456 int enter_uid = 0; 457 int enter_hwaddr = 0; 458 int do_pftable = 0; 459 struct lease *lp; 460 461 /* Static leases are not currently kept in the database... */ 462 if (lease->flags & STATIC_LEASE) 463 return 1; 464 465 /* 466 * If the existing lease hasn't expired and has a different 467 * unique identifier or, if it doesn't have a unique 468 * identifier, a different hardware address, then the two 469 * leases are in conflict. If the existing lease has a uid 470 * and the new one doesn't, but they both have the same 471 * hardware address, and dynamic bootp is allowed on this 472 * lease, then we allow that, in case a dynamic BOOTP lease is 473 * requested *after* a DHCP lease has been assigned. 474 */ 475 if (!(lease->flags & ABANDONED_LEASE) && 476 comp->ends > cur_time && uid_or_hwaddr_cmp(comp, lease)) { 477 warning("Lease conflict at %s", piaddr(comp->ip_addr)); 478 return 0; 479 } else { 480 /* If there's a Unique ID, dissociate it from the hash 481 table and free it if necessary. */ 482 if (comp->uid) { 483 uid_hash_delete(comp); 484 enter_uid = 1; 485 if (comp->uid != &comp->uid_buf[0]) { 486 free(comp->uid); 487 comp->uid_max = 0; 488 comp->uid_len = 0; 489 } 490 comp->uid = NULL; 491 } else 492 enter_uid = 1; 493 494 if (comp->hardware_addr.htype && 495 hwaddrcmp(&comp->hardware_addr, &lease->hardware_addr)) { 496 hw_hash_delete(comp); 497 enter_hwaddr = 1; 498 do_pftable = 1; 499 } else if (!comp->hardware_addr.htype) { 500 enter_hwaddr = 1; 501 do_pftable = 1; 502 } 503 504 /* Copy the data files, but not the linkages. */ 505 comp->starts = lease->starts; 506 if (lease->uid) { 507 if (lease->uid_len <= sizeof (lease->uid_buf)) { 508 memcpy(comp->uid_buf, lease->uid, lease->uid_len); 509 comp->uid = &comp->uid_buf[0]; 510 comp->uid_max = sizeof comp->uid_buf; 511 } else if (lease->uid != &lease->uid_buf[0]) { 512 comp->uid = lease->uid; 513 comp->uid_max = lease->uid_max; 514 lease->uid = NULL; 515 lease->uid_max = 0; 516 } else { 517 error("corrupt lease uid."); /* XXX */ 518 } 519 } else { 520 comp->uid = NULL; 521 comp->uid_max = 0; 522 } 523 comp->uid_len = lease->uid_len; 524 comp->host = lease->host; 525 comp->hardware_addr = lease->hardware_addr; 526 comp->flags = ((lease->flags & ~PERSISTENT_FLAGS) | 527 (comp->flags & ~EPHEMERAL_FLAGS)); 528 529 /* Record the lease in the uid hash if necessary. */ 530 if (enter_uid && lease->uid) 531 uid_hash_add(comp); 532 533 /* Record it in the hardware address hash if necessary. */ 534 if (enter_hwaddr && lease->hardware_addr.htype) 535 hw_hash_add(comp); 536 537 /* Remove the lease from its current place in the 538 timeout sequence. */ 539 if (comp->prev) 540 comp->prev->next = comp->next; 541 else 542 comp->shared_network->leases = comp->next; 543 if (comp->next) 544 comp->next->prev = comp->prev; 545 if (comp->shared_network->last_lease == comp) 546 comp->shared_network->last_lease = comp->prev; 547 548 /* Find the last insertion point... */ 549 if (comp == comp->shared_network->insertion_point || 550 !comp->shared_network->insertion_point) 551 lp = comp->shared_network->leases; 552 else 553 lp = comp->shared_network->insertion_point; 554 555 if (!lp) { 556 /* Nothing on the list yet? Just make comp the 557 head of the list. */ 558 comp->shared_network->leases = comp; 559 comp->shared_network->last_lease = comp; 560 } else if (lp->ends > lease->ends) { 561 /* Skip down the list until we run out of list 562 or find a place for comp. */ 563 while (lp->next && lp->ends > lease->ends) { 564 lp = lp->next; 565 } 566 if (lp->ends > lease->ends) { 567 /* If we ran out of list, put comp 568 at the end. */ 569 lp->next = comp; 570 comp->prev = lp; 571 comp->next = NULL; 572 comp->shared_network->last_lease = comp; 573 } else { 574 /* If we didn't, put it between lp and 575 the previous item on the list. */ 576 if ((comp->prev = lp->prev)) 577 comp->prev->next = comp; 578 comp->next = lp; 579 lp->prev = comp; 580 } 581 } else { 582 /* Skip up the list until we run out of list 583 or find a place for comp. */ 584 while (lp->prev && lp->ends < lease->ends) { 585 lp = lp->prev; 586 } 587 if (lp->ends < lease->ends) { 588 /* If we ran out of list, put comp 589 at the beginning. */ 590 lp->prev = comp; 591 comp->next = lp; 592 comp->prev = NULL; 593 comp->shared_network->leases = comp; 594 } else { 595 /* If we didn't, put it between lp and 596 the next item on the list. */ 597 if ((comp->next = lp->next)) 598 comp->next->prev = comp; 599 comp->prev = lp; 600 lp->next = comp; 601 } 602 } 603 comp->shared_network->insertion_point = comp; 604 comp->ends = lease->ends; 605 } 606 607 pfmsg('L', lease); /* address is leased. remove from purgatory */ 608 if (do_pftable) /* address changed hwaddr. remove from overload */ 609 pfmsg('C', lease); 610 611 /* Return zero if we didn't commit the lease to permanent storage; 612 nonzero if we did. */ 613 return commit && write_lease(comp) && commit_leases(); 614 } 615 616 /* Release the specified lease and re-hash it as appropriate. */ 617 618 void 619 release_lease(struct lease *lease) 620 { 621 struct lease lt; 622 623 lt = *lease; 624 if (lt.ends > cur_time) { 625 lt.ends = cur_time; 626 supersede_lease(lease, <, 1); 627 note("Released lease for IP address %s", 628 piaddr(lease->ip_addr)); 629 } 630 } 631 632 633 /* 634 * Abandon the specified lease for the specified time. sets it's 635 * particulars to zero, the end time appropriately and re-hash it as 636 * appropriate. abandons permanently if abtime is 0 637 */ 638 void 639 abandon_lease(struct lease *lease, char *message) 640 { 641 struct lease lt; 642 time_t abtime; 643 644 abtime = lease->subnet->group->default_lease_time; 645 lease->flags |= ABANDONED_LEASE; 646 lt = *lease; 647 lt.ends = cur_time + abtime; 648 warning("Abandoning IP address %s for %lld seconds: %s", 649 piaddr(lease->ip_addr), (long long)abtime, message); 650 lt.hardware_addr.htype = 0; 651 lt.hardware_addr.hlen = 0; 652 lt.uid = NULL; 653 lt.uid_len = 0; 654 supersede_lease(lease, <, 1); 655 656 pfmsg('A', lease); /* address is abandoned. send to purgatory */ 657 return; 658 } 659 660 /* Locate the lease associated with a given IP address... */ 661 struct lease * 662 find_lease_by_ip_addr(struct iaddr addr) 663 { 664 return (struct lease *)hash_lookup(lease_ip_addr_hash, 665 addr.iabuf, addr.len); 666 } 667 668 struct lease *find_lease_by_uid(unsigned char *uid, int len) 669 { 670 return (struct lease *)hash_lookup(lease_uid_hash, uid, len); 671 } 672 673 struct lease * 674 find_lease_by_hw_addr(unsigned char *hwaddr, int hwlen) 675 { 676 return (struct lease *)hash_lookup(lease_hw_addr_hash, hwaddr, hwlen); 677 } 678 679 /* Add the specified lease to the uid hash. */ 680 void 681 uid_hash_add(struct lease *lease) 682 { 683 struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len); 684 struct lease *scan; 685 686 /* If it's not in the hash, just add it. */ 687 if (!head) 688 add_hash(lease_uid_hash, lease->uid, 689 lease->uid_len, (unsigned char *)lease); 690 else { 691 /* Otherwise, attach it to the end of the list. */ 692 for (scan = head; scan->n_uid; scan = scan->n_uid) 693 ; 694 scan->n_uid = lease; 695 } 696 } 697 698 /* Delete the specified lease from the uid hash. */ 699 void 700 uid_hash_delete(struct lease *lease) 701 { 702 struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len); 703 struct lease *scan; 704 705 /* If it's not in the hash, we have no work to do. */ 706 if (!head) { 707 lease->n_uid = NULL; 708 return; 709 } 710 711 /* If the lease we're freeing is at the head of the list, 712 remove the hash table entry and add a new one with the 713 next lease on the list (if there is one). */ 714 if (head == lease) { 715 delete_hash_entry(lease_uid_hash, lease->uid, lease->uid_len); 716 if (lease->n_uid) 717 add_hash(lease_uid_hash, lease->n_uid->uid, 718 lease->n_uid->uid_len, 719 (unsigned char *)(lease->n_uid)); 720 } else { 721 /* Otherwise, look for the lease in the list of leases 722 attached to the hash table entry, and remove it if 723 we find it. */ 724 for (scan = head; scan->n_uid; scan = scan->n_uid) { 725 if (scan->n_uid == lease) { 726 scan->n_uid = scan->n_uid->n_uid; 727 break; 728 } 729 } 730 } 731 lease->n_uid = NULL; 732 } 733 734 /* Add the specified lease to the hardware address hash. */ 735 void 736 hw_hash_add(struct lease *lease) 737 { 738 struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr, 739 lease->hardware_addr.hlen); 740 struct lease *scan; 741 742 /* If it's not in the hash, just add it. */ 743 if (!head) 744 add_hash(lease_hw_addr_hash, lease->hardware_addr.haddr, 745 lease->hardware_addr.hlen, (unsigned char *)lease); 746 else { 747 /* Otherwise, attach it to the end of the list. */ 748 for (scan = head; scan->n_hw; scan = scan->n_hw) 749 ; 750 scan->n_hw = lease; 751 } 752 } 753 754 /* Delete the specified lease from the hardware address hash. */ 755 void 756 hw_hash_delete(struct lease *lease) 757 { 758 struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr, 759 lease->hardware_addr.hlen); 760 struct lease *scan; 761 762 /* If it's not in the hash, we have no work to do. */ 763 if (!head) { 764 lease->n_hw = NULL; 765 return; 766 } 767 768 /* If the lease we're freeing is at the head of the list, 769 remove the hash table entry and add a new one with the 770 next lease on the list (if there is one). */ 771 if (head == lease) { 772 delete_hash_entry(lease_hw_addr_hash, 773 lease->hardware_addr.haddr, lease->hardware_addr.hlen); 774 if (lease->n_hw) 775 add_hash(lease_hw_addr_hash, 776 lease->n_hw->hardware_addr.haddr, 777 lease->n_hw->hardware_addr.hlen, 778 (unsigned char *)(lease->n_hw)); 779 } else { 780 /* 781 * Otherwise, look for the lease in the list of leases 782 * attached to the hash table entry, and remove it if 783 * we find it. 784 */ 785 for (scan = head; scan->n_hw; scan = scan->n_hw) { 786 if (scan->n_hw == lease) { 787 scan->n_hw = scan->n_hw->n_hw; 788 break; 789 } 790 } 791 } 792 lease->n_hw = NULL; 793 } 794 795 796 struct class * 797 add_class(int type, char *name) 798 { 799 struct class *class; 800 char *tname; 801 802 class = calloc(1, sizeof(*class)); 803 tname = strdup(name); 804 805 if (!vendor_class_hash) 806 vendor_class_hash = new_hash(); 807 if (!user_class_hash) 808 user_class_hash = new_hash(); 809 810 if (!tname || !class || !vendor_class_hash || !user_class_hash) { 811 warning("No memory for %s.", name); 812 free(class); 813 free(tname); 814 return NULL; 815 } 816 817 class->name = tname; 818 819 if (type) 820 add_hash(user_class_hash, (unsigned char *)tname, 821 strlen(tname), (unsigned char *)class); 822 else 823 add_hash(vendor_class_hash, (unsigned char *)tname, 824 strlen(tname), (unsigned char *)class); 825 826 return class; 827 } 828 829 struct class * 830 find_class(int type, unsigned char *name, int len) 831 { 832 return (struct class *)hash_lookup(type ? user_class_hash : 833 vendor_class_hash, name, len); 834 } 835 836 struct group * 837 clone_group(struct group *group, char *caller) 838 { 839 struct group *g; 840 841 g = calloc(1, sizeof(struct group)); 842 if (!g) 843 error("%s: can't allocate new group", caller); 844 *g = *group; 845 return g; 846 } 847 848 /* Write all interesting leases to permanent storage. */ 849 850 void 851 write_leases(void) 852 { 853 struct lease *l; 854 struct shared_network *s; 855 856 for (s = shared_networks; s; s = s->next) { 857 for (l = s->leases; l; l = l->next) { 858 if (l->hardware_addr.hlen || l->uid_len || 859 (l->flags & ABANDONED_LEASE)) { 860 if (!write_lease(l)) 861 error("Can't rewrite lease database"); 862 if (syncsend) 863 sync_lease(l); 864 } 865 } 866 } 867 if (!commit_leases()) 868 error("Can't commit leases to new database: %m"); 869 } 870