1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * dhcpcd - DHCP client daemon 4 * Copyright (c) 2006-2025 Roy Marples <roy (at) 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 else if (opt->type & OT_URI) 129 printf(" uri"); 130 if (opt->type & OT_RFC3361) 131 printf(" rfc3361"); 132 if (opt->type & OT_RFC3442) 133 printf(" rfc3442"); 134 if (opt->type & OT_REQUEST) 135 printf(" request"); 136 if (opt->type & OT_NOREQ) 137 printf(" norequest"); 138 if (opt->type & OT_TRUNCATED) 139 printf(" truncated"); 140 putchar('\n'); 141 fflush(stdout); 142 } 143 144 struct dhcp_opt * 145 vivso_find(uint32_t iana_en, const void *arg) 146 { 147 const struct interface *ifp; 148 size_t i; 149 struct dhcp_opt *opt; 150 151 ifp = arg; 152 for (i = 0, opt = ifp->options->vivso_override; 153 i < ifp->options->vivso_override_len; 154 i++, opt++) 155 if (opt->option == iana_en) 156 return opt; 157 for (i = 0, opt = ifp->ctx->vivso; 158 i < ifp->ctx->vivso_len; 159 i++, opt++) 160 if (opt->option == iana_en) 161 return opt; 162 return NULL; 163 } 164 165 ssize_t 166 dhcp_vendor(char *str, size_t len) 167 { 168 struct utsname utn; 169 char *p; 170 int l; 171 172 if (uname(&utn) == -1) 173 return (ssize_t)snprintf(str, len, "%s-%s", 174 PACKAGE, VERSION); 175 p = str; 176 l = snprintf(p, len, 177 "%s-%s:%s-%s:%s", PACKAGE, VERSION, 178 utn.sysname, utn.release, utn.machine); 179 if (l == -1 || (size_t)(l + 1) > len) 180 return -1; 181 p += l; 182 len -= (size_t)l; 183 l = if_machinearch(p + 1, len - 1); 184 if (l == -1 || (size_t)(l + 1) > len) 185 return -1; 186 *p = ':'; 187 p += l; 188 return p - str; 189 } 190 191 int 192 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len, 193 const struct dhcp_opt *odopts, size_t odopts_len, 194 uint8_t *mask, const char *opts, int add) 195 { 196 char *token, *o, *p; 197 const struct dhcp_opt *opt; 198 int match, e; 199 unsigned int n; 200 size_t i; 201 202 if (opts == NULL) 203 return -1; 204 o = p = strdup(opts); 205 while ((token = strsep(&p, ", "))) { 206 if (*token == '\0') 207 continue; 208 if (strncmp(token, "dhcp6_", 6) == 0) 209 token += 6; 210 if (strncmp(token, "nd_", 3) == 0) 211 token += 3; 212 match = 0; 213 for (i = 0, opt = odopts; i < odopts_len; i++, opt++) { 214 if (opt->var == NULL || opt->option == 0) 215 continue; /* buggy dhcpcd-definitions.conf */ 216 if (strcmp(opt->var, token) == 0) 217 match = 1; 218 else { 219 n = (unsigned int)strtou(token, NULL, 0, 220 0, UINT_MAX, &e); 221 if (e == 0 && opt->option == n) 222 match = 1; 223 } 224 if (match) 225 break; 226 } 227 if (match == 0) { 228 for (i = 0, opt = dopts; i < dopts_len; i++, opt++) { 229 if (strcmp(opt->var, token) == 0) 230 match = 1; 231 else { 232 n = (unsigned int)strtou(token, NULL, 0, 233 0, UINT_MAX, &e); 234 if (e == 0 && opt->option == n) 235 match = 1; 236 } 237 if (match) 238 break; 239 } 240 } 241 if (!match || !opt->option) { 242 free(o); 243 errno = ENOENT; 244 return -1; 245 } 246 if (add == 2 && !(opt->type & OT_ADDRIPV4)) { 247 free(o); 248 errno = EINVAL; 249 return -1; 250 } 251 if (add == 1 || add == 2) 252 add_option_mask(mask, opt->option); 253 else 254 del_option_mask(mask, opt->option); 255 } 256 free(o); 257 return 0; 258 } 259 260 size_t 261 encode_rfc1035(const char *src, uint8_t *dst) 262 { 263 uint8_t *p; 264 uint8_t *lp; 265 size_t len; 266 uint8_t has_dot; 267 268 if (src == NULL || *src == '\0') 269 return 0; 270 271 if (dst) { 272 p = dst; 273 lp = p++; 274 } 275 /* Silence bogus GCC warnings */ 276 else 277 p = lp = NULL; 278 279 len = 1; 280 has_dot = 0; 281 for (; *src; src++) { 282 if (*src == '\0') 283 break; 284 if (*src == '.') { 285 /* Skip the trailing . */ 286 if (src[1] == '\0') 287 break; 288 has_dot = 1; 289 if (dst) { 290 *lp = (uint8_t)(p - lp - 1); 291 if (*lp == '\0') 292 return len; 293 lp = p++; 294 } 295 } else if (dst) 296 *p++ = (uint8_t)*src; 297 len++; 298 } 299 300 if (dst) { 301 *lp = (uint8_t)(p - lp - 1); 302 if (has_dot) 303 *p++ = '\0'; 304 } 305 306 if (has_dot) 307 len++; 308 309 return len; 310 } 311 312 /* Decode an RFC1035 DNS search order option into a space 313 * separated string. Returns length of string (including 314 * terminating zero) or zero on error. out may be NULL 315 * to just determine output length. */ 316 ssize_t 317 decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl) 318 { 319 const char *start; 320 size_t start_len, l, d_len, o_len; 321 const uint8_t *r, *q = p, *e; 322 int hops; 323 uint8_t ltype; 324 325 o_len = 0; 326 start = out; 327 start_len = len; 328 q = p; 329 e = p + pl; 330 while (q < e) { 331 r = NULL; 332 d_len = 0; 333 hops = 0; 334 /* Check we are inside our length again in-case 335 * the name isn't fully qualified (ie, not terminated) */ 336 while (q < e && (l = (size_t)*q++)) { 337 ltype = l & 0xc0; 338 if (ltype == 0x80 || ltype == 0x40) { 339 /* Currently reserved for future use as noted 340 * in RFC1035 4.1.4 as the 10 and 01 341 * combinations. */ 342 errno = ENOTSUP; 343 return -1; 344 } 345 else if (ltype == 0xc0) { /* pointer */ 346 if (q == e) { 347 errno = ERANGE; 348 return -1; 349 } 350 l = (l & 0x3f) << 8; 351 l |= *q++; 352 /* save source of first jump. */ 353 if (!r) 354 r = q; 355 hops++; 356 if (hops > 255) { 357 errno = ERANGE; 358 return -1; 359 } 360 q = p + l; 361 if (q >= e) { 362 errno = ERANGE; 363 return -1; 364 } 365 } else { 366 /* straightforward name segment, add with '.' */ 367 if (q + l > e) { 368 errno = ERANGE; 369 return -1; 370 } 371 if (l > NS_MAXLABEL) { 372 errno = EINVAL; 373 return -1; 374 } 375 d_len += l + 1; 376 if (out) { 377 if (l + 1 > len) { 378 errno = ENOBUFS; 379 return -1; 380 } 381 memcpy(out, q, l); 382 out += l; 383 *out++ = '.'; 384 len -= l; 385 len--; 386 } 387 q += l; 388 } 389 } 390 391 /* Don't count the trailing NUL */ 392 if (d_len > NS_MAXDNAME + 1) { 393 errno = E2BIG; 394 return -1; 395 } 396 o_len += d_len; 397 398 /* change last dot to space */ 399 if (out && out != start) 400 *(out - 1) = ' '; 401 if (r) 402 q = r; 403 } 404 405 /* change last space to zero terminator */ 406 if (out) { 407 if (out != start) 408 *(out - 1) = '\0'; 409 else if (start_len > 0) 410 *out = '\0'; 411 } 412 413 /* Remove the trailing NUL */ 414 if (o_len != 0) 415 o_len--; 416 417 return (ssize_t)o_len; 418 } 419 420 /* Check for a valid name as per RFC952 and RFC1123 section 2.1 */ 421 static ssize_t 422 valid_domainname(char *lbl, int type) 423 { 424 char *slbl = lbl, *lst = NULL; 425 unsigned char c; 426 int len = 0; 427 bool start = true, errset = false; 428 429 if (lbl == NULL || *lbl == '\0') { 430 errno = EINVAL; 431 return 0; 432 } 433 434 for (;;) { 435 c = (unsigned char)*lbl++; 436 if (c == '\0') 437 return lbl - slbl - 1; 438 if (c == ' ') { 439 if (lbl - 1 == slbl) /* No space at start */ 440 break; 441 if (!(type & OT_ARRAY)) 442 break; 443 /* Skip to the next label */ 444 if (!start) { 445 start = true; 446 lst = lbl - 1; 447 } 448 if (len) 449 len = 0; 450 continue; 451 } 452 if (c == '.') { 453 if (*lbl == '.') 454 break; 455 len = 0; 456 continue; 457 } 458 if (((c == '-' || c == '_') && 459 !start && *lbl != ' ' && *lbl != '\0') || 460 isalnum(c)) 461 { 462 if (++len > NS_MAXLABEL) { 463 errno = ERANGE; 464 errset = true; 465 break; 466 } 467 } else 468 break; 469 if (start) 470 start = false; 471 } 472 473 if (!errset) 474 errno = EINVAL; 475 if (lst) { 476 /* At least one valid domain, return it */ 477 *lst = '\0'; 478 return lst - slbl; 479 } 480 return 0; 481 } 482 483 /* 484 * Prints a chunk of data to a string. 485 * PS_SHELL goes as it is these days, it's upto the target to validate it. 486 * PS_SAFE has all non ascii and non printables changes to escaped octal. 487 */ 488 static const char hexchrs[] = "0123456789abcdef"; 489 ssize_t 490 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl) 491 { 492 char *odst; 493 uint8_t c; 494 const uint8_t *e; 495 size_t bytes; 496 497 odst = dst; 498 bytes = 0; 499 e = data + dl; 500 501 while (data < e) { 502 c = *data++; 503 if (type & OT_BINHEX) { 504 if (dst) { 505 if (len == 0 || len == 1) { 506 errno = ENOBUFS; 507 return -1; 508 } 509 *dst++ = hexchrs[(c & 0xF0) >> 4]; 510 *dst++ = hexchrs[(c & 0x0F)]; 511 len -= 2; 512 } 513 bytes += 2; 514 continue; 515 } 516 if (type & OT_ASCII && (!isascii(c))) { 517 errno = EINVAL; 518 break; 519 } 520 if (!(type & (OT_ASCII | OT_RAW | OT_ESCSTRING | OT_ESCFILE)) && 521 (!isascii(c) && !isprint(c))) 522 { 523 errno = EINVAL; 524 break; 525 } 526 if (type & OT_URI && isspace(c)) { 527 errno = EINVAL; 528 break; 529 } 530 if ((type & (OT_ESCSTRING | OT_ESCFILE) && 531 (c == '\\' || !isascii(c) || !isprint(c))) || 532 (type & OT_ESCFILE && (c == '/' || c == ' '))) 533 { 534 errno = EINVAL; 535 if (c == '\\') { 536 if (dst) { 537 if (len == 0 || len == 1) { 538 errno = ENOBUFS; 539 return -1; 540 } 541 *dst++ = '\\'; *dst++ = '\\'; 542 len -= 2; 543 } 544 bytes += 2; 545 continue; 546 } 547 if (dst) { 548 if (len < 5) { 549 errno = ENOBUFS; 550 return -1; 551 } 552 *dst++ = '\\'; 553 *dst++ = (char)(((c >> 6) & 03) + '0'); 554 *dst++ = (char)(((c >> 3) & 07) + '0'); 555 *dst++ = (char)(( c & 07) + '0'); 556 len -= 4; 557 } 558 bytes += 4; 559 } else { 560 if (dst) { 561 if (len == 0) { 562 errno = ENOBUFS; 563 return -1; 564 } 565 *dst++ = (char)c; 566 len--; 567 } 568 bytes++; 569 } 570 } 571 572 /* NULL */ 573 if (dst) { 574 if (len == 0) { 575 errno = ENOBUFS; 576 return -1; 577 } 578 *dst = '\0'; 579 580 /* Now we've printed it, validate the domain */ 581 if (type & OT_DOMAIN && !valid_domainname(odst, type)) { 582 *odst = '\0'; 583 return 1; 584 } 585 586 } 587 588 return (ssize_t)bytes; 589 } 590 591 #define ADDR6SZ 16 592 static ssize_t 593 dhcp_optlen(const struct dhcp_opt *opt, size_t dl) 594 { 595 size_t sz; 596 597 if (opt->type & OT_ADDRIPV6) 598 sz = ADDR6SZ; 599 else if (opt->type & (OT_INT32 | OT_UINT32 | OT_ADDRIPV4)) 600 sz = sizeof(uint32_t); 601 else if (opt->type & (OT_INT16 | OT_UINT16)) 602 sz = sizeof(uint16_t); 603 else if (opt->type & (OT_INT8 | OT_UINT8 | OT_BITFLAG)) 604 sz = sizeof(uint8_t); 605 else if (opt->type & OT_FLAG) 606 return 0; 607 else { 608 /* All other types are variable length */ 609 if (opt->len) { 610 if ((size_t)opt->len > dl) { 611 errno = EOVERFLOW; 612 return -1; 613 } 614 return (ssize_t)opt->len; 615 } 616 return (ssize_t)dl; 617 } 618 if (dl < sz) { 619 if (opt->type & OT_TRUNCATED) 620 return (ssize_t)dl; 621 errno = EOVERFLOW; 622 return -1; 623 } 624 625 /* Trim any extra data. 626 * Maybe we need a setting to reject DHCP options with extra data? */ 627 if (opt->type & OT_ARRAY) 628 return (ssize_t)(dl - (dl % sz)); 629 return (ssize_t)sz; 630 } 631 632 static ssize_t 633 print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt, 634 int vname, 635 const uint8_t *data, size_t dl, const char *ifname) 636 { 637 fpos_t fp_pos; 638 const uint8_t *e, *t; 639 uint16_t u16; 640 int16_t s16; 641 uint32_t u32; 642 int32_t s32; 643 struct in_addr addr; 644 ssize_t sl; 645 size_t l; 646 647 /* Ensure a valid length */ 648 dl = (size_t)dhcp_optlen(opt, dl); 649 if ((ssize_t)dl == -1) 650 return 0; 651 652 if (fgetpos(fp, &fp_pos) == -1) 653 return -1; 654 if (fprintf(fp, "%s", prefix) == -1) 655 goto err; 656 657 /* We printed something, so always goto err from now-on 658 * to terminate the string. */ 659 if (vname) { 660 if (fprintf(fp, "_%s", opt->var) == -1) 661 goto err; 662 } 663 if (fputc('=', fp) == EOF) 664 goto err; 665 if (dl == 0) 666 goto done; 667 668 if (opt->type & OT_RFC1035) { 669 char domain[NS_MAXDNAME]; 670 671 sl = decode_rfc1035(domain, sizeof(domain), data, dl); 672 if (sl == -1) 673 goto err; 674 if (sl == 0) 675 goto done; 676 if (!valid_domainname(domain, opt->type)) 677 goto err; 678 return efprintf(fp, "%s", domain); 679 } 680 681 #ifdef INET 682 if (opt->type & OT_RFC3361) 683 return print_rfc3361(fp, data, dl); 684 685 if (opt->type & OT_RFC3442) 686 return print_rfc3442(fp, data, dl); 687 #endif 688 689 /* Produces a space separated list of URIs. 690 * This is valid as a URI cannot contain a space. */ 691 if ((opt->type & (OT_ARRAY | OT_URI)) == (OT_ARRAY | OT_URI)) { 692 #ifdef SMALL 693 errno = ENOTSUP; 694 return -1; 695 #else 696 char buf[UINT16_MAX + 1]; 697 uint16_t sz; 698 bool first = true; 699 700 while (dl) { 701 if (dl < 2) { 702 errno = EINVAL; 703 goto err; 704 } 705 706 memcpy(&u16, data, sizeof(u16)); 707 sz = ntohs(u16); 708 data += sizeof(u16); 709 dl -= sizeof(u16); 710 711 if (sz == 0) 712 continue; 713 if (sz > dl) { 714 errno = EINVAL; 715 goto err; 716 } 717 718 if (print_string(buf, sizeof(buf), 719 opt->type, data, sz) == -1) 720 goto err; 721 722 if (first) 723 first = false; 724 else if (fputc(' ', fp) == EOF) 725 goto err; 726 727 if (fprintf(fp, "%s", buf) == -1) 728 goto err; 729 730 data += sz; 731 dl -= sz; 732 } 733 734 if (fputc('\0', fp) == EOF) 735 goto err; 736 return 0; 737 #endif 738 } 739 740 if (opt->type & (OT_STRING | OT_URI)) { 741 char buf[1024]; 742 743 if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1) 744 goto err; 745 return efprintf(fp, "%s", buf); 746 } 747 748 if (opt->type & OT_FLAG) 749 return efprintf(fp, "1"); 750 751 if (opt->type & OT_BITFLAG) { 752 /* bitflags are a string, MSB first, such as ABCDEFGH 753 * where A is 10000000, B is 01000000, etc. */ 754 for (l = 0, sl = sizeof(opt->bitflags) - 1; 755 l < sizeof(opt->bitflags); 756 l++, sl--) 757 { 758 if (opt->bitflags[l] == '1') { 759 if (fprintf(fp, "%d", *data & (1 << sl)) == -1) 760 goto err; 761 continue; 762 } 763 /* Don't print NULL or 0 flags */ 764 if (opt->bitflags[l] != '\0' && 765 opt->bitflags[l] != '0' && 766 *data & (1 << sl)) 767 { 768 if (fputc(opt->bitflags[l], fp) == EOF) 769 goto err; 770 } 771 } 772 goto done; 773 } 774 775 t = data; 776 e = data + dl; 777 while (data < e) { 778 if (data != t) { 779 if (fputc(' ', fp) == EOF) 780 goto err; 781 } 782 if (opt->type & OT_UINT8) { 783 if (fprintf(fp, "%u", *data) == -1) 784 goto err; 785 data++; 786 } else if (opt->type & OT_INT8) { 787 if (fprintf(fp, "%d", *data) == -1) 788 goto err; 789 data++; 790 } else if (opt->type & OT_UINT16) { 791 memcpy(&u16, data, sizeof(u16)); 792 u16 = ntohs(u16); 793 if (fprintf(fp, "%u", u16) == -1) 794 goto err; 795 data += sizeof(u16); 796 } else if (opt->type & OT_INT16) { 797 memcpy(&u16, data, sizeof(u16)); 798 s16 = (int16_t)ntohs(u16); 799 if (fprintf(fp, "%d", s16) == -1) 800 goto err; 801 data += sizeof(u16); 802 } else if (opt->type & OT_UINT32) { 803 memcpy(&u32, data, sizeof(u32)); 804 u32 = ntohl(u32); 805 if (fprintf(fp, "%u", u32) == -1) 806 goto err; 807 data += sizeof(u32); 808 } else if (opt->type & OT_INT32) { 809 memcpy(&u32, data, sizeof(u32)); 810 s32 = (int32_t)ntohl(u32); 811 if (fprintf(fp, "%d", s32) == -1) 812 goto err; 813 data += sizeof(u32); 814 } else if (opt->type & OT_ADDRIPV4) { 815 memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); 816 if (fprintf(fp, "%s", inet_ntoa(addr)) == -1) 817 goto err; 818 data += sizeof(addr.s_addr); 819 } else if (opt->type & OT_ADDRIPV6) { 820 uint8_t databuf[sizeof(struct in6_addr)] = { 0 }; 821 size_t datalen = e - data >= 16 ? 16 : (size_t)(e - data); 822 char buf[INET6_ADDRSTRLEN]; 823 824 /* avoid inet_ntop going beyond our option space by 825 * copying out into a temporary buffer. */ 826 memcpy(databuf, data, datalen); 827 if (inet_ntop(AF_INET6, databuf, buf, sizeof(buf)) == NULL) 828 goto err; 829 if (fprintf(fp, "%s", buf) == -1) 830 goto err; 831 if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) { 832 if (fprintf(fp,"%%%s", ifname) == -1) 833 goto err; 834 } 835 data += 16; 836 } else { 837 errno = EINVAL; 838 goto err; 839 } 840 } 841 842 done: 843 if (fputc('\0', fp) == EOF) 844 return -1; 845 return 1; 846 847 err: 848 (void)fsetpos(fp, &fp_pos); 849 return -1; 850 } 851 852 int 853 dhcp_set_leasefile(char *leasefile, size_t len, int family, 854 const struct interface *ifp) 855 { 856 char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */ 857 858 if (ifp->name[0] == '\0') { 859 strlcpy(leasefile, ifp->ctx->pidfile, len); 860 return 0; 861 } 862 863 switch (family) { 864 case AF_INET: 865 case AF_INET6: 866 break; 867 default: 868 errno = EINVAL; 869 return -1; 870 } 871 872 if (ifp->wireless) { 873 ssid[0] = '-'; 874 print_string(ssid + 1, sizeof(ssid) - 1, 875 OT_ESCFILE, 876 (const uint8_t *)ifp->ssid, ifp->ssid_len); 877 } else 878 ssid[0] = '\0'; 879 return snprintf(leasefile, len, 880 family == AF_INET ? LEASEFILE : LEASEFILE6, 881 ifp->name, ssid); 882 } 883 884 void 885 dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix, 886 const char *ifname, struct dhcp_opt *opt, 887 const uint8_t *(*dgetopt)(struct dhcpcd_ctx *, 888 size_t *, unsigned int *, size_t *, 889 const uint8_t *, size_t, struct dhcp_opt **), 890 const uint8_t *od, size_t ol) 891 { 892 size_t i, eos, eol; 893 ssize_t eo; 894 unsigned int eoc; 895 const uint8_t *eod; 896 int ov; 897 struct dhcp_opt *eopt, *oopt; 898 char *pfx; 899 900 /* If no embedded or encapsulated options, it's easy */ 901 if (opt->embopts_len == 0 && opt->encopts_len == 0) { 902 if (opt->type & OT_RESERVED) 903 return; 904 if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1) 905 logerr("%s: %s %d", ifname, __func__, opt->option); 906 return; 907 } 908 909 /* Create a new prefix based on the option */ 910 if (opt->type & OT_INDEX) { 911 if (asprintf(&pfx, "%s_%s%d", 912 prefix, opt->var, ++opt->index) == -1) 913 pfx = NULL; 914 } else { 915 if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1) 916 pfx = NULL; 917 } 918 if (pfx == NULL) { 919 logerr(__func__); 920 return; 921 } 922 923 /* Embedded options are always processed first as that 924 * is a fixed layout */ 925 for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) { 926 eo = dhcp_optlen(eopt, ol); 927 if (eo == -1) { 928 logerrx("%s: %s %d.%d/%zu: " 929 "malformed embedded option", 930 ifname, __func__, opt->option, 931 eopt->option, i); 932 goto out; 933 } 934 if (eo == 0) { 935 /* An option was expected, but there is no data 936 * data for it. 937 * This may not be an error as some options like 938 * DHCP FQDN in RFC4702 have a string as the last 939 * option which is optional. */ 940 if (ol != 0 || !(eopt->type & OT_OPTIONAL)) 941 logerrx("%s: %s %d.%d/%zu: " 942 "missing embedded option", 943 ifname, __func__, opt->option, 944 eopt->option, i); 945 goto out; 946 } 947 /* Use the option prefix if the embedded option 948 * name is different. 949 * This avoids new_fqdn_fqdn which would be silly. */ 950 if (!(eopt->type & OT_RESERVED)) { 951 ov = strcmp(opt->var, eopt->var); 952 if (print_option(fp, pfx, eopt, ov, od, (size_t)eo, 953 ifname) == -1) 954 logerr("%s: %s %d.%d/%zu", 955 ifname, __func__, 956 opt->option, eopt->option, i); 957 } 958 od += (size_t)eo; 959 ol -= (size_t)eo; 960 } 961 962 /* Enumerate our encapsulated options */ 963 if (opt->encopts_len && ol > 0) { 964 /* Zero any option indexes 965 * We assume that referenced encapsulated options are NEVER 966 * recursive as the index order could break. */ 967 for (i = 0, eopt = opt->encopts; 968 i < opt->encopts_len; 969 i++, eopt++) 970 { 971 eoc = opt->option; 972 if (eopt->type & OT_OPTION) { 973 dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt); 974 if (oopt) 975 oopt->index = 0; 976 } 977 } 978 979 while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) { 980 for (i = 0, eopt = opt->encopts; 981 i < opt->encopts_len; 982 i++, eopt++) 983 { 984 if (eopt->option != eoc) 985 continue; 986 if (eopt->type & OT_OPTION) { 987 if (oopt == NULL) 988 /* Report error? */ 989 continue; 990 } 991 dhcp_envoption(ctx, fp, pfx, ifname, 992 eopt->type & OT_OPTION ? oopt:eopt, 993 dgetopt, eod, eol); 994 } 995 od += eos + eol; 996 ol -= eos + eol; 997 } 998 } 999 1000 out: 1001 free(pfx); 1002 } 1003 1004 void 1005 dhcp_zero_index(struct dhcp_opt *opt) 1006 { 1007 size_t i; 1008 struct dhcp_opt *o; 1009 1010 opt->index = 0; 1011 for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++) 1012 dhcp_zero_index(o); 1013 for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++) 1014 dhcp_zero_index(o); 1015 } 1016 1017 ssize_t 1018 dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len) 1019 { 1020 1021 #ifdef PRIVSEP 1022 if (ctx->options & DHCPCD_PRIVSEP && 1023 !(ctx->options & DHCPCD_PRIVSEPROOT)) 1024 return ps_root_readfile(ctx, file, data, len); 1025 #else 1026 UNUSED(ctx); 1027 #endif 1028 1029 return readfile(file, data, len); 1030 } 1031 1032 ssize_t 1033 dhcp_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode, 1034 const void *data, size_t len) 1035 { 1036 1037 #ifdef PRIVSEP 1038 if (ctx->options & DHCPCD_PRIVSEP && 1039 !(ctx->options & DHCPCD_PRIVSEPROOT)) 1040 return ps_root_writefile(ctx, file, mode, data, len); 1041 #else 1042 UNUSED(ctx); 1043 #endif 1044 1045 return writefile(file, mode, data, len); 1046 } 1047 1048 int 1049 dhcp_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time) 1050 { 1051 1052 #ifdef PRIVSEP 1053 if (ctx->options & DHCPCD_PRIVSEP && 1054 !(ctx->options & DHCPCD_PRIVSEPROOT)) 1055 return (int)ps_root_filemtime(ctx, file, time); 1056 #else 1057 UNUSED(ctx); 1058 #endif 1059 1060 return filemtime(file, time); 1061 } 1062 1063 int 1064 dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file) 1065 { 1066 1067 #ifdef PRIVSEP 1068 if (ctx->options & DHCPCD_PRIVSEP && 1069 !(ctx->options & DHCPCD_PRIVSEPROOT)) 1070 return (int)ps_root_unlink(ctx, file); 1071 #else 1072 UNUSED(ctx); 1073 #endif 1074 1075 return unlink(file); 1076 } 1077 1078 size_t 1079 dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file) 1080 { 1081 char buf[BUFSIZ]; 1082 ssize_t bytes; 1083 size_t len; 1084 1085 bytes = dhcp_readfile(ctx, file, buf, sizeof(buf)); 1086 if (bytes == -1 || bytes == sizeof(buf)) 1087 return 0; 1088 1089 bytes[buf] = '\0'; 1090 len = hwaddr_aton(NULL, buf); 1091 if (len == 0) 1092 return 0; 1093 *data = malloc(len); 1094 if (*data == NULL) 1095 return 0; 1096 hwaddr_aton(*data, buf); 1097 return len; 1098 } 1099