clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name memory.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/dhcpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/dhcpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/dhcpd/memory.c
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | #include <sys/types.h> |
| 42 | #include <sys/socket.h> |
| 43 | |
| 44 | #include <arpa/inet.h> |
| 45 | |
| 46 | #include <net/if.h> |
| 47 | |
| 48 | #include <netdb.h> |
| 49 | #include <stdio.h> |
| 50 | #include <stdlib.h> |
| 51 | #include <string.h> |
| 52 | |
| 53 | #include "dhcp.h" |
| 54 | #include "tree.h" |
| 55 | #include "dhcpd.h" |
| 56 | #include "log.h" |
| 57 | #include "sync.h" |
| 58 | |
| 59 | struct subnet *subnets; |
| 60 | static struct shared_network *shared_networks; |
| 61 | static struct hash_table *host_hw_addr_hash; |
| 62 | static struct hash_table *host_uid_hash; |
| 63 | static struct hash_table *lease_uid_hash; |
| 64 | static struct hash_table *lease_ip_addr_hash; |
| 65 | static struct hash_table *lease_hw_addr_hash; |
| 66 | static struct lease *dangling_leases; |
| 67 | |
| 68 | static struct hash_table *vendor_class_hash; |
| 69 | static struct hash_table *user_class_hash; |
| 70 | |
| 71 | extern int syncsend; |
| 72 | |
| 73 | void |
| 74 | enter_host(struct host_decl *hd) |
| 75 | { |
| 76 | struct host_decl *hp = NULL, *np = NULL; |
| 77 | |
| 78 | hd->n_ipaddr = NULL; |
| 79 | if (hd->interface.hlen) { |
| 80 | if (!host_hw_addr_hash) |
| 81 | host_hw_addr_hash = new_hash(); |
| 82 | else |
| 83 | hp = (struct host_decl *)hash_lookup(host_hw_addr_hash, |
| 84 | hd->interface.haddr, hd->interface.hlen); |
| 85 | |
| 86 | |
| 87 | |
| 88 | |
| 89 | |
| 90 | if (!hp) |
| 91 | add_hash(host_hw_addr_hash, hd->interface.haddr, |
| 92 | hd->interface.hlen, (unsigned char *)hd); |
| 93 | } |
| 94 | |
| 95 | |
| 96 | |
| 97 | |
| 98 | |
| 99 | if (hp) { |
| 100 | for (np = hp; np->n_ipaddr; np = np->n_ipaddr) |
| 101 | ; |
| 102 | np->n_ipaddr = hd; |
| 103 | } |
| 104 | |
| 105 | if (hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]) { |
| 106 | if (!tree_evaluate( |
| 107 | hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER])) |
| 108 | return; |
| 109 | |
| 110 | |
| 111 | |
| 112 | if (!host_uid_hash) { |
| 113 | host_uid_hash = new_hash(); |
| 114 | hp = NULL; |
| 115 | } else |
| 116 | hp = (struct host_decl *)hash_lookup(host_uid_hash, |
| 117 | hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->value, |
| 118 | hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->len); |
| 119 | |
| 120 | |
| 121 | |
| 122 | |
| 123 | |
| 124 | |
| 125 | if (hp) { |
| 126 | |
| 127 | if (!np) { |
| 128 | for (np = hp; np->n_ipaddr; |
| 129 | np = np->n_ipaddr) |
| 130 | ; |
| 131 | np->n_ipaddr = hd; |
| 132 | } |
| 133 | } else { |
| 134 | add_hash(host_uid_hash, |
| 135 | hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->value, |
| 136 | hd->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->len, |
| 137 | (unsigned char *)hd); |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | struct host_decl * |
| 143 | find_hosts_by_haddr(int htype, unsigned char *haddr, int hlen) |
| 144 | { |
| 145 | return (struct host_decl *)hash_lookup(host_hw_addr_hash, |
| 146 | haddr, hlen); |
| 147 | } |
| 148 | |
| 149 | struct host_decl * |
| 150 | find_hosts_by_uid(unsigned char *data, int len) |
| 151 | { |
| 152 | return (struct host_decl *)hash_lookup(host_uid_hash, data, len); |
| 153 | } |
| 154 | |
| 155 | |
| 156 | |
| 157 | |
| 158 | |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | struct subnet * |
| 165 | find_host_for_network(struct host_decl **host, struct iaddr *addr, |
| 166 | struct shared_network *share) |
| 167 | { |
| 168 | struct subnet *subnet; |
| 169 | struct iaddr ip_address; |
| 170 | struct host_decl *hp; |
| 171 | int i; |
| 172 | |
| 173 | for (hp = *host; hp; hp = hp->n_ipaddr) { |
| 174 | if (!hp->fixed_addr || !tree_evaluate(hp->fixed_addr)) |
| 175 | continue; |
| 176 | for (i = 0; i < hp->fixed_addr->len; i += 4) { |
| 177 | ip_address.len = 4; |
| 178 | memcpy(ip_address.iabuf, hp->fixed_addr->value + i, 4); |
| 179 | subnet = find_grouped_subnet(share, ip_address); |
| 180 | if (subnet) { |
| 181 | *addr = ip_address; |
| 182 | *host = hp; |
| 183 | return subnet; |
| 184 | } |
| 185 | } |
| 186 | } |
| 187 | return NULL; |
| 188 | } |
| 189 | |
| 190 | void |
| 191 | new_address_range(struct iaddr low, struct iaddr high, struct subnet *subnet, |
| 192 | int dynamic) |
| 193 | { |
| 194 | struct lease *address_range, *lp, *plp; |
| 195 | struct iaddr net; |
| 196 | int min, max, i; |
| 197 | char lowbuf[16], highbuf[16], netbuf[16]; |
| 198 | struct shared_network *share = subnet->shared_network; |
| 199 | struct hostent *h; |
| 200 | struct in_addr ia; |
| 201 | |
| 202 | |
| 203 | if (!share) { |
| 1 | Assuming 'share' is non-null | |
|
| |
| 204 | strlcpy(netbuf, piaddr(subnet->net), sizeof(netbuf)); |
| 205 | fatalx("No shared network for network %s (%s)", |
| 206 | netbuf, piaddr(subnet->netmask)); |
| 207 | } |
| 208 | |
| 209 | |
| 210 | if (!lease_uid_hash) |
| 3 | | Assuming 'lease_uid_hash' is non-null | |
|
| |
| 211 | lease_uid_hash = new_hash(); |
| 212 | if (!lease_ip_addr_hash) |
| 5 | | Assuming 'lease_ip_addr_hash' is non-null | |
|
| |
| 213 | lease_ip_addr_hash = new_hash(); |
| 214 | if (!lease_hw_addr_hash) |
| 7 | | Assuming 'lease_hw_addr_hash' is non-null | |
|
| |
| 215 | lease_hw_addr_hash = new_hash(); |
| 216 | |
| 217 | |
| 218 | net = subnet_number(low, subnet->netmask); |
| 219 | if (!addr_eq(net, subnet_number(high, subnet->netmask))) { |
| 9 | | Assuming the condition is false | |
|
| |
| 220 | strlcpy(lowbuf, piaddr(low), sizeof(lowbuf)); |
| 221 | strlcpy(highbuf, piaddr(high), sizeof(highbuf)); |
| 222 | strlcpy(netbuf, piaddr(subnet->netmask), sizeof(netbuf)); |
| 223 | fatalx("Address range %s to %s, netmask %s spans %s!", |
| 224 | lowbuf, highbuf, netbuf, "multiple subnets"); |
| 225 | } |
| 226 | |
| 227 | |
| 228 | if (!addr_eq(net, subnet->net)) { |
| 11 | | Assuming the condition is false | |
|
| |
| 229 | strlcpy(lowbuf, piaddr(low), sizeof(lowbuf)); |
| 230 | strlcpy(highbuf, piaddr(high), sizeof(highbuf)); |
| 231 | strlcpy(netbuf, piaddr(subnet->netmask), sizeof(netbuf)); |
| 232 | fatalx("Address range %s to %s not on net %s/%s!", |
| 233 | lowbuf, highbuf, piaddr(subnet->net), netbuf); |
| 234 | } |
| 235 | |
| 236 | |
| 237 | max = host_addr(high, subnet->netmask); |
| 238 | min = host_addr(low, subnet->netmask); |
| 239 | |
| 240 | |
| 241 | if (min > max) { |
| 13 | | Assuming 'min' is <= 'max' | |
|
| |
| 242 | max = min; |
| 243 | min = host_addr(high, subnet->netmask); |
| 244 | } |
| 245 | |
| 246 | |
| 247 | address_range = calloc(max - min + 1, sizeof(struct lease)); |
| |
| 248 | if (!address_range) { |
| 16 | | Assuming 'address_range' is non-null | |
|
| |
| 249 | strlcpy(lowbuf, piaddr(low), sizeof(lowbuf)); |
| 250 | strlcpy(highbuf, piaddr(high), sizeof(highbuf)); |
| 251 | fatalx("No memory for address range %s-%s.", lowbuf, highbuf); |
| 252 | } |
| 253 | memset(address_range, 0, (sizeof *address_range) * (max - min + 1)); |
| 254 | |
| 255 | |
| 256 | if (!share->last_lease) |
| 18 | | Assuming field 'last_lease' is non-null | |
|
| |
| 257 | share->last_lease = &address_range[0]; |
| 258 | |
| 259 | |
| 260 | for (i = 0; i < max - min + 1; i++) { |
| 20 | | Assuming the condition is false | |
|
| 21 | | Loop condition is false. Execution continues on line 296 | |
|
| 261 | address_range[i].ip_addr = ip_addr(subnet->net, |
| 262 | subnet->netmask, i + min); |
| 263 | address_range[i].starts = address_range[i].timestamp = |
| 264 | MIN_TIME; |
| 265 | address_range[i].ends = MIN_TIME; |
| 266 | address_range[i].subnet = subnet; |
| 267 | address_range[i].shared_network = share; |
| 268 | address_range[i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0; |
| 269 | |
| 270 | memcpy(&ia, address_range[i].ip_addr.iabuf, 4); |
| 271 | |
| 272 | if (subnet->group->get_lease_hostnames) { |
| 273 | h = gethostbyaddr((char *)&ia, sizeof ia, AF_INET); |
| 274 | if (!h) |
| 275 | log_warnx("No hostname for %s", inet_ntoa(ia)); |
| 276 | else { |
| 277 | address_range[i].hostname = strdup(h->h_name); |
| 278 | if (address_range[i].hostname == NULL) |
| 279 | fatalx("no memory for hostname %s.", |
| 280 | h->h_name); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | |
| 285 | address_range[i].next = share->leases; |
| 286 | address_range[i].prev = NULL; |
| 287 | share->leases = &address_range[i]; |
| 288 | if (address_range[i].next) |
| 289 | address_range[i].next->prev = share->leases; |
| 290 | add_hash(lease_ip_addr_hash, address_range[i].ip_addr.iabuf, |
| 291 | address_range[i].ip_addr.len, |
| 292 | (unsigned char *)&address_range[i]); |
| 293 | } |
| 294 | |
| 295 | |
| 296 | plp = NULL; |
| 297 | for (lp = dangling_leases; lp; lp = lp->next) { |
| 22 | | Loop condition is false. Execution continues on line 193 | |
|
| 298 | struct iaddr lnet; |
| 299 | int lhost; |
| 300 | |
| 301 | lnet = subnet_number(lp->ip_addr, subnet->netmask); |
| 302 | lhost = host_addr(lp->ip_addr, subnet->netmask); |
| 303 | |
| 304 | |
| 305 | |
| 306 | |
| 307 | if (addr_eq(lnet, subnet->net) && lhost >= i && lhost <= max) { |
| 308 | if (plp) { |
| 309 | plp->next = lp->next; |
| 310 | } else { |
| 311 | dangling_leases = lp->next; |
| 312 | } |
| 313 | lp->next = NULL; |
| 314 | address_range[lhost - i].hostname = lp->hostname; |
| 315 | address_range[lhost - i].client_hostname = |
| 316 | lp->client_hostname; |
| 317 | supersede_lease(&address_range[lhost - i], lp, 0); |
| 318 | free(lp); |
| 319 | return; |
| 320 | } else |
| 321 | plp = lp; |
| 322 | } |
| 323 | } |
| 23 | | Potential leak of memory pointed to by 'address_range' |
|
| 324 | |
| 325 | struct subnet * |
| 326 | find_subnet(struct iaddr addr) |
| 327 | { |
| 328 | struct subnet *rv; |
| 329 | |
| 330 | for (rv = subnets; rv; rv = rv->next_subnet) { |
| 331 | if (addr_eq(subnet_number(addr, rv->netmask), rv->net)) |
| 332 | return rv; |
| 333 | } |
| 334 | return NULL; |
| 335 | } |
| 336 | |
| 337 | struct subnet * |
| 338 | find_grouped_subnet(struct shared_network *share, struct iaddr addr) |
| 339 | { |
| 340 | struct subnet *rv; |
| 341 | |
| 342 | for (rv = share->subnets; rv; rv = rv->next_sibling) { |
| 343 | if (addr_eq(subnet_number(addr, rv->netmask), rv->net)) |
| 344 | return rv; |
| 345 | } |
| 346 | return NULL; |
| 347 | } |
| 348 | |
| 349 | int |
| 350 | subnet_inner_than(struct subnet *subnet, struct subnet *scan, int warnp) |
| 351 | { |
| 352 | if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) || |
| 353 | addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) { |
| 354 | char n1buf[16]; |
| 355 | int i, j; |
| 356 | |
| 357 | for (i = 0; i < 32; i++) |
| 358 | if (subnet->netmask.iabuf[3 - (i >> 3)] & |
| 359 | (1 << (i & 7))) |
| 360 | break; |
| 361 | for (j = 0; j < 32; j++) |
| 362 | if (scan->netmask.iabuf[3 - (j >> 3)] & |
| 363 | (1 << (j & 7))) |
| 364 | break; |
| 365 | strlcpy(n1buf, piaddr(subnet->net), sizeof(n1buf)); |
| 366 | if (warnp) |
| 367 | log_warnx("%ssubnet %s/%d conflicts with subnet %s/%d", |
| 368 | "Warning: ", n1buf, 32 - i, |
| 369 | piaddr(scan->net), 32 - j); |
| 370 | if (i < j) |
| 371 | return 1; |
| 372 | } |
| 373 | return 0; |
| 374 | } |
| 375 | |
| 376 | |
| 377 | void |
| 378 | enter_subnet(struct subnet *subnet) |
| 379 | { |
| 380 | struct subnet *scan, *prev = NULL; |
| 381 | |
| 382 | |
| 383 | for (scan = subnets; scan; scan = scan->next_subnet) { |
| 384 | |
| 385 | |
| 386 | |
| 387 | |
| 388 | |
| 389 | if (subnet_inner_than(subnet, scan, 1)) { |
| 390 | if (prev) { |
| 391 | prev->next_subnet = subnet; |
| 392 | } else |
| 393 | subnets = subnet; |
| 394 | subnet->next_subnet = scan; |
| 395 | return; |
| 396 | } |
| 397 | prev = scan; |
| 398 | } |
| 399 | |
| 400 | |
| 401 | subnet->next_subnet = subnets; |
| 402 | subnets = subnet; |
| 403 | } |
| 404 | |
| 405 | |
| 406 | void |
| 407 | enter_shared_network(struct shared_network *share) |
| 408 | { |
| 409 | |
| 410 | share->next = shared_networks; |
| 411 | shared_networks = share; |
| 412 | } |
| 413 | |
| 414 | |
| 415 | |
| 416 | |
| 417 | |
| 418 | |
| 419 | |
| 420 | |
| 421 | void |
| 422 | enter_lease(struct lease *lease) |
| 423 | { |
| 424 | struct lease *comp = find_lease_by_ip_addr(lease->ip_addr); |
| 425 | |
| 426 | |
| 427 | if (!comp) { |
| 428 | comp = calloc(1, sizeof(struct lease)); |
| 429 | if (!comp) |
| 430 | fatalx("No memory for lease %s\n", |
| 431 | piaddr(lease->ip_addr)); |
| 432 | *comp = *lease; |
| 433 | comp->next = dangling_leases; |
| 434 | comp->prev = NULL; |
| 435 | dangling_leases = comp; |
| 436 | } else { |
| 437 | |
| 438 | comp->hostname = lease->hostname; |
| 439 | comp->client_hostname = lease->client_hostname; |
| 440 | supersede_lease(comp, lease, 0); |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | static inline int |
| 445 | hwaddrcmp(struct hardware *a, struct hardware *b) |
| 446 | { |
| 447 | return ((a->htype != b->htype) || (a->hlen != b->hlen) || |
| 448 | memcmp(a->haddr, b->haddr, b->hlen)); |
| 449 | } |
| 450 | |
| 451 | static inline int |
| 452 | uidcmp(struct lease *a, struct lease *b) |
| 453 | { |
| 454 | return (a->uid_len != b->uid_len || memcmp(a->uid, b->uid, |
| 455 | b->uid_len)); |
| 456 | } |
| 457 | |
| 458 | static inline int |
| 459 | uid_or_hwaddr_cmp(struct lease *a, struct lease *b) |
| 460 | { |
| 461 | if (a->uid && b->uid) |
| 462 | return uidcmp(a, b); |
| 463 | return hwaddrcmp(&a->hardware_addr, &b->hardware_addr); |
| 464 | } |
| 465 | |
| 466 | |
| 467 | |
| 468 | |
| 469 | |
| 470 | |
| 471 | |
| 472 | int |
| 473 | supersede_lease(struct lease *comp, struct lease *lease, int commit) |
| 474 | { |
| 475 | int enter_uid = 0; |
| 476 | int enter_hwaddr = 0; |
| 477 | int do_pftable = 0; |
| 478 | struct lease *lp; |
| 479 | |
| 480 | |
| 481 | if (lease->flags & STATIC_LEASE) |
| 482 | return 1; |
| 483 | |
| 484 | |
| 485 | |
| 486 | |
| 487 | |
| 488 | |
| 489 | |
| 490 | |
| 491 | |
| 492 | |
| 493 | |
| 494 | if (!(lease->flags & ABANDONED_LEASE) && |
| 495 | comp->ends > cur_time && uid_or_hwaddr_cmp(comp, lease)) { |
| 496 | log_warnx("Lease conflict at %s", piaddr(comp->ip_addr)); |
| 497 | return 0; |
| 498 | } else { |
| 499 | |
| 500 | |
| 501 | if (comp->uid) { |
| 502 | uid_hash_delete(comp); |
| 503 | enter_uid = 1; |
| 504 | if (comp->uid != &comp->uid_buf[0]) { |
| 505 | if (comp->uid != lease->uid) |
| 506 | free(comp->uid); |
| 507 | comp->uid_max = 0; |
| 508 | comp->uid_len = 0; |
| 509 | } |
| 510 | comp->uid = NULL; |
| 511 | } else |
| 512 | enter_uid = 1; |
| 513 | |
| 514 | if (comp->hardware_addr.htype && |
| 515 | hwaddrcmp(&comp->hardware_addr, &lease->hardware_addr)) { |
| 516 | hw_hash_delete(comp); |
| 517 | enter_hwaddr = 1; |
| 518 | do_pftable = 1; |
| 519 | } else if (!comp->hardware_addr.htype) { |
| 520 | enter_hwaddr = 1; |
| 521 | do_pftable = 1; |
| 522 | } |
| 523 | |
| 524 | |
| 525 | comp->starts = lease->starts; |
| 526 | if (lease->uid) { |
| 527 | if (lease->uid_len <= sizeof (lease->uid_buf)) { |
| 528 | memcpy(comp->uid_buf, lease->uid, |
| 529 | lease->uid_len); |
| 530 | comp->uid = &comp->uid_buf[0]; |
| 531 | comp->uid_max = sizeof comp->uid_buf; |
| 532 | } else if (lease->uid != &lease->uid_buf[0]) { |
| 533 | comp->uid = lease->uid; |
| 534 | comp->uid_max = lease->uid_max; |
| 535 | lease->uid = NULL; |
| 536 | lease->uid_max = 0; |
| 537 | } else { |
| 538 | fatalx("corrupt lease uid."); |
| 539 | } |
| 540 | } else { |
| 541 | comp->uid = NULL; |
| 542 | comp->uid_max = 0; |
| 543 | } |
| 544 | comp->uid_len = lease->uid_len; |
| 545 | comp->host = lease->host; |
| 546 | comp->hardware_addr = lease->hardware_addr; |
| 547 | comp->flags = ((lease->flags & ~PERSISTENT_FLAGS) | |
| 548 | (comp->flags & ~EPHEMERAL_FLAGS)); |
| 549 | |
| 550 | |
| 551 | if (enter_uid && lease->uid) |
| 552 | uid_hash_add(comp); |
| 553 | |
| 554 | |
| 555 | if (enter_hwaddr && lease->hardware_addr.htype) |
| 556 | hw_hash_add(comp); |
| 557 | |
| 558 | |
| 559 | |
| 560 | if (comp->prev) |
| 561 | comp->prev->next = comp->next; |
| 562 | else |
| 563 | comp->shared_network->leases = comp->next; |
| 564 | if (comp->next) |
| 565 | comp->next->prev = comp->prev; |
| 566 | if (comp->shared_network->last_lease == comp) |
| 567 | comp->shared_network->last_lease = comp->prev; |
| 568 | |
| 569 | |
| 570 | if (comp == comp->shared_network->insertion_point || |
| 571 | !comp->shared_network->insertion_point) |
| 572 | lp = comp->shared_network->leases; |
| 573 | else |
| 574 | lp = comp->shared_network->insertion_point; |
| 575 | |
| 576 | if (!lp) { |
| 577 | |
| 578 | |
| 579 | comp->shared_network->leases = comp; |
| 580 | comp->shared_network->last_lease = comp; |
| 581 | } else if (lp->ends > lease->ends) { |
| 582 | |
| 583 | |
| 584 | while (lp->next && lp->ends > lease->ends) { |
| 585 | lp = lp->next; |
| 586 | } |
| 587 | if (lp->ends > lease->ends) { |
| 588 | |
| 589 | |
| 590 | lp->next = comp; |
| 591 | comp->prev = lp; |
| 592 | comp->next = NULL; |
| 593 | comp->shared_network->last_lease = comp; |
| 594 | } else { |
| 595 | |
| 596 | |
| 597 | if ((comp->prev = lp->prev)) |
| 598 | comp->prev->next = comp; |
| 599 | comp->next = lp; |
| 600 | lp->prev = comp; |
| 601 | } |
| 602 | } else { |
| 603 | |
| 604 | |
| 605 | while (lp->prev && lp->ends < lease->ends) { |
| 606 | lp = lp->prev; |
| 607 | } |
| 608 | if (lp->ends < lease->ends) { |
| 609 | |
| 610 | |
| 611 | lp->prev = comp; |
| 612 | comp->next = lp; |
| 613 | comp->prev = NULL; |
| 614 | comp->shared_network->leases = comp; |
| 615 | } else { |
| 616 | |
| 617 | |
| 618 | if ((comp->next = lp->next)) |
| 619 | comp->next->prev = comp; |
| 620 | comp->prev = lp; |
| 621 | lp->next = comp; |
| 622 | } |
| 623 | } |
| 624 | comp->shared_network->insertion_point = comp; |
| 625 | comp->ends = lease->ends; |
| 626 | } |
| 627 | |
| 628 | pfmsg('L', lease); |
| 629 | if (do_pftable) |
| 630 | pfmsg('C', lease); |
| 631 | |
| 632 | |
| 633 | |
| 634 | return commit && write_lease(comp) && commit_leases(); |
| 635 | } |
| 636 | |
| 637 | |
| 638 | |
| 639 | void |
| 640 | release_lease(struct lease *lease) |
| 641 | { |
| 642 | struct lease lt; |
| 643 | |
| 644 | lt = *lease; |
| 645 | if (lt.ends > cur_time) { |
| 646 | lt.ends = cur_time; |
| 647 | supersede_lease(lease, <, 1); |
| 648 | log_info("Released lease for IP address %s", |
| 649 | piaddr(lease->ip_addr)); |
| 650 | pfmsg('R', lease); |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | |
| 655 | |
| 656 | |
| 657 | |
| 658 | |
| 659 | |
| 660 | void |
| 661 | abandon_lease(struct lease *lease, char *message) |
| 662 | { |
| 663 | struct lease lt; |
| 664 | time_t abtime; |
| 665 | |
| 666 | abtime = lease->subnet->group->default_lease_time; |
| 667 | lease->flags |= ABANDONED_LEASE; |
| 668 | lt = *lease; |
| 669 | lt.ends = cur_time + abtime; |
| 670 | log_warnx("Abandoning IP address %s for %lld seconds: %s", |
| 671 | piaddr(lease->ip_addr), (long long)abtime, message); |
| 672 | lt.hardware_addr.htype = 0; |
| 673 | lt.hardware_addr.hlen = 0; |
| 674 | lt.uid = NULL; |
| 675 | lt.uid_len = 0; |
| 676 | supersede_lease(lease, <, 1); |
| 677 | |
| 678 | pfmsg('A', lease); |
| 679 | return; |
| 680 | } |
| 681 | |
| 682 | |
| 683 | struct lease * |
| 684 | find_lease_by_ip_addr(struct iaddr addr) |
| 685 | { |
| 686 | return (struct lease *)hash_lookup(lease_ip_addr_hash, |
| 687 | addr.iabuf, addr.len); |
| 688 | } |
| 689 | |
| 690 | struct lease * |
| 691 | find_lease_by_uid(unsigned char *uid, int len) |
| 692 | { |
| 693 | return (struct lease *)hash_lookup(lease_uid_hash, uid, len); |
| 694 | } |
| 695 | |
| 696 | struct lease * |
| 697 | find_lease_by_hw_addr(unsigned char *hwaddr, int hwlen) |
| 698 | { |
| 699 | return (struct lease *)hash_lookup(lease_hw_addr_hash, hwaddr, hwlen); |
| 700 | } |
| 701 | |
| 702 | |
| 703 | void |
| 704 | uid_hash_add(struct lease *lease) |
| 705 | { |
| 706 | struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len); |
| 707 | struct lease *scan; |
| 708 | |
| 709 | |
| 710 | if (!head) |
| 711 | add_hash(lease_uid_hash, lease->uid, |
| 712 | lease->uid_len, (unsigned char *)lease); |
| 713 | else { |
| 714 | |
| 715 | for (scan = head; scan->n_uid; scan = scan->n_uid) |
| 716 | ; |
| 717 | scan->n_uid = lease; |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | |
| 722 | void |
| 723 | uid_hash_delete(struct lease *lease) |
| 724 | { |
| 725 | struct lease *head = find_lease_by_uid(lease->uid, lease->uid_len); |
| 726 | struct lease *scan; |
| 727 | |
| 728 | |
| 729 | if (!head) { |
| 730 | lease->n_uid = NULL; |
| 731 | return; |
| 732 | } |
| 733 | |
| 734 | |
| 735 | |
| 736 | |
| 737 | if (head == lease) { |
| 738 | delete_hash_entry(lease_uid_hash, lease->uid, lease->uid_len); |
| 739 | if (lease->n_uid) |
| 740 | add_hash(lease_uid_hash, lease->n_uid->uid, |
| 741 | lease->n_uid->uid_len, |
| 742 | (unsigned char *)(lease->n_uid)); |
| 743 | } else { |
| 744 | |
| 745 | |
| 746 | |
| 747 | for (scan = head; scan->n_uid; scan = scan->n_uid) { |
| 748 | if (scan->n_uid == lease) { |
| 749 | scan->n_uid = scan->n_uid->n_uid; |
| 750 | break; |
| 751 | } |
| 752 | } |
| 753 | } |
| 754 | lease->n_uid = NULL; |
| 755 | } |
| 756 | |
| 757 | |
| 758 | void |
| 759 | hw_hash_add(struct lease *lease) |
| 760 | { |
| 761 | struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr, |
| 762 | lease->hardware_addr.hlen); |
| 763 | struct lease *scan; |
| 764 | |
| 765 | |
| 766 | if (!head) |
| 767 | add_hash(lease_hw_addr_hash, lease->hardware_addr.haddr, |
| 768 | lease->hardware_addr.hlen, (unsigned char *)lease); |
| 769 | else { |
| 770 | |
| 771 | for (scan = head; scan->n_hw; scan = scan->n_hw) |
| 772 | ; |
| 773 | scan->n_hw = lease; |
| 774 | } |
| 775 | } |
| 776 | |
| 777 | |
| 778 | void |
| 779 | hw_hash_delete(struct lease *lease) |
| 780 | { |
| 781 | struct lease *head = find_lease_by_hw_addr(lease->hardware_addr.haddr, |
| 782 | lease->hardware_addr.hlen); |
| 783 | struct lease *scan; |
| 784 | |
| 785 | |
| 786 | if (!head) { |
| 787 | lease->n_hw = NULL; |
| 788 | return; |
| 789 | } |
| 790 | |
| 791 | |
| 792 | |
| 793 | |
| 794 | if (head == lease) { |
| 795 | delete_hash_entry(lease_hw_addr_hash, |
| 796 | lease->hardware_addr.haddr, lease->hardware_addr.hlen); |
| 797 | if (lease->n_hw) |
| 798 | add_hash(lease_hw_addr_hash, |
| 799 | lease->n_hw->hardware_addr.haddr, |
| 800 | lease->n_hw->hardware_addr.hlen, |
| 801 | (unsigned char *)(lease->n_hw)); |
| 802 | } else { |
| 803 | |
| 804 | |
| 805 | |
| 806 | |
| 807 | |
| 808 | for (scan = head; scan->n_hw; scan = scan->n_hw) { |
| 809 | if (scan->n_hw == lease) { |
| 810 | scan->n_hw = scan->n_hw->n_hw; |
| 811 | break; |
| 812 | } |
| 813 | } |
| 814 | } |
| 815 | lease->n_hw = NULL; |
| 816 | } |
| 817 | |
| 818 | |
| 819 | struct class * |
| 820 | add_class(int type, char *name) |
| 821 | { |
| 822 | struct class *class; |
| 823 | char *tname; |
| 824 | |
| 825 | class = calloc(1, sizeof(*class)); |
| 826 | tname = strdup(name); |
| 827 | |
| 828 | if (!vendor_class_hash) |
| 829 | vendor_class_hash = new_hash(); |
| 830 | if (!user_class_hash) |
| 831 | user_class_hash = new_hash(); |
| 832 | |
| 833 | if (!tname || !class || !vendor_class_hash || !user_class_hash) { |
| 834 | log_warnx("No memory for %s.", name); |
| 835 | free(class); |
| 836 | free(tname); |
| 837 | return NULL; |
| 838 | } |
| 839 | |
| 840 | class->name = tname; |
| 841 | |
| 842 | if (type) |
| 843 | add_hash(user_class_hash, (unsigned char *)tname, |
| 844 | strlen(tname), (unsigned char *)class); |
| 845 | else |
| 846 | add_hash(vendor_class_hash, (unsigned char *)tname, |
| 847 | strlen(tname), (unsigned char *)class); |
| 848 | |
| 849 | return class; |
| 850 | } |
| 851 | |
| 852 | struct class * |
| 853 | find_class(int type, unsigned char *name, int len) |
| 854 | { |
| 855 | return (struct class *)hash_lookup(type ? user_class_hash : |
| 856 | vendor_class_hash, name, len); |
| 857 | } |
| 858 | |
| 859 | struct group * |
| 860 | clone_group(struct group *group, char *caller) |
| 861 | { |
| 862 | struct group *g; |
| 863 | |
| 864 | g = calloc(1, sizeof(struct group)); |
| 865 | if (!g) |
| 866 | fatalx("%s: can't allocate new group", caller); |
| 867 | *g = *group; |
| 868 | return g; |
| 869 | } |
| 870 | |
| 871 | |
| 872 | |
| 873 | void |
| 874 | write_leases(void) |
| 875 | { |
| 876 | struct lease *l; |
| 877 | struct shared_network *s; |
| 878 | |
| 879 | for (s = shared_networks; s; s = s->next) { |
| 880 | for (l = s->leases; l; l = l->next) { |
| 881 | if (l->hardware_addr.hlen || l->uid_len || |
| 882 | (l->flags & ABANDONED_LEASE)) { |
| 883 | if (!write_lease(l)) |
| 884 | fatalx("Can't rewrite lease database"); |
| 885 | if (syncsend) |
| 886 | sync_lease(l); |
| 887 | } |
| 888 | } |
| 889 | } |
| 890 | if (!commit_leases()) |
| 891 | fatal("Can't commit leases to new database"); |
| 892 | } |