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