1 /* $OpenBSD: memory.c,v 1.20 2010/03/27 14:11:38 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 "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 /* 427 * Replace the data in an existing lease with the data in a new lease; 428 * adjust hash tables to suit, and insertion sort the lease into the 429 * list of leases by expiry time so that we can always find the oldest 430 * lease. 431 */ 432 int 433 supersede_lease(struct lease *comp, struct lease *lease, int commit) 434 { 435 int enter_uid = 0; 436 int enter_hwaddr = 0; 437 int do_pftable = 0; 438 struct lease *lp; 439 440 /* Static leases are not currently kept in the database... */ 441 if (lease->flags & STATIC_LEASE) 442 return 1; 443 444 /* 445 * If the existing lease hasn't expired and has a different 446 * unique identifier or, if it doesn't have a unique 447 * identifier, a different hardware address, then the two 448 * leases are in conflict. If the existing lease has a uid 449 * and the new one doesn't, but they both have the same 450 * hardware address, and dynamic bootp is allowed on this 451 * lease, then we allow that, in case a dynamic BOOTP lease is 452 * requested *after* a DHCP lease has been assigned. 453 */ 454 if (!(lease->flags & ABANDONED_LEASE) && 455 comp->ends > cur_time && 456 (((comp->uid && lease->uid) && 457 (comp->uid_len != lease->uid_len || 458 memcmp (comp->uid, lease->uid, comp->uid_len))) || 459 (!comp->uid && 460 ((comp->hardware_addr.htype != 461 lease->hardware_addr.htype) || 462 (comp->hardware_addr.hlen != 463 lease->hardware_addr.hlen) || 464 memcmp(comp->hardware_addr.haddr, lease->hardware_addr.haddr, 465 comp->hardware_addr.hlen))))) { 466 warning("Lease conflict at %s", piaddr(comp->ip_addr)); 467 return 0; 468 } else { 469 /* If there's a Unique ID, dissociate it from the hash 470 table and free it if necessary. */ 471 if (comp->uid) { 472 uid_hash_delete(comp); 473 enter_uid = 1; 474 if (comp->uid != &comp->uid_buf[0]) { 475 free(comp->uid); 476 comp->uid_max = 0; 477 comp->uid_len = 0; 478 } 479 comp->uid = NULL; 480 } else 481 enter_uid = 1; 482 483 if (comp->hardware_addr.htype && 484 ((comp->hardware_addr.hlen != 485 lease->hardware_addr.hlen) || 486 (comp->hardware_addr.htype != 487 lease->hardware_addr.htype) || 488 memcmp(comp->hardware_addr.haddr, lease->hardware_addr.haddr, 489 comp->hardware_addr.hlen))) { 490 hw_hash_delete(comp); 491 enter_hwaddr = 1; 492 do_pftable = 1; 493 } else if (!comp->hardware_addr.htype) { 494 enter_hwaddr = 1; 495 do_pftable = 1; 496 } 497 498 /* Copy the data files, but not the linkages. */ 499 comp->starts = lease->starts; 500 if (lease->uid) { 501 if (lease->uid_len <= sizeof (lease->uid_buf)) { 502 memcpy(comp->uid_buf, lease->uid, lease->uid_len); 503 comp->uid = &comp->uid_buf[0]; 504 comp->uid_max = sizeof comp->uid_buf; 505 } else if (lease->uid != &lease->uid_buf[0]) { 506 comp->uid = lease->uid; 507 comp->uid_max = lease->uid_max; 508 lease->uid = NULL; 509 lease->uid_max = 0; 510 } else { 511 error("corrupt lease uid."); /* XXX */ 512 } 513 } else { 514 comp->uid = NULL; 515 comp->uid_max = 0; 516 } 517 comp->uid_len = lease->uid_len; 518 comp->host = lease->host; 519 comp->hardware_addr = lease->hardware_addr; 520 comp->flags = ((lease->flags & ~PERSISTENT_FLAGS) | 521 (comp->flags & ~EPHEMERAL_FLAGS)); 522 523 /* Record the lease in the uid hash if necessary. */ 524 if (enter_uid && lease->uid) 525 uid_hash_add(comp); 526 527 /* Record it in the hardware address hash if necessary. */ 528 if (enter_hwaddr && lease->hardware_addr.htype) 529 hw_hash_add(comp); 530 531 /* Remove the lease from its current place in the 532 timeout sequence. */ 533 if (comp->prev) 534 comp->prev->next = comp->next; 535 else 536 comp->shared_network->leases = comp->next; 537 if (comp->next) 538 comp->next->prev = comp->prev; 539 if (comp->shared_network->last_lease == comp) 540 comp->shared_network->last_lease = comp->prev; 541 542 /* Find the last insertion point... */ 543 if (comp == comp->shared_network->insertion_point || 544 !comp->shared_network->insertion_point) 545 lp = comp->shared_network->leases; 546 else 547 lp = comp->shared_network->insertion_point; 548 549 if (!lp) { 550 /* Nothing on the list yet? Just make comp the 551 head of the list. */ 552 comp->shared_network->leases = comp; 553 comp->shared_network->last_lease = comp; 554 } else if (lp->ends > lease->ends) { 555 /* Skip down the list until we run out of list 556 or find a place for comp. */ 557 while (lp->next && lp->ends > lease->ends) { 558 lp = lp->next; 559 } 560 if (lp->ends > lease->ends) { 561 /* If we ran out of list, put comp 562 at the end. */ 563 lp->next = comp; 564 comp->prev = lp; 565 comp->next = NULL; 566 comp->shared_network->last_lease = comp; 567 } else { 568 /* If we didn't, put it between lp and 569 the previous item on the list. */ 570 if ((comp->prev = lp->prev)) 571 comp->prev->next = comp; 572 comp->next = lp; 573 lp->prev = comp; 574 } 575 } else { 576 /* Skip up the list until we run out of list 577 or find a place for comp. */ 578 while (lp->prev && lp->ends < lease->ends) { 579 lp = lp->prev; 580 } 581 if (lp->ends < lease->ends) { 582 /* If we ran out of list, put comp 583 at the beginning. */ 584 lp->prev = comp; 585 comp->next = lp; 586 comp->prev = NULL; 587 comp->shared_network->leases = comp; 588 } else { 589 /* If we didn't, put it between lp and 590 the next item on the list. */ 591 if ((comp->next = lp->next)) 592 comp->next->prev = comp; 593 comp->prev = lp; 594 lp->next = comp; 595 } 596 } 597 comp->shared_network->insertion_point = comp; 598 comp->ends = lease->ends; 599 } 600 601 pfmsg('L', lease); /* address is leased. remove from purgatory */ 602 if (do_pftable) /* address changed hwaddr. remove from overload */ 603 pfmsg('C', lease); 604 605 /* Return zero if we didn't commit the lease to permanent storage; 606 nonzero if we did. */ 607 return commit && write_lease(comp) && commit_leases(); 608 } 609 610 /* Release the specified lease and re-hash it as appropriate. */ 611 612 void 613 release_lease(struct lease *lease) 614 { 615 struct lease lt; 616 617 lt = *lease; 618 if (lt.ends > cur_time) { 619 lt.ends = cur_time; 620 supersede_lease(lease, <, 1); 621 note("Released lease for IP address %s", 622 piaddr(lease->ip_addr)); 623 } 624 } 625 626 627 /* 628 * Abandon the specified lease for the specified time. sets it's 629 * particulars to zero, the end time appropriately and re-hash it as 630 * appropriate. abandons permanently if abtime is 0 631 */ 632 void 633 abandon_lease(struct lease *lease, char *message) 634 { 635 struct lease lt; 636 time_t abtime; 637 638 abtime = lease->subnet->group->default_lease_time; 639 lease->flags |= ABANDONED_LEASE; 640 lt = *lease; 641 lt.ends = cur_time + abtime; 642 warning("Abandoning IP address %s for %d seconds: %s", 643 piaddr(lease->ip_addr), abtime, message); 644 lt.hardware_addr.htype = 0; 645 lt.hardware_addr.hlen = 0; 646 lt.uid = NULL; 647 lt.uid_len = 0; 648 supersede_lease(lease, <, 1); 649 650 pfmsg('A', lease); /* address is abandoned. send to purgatory */ 651 return; 652 } 653 654 /* Locate the lease associated with a given IP address... */ 655 struct lease * 656 find_lease_by_ip_addr(struct iaddr addr) 657 { 658 return (struct lease *)hash_lookup(lease_ip_addr_hash, 659 addr.iabuf, addr.len); 660 } 661 662 struct lease *find_lease_by_uid(unsigned char *uid, int len) 663 { 664 return (struct lease *)hash_lookup(lease_uid_hash, uid, len); 665 } 666 667 struct lease * 668 find_lease_by_hw_addr(unsigned char *hwaddr, int hwlen) 669 { 670 return (struct lease *)hash_lookup(lease_hw_addr_hash, hwaddr, hwlen); 671 } 672 673 /* Add the specified lease to the uid hash. */ 674 void 675 uid_hash_add(struct lease *lease) 676 { 677 struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len); 678 struct lease *scan; 679 680 /* If it's not in the hash, just add it. */ 681 if (!head) 682 add_hash(lease_uid_hash, lease->uid, 683 lease->uid_len, (unsigned char *)lease); 684 else { 685 /* Otherwise, attach it to the end of the list. */ 686 for (scan = head; scan->n_uid; scan = scan->n_uid) 687 ; 688 scan->n_uid = lease; 689 } 690 } 691 692 /* Delete the specified lease from the uid hash. */ 693 void 694 uid_hash_delete(struct lease *lease) 695 { 696 struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len); 697 struct lease *scan; 698 699 /* If it's not in the hash, we have no work to do. */ 700 if (!head) { 701 lease->n_uid = NULL; 702 return; 703 } 704 705 /* If the lease we're freeing is at the head of the list, 706 remove the hash table entry and add a new one with the 707 next lease on the list (if there is one). */ 708 if (head == lease) { 709 delete_hash_entry(lease_uid_hash, lease->uid, lease->uid_len); 710 if (lease->n_uid) 711 add_hash(lease_uid_hash, lease->n_uid->uid, 712 lease->n_uid->uid_len, 713 (unsigned char *)(lease->n_uid)); 714 } else { 715 /* Otherwise, look for the lease in the list of leases 716 attached to the hash table entry, and remove it if 717 we find it. */ 718 for (scan = head; scan->n_uid; scan = scan->n_uid) { 719 if (scan->n_uid == lease) { 720 scan->n_uid = scan->n_uid->n_uid; 721 break; 722 } 723 } 724 } 725 lease->n_uid = NULL; 726 } 727 728 /* Add the specified lease to the hardware address hash. */ 729 void 730 hw_hash_add(struct lease *lease) 731 { 732 struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr, 733 lease->hardware_addr.hlen); 734 struct lease *scan; 735 736 /* If it's not in the hash, just add it. */ 737 if (!head) 738 add_hash(lease_hw_addr_hash, lease->hardware_addr.haddr, 739 lease->hardware_addr.hlen, (unsigned char *)lease); 740 else { 741 /* Otherwise, attach it to the end of the list. */ 742 for (scan = head; scan->n_hw; scan = scan->n_hw) 743 ; 744 scan->n_hw = lease; 745 } 746 } 747 748 /* Delete the specified lease from the hardware address hash. */ 749 void 750 hw_hash_delete(struct lease *lease) 751 { 752 struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr, 753 lease->hardware_addr.hlen); 754 struct lease *scan; 755 756 /* If it's not in the hash, we have no work to do. */ 757 if (!head) { 758 lease->n_hw = NULL; 759 return; 760 } 761 762 /* If the lease we're freeing is at the head of the list, 763 remove the hash table entry and add a new one with the 764 next lease on the list (if there is one). */ 765 if (head == lease) { 766 delete_hash_entry(lease_hw_addr_hash, 767 lease->hardware_addr.haddr, lease->hardware_addr.hlen); 768 if (lease->n_hw) 769 add_hash(lease_hw_addr_hash, 770 lease->n_hw->hardware_addr.haddr, 771 lease->n_hw->hardware_addr.hlen, 772 (unsigned char *)(lease->n_hw)); 773 } else { 774 /* 775 * Otherwise, look for the lease in the list of leases 776 * attached to the hash table entry, and remove it if 777 * we find it. 778 */ 779 for (scan = head; scan->n_hw; scan = scan->n_hw) { 780 if (scan->n_hw == lease) { 781 scan->n_hw = scan->n_hw->n_hw; 782 break; 783 } 784 } 785 } 786 lease->n_hw = NULL; 787 } 788 789 790 struct class * 791 add_class(int type, char *name) 792 { 793 struct class *class; 794 char *tname; 795 796 class = calloc(1, sizeof(*class)); 797 tname = strdup(name); 798 799 if (!vendor_class_hash) 800 vendor_class_hash = new_hash(); 801 if (!user_class_hash) 802 user_class_hash = new_hash(); 803 804 if (!tname || !class || !vendor_class_hash || !user_class_hash) { 805 warning("No memory for %s.", name); 806 free(class); 807 free(tname); 808 return NULL; 809 } 810 811 class->name = tname; 812 813 if (type) 814 add_hash(user_class_hash, (unsigned char *)tname, 815 strlen(tname), (unsigned char *)class); 816 else 817 add_hash(vendor_class_hash, (unsigned char *)tname, 818 strlen(tname), (unsigned char *)class); 819 820 return class; 821 } 822 823 struct class * 824 find_class(int type, unsigned char *name, int len) 825 { 826 return (struct class *)hash_lookup(type ? user_class_hash : 827 vendor_class_hash, name, len); 828 } 829 830 struct group * 831 clone_group(struct group *group, char *caller) 832 { 833 struct group *g; 834 835 g = calloc(1, sizeof(struct group)); 836 if (!g) 837 error("%s: can't allocate new group", caller); 838 *g = *group; 839 return g; 840 } 841 842 /* Write all interesting leases to permanent storage. */ 843 844 void 845 write_leases(void) 846 { 847 struct lease *l; 848 struct shared_network *s; 849 850 for (s = shared_networks; s; s = s->next) { 851 for (l = s->leases; l; l = l->next) { 852 if (l->hardware_addr.hlen || l->uid_len || 853 (l->flags & ABANDONED_LEASE)) { 854 if (!write_lease(l)) 855 error("Can't rewrite lease database"); 856 if (syncsend) 857 sync_lease(l); 858 } 859 } 860 } 861 if (!commit_leases()) 862 error("Can't commit leases to new database: %m"); 863 } 864