1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * dhcpcd - DHCP client daemon 4 * Copyright (c) 2006-2021 Roy Marples <roy@marples.name> 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 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/utsname.h> 30 31 #include <ctype.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <inttypes.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "config.h" 40 41 #include "common.h" 42 #include "dhcp-common.h" 43 #include "dhcp.h" 44 #include "if.h" 45 #include "ipv6.h" 46 #include "logerr.h" 47 #include "script.h" 48 49 const char * 50 dhcp_get_hostname(char *buf, size_t buf_len, const struct if_options *ifo) 51 { 52 53 if (ifo->hostname[0] == '\0') { 54 if (gethostname(buf, buf_len) != 0) 55 return NULL; 56 buf[buf_len - 1] = '\0'; 57 } else 58 strlcpy(buf, ifo->hostname, buf_len); 59 60 /* Deny sending of these local hostnames */ 61 if (buf[0] == '\0' || buf[0] == '.' || 62 strcmp(buf, "(none)") == 0 || 63 strcmp(buf, "localhost") == 0 || 64 strncmp(buf, "localhost.", strlen("localhost.")) == 0) 65 return NULL; 66 67 /* Shorten the hostname if required */ 68 if (ifo->options & DHCPCD_HOSTNAME_SHORT) { 69 char *hp; 70 71 hp = strchr(buf, '.'); 72 if (hp != NULL) 73 *hp = '\0'; 74 } 75 76 return buf; 77 } 78 79 void 80 dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols) 81 { 82 83 while (cols < 40) { 84 putchar(' '); 85 cols++; 86 } 87 putchar('\t'); 88 if (opt->type & OT_EMBED) 89 printf(" embed"); 90 if (opt->type & OT_ENCAP) 91 printf(" encap"); 92 if (opt->type & OT_INDEX) 93 printf(" index"); 94 if (opt->type & OT_ARRAY) 95 printf(" array"); 96 if (opt->type & OT_UINT8) 97 printf(" uint8"); 98 else if (opt->type & OT_INT8) 99 printf(" int8"); 100 else if (opt->type & OT_UINT16) 101 printf(" uint16"); 102 else if (opt->type & OT_INT16) 103 printf(" int16"); 104 else if (opt->type & OT_UINT32) 105 printf(" uint32"); 106 else if (opt->type & OT_INT32) 107 printf(" int32"); 108 else if (opt->type & OT_ADDRIPV4) 109 printf(" ipaddress"); 110 else if (opt->type & OT_ADDRIPV6) 111 printf(" ip6address"); 112 else if (opt->type & OT_FLAG) 113 printf(" flag"); 114 else if (opt->type & OT_BITFLAG) 115 printf(" bitflags"); 116 else if (opt->type & OT_RFC1035) 117 printf(" domain"); 118 else if (opt->type & OT_DOMAIN) 119 printf(" dname"); 120 else if (opt->type & OT_ASCII) 121 printf(" ascii"); 122 else if (opt->type & OT_RAW) 123 printf(" raw"); 124 else if (opt->type & OT_BINHEX) 125 printf(" binhex"); 126 else if (opt->type & OT_STRING) 127 printf(" string"); 128 if (opt->type & OT_RFC3361) 129 printf(" rfc3361"); 130 if (opt->type & OT_RFC3442) 131 printf(" rfc3442"); 132 if (opt->type & OT_REQUEST) 133 printf(" request"); 134 if (opt->type & OT_NOREQ) 135 printf(" norequest"); 136 putchar('\n'); 137 } 138 139 struct dhcp_opt * 140 vivso_find(uint32_t iana_en, const void *arg) 141 { 142 const struct interface *ifp; 143 size_t i; 144 struct dhcp_opt *opt; 145 146 ifp = arg; 147 for (i = 0, opt = ifp->options->vivso_override; 148 i < ifp->options->vivso_override_len; 149 i++, opt++) 150 if (opt->option == iana_en) 151 return opt; 152 for (i = 0, opt = ifp->ctx->vivso; 153 i < ifp->ctx->vivso_len; 154 i++, opt++) 155 if (opt->option == iana_en) 156 return opt; 157 return NULL; 158 } 159 160 ssize_t 161 dhcp_vendor(char *str, size_t len) 162 { 163 struct utsname utn; 164 char *p; 165 int l; 166 167 if (uname(&utn) == -1) 168 return (ssize_t)snprintf(str, len, "%s-%s", 169 PACKAGE, VERSION); 170 p = str; 171 l = snprintf(p, len, 172 "%s-%s:%s-%s:%s", PACKAGE, VERSION, 173 utn.sysname, utn.release, utn.machine); 174 if (l == -1 || (size_t)(l + 1) > len) 175 return -1; 176 p += l; 177 len -= (size_t)l; 178 l = if_machinearch(p + 1, len - 1); 179 if (l == -1 || (size_t)(l + 1) > len) 180 return -1; 181 *p = ':'; 182 p += l; 183 return p - str; 184 } 185 186 int 187 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len, 188 const struct dhcp_opt *odopts, size_t odopts_len, 189 uint8_t *mask, const char *opts, int add) 190 { 191 char *token, *o, *p; 192 const struct dhcp_opt *opt; 193 int match, e; 194 unsigned int n; 195 size_t i; 196 197 if (opts == NULL) 198 return -1; 199 o = p = strdup(opts); 200 while ((token = strsep(&p, ", "))) { 201 if (*token == '\0') 202 continue; 203 if (strncmp(token, "dhcp6_", 6) == 0) 204 token += 6; 205 if (strncmp(token, "nd_", 3) == 0) 206 token += 3; 207 match = 0; 208 for (i = 0, opt = odopts; i < odopts_len; i++, opt++) { 209 if (opt->var == NULL || opt->option == 0) 210 continue; /* buggy dhcpcd-definitions.conf */ 211 if (strcmp(opt->var, token) == 0) 212 match = 1; 213 else { 214 n = (unsigned int)strtou(token, NULL, 0, 215 0, UINT_MAX, &e); 216 if (e == 0 && opt->option == n) 217 match = 1; 218 } 219 if (match) 220 break; 221 } 222 if (match == 0) { 223 for (i = 0, opt = dopts; i < dopts_len; i++, opt++) { 224 if (strcmp(opt->var, token) == 0) 225 match = 1; 226 else { 227 n = (unsigned int)strtou(token, NULL, 0, 228 0, UINT_MAX, &e); 229 if (e == 0 && opt->option == n) 230 match = 1; 231 } 232 if (match) 233 break; 234 } 235 } 236 if (!match || !opt->option) { 237 free(o); 238 errno = ENOENT; 239 return -1; 240 } 241 if (add == 2 && !(opt->type & OT_ADDRIPV4)) { 242 free(o); 243 errno = EINVAL; 244 return -1; 245 } 246 if (add == 1 || add == 2) 247 add_option_mask(mask, opt->option); 248 else 249 del_option_mask(mask, opt->option); 250 } 251 free(o); 252 return 0; 253 } 254 255 size_t 256 encode_rfc1035(const char *src, uint8_t *dst) 257 { 258 uint8_t *p; 259 uint8_t *lp; 260 size_t len; 261 uint8_t has_dot; 262 263 if (src == NULL || *src == '\0') 264 return 0; 265 266 if (dst) { 267 p = dst; 268 lp = p++; 269 } 270 /* Silence bogus GCC warnings */ 271 else 272 p = lp = NULL; 273 274 len = 1; 275 has_dot = 0; 276 for (; *src; src++) { 277 if (*src == '\0') 278 break; 279 if (*src == '.') { 280 /* Skip the trailing . */ 281 if (src[1] == '\0') 282 break; 283 has_dot = 1; 284 if (dst) { 285 *lp = (uint8_t)(p - lp - 1); 286 if (*lp == '\0') 287 return len; 288 lp = p++; 289 } 290 } else if (dst) 291 *p++ = (uint8_t)*src; 292 len++; 293 } 294 295 if (dst) { 296 *lp = (uint8_t)(p - lp - 1); 297 if (has_dot) 298 *p++ = '\0'; 299 } 300 301 if (has_dot) 302 len++; 303 304 return len; 305 } 306 307 /* Decode an RFC1035 DNS search order option into a space 308 * separated string. Returns length of string (including 309 * terminating zero) or zero on error. out may be NULL 310 * to just determine output length. */ 311 ssize_t 312 decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl) 313 { 314 const char *start; 315 size_t start_len, l, d_len, o_len; 316 const uint8_t *r, *q = p, *e; 317 int hops; 318 uint8_t ltype; 319 320 o_len = 0; 321 start = out; 322 start_len = len; 323 q = p; 324 e = p + pl; 325 while (q < e) { 326 r = NULL; 327 d_len = 0; 328 hops = 0; 329 /* Check we are inside our length again in-case 330 * the name isn't fully qualified (ie, not terminated) */ 331 while (q < e && (l = (size_t)*q++)) { 332 ltype = l & 0xc0; 333 if (ltype == 0x80 || ltype == 0x40) { 334 /* Currently reserved for future use as noted 335 * in RFC1035 4.1.4 as the 10 and 01 336 * combinations. */ 337 errno = ENOTSUP; 338 return -1; 339 } 340 else if (ltype == 0xc0) { /* pointer */ 341 if (q == e) { 342 errno = ERANGE; 343 return -1; 344 } 345 l = (l & 0x3f) << 8; 346 l |= *q++; 347 /* save source of first jump. */ 348 if (!r) 349 r = q; 350 hops++; 351 if (hops > 255) { 352 errno = ERANGE; 353 return -1; 354 } 355 q = p + l; 356 if (q >= e) { 357 errno = ERANGE; 358 return -1; 359 } 360 } else { 361 /* straightforward name segment, add with '.' */ 362 if (q + l > e) { 363 errno = ERANGE; 364 return -1; 365 } 366 if (l > NS_MAXLABEL) { 367 errno = EINVAL; 368 return -1; 369 } 370 d_len += l + 1; 371 if (out) { 372 if (l + 1 > len) { 373 errno = ENOBUFS; 374 return -1; 375 } 376 memcpy(out, q, l); 377 out += l; 378 *out++ = '.'; 379 len -= l; 380 len--; 381 } 382 q += l; 383 } 384 } 385 386 /* Don't count the trailing NUL */ 387 if (d_len > NS_MAXDNAME + 1) { 388 errno = E2BIG; 389 return -1; 390 } 391 o_len += d_len; 392 393 /* change last dot to space */ 394 if (out && out != start) 395 *(out - 1) = ' '; 396 if (r) 397 q = r; 398 } 399 400 /* change last space to zero terminator */ 401 if (out) { 402 if (out != start) 403 *(out - 1) = '\0'; 404 else if (start_len > 0) 405 *out = '\0'; 406 } 407 408 /* Remove the trailing NUL */ 409 if (o_len != 0) 410 o_len--; 411 412 return (ssize_t)o_len; 413 } 414 415 /* Check for a valid name as per RFC952 and RFC1123 section 2.1 */ 416 static int 417 valid_domainname(char *lbl, int type) 418 { 419 char *slbl, *lst; 420 unsigned char c; 421 int start, len, errset; 422 423 if (lbl == NULL || *lbl == '\0') { 424 errno = EINVAL; 425 return 0; 426 } 427 428 slbl = lbl; 429 lst = NULL; 430 start = 1; 431 len = errset = 0; 432 for (;;) { 433 c = (unsigned char)*lbl++; 434 if (c == '\0') 435 return 1; 436 if (c == ' ') { 437 if (lbl - 1 == slbl) /* No space at start */ 438 break; 439 if (!(type & OT_ARRAY)) 440 break; 441 /* Skip to the next label */ 442 if (!start) { 443 start = 1; 444 lst = lbl - 1; 445 } 446 if (len) 447 len = 0; 448 continue; 449 } 450 if (c == '.') { 451 if (*lbl == '.') 452 break; 453 len = 0; 454 continue; 455 } 456 if (((c == '-' || c == '_') && 457 !start && *lbl != ' ' && *lbl != '\0') || 458 isalnum(c)) 459 { 460 if (++len > NS_MAXLABEL) { 461 errno = ERANGE; 462 errset = 1; 463 break; 464 } 465 } else 466 break; 467 if (start) 468 start = 0; 469 } 470 471 if (!errset) 472 errno = EINVAL; 473 if (lst) { 474 /* At least one valid domain, return it */ 475 *lst = '\0'; 476 return 1; 477 } 478 return 0; 479 } 480 481 /* 482 * Prints a chunk of data to a string. 483 * PS_SHELL goes as it is these days, it's upto the target to validate it. 484 * PS_SAFE has all non ascii and non printables changes to escaped octal. 485 */ 486 static const char hexchrs[] = "0123456789abcdef"; 487 ssize_t 488 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl) 489 { 490 char *odst; 491 uint8_t c; 492 const uint8_t *e; 493 size_t bytes; 494 495 odst = dst; 496 bytes = 0; 497 e = data + dl; 498 499 while (data < e) { 500 c = *data++; 501 if (type & OT_BINHEX) { 502 if (dst) { 503 if (len == 0 || len == 1) { 504 errno = ENOBUFS; 505 return -1; 506 } 507 *dst++ = hexchrs[(c & 0xF0) >> 4]; 508 *dst++ = hexchrs[(c & 0x0F)]; 509 len -= 2; 510 } 511 bytes += 2; 512 continue; 513 } 514 if (type & OT_ASCII && (!isascii(c))) { 515 errno = EINVAL; 516 break; 517 } 518 if (!(type & (OT_ASCII | OT_RAW | OT_ESCSTRING | OT_ESCFILE)) && 519 (!isascii(c) && !isprint(c))) 520 { 521 errno = EINVAL; 522 break; 523 } 524 if ((type & (OT_ESCSTRING | OT_ESCFILE) && 525 (c == '\\' || !isascii(c) || !isprint(c))) || 526 (type & OT_ESCFILE && (c == '/' || c == ' '))) 527 { 528 errno = EINVAL; 529 if (c == '\\') { 530 if (dst) { 531 if (len == 0 || len == 1) { 532 errno = ENOBUFS; 533 return -1; 534 } 535 *dst++ = '\\'; *dst++ = '\\'; 536 len -= 2; 537 } 538 bytes += 2; 539 continue; 540 } 541 if (dst) { 542 if (len < 5) { 543 errno = ENOBUFS; 544 return -1; 545 } 546 *dst++ = '\\'; 547 *dst++ = (char)(((c >> 6) & 03) + '0'); 548 *dst++ = (char)(((c >> 3) & 07) + '0'); 549 *dst++ = (char)(( c & 07) + '0'); 550 len -= 4; 551 } 552 bytes += 4; 553 } else { 554 if (dst) { 555 if (len == 0) { 556 errno = ENOBUFS; 557 return -1; 558 } 559 *dst++ = (char)c; 560 len--; 561 } 562 bytes++; 563 } 564 } 565 566 /* NULL */ 567 if (dst) { 568 if (len == 0) { 569 errno = ENOBUFS; 570 return -1; 571 } 572 *dst = '\0'; 573 574 /* Now we've printed it, validate the domain */ 575 if (type & OT_DOMAIN && !valid_domainname(odst, type)) { 576 *odst = '\0'; 577 return 1; 578 } 579 580 } 581 582 return (ssize_t)bytes; 583 } 584 585 #define ADDR6SZ 16 586 static ssize_t 587 dhcp_optlen(const struct dhcp_opt *opt, size_t dl) 588 { 589 size_t sz; 590 591 if (opt->type & OT_ADDRIPV6) 592 sz = ADDR6SZ; 593 else if (opt->type & (OT_INT32 | OT_UINT32 | OT_ADDRIPV4)) 594 sz = sizeof(uint32_t); 595 else if (opt->type & (OT_INT16 | OT_UINT16)) 596 sz = sizeof(uint16_t); 597 else if (opt->type & (OT_INT8 | OT_UINT8 | OT_BITFLAG)) 598 sz = sizeof(uint8_t); 599 else if (opt->type & OT_FLAG) 600 return 0; 601 else { 602 /* All other types are variable length */ 603 if (opt->len) { 604 if ((size_t)opt->len > dl) { 605 errno = EOVERFLOW; 606 return -1; 607 } 608 return (ssize_t)opt->len; 609 } 610 return (ssize_t)dl; 611 } 612 if (dl < sz) { 613 errno = EOVERFLOW; 614 return -1; 615 } 616 617 /* Trim any extra data. 618 * Maybe we need a setting to reject DHCP options with extra data? */ 619 if (opt->type & OT_ARRAY) 620 return (ssize_t)(dl - (dl % sz)); 621 return (ssize_t)sz; 622 } 623 624 static ssize_t 625 print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt, 626 int vname, 627 const uint8_t *data, size_t dl, const char *ifname) 628 { 629 fpos_t fp_pos; 630 const uint8_t *e, *t; 631 uint16_t u16; 632 int16_t s16; 633 uint32_t u32; 634 int32_t s32; 635 struct in_addr addr; 636 ssize_t sl; 637 size_t l; 638 639 /* Ensure a valid length */ 640 dl = (size_t)dhcp_optlen(opt, dl); 641 if ((ssize_t)dl == -1) 642 return 0; 643 644 if (fgetpos(fp, &fp_pos) == -1) 645 return -1; 646 if (fprintf(fp, "%s", prefix) == -1) 647 goto err; 648 649 /* We printed something, so always goto err from now-on 650 * to terminate the string. */ 651 if (vname) { 652 if (fprintf(fp, "_%s", opt->var) == -1) 653 goto err; 654 } 655 if (fputc('=', fp) == EOF) 656 goto err; 657 if (dl == 0) 658 goto done; 659 660 if (opt->type & OT_RFC1035) { 661 char domain[NS_MAXDNAME]; 662 663 sl = decode_rfc1035(domain, sizeof(domain), data, dl); 664 if (sl == -1) 665 goto err; 666 if (sl == 0) 667 goto done; 668 if (valid_domainname(domain, opt->type) == -1) 669 goto err; 670 return efprintf(fp, "%s", domain); 671 } 672 673 #ifdef INET 674 if (opt->type & OT_RFC3361) 675 return print_rfc3361(fp, data, dl); 676 677 if (opt->type & OT_RFC3442) 678 return print_rfc3442(fp, data, dl); 679 #endif 680 681 if (opt->type & OT_STRING) { 682 char buf[1024]; 683 684 if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1) 685 goto err; 686 return efprintf(fp, "%s", buf); 687 } 688 689 if (opt->type & OT_FLAG) 690 return efprintf(fp, "1"); 691 692 if (opt->type & OT_BITFLAG) { 693 /* bitflags are a string, MSB first, such as ABCDEFGH 694 * where A is 10000000, B is 01000000, etc. */ 695 for (l = 0, sl = sizeof(opt->bitflags) - 1; 696 l < sizeof(opt->bitflags); 697 l++, sl--) 698 { 699 /* Don't print NULL or 0 flags */ 700 if (opt->bitflags[l] != '\0' && 701 opt->bitflags[l] != '0' && 702 *data & (1 << sl)) 703 { 704 if (fputc(opt->bitflags[l], fp) == EOF) 705 goto err; 706 } 707 } 708 goto done; 709 } 710 711 t = data; 712 e = data + dl; 713 while (data < e) { 714 if (data != t) { 715 if (fputc(' ', fp) == EOF) 716 goto err; 717 } 718 if (opt->type & OT_UINT8) { 719 if (fprintf(fp, "%u", *data) == -1) 720 goto err; 721 data++; 722 } else if (opt->type & OT_INT8) { 723 if (fprintf(fp, "%d", *data) == -1) 724 goto err; 725 data++; 726 } else if (opt->type & OT_UINT16) { 727 memcpy(&u16, data, sizeof(u16)); 728 u16 = ntohs(u16); 729 if (fprintf(fp, "%u", u16) == -1) 730 goto err; 731 data += sizeof(u16); 732 } else if (opt->type & OT_INT16) { 733 memcpy(&u16, data, sizeof(u16)); 734 s16 = (int16_t)ntohs(u16); 735 if (fprintf(fp, "%d", s16) == -1) 736 goto err; 737 data += sizeof(u16); 738 } else if (opt->type & OT_UINT32) { 739 memcpy(&u32, data, sizeof(u32)); 740 u32 = ntohl(u32); 741 if (fprintf(fp, "%u", u32) == -1) 742 goto err; 743 data += sizeof(u32); 744 } else if (opt->type & OT_INT32) { 745 memcpy(&u32, data, sizeof(u32)); 746 s32 = (int32_t)ntohl(u32); 747 if (fprintf(fp, "%d", s32) == -1) 748 goto err; 749 data += sizeof(u32); 750 } else if (opt->type & OT_ADDRIPV4) { 751 memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); 752 if (fprintf(fp, "%s", inet_ntoa(addr)) == -1) 753 goto err; 754 data += sizeof(addr.s_addr); 755 } else if (opt->type & OT_ADDRIPV6) { 756 char buf[INET6_ADDRSTRLEN]; 757 758 if (inet_ntop(AF_INET6, data, buf, sizeof(buf)) == NULL) 759 goto err; 760 if (fprintf(fp, "%s", buf) == -1) 761 goto err; 762 if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) { 763 if (fprintf(fp,"%%%s", ifname) == -1) 764 goto err; 765 } 766 data += 16; 767 } else { 768 errno = EINVAL; 769 goto err; 770 } 771 } 772 773 done: 774 if (fputc('\0', fp) == EOF) 775 return -1; 776 return 1; 777 778 err: 779 (void)fsetpos(fp, &fp_pos); 780 return -1; 781 } 782 783 int 784 dhcp_set_leasefile(char *leasefile, size_t len, int family, 785 const struct interface *ifp) 786 { 787 char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */ 788 789 if (ifp->name[0] == '\0') { 790 strlcpy(leasefile, ifp->ctx->pidfile, len); 791 return 0; 792 } 793 794 switch (family) { 795 case AF_INET: 796 case AF_INET6: 797 break; 798 default: 799 errno = EINVAL; 800 return -1; 801 } 802 803 if (ifp->wireless) { 804 ssid[0] = '-'; 805 print_string(ssid + 1, sizeof(ssid) - 1, 806 OT_ESCFILE, 807 (const uint8_t *)ifp->ssid, ifp->ssid_len); 808 } else 809 ssid[0] = '\0'; 810 return snprintf(leasefile, len, 811 family == AF_INET ? LEASEFILE : LEASEFILE6, 812 ifp->name, ssid); 813 } 814 815 void 816 dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix, 817 const char *ifname, struct dhcp_opt *opt, 818 const uint8_t *(*dgetopt)(struct dhcpcd_ctx *, 819 size_t *, unsigned int *, size_t *, 820 const uint8_t *, size_t, struct dhcp_opt **), 821 const uint8_t *od, size_t ol) 822 { 823 size_t i, eos, eol; 824 ssize_t eo; 825 unsigned int eoc; 826 const uint8_t *eod; 827 int ov; 828 struct dhcp_opt *eopt, *oopt; 829 char *pfx; 830 831 /* If no embedded or encapsulated options, it's easy */ 832 if (opt->embopts_len == 0 && opt->encopts_len == 0) { 833 if (opt->type & OT_RESERVED) 834 return; 835 if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1) 836 logerr("%s: %s %d", ifname, __func__, opt->option); 837 return; 838 } 839 840 /* Create a new prefix based on the option */ 841 if (opt->type & OT_INDEX) { 842 if (asprintf(&pfx, "%s_%s%d", 843 prefix, opt->var, ++opt->index) == -1) 844 pfx = NULL; 845 } else { 846 if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1) 847 pfx = NULL; 848 } 849 if (pfx == NULL) { 850 logerr(__func__); 851 return; 852 } 853 854 /* Embedded options are always processed first as that 855 * is a fixed layout */ 856 for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) { 857 eo = dhcp_optlen(eopt, ol); 858 if (eo == -1) { 859 logerrx("%s: %s %d.%d/%zu: " 860 "malformed embedded option", 861 ifname, __func__, opt->option, 862 eopt->option, i); 863 goto out; 864 } 865 if (eo == 0) { 866 /* An option was expected, but there is no data 867 * data for it. 868 * This may not be an error as some options like 869 * DHCP FQDN in RFC4702 have a string as the last 870 * option which is optional. */ 871 if (ol != 0 || !(eopt->type & OT_OPTIONAL)) 872 logerrx("%s: %s %d.%d/%zu: " 873 "missing embedded option", 874 ifname, __func__, opt->option, 875 eopt->option, i); 876 goto out; 877 } 878 /* Use the option prefix if the embedded option 879 * name is different. 880 * This avoids new_fqdn_fqdn which would be silly. */ 881 if (!(eopt->type & OT_RESERVED)) { 882 ov = strcmp(opt->var, eopt->var); 883 if (print_option(fp, pfx, eopt, ov, od, (size_t)eo, 884 ifname) == -1) 885 logerr("%s: %s %d.%d/%zu", 886 ifname, __func__, 887 opt->option, eopt->option, i); 888 } 889 od += (size_t)eo; 890 ol -= (size_t)eo; 891 } 892 893 /* Enumerate our encapsulated options */ 894 if (opt->encopts_len && ol > 0) { 895 /* Zero any option indexes 896 * We assume that referenced encapsulated options are NEVER 897 * recursive as the index order could break. */ 898 for (i = 0, eopt = opt->encopts; 899 i < opt->encopts_len; 900 i++, eopt++) 901 { 902 eoc = opt->option; 903 if (eopt->type & OT_OPTION) { 904 dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt); 905 if (oopt) 906 oopt->index = 0; 907 } 908 } 909 910 while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) { 911 for (i = 0, eopt = opt->encopts; 912 i < opt->encopts_len; 913 i++, eopt++) 914 { 915 if (eopt->option != eoc) 916 continue; 917 if (eopt->type & OT_OPTION) { 918 if (oopt == NULL) 919 /* Report error? */ 920 continue; 921 } 922 dhcp_envoption(ctx, fp, pfx, ifname, 923 eopt->type & OT_OPTION ? oopt:eopt, 924 dgetopt, eod, eol); 925 } 926 od += eos + eol; 927 ol -= eos + eol; 928 } 929 } 930 931 out: 932 free(pfx); 933 } 934 935 void 936 dhcp_zero_index(struct dhcp_opt *opt) 937 { 938 size_t i; 939 struct dhcp_opt *o; 940 941 opt->index = 0; 942 for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++) 943 dhcp_zero_index(o); 944 for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++) 945 dhcp_zero_index(o); 946 } 947 948 ssize_t 949 dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len) 950 { 951 952 #ifdef PRIVSEP 953 if (ctx->options & DHCPCD_PRIVSEP && 954 !(ctx->options & DHCPCD_PRIVSEPROOT)) 955 return ps_root_readfile(ctx, file, data, len); 956 #else 957 UNUSED(ctx); 958 #endif 959 960 return readfile(file, data, len); 961 } 962 963 ssize_t 964 dhcp_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode, 965 const void *data, size_t len) 966 { 967 968 #ifdef PRIVSEP 969 if (ctx->options & DHCPCD_PRIVSEP && 970 !(ctx->options & DHCPCD_PRIVSEPROOT)) 971 return ps_root_writefile(ctx, file, mode, data, len); 972 #else 973 UNUSED(ctx); 974 #endif 975 976 return writefile(file, mode, data, len); 977 } 978 979 int 980 dhcp_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time) 981 { 982 983 #ifdef PRIVSEP 984 if (ctx->options & DHCPCD_PRIVSEP && 985 !(ctx->options & DHCPCD_PRIVSEPROOT)) 986 return (int)ps_root_filemtime(ctx, file, time); 987 #else 988 UNUSED(ctx); 989 #endif 990 991 return filemtime(file, time); 992 } 993 994 int 995 dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file) 996 { 997 998 #ifdef PRIVSEP 999 if (ctx->options & DHCPCD_PRIVSEP && 1000 !(ctx->options & DHCPCD_PRIVSEPROOT)) 1001 return (int)ps_root_unlink(ctx, file); 1002 #else 1003 UNUSED(ctx); 1004 #endif 1005 1006 return unlink(file); 1007 } 1008 1009 size_t 1010 dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file) 1011 { 1012 char buf[BUFSIZ]; 1013 ssize_t bytes; 1014 size_t len; 1015 1016 bytes = dhcp_readfile(ctx, file, buf, sizeof(buf)); 1017 if (bytes == -1 || bytes == sizeof(buf)) 1018 return 0; 1019 1020 bytes[buf] = '\0'; 1021 len = hwaddr_aton(NULL, buf); 1022 if (len == 0) 1023 return 0; 1024 *data = malloc(len); 1025 if (*data == NULL) 1026 return 0; 1027 hwaddr_aton(*data, buf); 1028 return len; 1029 } 1030