1 /*- 2 * Copyright (c) 2013 Baptiste Daroussin <bapt@FreeBSD.org> 3 * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/sbuf.h> 33 #include <sys/elf_common.h> 34 #include <sys/endian.h> 35 36 #include <assert.h> 37 #include <yaml.h> 38 #include <ctype.h> 39 #include <err.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <gelf.h> 43 #include <inttypes.h> 44 #include <paths.h> 45 #include <stdbool.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "elf_tables.h" 50 #include "config.h" 51 52 #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 53 54 struct config_entry { 55 uint8_t type; 56 const char *key; 57 const char *val; 58 char *value; 59 bool envset; 60 }; 61 62 static struct config_entry c[] = { 63 [PACKAGESITE] = { 64 PKG_CONFIG_STRING, 65 "PACKAGESITE", 66 URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 67 NULL, 68 false, 69 }, 70 [ABI] = { 71 PKG_CONFIG_STRING, 72 "ABI", 73 NULL, 74 NULL, 75 false, 76 }, 77 [MIRROR_TYPE] = { 78 PKG_CONFIG_STRING, 79 "MIRROR_TYPE", 80 "SRV", 81 NULL, 82 false, 83 }, 84 [ASSUME_ALWAYS_YES] = { 85 PKG_CONFIG_BOOL, 86 "ASSUME_ALWAYS_YES", 87 "NO", 88 NULL, 89 false, 90 }, 91 [SIGNATURE_TYPE] = { 92 PKG_CONFIG_STRING, 93 "SIGNATURE_TYPE", 94 NULL, 95 NULL, 96 false, 97 }, 98 [FINGERPRINTS] = { 99 PKG_CONFIG_STRING, 100 "FINGERPRINTS", 101 NULL, 102 NULL, 103 false, 104 }, 105 }; 106 107 static const char * 108 elf_corres_to_string(struct _elf_corres *m, int e) 109 { 110 int i; 111 112 for (i = 0; m[i].string != NULL; i++) 113 if (m[i].elf_nb == e) 114 return (m[i].string); 115 116 return ("unknown"); 117 } 118 119 static const char * 120 aeabi_parse_arm_attributes(void *data, size_t length) 121 { 122 uint32_t sect_len; 123 uint8_t *section = data; 124 125 #define MOVE(len) do { \ 126 assert(length >= (len)); \ 127 section += (len); \ 128 length -= (len); \ 129 } while (0) 130 131 if (length == 0 || *section != 'A') 132 return (NULL); 133 134 MOVE(1); 135 136 /* Read the section length */ 137 if (length < sizeof(sect_len)) 138 return (NULL); 139 140 memcpy(§_len, section, sizeof(sect_len)); 141 142 /* 143 * The section length should be no longer than the section it is within 144 */ 145 if (sect_len > length) 146 return (NULL); 147 148 MOVE(sizeof(sect_len)); 149 150 /* Skip the vendor name */ 151 while (length != 0) { 152 if (*section == '\0') 153 break; 154 MOVE(1); 155 } 156 if (length == 0) 157 return (NULL); 158 MOVE(1); 159 160 while (length != 0) { 161 uint32_t tag_length; 162 163 switch(*section) { 164 case 1: /* Tag_File */ 165 MOVE(1); 166 if (length < sizeof(tag_length)) 167 return (NULL); 168 memcpy(&tag_length, section, sizeof(tag_length)); 169 break; 170 case 2: /* Tag_Section */ 171 case 3: /* Tag_Symbol */ 172 default: 173 return (NULL); 174 } 175 /* At least space for the tag and size */ 176 if (tag_length <= 5) 177 return (NULL); 178 tag_length--; 179 /* Check the tag fits */ 180 if (tag_length > length) 181 return (NULL); 182 183 #define MOVE_TAG(len) do { \ 184 assert(tag_length >= (len)); \ 185 MOVE(len); \ 186 tag_length -= (len); \ 187 } while(0) 188 189 MOVE(sizeof(tag_length)); 190 tag_length -= sizeof(tag_length); 191 192 while (tag_length != 0) { 193 uint8_t tag; 194 195 assert(tag_length >= length); 196 197 tag = *section; 198 MOVE_TAG(1); 199 200 /* 201 * These tag values come from: 202 * 203 * Addenda to, and Errata in, the ABI for the 204 * ARM Architecture. Release 2.08, section 2.3. 205 */ 206 if (tag == 6) { /* == Tag_CPU_arch */ 207 uint8_t val; 208 209 val = *section; 210 /* 211 * We don't support values that require 212 * more than one byte. 213 */ 214 if (val & (1 << 7)) 215 return (NULL); 216 217 /* We have an ARMv4 or ARMv5 */ 218 if (val <= 5) 219 return ("arm"); 220 else /* We have an ARMv6+ */ 221 return ("armv6"); 222 } else if (tag == 4 || tag == 5 || tag == 32 || 223 tag == 65 || tag == 67) { 224 while (*section != '\0' && length != 0) 225 MOVE_TAG(1); 226 if (tag_length == 0) 227 return (NULL); 228 /* Skip the last byte */ 229 MOVE_TAG(1); 230 } else if ((tag >= 7 && tag <= 31) || tag == 34 || 231 tag == 36 || tag == 38 || tag == 42 || tag == 44 || 232 tag == 64 || tag == 66 || tag == 68 || tag == 70) { 233 /* Skip the uleb128 data */ 234 while (*section & (1 << 7) && length != 0) 235 MOVE_TAG(1); 236 if (tag_length == 0) 237 return (NULL); 238 /* Skip the last byte */ 239 MOVE_TAG(1); 240 } else 241 return (NULL); 242 #undef MOVE_TAG 243 } 244 245 break; 246 } 247 return (NULL); 248 #undef MOVE 249 } 250 251 static int 252 pkg_get_myabi(char *dest, size_t sz) 253 { 254 Elf *elf; 255 Elf_Data *data; 256 Elf_Note note; 257 Elf_Scn *scn; 258 char *src, *osname; 259 const char *arch, *abi, *fpu, *endian_corres_str; 260 const char *wordsize_corres_str; 261 GElf_Ehdr elfhdr; 262 GElf_Shdr shdr; 263 int fd, i, ret; 264 uint32_t version; 265 266 version = 0; 267 ret = -1; 268 scn = NULL; 269 abi = NULL; 270 271 if (elf_version(EV_CURRENT) == EV_NONE) { 272 warnx("ELF library initialization failed: %s", 273 elf_errmsg(-1)); 274 return (-1); 275 } 276 277 if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 278 warn("open()"); 279 return (-1); 280 } 281 282 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 283 ret = -1; 284 warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 285 goto cleanup; 286 } 287 288 if (gelf_getehdr(elf, &elfhdr) == NULL) { 289 ret = -1; 290 warn("getehdr() failed: %s.", elf_errmsg(-1)); 291 goto cleanup; 292 } 293 while ((scn = elf_nextscn(elf, scn)) != NULL) { 294 if (gelf_getshdr(scn, &shdr) != &shdr) { 295 ret = -1; 296 warn("getshdr() failed: %s.", elf_errmsg(-1)); 297 goto cleanup; 298 } 299 300 if (shdr.sh_type == SHT_NOTE) 301 break; 302 } 303 304 if (scn == NULL) { 305 ret = -1; 306 warn("failed to get the note section"); 307 goto cleanup; 308 } 309 310 data = elf_getdata(scn, NULL); 311 src = data->d_buf; 312 for (;;) { 313 memcpy(¬e, src, sizeof(Elf_Note)); 314 src += sizeof(Elf_Note); 315 if (note.n_type == NT_VERSION) 316 break; 317 src += note.n_namesz + note.n_descsz; 318 } 319 osname = src; 320 src += roundup2(note.n_namesz, 4); 321 if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 322 version = be32dec(src); 323 else 324 version = le32dec(src); 325 326 for (i = 0; osname[i] != '\0'; i++) 327 osname[i] = (char)tolower(osname[i]); 328 329 wordsize_corres_str = elf_corres_to_string(wordsize_corres, 330 (int)elfhdr.e_ident[EI_CLASS]); 331 332 arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 333 334 snprintf(dest, sz, "%s:%d", 335 osname, version / 100000); 336 337 ret = 0; 338 339 switch (elfhdr.e_machine) { 340 case EM_ARM: 341 endian_corres_str = elf_corres_to_string(endian_corres, 342 (int)elfhdr.e_ident[EI_DATA]); 343 344 /* FreeBSD doesn't support the hard-float ABI yet */ 345 fpu = "softfp"; 346 if ((elfhdr.e_flags & 0xFF000000) != 0) { 347 const char *sh_name = NULL; 348 size_t shstrndx; 349 350 /* This is an EABI file, the conformance level is set */ 351 abi = "eabi"; 352 /* Find which TARGET_ARCH we are building for. */ 353 elf_getshdrstrndx(elf, &shstrndx); 354 while ((scn = elf_nextscn(elf, scn)) != NULL) { 355 sh_name = NULL; 356 if (gelf_getshdr(scn, &shdr) != &shdr) { 357 scn = NULL; 358 break; 359 } 360 361 sh_name = elf_strptr(elf, shstrndx, 362 shdr.sh_name); 363 if (sh_name == NULL) 364 continue; 365 if (strcmp(".ARM.attributes", sh_name) == 0) 366 break; 367 } 368 if (scn != NULL && sh_name != NULL) { 369 data = elf_getdata(scn, NULL); 370 /* 371 * Prior to FreeBSD 10.0 libelf would return 372 * NULL from elf_getdata on the .ARM.attributes 373 * section. As this was the first release to 374 * get armv6 support assume a NULL value means 375 * arm. 376 * 377 * This assumption can be removed when 9.x 378 * is unsupported. 379 */ 380 if (data != NULL) { 381 arch = aeabi_parse_arm_attributes( 382 data->d_buf, data->d_size); 383 if (arch == NULL) { 384 ret = 1; 385 warn("unknown ARM ARCH"); 386 goto cleanup; 387 } 388 } 389 } else { 390 ret = 1; 391 warn("Unable to find the .ARM.attributes " 392 "section"); 393 goto cleanup; 394 } 395 } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 396 /* 397 * EABI executables all have this field set to 398 * ELFOSABI_NONE, therefore it must be an oabi file. 399 */ 400 abi = "oabi"; 401 } else { 402 ret = 1; 403 warn("unknown ARM ABI"); 404 goto cleanup; 405 } 406 snprintf(dest + strlen(dest), sz - strlen(dest), 407 ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 408 endian_corres_str, abi, fpu); 409 break; 410 case EM_MIPS: 411 /* 412 * this is taken from binutils sources: 413 * include/elf/mips.h 414 * mapping is figured out from binutils: 415 * gas/config/tc-mips.c 416 */ 417 switch (elfhdr.e_flags & EF_MIPS_ABI) { 418 case E_MIPS_ABI_O32: 419 abi = "o32"; 420 break; 421 case E_MIPS_ABI_N32: 422 abi = "n32"; 423 break; 424 default: 425 if (elfhdr.e_ident[EI_DATA] == 426 ELFCLASS32) 427 abi = "o32"; 428 else if (elfhdr.e_ident[EI_DATA] == 429 ELFCLASS64) 430 abi = "n64"; 431 break; 432 } 433 endian_corres_str = elf_corres_to_string(endian_corres, 434 (int)elfhdr.e_ident[EI_DATA]); 435 436 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 437 arch, wordsize_corres_str, endian_corres_str, abi); 438 break; 439 default: 440 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 441 arch, wordsize_corres_str); 442 } 443 444 cleanup: 445 if (elf != NULL) 446 elf_end(elf); 447 448 close(fd); 449 return (ret); 450 } 451 452 static void 453 subst_packagesite(const char *abi) 454 { 455 struct sbuf *newval; 456 const char *variable_string; 457 const char *oldval; 458 459 if (c[PACKAGESITE].value != NULL) 460 oldval = c[PACKAGESITE].value; 461 else 462 oldval = c[PACKAGESITE].val; 463 464 if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 465 return; 466 467 newval = sbuf_new_auto(); 468 sbuf_bcat(newval, oldval, variable_string - oldval); 469 sbuf_cat(newval, abi); 470 sbuf_cat(newval, variable_string + strlen("${ABI}")); 471 sbuf_finish(newval); 472 473 free(c[PACKAGESITE].value); 474 c[PACKAGESITE].value = strdup(sbuf_data(newval)); 475 } 476 477 static void 478 config_parse(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype) 479 { 480 yaml_node_pair_t *pair; 481 yaml_node_t *key, *val; 482 struct sbuf *buf = sbuf_new_auto(); 483 int i; 484 size_t j; 485 486 pair = node->data.mapping.pairs.start; 487 488 while (pair < node->data.mapping.pairs.top) { 489 key = yaml_document_get_node(doc, pair->key); 490 val = yaml_document_get_node(doc, pair->value); 491 492 /* 493 * ignoring silently empty keys can be empty lines 494 * or user mistakes 495 */ 496 if (key->data.scalar.length <= 0) { 497 ++pair; 498 continue; 499 } 500 501 /* 502 * silently skip on purpose to allow user to leave 503 * empty lines without complaining 504 */ 505 if (val->type == YAML_NO_NODE || 506 (val->type == YAML_SCALAR_NODE && 507 val->data.scalar.length <= 0)) { 508 ++pair; 509 continue; 510 } 511 512 sbuf_clear(buf); 513 514 if (conftype == CONFFILE_PKG) { 515 for (j = 0; j < strlen(key->data.scalar.value); ++j) 516 sbuf_putc(buf, 517 toupper(key->data.scalar.value[j])); 518 sbuf_finish(buf); 519 } else if (conftype == CONFFILE_REPO) { 520 /* The CONFFILE_REPO type is more restrictive. Only 521 parse known elements. */ 522 if (strcasecmp(key->data.scalar.value, "url") == 0) 523 sbuf_cpy(buf, "PACKAGESITE"); 524 else if (strcasecmp(key->data.scalar.value, 525 "mirror_type") == 0) 526 sbuf_cpy(buf, "MIRROR_TYPE"); 527 else if (strcasecmp(key->data.scalar.value, 528 "signature_type") == 0) 529 sbuf_cpy(buf, "SIGNATURE_TYPE"); 530 else if (strcasecmp(key->data.scalar.value, 531 "fingerprints") == 0) 532 sbuf_cpy(buf, "FINGERPRINTS"); 533 else { /* Skip unknown entries for future use. */ 534 ++pair; 535 continue; 536 } 537 sbuf_finish(buf); 538 } 539 540 for (i = 0; i < CONFIG_SIZE; i++) { 541 if (strcmp(sbuf_data(buf), c[i].key) == 0) 542 break; 543 } 544 545 /* Silently skip unknown keys to be future compatible. */ 546 if (i == CONFIG_SIZE) { 547 ++pair; 548 continue; 549 } 550 551 /* env has priority over config file */ 552 if (c[i].envset) { 553 ++pair; 554 continue; 555 } 556 557 c[i].value = strdup(val->data.scalar.value); 558 ++pair; 559 } 560 561 sbuf_delete(buf); 562 } 563 564 /*- 565 * Parse new repo style configs in style: 566 * Name: 567 * URL: 568 * MIRROR_TYPE: 569 * etc... 570 */ 571 static void 572 parse_repo_file(yaml_document_t *doc, yaml_node_t *node) 573 { 574 yaml_node_pair_t *pair; 575 576 pair = node->data.mapping.pairs.start; 577 while (pair < node->data.mapping.pairs.top) { 578 yaml_node_t *key = yaml_document_get_node(doc, pair->key); 579 yaml_node_t *val = yaml_document_get_node(doc, pair->value); 580 581 if (key->data.scalar.length <= 0) { 582 ++pair; 583 continue; 584 } 585 586 if (val->type != YAML_MAPPING_NODE) { 587 ++pair; 588 continue; 589 } 590 591 config_parse(doc, val, CONFFILE_REPO); 592 ++pair; 593 } 594 } 595 596 597 static int 598 read_conf_file(const char *confpath, pkg_conf_file_t conftype) 599 { 600 FILE *fp; 601 yaml_parser_t parser; 602 yaml_document_t doc; 603 yaml_node_t *node; 604 605 if ((fp = fopen(confpath, "r")) == NULL) { 606 if (errno != ENOENT) 607 err(EXIT_FAILURE, "Unable to open configuration " 608 "file %s", confpath); 609 /* no configuration present */ 610 return (1); 611 } 612 613 yaml_parser_initialize(&parser); 614 yaml_parser_set_input_file(&parser, fp); 615 yaml_parser_load(&parser, &doc); 616 617 node = yaml_document_get_root_node(&doc); 618 619 if (node == NULL || node->type != YAML_MAPPING_NODE) 620 warnx("Invalid configuration format, ignoring the " 621 "configuration file %s", confpath); 622 else { 623 if (conftype == CONFFILE_PKG) 624 config_parse(&doc, node, conftype); 625 else if (conftype == CONFFILE_REPO) 626 parse_repo_file(&doc, node); 627 } 628 629 yaml_document_delete(&doc); 630 yaml_parser_delete(&parser); 631 632 return (0); 633 } 634 635 int 636 config_init(void) 637 { 638 const char *val; 639 int i; 640 const char *localbase; 641 char confpath[MAXPATHLEN]; 642 char abi[BUFSIZ]; 643 644 for (i = 0; i < CONFIG_SIZE; i++) { 645 val = getenv(c[i].key); 646 if (val != NULL) { 647 c[i].val = val; 648 c[i].envset = true; 649 } 650 } 651 652 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 653 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 654 localbase); 655 656 if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 657 CONFFILE_PKG)) 658 goto finalize; 659 660 snprintf(confpath, sizeof(confpath), "/etc/pkg/FreeBSD.conf"); 661 if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 662 CONFFILE_REPO)) 663 goto finalize; 664 665 finalize: 666 if (c[ABI].val == NULL && c[ABI].value == NULL) { 667 if (pkg_get_myabi(abi, BUFSIZ) != 0) 668 errx(EXIT_FAILURE, "Failed to determine the system " 669 "ABI"); 670 c[ABI].val = abi; 671 } 672 673 subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 674 675 return (0); 676 } 677 678 int 679 config_string(pkg_config_key k, const char **val) 680 { 681 if (c[k].type != PKG_CONFIG_STRING) 682 return (-1); 683 684 if (c[k].value != NULL) 685 *val = c[k].value; 686 else 687 *val = c[k].val; 688 689 return (0); 690 } 691 692 int 693 config_bool(pkg_config_key k, bool *val) 694 { 695 const char *value; 696 697 if (c[k].type != PKG_CONFIG_BOOL) 698 return (-1); 699 700 *val = false; 701 702 if (c[k].value != NULL) 703 value = c[k].value; 704 else 705 value = c[k].val; 706 707 if (strcasecmp(value, "true") == 0 || 708 strcasecmp(value, "yes") == 0 || 709 strcasecmp(value, "on") == 0 || 710 *value == '1') 711 *val = true; 712 713 return (0); 714 } 715 716 void 717 config_finish(void) { 718 int i; 719 720 for (i = 0; i < CONFIG_SIZE; i++) 721 free(c[i].value); 722 } 723