13aa4b42aSBaptiste Daroussin /*- 29950eceeSBaptiste Daroussin * Copyright (c) 2012-2013 Baptiste Daroussin <bapt@FreeBSD.org> 3f12db248SBryan Drewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 43aa4b42aSBaptiste Daroussin * All rights reserved. 53aa4b42aSBaptiste Daroussin * 63aa4b42aSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 73aa4b42aSBaptiste Daroussin * modification, are permitted provided that the following conditions 83aa4b42aSBaptiste Daroussin * are met: 93aa4b42aSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 103aa4b42aSBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 113aa4b42aSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 123aa4b42aSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 133aa4b42aSBaptiste Daroussin * documentation and/or other materials provided with the distribution. 143aa4b42aSBaptiste Daroussin * 153aa4b42aSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163aa4b42aSBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173aa4b42aSBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183aa4b42aSBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193aa4b42aSBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203aa4b42aSBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213aa4b42aSBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223aa4b42aSBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233aa4b42aSBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243aa4b42aSBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253aa4b42aSBaptiste Daroussin * SUCH DAMAGE. 263aa4b42aSBaptiste Daroussin */ 273aa4b42aSBaptiste Daroussin 283aa4b42aSBaptiste Daroussin #include <sys/cdefs.h> 293aa4b42aSBaptiste Daroussin __FBSDID("$FreeBSD$"); 303aa4b42aSBaptiste Daroussin 313aa4b42aSBaptiste Daroussin #include <sys/param.h> 32f12db248SBryan Drewery #include <sys/queue.h> 33f12db248SBryan Drewery #include <sys/types.h> 34f12db248SBryan Drewery #include <sys/sbuf.h> 353b05c2a8SBaptiste Daroussin #include <sys/wait.h> 363aa4b42aSBaptiste Daroussin 37f12db248SBryan Drewery #define _WITH_GETLINE 383aa4b42aSBaptiste Daroussin #include <archive.h> 393aa4b42aSBaptiste Daroussin #include <archive_entry.h> 40f12db248SBryan Drewery #include <dirent.h> 413aa4b42aSBaptiste Daroussin #include <err.h> 423aa4b42aSBaptiste Daroussin #include <errno.h> 43b70213b5SBaptiste Daroussin #include <fcntl.h> 443b05c2a8SBaptiste Daroussin #include <fetch.h> 45a6454741SBaptiste Daroussin #include <paths.h> 469950eceeSBaptiste Daroussin #include <stdbool.h> 473aa4b42aSBaptiste Daroussin #include <stdlib.h> 483aa4b42aSBaptiste Daroussin #include <stdio.h> 493aa4b42aSBaptiste Daroussin #include <string.h> 503aa4b42aSBaptiste Daroussin #include <time.h> 513aa4b42aSBaptiste Daroussin #include <unistd.h> 52f12db248SBryan Drewery #include <yaml.h> 53f12db248SBryan Drewery 54f12db248SBryan Drewery #include <openssl/err.h> 55f12db248SBryan Drewery #include <openssl/ssl.h> 563aa4b42aSBaptiste Daroussin 5729aaa961SBaptiste Daroussin #include "dns_utils.h" 589950eceeSBaptiste Daroussin #include "config.h" 593aa4b42aSBaptiste Daroussin 60f12db248SBryan Drewery struct sig_cert { 61516aaf7cSBryan Drewery char *name; 62f12db248SBryan Drewery unsigned char *sig; 63f12db248SBryan Drewery int siglen; 64f12db248SBryan Drewery unsigned char *cert; 65f12db248SBryan Drewery int certlen; 66f12db248SBryan Drewery bool trusted; 67f12db248SBryan Drewery }; 68f12db248SBryan Drewery 69f12db248SBryan Drewery typedef enum { 70f12db248SBryan Drewery HASH_UNKNOWN, 71f12db248SBryan Drewery HASH_SHA256, 72f12db248SBryan Drewery } hash_t; 73f12db248SBryan Drewery 74f12db248SBryan Drewery struct fingerprint { 75f12db248SBryan Drewery hash_t type; 76516aaf7cSBryan Drewery char *name; 77f12db248SBryan Drewery char hash[BUFSIZ]; 78f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 79f12db248SBryan Drewery }; 80f12db248SBryan Drewery 81f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 82f12db248SBryan Drewery 833aa4b42aSBaptiste Daroussin static int 843aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 853aa4b42aSBaptiste Daroussin { 863aa4b42aSBaptiste Daroussin struct archive *a; 873aa4b42aSBaptiste Daroussin struct archive_entry *ae; 883aa4b42aSBaptiste Daroussin char *end; 893aa4b42aSBaptiste Daroussin int ret, r; 903aa4b42aSBaptiste Daroussin 91a6454741SBaptiste Daroussin ret = -1; 923aa4b42aSBaptiste Daroussin a = archive_read_new(); 93a6454741SBaptiste Daroussin if (a == NULL) { 94a6454741SBaptiste Daroussin warn("archive_read_new"); 95a6454741SBaptiste Daroussin return (ret); 96a6454741SBaptiste Daroussin } 97ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 983aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 993aa4b42aSBaptiste Daroussin 100a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 101a6454741SBaptiste Daroussin warn("lseek"); 102a6454741SBaptiste Daroussin goto cleanup; 103a6454741SBaptiste Daroussin } 1043aa4b42aSBaptiste Daroussin 1053aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 106a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1073aa4b42aSBaptiste Daroussin goto cleanup; 1083aa4b42aSBaptiste Daroussin } 1093aa4b42aSBaptiste Daroussin 1103aa4b42aSBaptiste Daroussin ae = NULL; 1113aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1123aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1133aa4b42aSBaptiste Daroussin if (end == NULL) 1143aa4b42aSBaptiste Daroussin continue; 1153aa4b42aSBaptiste Daroussin 1163aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1173aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1183aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1193aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1203aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 121a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1223aa4b42aSBaptiste Daroussin break; 1233aa4b42aSBaptiste Daroussin } 1243aa4b42aSBaptiste Daroussin } 1253aa4b42aSBaptiste Daroussin 126a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 127a6454741SBaptiste Daroussin ret = 0; 128a6454741SBaptiste Daroussin else 1293aa4b42aSBaptiste Daroussin warnx("fail to extract pkg-static"); 1303aa4b42aSBaptiste Daroussin 1313aa4b42aSBaptiste Daroussin cleanup: 132ff75c36aSBaptiste Daroussin archive_read_free(a); 1333b05c2a8SBaptiste Daroussin return (ret); 1343aa4b42aSBaptiste Daroussin 1353aa4b42aSBaptiste Daroussin } 1363aa4b42aSBaptiste Daroussin 1373aa4b42aSBaptiste Daroussin static int 138*5212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1393aa4b42aSBaptiste Daroussin { 1403aa4b42aSBaptiste Daroussin int pstat; 1413aa4b42aSBaptiste Daroussin pid_t pid; 1423aa4b42aSBaptiste Daroussin 1433aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1443aa4b42aSBaptiste Daroussin case -1: 1453aa4b42aSBaptiste Daroussin return (-1); 1463aa4b42aSBaptiste Daroussin case 0: 147*5212e8baSBryan Drewery if (force) 148*5212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 149*5212e8baSBryan Drewery (char *)NULL); 150*5212e8baSBryan Drewery else 151*5212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 152*5212e8baSBryan Drewery (char *)NULL); 1533b05c2a8SBaptiste Daroussin _exit(1); 1543aa4b42aSBaptiste Daroussin default: 1553aa4b42aSBaptiste Daroussin break; 1563aa4b42aSBaptiste Daroussin } 1573aa4b42aSBaptiste Daroussin 158a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1593aa4b42aSBaptiste Daroussin if (errno != EINTR) 1603aa4b42aSBaptiste Daroussin return (-1); 1613aa4b42aSBaptiste Daroussin 162a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1633aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 164a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 165a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 166a6454741SBaptiste Daroussin return (pstat); 1673aa4b42aSBaptiste Daroussin } 1683aa4b42aSBaptiste Daroussin 1693aa4b42aSBaptiste Daroussin static int 170f12db248SBryan Drewery fetch_to_fd(const char *url, char *path) 1713aa4b42aSBaptiste Daroussin { 17229aaa961SBaptiste Daroussin struct url *u; 17329aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 174a6454741SBaptiste Daroussin struct url_stat st; 175f12db248SBryan Drewery FILE *remote; 176f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 177f12db248SBryan Drewery int fd; 178f12db248SBryan Drewery int retry, max_retry; 1793aa4b42aSBaptiste Daroussin off_t done, r; 180f12db248SBryan Drewery time_t now, last; 181f12db248SBryan Drewery char buf[10240]; 182f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 183f12db248SBryan Drewery static const char *mirror_type = NULL; 1843aa4b42aSBaptiste Daroussin 1853aa4b42aSBaptiste Daroussin done = 0; 186a6454741SBaptiste Daroussin last = 0; 18729aaa961SBaptiste Daroussin max_retry = 3; 18829aaa961SBaptiste Daroussin current = mirrors = NULL; 189f12db248SBryan Drewery remote = NULL; 1903aa4b42aSBaptiste Daroussin 191f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 192f12db248SBryan Drewery != 0) { 1939950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 1949950eceeSBaptiste Daroussin return (-1); 1959950eceeSBaptiste Daroussin } 19662940ea9SBryan Drewery 197f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 1983aa4b42aSBaptiste Daroussin warn("mkstemp()"); 1993b05c2a8SBaptiste Daroussin return (-1); 2003aa4b42aSBaptiste Daroussin } 2013aa4b42aSBaptiste Daroussin 20229aaa961SBaptiste Daroussin retry = max_retry; 20329aaa961SBaptiste Daroussin 20429aaa961SBaptiste Daroussin u = fetchParseURL(url); 20529aaa961SBaptiste Daroussin while (remote == NULL) { 20629aaa961SBaptiste Daroussin if (retry == max_retry) { 2079950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2089950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 20929aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 21029aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 21129aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 21229aaa961SBaptiste Daroussin current = mirrors; 21329aaa961SBaptiste Daroussin } 21429aaa961SBaptiste Daroussin } 21529aaa961SBaptiste Daroussin 21635e07a7aSBaptiste Daroussin if (mirrors != NULL) { 21729aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 21835e07a7aSBaptiste Daroussin u->port = current->port; 21935e07a7aSBaptiste Daroussin } 22029aaa961SBaptiste Daroussin 22129aaa961SBaptiste Daroussin remote = fetchXGet(u, &st, ""); 22229aaa961SBaptiste Daroussin if (remote == NULL) { 22329aaa961SBaptiste Daroussin --retry; 22429aaa961SBaptiste Daroussin if (retry <= 0) 22529aaa961SBaptiste Daroussin goto fetchfail; 22629aaa961SBaptiste Daroussin if (mirrors == NULL) { 2273aa4b42aSBaptiste Daroussin sleep(1); 22829aaa961SBaptiste Daroussin } else { 22929aaa961SBaptiste Daroussin current = current->next; 23029aaa961SBaptiste Daroussin if (current == NULL) 23129aaa961SBaptiste Daroussin current = mirrors; 23229aaa961SBaptiste Daroussin } 23329aaa961SBaptiste Daroussin } 23429aaa961SBaptiste Daroussin } 235a6454741SBaptiste Daroussin 236a6454741SBaptiste Daroussin if (remote == NULL) 237a6454741SBaptiste Daroussin goto fetchfail; 2383aa4b42aSBaptiste Daroussin 2393aa4b42aSBaptiste Daroussin while (done < st.size) { 2403aa4b42aSBaptiste Daroussin if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) 2413aa4b42aSBaptiste Daroussin break; 2423aa4b42aSBaptiste Daroussin 2433aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2443aa4b42aSBaptiste Daroussin warn("write()"); 245f12db248SBryan Drewery goto fetchfail; 2463aa4b42aSBaptiste Daroussin } 2473aa4b42aSBaptiste Daroussin 2483aa4b42aSBaptiste Daroussin done += r; 2493aa4b42aSBaptiste Daroussin now = time(NULL); 250a6454741SBaptiste Daroussin if (now > last || done == st.size) 2513aa4b42aSBaptiste Daroussin last = now; 2523aa4b42aSBaptiste Daroussin } 2533aa4b42aSBaptiste Daroussin 254a6454741SBaptiste Daroussin if (ferror(remote)) 255a6454741SBaptiste Daroussin goto fetchfail; 2563aa4b42aSBaptiste Daroussin 257f12db248SBryan Drewery goto cleanup; 258f12db248SBryan Drewery 259f12db248SBryan Drewery fetchfail: 260f12db248SBryan Drewery if (fd != -1) { 261f12db248SBryan Drewery close(fd); 262f12db248SBryan Drewery fd = -1; 263f12db248SBryan Drewery unlink(path); 264f12db248SBryan Drewery } 265f12db248SBryan Drewery 266f12db248SBryan Drewery cleanup: 267f12db248SBryan Drewery if (remote != NULL) 268f12db248SBryan Drewery fclose(remote); 269f12db248SBryan Drewery 270f12db248SBryan Drewery return fd; 271f12db248SBryan Drewery } 272f12db248SBryan Drewery 273f12db248SBryan Drewery static struct fingerprint * 274f12db248SBryan Drewery parse_fingerprint(yaml_document_t *doc, yaml_node_t *node) 275f12db248SBryan Drewery { 276f12db248SBryan Drewery yaml_node_pair_t *pair; 277f12db248SBryan Drewery yaml_char_t *function, *fp; 278f12db248SBryan Drewery struct fingerprint *f; 279f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 280f12db248SBryan Drewery 281f12db248SBryan Drewery function = fp = NULL; 282f12db248SBryan Drewery 283f12db248SBryan Drewery pair = node->data.mapping.pairs.start; 284f12db248SBryan Drewery while (pair < node->data.mapping.pairs.top) { 285f12db248SBryan Drewery yaml_node_t *key = yaml_document_get_node(doc, pair->key); 286f12db248SBryan Drewery yaml_node_t *val = yaml_document_get_node(doc, pair->value); 287f12db248SBryan Drewery 288f12db248SBryan Drewery if (key->data.scalar.length <= 0) { 289f12db248SBryan Drewery ++pair; 290f12db248SBryan Drewery continue; 291f12db248SBryan Drewery } 292f12db248SBryan Drewery 293f12db248SBryan Drewery if (val->type != YAML_SCALAR_NODE) { 294f12db248SBryan Drewery ++pair; 295f12db248SBryan Drewery continue; 296f12db248SBryan Drewery } 297f12db248SBryan Drewery 298f12db248SBryan Drewery if (strcasecmp(key->data.scalar.value, "function") == 0) 299f12db248SBryan Drewery function = val->data.scalar.value; 300f12db248SBryan Drewery else if (strcasecmp(key->data.scalar.value, "fingerprint") 301f12db248SBryan Drewery == 0) 302f12db248SBryan Drewery fp = val->data.scalar.value; 303f12db248SBryan Drewery 304f12db248SBryan Drewery ++pair; 305f12db248SBryan Drewery continue; 306f12db248SBryan Drewery } 307f12db248SBryan Drewery 308f12db248SBryan Drewery if (fp == NULL || function == NULL) 309f12db248SBryan Drewery return (NULL); 310f12db248SBryan Drewery 311f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 312f12db248SBryan Drewery fct = HASH_SHA256; 313f12db248SBryan Drewery 314f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 315f12db248SBryan Drewery fprintf(stderr, "Unsupported hashing function: %s\n", function); 316f12db248SBryan Drewery return (NULL); 317f12db248SBryan Drewery } 318f12db248SBryan Drewery 319f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 320f12db248SBryan Drewery f->type = fct; 321f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 322f12db248SBryan Drewery 323f12db248SBryan Drewery return (f); 324f12db248SBryan Drewery } 325f12db248SBryan Drewery 326516aaf7cSBryan Drewery static void 327516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 328516aaf7cSBryan Drewery { 329516aaf7cSBryan Drewery struct fingerprint* fingerprint; 330516aaf7cSBryan Drewery 331516aaf7cSBryan Drewery STAILQ_FOREACH(fingerprint, list, next) { 332516aaf7cSBryan Drewery if (fingerprint->name) 333516aaf7cSBryan Drewery free(fingerprint->name); 334516aaf7cSBryan Drewery free(fingerprint); 335516aaf7cSBryan Drewery } 336516aaf7cSBryan Drewery free(list); 337516aaf7cSBryan Drewery } 338516aaf7cSBryan Drewery 339f12db248SBryan Drewery static struct fingerprint * 340f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 341f12db248SBryan Drewery { 342f12db248SBryan Drewery yaml_parser_t parser; 343f12db248SBryan Drewery yaml_document_t doc; 344f12db248SBryan Drewery yaml_node_t *node; 345f12db248SBryan Drewery FILE *fp; 346f12db248SBryan Drewery struct fingerprint *f; 347f12db248SBryan Drewery char path[MAXPATHLEN]; 348f12db248SBryan Drewery 349f12db248SBryan Drewery f = NULL; 350f12db248SBryan Drewery 351f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 352f12db248SBryan Drewery 353f12db248SBryan Drewery if ((fp = fopen(path, "r")) == NULL) 354f12db248SBryan Drewery return (NULL); 355f12db248SBryan Drewery 356f12db248SBryan Drewery yaml_parser_initialize(&parser); 357f12db248SBryan Drewery yaml_parser_set_input_file(&parser, fp); 358f12db248SBryan Drewery yaml_parser_load(&parser, &doc); 359f12db248SBryan Drewery 360f12db248SBryan Drewery node = yaml_document_get_root_node(&doc); 361f12db248SBryan Drewery if (node == NULL || node->type != YAML_MAPPING_NODE) 362f12db248SBryan Drewery goto out; 363f12db248SBryan Drewery 364f12db248SBryan Drewery f = parse_fingerprint(&doc, node); 365516aaf7cSBryan Drewery f->name = strdup(filename); 366f12db248SBryan Drewery 367f12db248SBryan Drewery out: 368f12db248SBryan Drewery yaml_document_delete(&doc); 369f12db248SBryan Drewery yaml_parser_delete(&parser); 370f12db248SBryan Drewery fclose(fp); 371f12db248SBryan Drewery 372f12db248SBryan Drewery return (f); 373f12db248SBryan Drewery } 374f12db248SBryan Drewery 375f12db248SBryan Drewery static struct fingerprint_list * 376f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 377f12db248SBryan Drewery { 378f12db248SBryan Drewery DIR *d; 379f12db248SBryan Drewery struct dirent *ent; 380f12db248SBryan Drewery struct fingerprint *finger; 381f12db248SBryan Drewery struct fingerprint_list *fingerprints; 382f12db248SBryan Drewery 383f12db248SBryan Drewery *count = 0; 384f12db248SBryan Drewery 385f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 386f12db248SBryan Drewery if (fingerprints == NULL) 387f12db248SBryan Drewery return (NULL); 388f12db248SBryan Drewery STAILQ_INIT(fingerprints); 389f12db248SBryan Drewery 390f12db248SBryan Drewery if ((d = opendir(path)) == NULL) 391f12db248SBryan Drewery return (NULL); 392f12db248SBryan Drewery 393f12db248SBryan Drewery while ((ent = readdir(d))) { 394f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 395f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 396f12db248SBryan Drewery continue; 397f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 398f12db248SBryan Drewery if (finger != NULL) { 399f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 400f12db248SBryan Drewery ++(*count); 401f12db248SBryan Drewery } 402f12db248SBryan Drewery } 403f12db248SBryan Drewery 404f12db248SBryan Drewery closedir(d); 405f12db248SBryan Drewery 406f12db248SBryan Drewery return (fingerprints); 407f12db248SBryan Drewery } 408f12db248SBryan Drewery 409f12db248SBryan Drewery static void 410f12db248SBryan Drewery sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 411f12db248SBryan Drewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 412f12db248SBryan Drewery { 413f12db248SBryan Drewery int i; 414f12db248SBryan Drewery 415f12db248SBryan Drewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 416f12db248SBryan Drewery sprintf(out + (i * 2), "%02x", hash[i]); 417f12db248SBryan Drewery 418f12db248SBryan Drewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 419f12db248SBryan Drewery } 420f12db248SBryan Drewery 421f12db248SBryan Drewery static void 422f12db248SBryan Drewery sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 423f12db248SBryan Drewery { 424f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 425f12db248SBryan Drewery SHA256_CTX sha256; 426f12db248SBryan Drewery 427f12db248SBryan Drewery out[0] = '\0'; 428f12db248SBryan Drewery 429f12db248SBryan Drewery SHA256_Init(&sha256); 430f12db248SBryan Drewery SHA256_Update(&sha256, buf, len); 431f12db248SBryan Drewery SHA256_Final(hash, &sha256); 432f12db248SBryan Drewery sha256_hash(hash, out); 433f12db248SBryan Drewery } 434f12db248SBryan Drewery 435f12db248SBryan Drewery static int 436f12db248SBryan Drewery sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 437f12db248SBryan Drewery { 438f12db248SBryan Drewery int my_fd; 439f12db248SBryan Drewery FILE *fp; 440f12db248SBryan Drewery char buffer[BUFSIZ]; 441f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 442f12db248SBryan Drewery size_t r; 443f12db248SBryan Drewery int ret; 444f12db248SBryan Drewery SHA256_CTX sha256; 445f12db248SBryan Drewery 446f12db248SBryan Drewery my_fd = -1; 447f12db248SBryan Drewery fp = NULL; 448f12db248SBryan Drewery r = 0; 449f12db248SBryan Drewery ret = 1; 450f12db248SBryan Drewery 451f12db248SBryan Drewery out[0] = '\0'; 452f12db248SBryan Drewery 453f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 454f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 455f12db248SBryan Drewery warnx("dup"); 456f12db248SBryan Drewery goto cleanup; 457f12db248SBryan Drewery } 458f12db248SBryan Drewery 459f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 460f12db248SBryan Drewery warnx("fdopen"); 461f12db248SBryan Drewery goto cleanup; 462f12db248SBryan Drewery } 463f12db248SBryan Drewery 464f12db248SBryan Drewery SHA256_Init(&sha256); 465f12db248SBryan Drewery 466f12db248SBryan Drewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 467f12db248SBryan Drewery SHA256_Update(&sha256, buffer, r); 468f12db248SBryan Drewery 469f12db248SBryan Drewery if (ferror(fp) != 0) { 470f12db248SBryan Drewery warnx("fread"); 471f12db248SBryan Drewery goto cleanup; 472f12db248SBryan Drewery } 473f12db248SBryan Drewery 474f12db248SBryan Drewery SHA256_Final(hash, &sha256); 475f12db248SBryan Drewery sha256_hash(hash, out); 476f12db248SBryan Drewery ret = 0; 477f12db248SBryan Drewery 478f12db248SBryan Drewery cleanup: 479f12db248SBryan Drewery if (fp != NULL) 480f12db248SBryan Drewery fclose(fp); 481f12db248SBryan Drewery else if (my_fd != -1) 482f12db248SBryan Drewery close(my_fd); 483f12db248SBryan Drewery (void)lseek(fd, 0, SEEK_SET); 484f12db248SBryan Drewery 485f12db248SBryan Drewery return (ret); 486f12db248SBryan Drewery } 487f12db248SBryan Drewery 488f12db248SBryan Drewery static EVP_PKEY * 489f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 490f12db248SBryan Drewery { 491f12db248SBryan Drewery EVP_PKEY *pkey; 492f12db248SBryan Drewery BIO *bp; 493f12db248SBryan Drewery char errbuf[1024]; 494f12db248SBryan Drewery 495c2788c07SBryan Drewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 496f12db248SBryan Drewery 497f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 498f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 499f12db248SBryan Drewery 500f12db248SBryan Drewery BIO_free(bp); 501f12db248SBryan Drewery 502f12db248SBryan Drewery return (pkey); 503f12db248SBryan Drewery } 504f12db248SBryan Drewery 505f12db248SBryan Drewery static bool 506f12db248SBryan Drewery rsa_verify_cert(int fd, const unsigned char *key, int keylen, 507f12db248SBryan Drewery unsigned char *sig, int siglen) 508f12db248SBryan Drewery { 509f12db248SBryan Drewery EVP_MD_CTX *mdctx; 510f12db248SBryan Drewery EVP_PKEY *pkey; 511f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 512f12db248SBryan Drewery char errbuf[1024]; 513f12db248SBryan Drewery bool ret; 514f12db248SBryan Drewery 515f12db248SBryan Drewery pkey = NULL; 516f12db248SBryan Drewery mdctx = NULL; 517f12db248SBryan Drewery ret = false; 518f12db248SBryan Drewery 519f12db248SBryan Drewery /* Compute SHA256 of the package. */ 520f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 521f12db248SBryan Drewery warn("lseek"); 522f12db248SBryan Drewery goto cleanup; 523f12db248SBryan Drewery } 524f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 525f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 526f12db248SBryan Drewery goto cleanup; 527f12db248SBryan Drewery } 528f12db248SBryan Drewery 529f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 530f12db248SBryan Drewery warnx("Error reading public key"); 531f12db248SBryan Drewery goto cleanup; 532f12db248SBryan Drewery } 533f12db248SBryan Drewery 534f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 535f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 536f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 537f12db248SBryan Drewery goto error; 538f12db248SBryan Drewery } 539f12db248SBryan Drewery 540f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 541f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 542f12db248SBryan Drewery goto error; 543f12db248SBryan Drewery } 544f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 545f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 546f12db248SBryan Drewery goto error; 547f12db248SBryan Drewery } 548f12db248SBryan Drewery 549f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 550f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 551f12db248SBryan Drewery goto error; 552f12db248SBryan Drewery } 553f12db248SBryan Drewery 554f12db248SBryan Drewery ret = true; 555f12db248SBryan Drewery printf("done\n"); 556f12db248SBryan Drewery goto cleanup; 557f12db248SBryan Drewery 558f12db248SBryan Drewery error: 559f12db248SBryan Drewery printf("failed\n"); 560f12db248SBryan Drewery 561f12db248SBryan Drewery cleanup: 562f12db248SBryan Drewery if (pkey) 563f12db248SBryan Drewery EVP_PKEY_free(pkey); 564f12db248SBryan Drewery if (mdctx) 565f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 566f12db248SBryan Drewery ERR_free_strings(); 567f12db248SBryan Drewery 568f12db248SBryan Drewery return (ret); 569f12db248SBryan Drewery } 570f12db248SBryan Drewery 571f12db248SBryan Drewery static struct sig_cert * 572f12db248SBryan Drewery parse_cert(int fd) { 573f12db248SBryan Drewery int my_fd; 574f12db248SBryan Drewery struct sig_cert *sc; 575f12db248SBryan Drewery FILE *fp; 576f12db248SBryan Drewery struct sbuf *buf, *sig, *cert; 577f12db248SBryan Drewery char *line; 578f12db248SBryan Drewery size_t linecap; 579f12db248SBryan Drewery ssize_t linelen; 580f12db248SBryan Drewery 581c2788c07SBryan Drewery buf = NULL; 582f12db248SBryan Drewery my_fd = -1; 583f12db248SBryan Drewery sc = NULL; 584f12db248SBryan Drewery line = NULL; 585f12db248SBryan Drewery linecap = 0; 586f12db248SBryan Drewery 587f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 588f12db248SBryan Drewery warn("lseek"); 589f12db248SBryan Drewery return (NULL); 590f12db248SBryan Drewery } 591f12db248SBryan Drewery 592f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 593f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 594f12db248SBryan Drewery warnx("dup"); 595f12db248SBryan Drewery return (NULL); 596f12db248SBryan Drewery } 597f12db248SBryan Drewery 598f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 599f12db248SBryan Drewery warn("fdopen"); 600f12db248SBryan Drewery close(my_fd); 601f12db248SBryan Drewery return (NULL); 602f12db248SBryan Drewery } 603f12db248SBryan Drewery 604f12db248SBryan Drewery sig = sbuf_new_auto(); 605f12db248SBryan Drewery cert = sbuf_new_auto(); 606f12db248SBryan Drewery 607f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 608f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 609f12db248SBryan Drewery buf = sig; 610f12db248SBryan Drewery continue; 611f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 612f12db248SBryan Drewery buf = cert; 613f12db248SBryan Drewery continue; 614f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 615f12db248SBryan Drewery break; 616f12db248SBryan Drewery } 617f12db248SBryan Drewery if (buf != NULL) 618f12db248SBryan Drewery sbuf_bcat(buf, line, linelen); 619f12db248SBryan Drewery } 620f12db248SBryan Drewery 621f12db248SBryan Drewery fclose(fp); 622f12db248SBryan Drewery 623f12db248SBryan Drewery /* Trim out unrelated trailing newline */ 624f12db248SBryan Drewery sbuf_setpos(sig, sbuf_len(sig) - 1); 625f12db248SBryan Drewery 626f12db248SBryan Drewery sbuf_finish(sig); 627f12db248SBryan Drewery sbuf_finish(cert); 628f12db248SBryan Drewery 629f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 630f12db248SBryan Drewery sc->siglen = sbuf_len(sig); 631f12db248SBryan Drewery sc->sig = calloc(1, sc->siglen); 632f12db248SBryan Drewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 633f12db248SBryan Drewery 634f12db248SBryan Drewery sc->certlen = sbuf_len(cert); 635f12db248SBryan Drewery sc->cert = strdup(sbuf_data(cert)); 636f12db248SBryan Drewery 637f12db248SBryan Drewery sbuf_delete(sig); 638f12db248SBryan Drewery sbuf_delete(cert); 639f12db248SBryan Drewery 640f12db248SBryan Drewery return (sc); 641f12db248SBryan Drewery } 642f12db248SBryan Drewery 643f12db248SBryan Drewery static bool 644f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 645f12db248SBryan Drewery { 646f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 647f12db248SBryan Drewery struct fingerprint *fingerprint; 648f12db248SBryan Drewery struct sig_cert *sc; 649f12db248SBryan Drewery bool ret; 650f12db248SBryan Drewery int trusted_count, revoked_count; 651f12db248SBryan Drewery const char *fingerprints; 652f12db248SBryan Drewery char path[MAXPATHLEN]; 653f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 654f12db248SBryan Drewery 655516aaf7cSBryan Drewery sc = NULL; 656f12db248SBryan Drewery trusted = revoked = NULL; 657f12db248SBryan Drewery ret = false; 658f12db248SBryan Drewery 659f12db248SBryan Drewery /* Read and parse fingerprints. */ 660f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 661f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 662f12db248SBryan Drewery goto cleanup; 663f12db248SBryan Drewery } 664f12db248SBryan Drewery 665f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 666f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 667f12db248SBryan Drewery warnx("Error loading trusted certificates"); 668f12db248SBryan Drewery goto cleanup; 669f12db248SBryan Drewery } 670f12db248SBryan Drewery 671f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 672f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 673f12db248SBryan Drewery goto cleanup; 674f12db248SBryan Drewery } 675f12db248SBryan Drewery 676f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 677f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 678f12db248SBryan Drewery warnx("Error loading revoked certificates"); 679f12db248SBryan Drewery goto cleanup; 680f12db248SBryan Drewery } 681f12db248SBryan Drewery 682f12db248SBryan Drewery /* Read certificate and signature in. */ 683f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 684f12db248SBryan Drewery warnx("Error parsing certificate"); 685f12db248SBryan Drewery goto cleanup; 686f12db248SBryan Drewery } 687f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 688f12db248SBryan Drewery sc->trusted = false; 689f12db248SBryan Drewery 690f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 691f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 692f12db248SBryan Drewery 693f12db248SBryan Drewery /* Check if this hash is revoked */ 694f12db248SBryan Drewery if (revoked != NULL) { 695f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 696f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 697516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 698516aaf7cSBryan Drewery "revoked certificate %s\n", 699516aaf7cSBryan Drewery fingerprint->name); 700f12db248SBryan Drewery goto cleanup; 701f12db248SBryan Drewery } 702f12db248SBryan Drewery } 703f12db248SBryan Drewery } 704f12db248SBryan Drewery 705f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 706f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 707f12db248SBryan Drewery sc->trusted = true; 708516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 709f12db248SBryan Drewery break; 710f12db248SBryan Drewery } 711f12db248SBryan Drewery } 712f12db248SBryan Drewery 713f12db248SBryan Drewery if (sc->trusted == false) { 714516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 715f12db248SBryan Drewery "package's certificate\n"); 716f12db248SBryan Drewery goto cleanup; 717f12db248SBryan Drewery } 718f12db248SBryan Drewery 719f12db248SBryan Drewery /* Verify the signature. */ 720516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 721f12db248SBryan Drewery if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig, 722f12db248SBryan Drewery sc->siglen) == false) { 723f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 724f12db248SBryan Drewery goto cleanup; 725f12db248SBryan Drewery } 726f12db248SBryan Drewery 727f12db248SBryan Drewery ret = true; 728f12db248SBryan Drewery 729f12db248SBryan Drewery cleanup: 730516aaf7cSBryan Drewery if (trusted) 731516aaf7cSBryan Drewery free_fingerprint_list(trusted); 732516aaf7cSBryan Drewery if (revoked) 733516aaf7cSBryan Drewery free_fingerprint_list(revoked); 734f12db248SBryan Drewery if (sc) { 735f12db248SBryan Drewery if (sc->cert) 736f12db248SBryan Drewery free(sc->cert); 737f12db248SBryan Drewery if (sc->sig) 738f12db248SBryan Drewery free(sc->sig); 739516aaf7cSBryan Drewery if (sc->name) 740516aaf7cSBryan Drewery free(sc->name); 741f12db248SBryan Drewery free(sc); 742f12db248SBryan Drewery } 743f12db248SBryan Drewery 744f12db248SBryan Drewery return (ret); 745f12db248SBryan Drewery } 746f12db248SBryan Drewery 747f12db248SBryan Drewery static int 748*5212e8baSBryan Drewery bootstrap_pkg(bool force) 749f12db248SBryan Drewery { 750f12db248SBryan Drewery FILE *config; 751f12db248SBryan Drewery int fd_pkg, fd_sig; 752f12db248SBryan Drewery int ret; 753f12db248SBryan Drewery char *site; 754f12db248SBryan Drewery char url[MAXPATHLEN]; 755f12db248SBryan Drewery char conf[MAXPATHLEN]; 756f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 757f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 758f12db248SBryan Drewery const char *packagesite; 759f12db248SBryan Drewery const char *signature_type; 760f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 761f12db248SBryan Drewery 762f12db248SBryan Drewery fd_sig = -1; 763f12db248SBryan Drewery ret = -1; 764f12db248SBryan Drewery config = NULL; 765f12db248SBryan Drewery 766f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 767f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 768f12db248SBryan Drewery return (-1); 769f12db248SBryan Drewery } 770f12db248SBryan Drewery 771f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 772f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 773f12db248SBryan Drewery return (-1); 774f12db248SBryan Drewery } 775f12db248SBryan Drewery 776f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 777f12db248SBryan Drewery 778f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 779f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 780f12db248SBryan Drewery no A record. */ 781f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 782f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 783f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 784f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 785f12db248SBryan Drewery 786f12db248SBryan Drewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 787f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 788f12db248SBryan Drewery 789f12db248SBryan Drewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 790f12db248SBryan Drewery goto fetchfail; 791f12db248SBryan Drewery 792f12db248SBryan Drewery if (signature_type != NULL && 793f12db248SBryan Drewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 794f12db248SBryan Drewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 795f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 796f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 797f12db248SBryan Drewery packagesite); 798f12db248SBryan Drewery 799f12db248SBryan Drewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 800f12db248SBryan Drewery fprintf(stderr, "Signature for pkg not available.\n"); 801f12db248SBryan Drewery goto fetchfail; 802f12db248SBryan Drewery } 803f12db248SBryan Drewery 804f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 805f12db248SBryan Drewery goto cleanup; 806f12db248SBryan Drewery } 807f12db248SBryan Drewery 808f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 809*5212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 8103aa4b42aSBaptiste Daroussin 8112fe3761eSBaptiste Daroussin snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf", 8122fe3761eSBaptiste Daroussin getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 8132fe3761eSBaptiste Daroussin 8142fe3761eSBaptiste Daroussin if (access(conf, R_OK) == -1) { 8152fe3761eSBaptiste Daroussin site = strrchr(url, '/'); 8162fe3761eSBaptiste Daroussin if (site == NULL) 8172fe3761eSBaptiste Daroussin goto cleanup; 8182fe3761eSBaptiste Daroussin site[0] = '\0'; 8192fe3761eSBaptiste Daroussin site = strrchr(url, '/'); 8202fe3761eSBaptiste Daroussin if (site == NULL) 8212fe3761eSBaptiste Daroussin goto cleanup; 8222fe3761eSBaptiste Daroussin site[0] = '\0'; 8232fe3761eSBaptiste Daroussin 8242fe3761eSBaptiste Daroussin config = fopen(conf, "w+"); 8252fe3761eSBaptiste Daroussin if (config == NULL) 8262fe3761eSBaptiste Daroussin goto cleanup; 827514ead92SBaptiste Daroussin fprintf(config, "packagesite: %s\n", url); 8282fe3761eSBaptiste Daroussin fclose(config); 8292fe3761eSBaptiste Daroussin } 8302fe3761eSBaptiste Daroussin 831a6454741SBaptiste Daroussin goto cleanup; 832a6454741SBaptiste Daroussin 833a6454741SBaptiste Daroussin fetchfail: 834a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 8354ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 8364ff9a7efSBryan Drewery "your system.\n"); 8374ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 8384ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 839a6454741SBaptiste Daroussin 8403aa4b42aSBaptiste Daroussin cleanup: 841f12db248SBryan Drewery if (fd_sig != -1) { 842f12db248SBryan Drewery close(fd_sig); 843f12db248SBryan Drewery unlink(tmpsig); 844f12db248SBryan Drewery } 845f12db248SBryan Drewery close(fd_pkg); 8463aa4b42aSBaptiste Daroussin unlink(tmppkg); 8473aa4b42aSBaptiste Daroussin 848a6454741SBaptiste Daroussin return (ret); 8493aa4b42aSBaptiste Daroussin } 8503aa4b42aSBaptiste Daroussin 851e18ad51cSAlexander Kabaev static const char confirmation_message[] = 852e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 853e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 854e18ad51cSAlexander Kabaev 855e18ad51cSAlexander Kabaev static int 856e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 857e18ad51cSAlexander Kabaev { 858e18ad51cSAlexander Kabaev int ret, c; 859e18ad51cSAlexander Kabaev 860e18ad51cSAlexander Kabaev c = getchar(); 861e18ad51cSAlexander Kabaev 862e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 863e18ad51cSAlexander Kabaev ret = 1; 864e18ad51cSAlexander Kabaev else 865e18ad51cSAlexander Kabaev ret = 0; 866e18ad51cSAlexander Kabaev 867e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 868e18ad51cSAlexander Kabaev c = getchar(); 869e18ad51cSAlexander Kabaev 870e18ad51cSAlexander Kabaev return (ret); 871e18ad51cSAlexander Kabaev } 872e18ad51cSAlexander Kabaev 87352cb76feSBryan Drewery static int 874*5212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 87552cb76feSBryan Drewery { 87652cb76feSBryan Drewery char path[MAXPATHLEN]; 87752cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 87852cb76feSBryan Drewery const char *signature_type; 87952cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 88052cb76feSBryan Drewery 88152cb76feSBryan Drewery fd_sig = -1; 88252cb76feSBryan Drewery ret = -1; 88352cb76feSBryan Drewery 88452cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 88552cb76feSBryan Drewery if (fd_pkg == -1) 88652cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 88752cb76feSBryan Drewery 88852cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 88952cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 89052cb76feSBryan Drewery return (-1); 89152cb76feSBryan Drewery } 89252cb76feSBryan Drewery if (signature_type != NULL && 89352cb76feSBryan Drewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 89452cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 89552cb76feSBryan Drewery 89652cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 89752cb76feSBryan Drewery fprintf(stderr, "Signature for pkg not available.\n"); 89852cb76feSBryan Drewery goto cleanup; 89952cb76feSBryan Drewery } 90052cb76feSBryan Drewery 90152cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 90252cb76feSBryan Drewery goto cleanup; 90352cb76feSBryan Drewery } 90452cb76feSBryan Drewery 90552cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 906*5212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 90752cb76feSBryan Drewery 90852cb76feSBryan Drewery cleanup: 90952cb76feSBryan Drewery close(fd_pkg); 91052cb76feSBryan Drewery if (fd_sig != -1) 91152cb76feSBryan Drewery close(fd_sig); 91252cb76feSBryan Drewery 91352cb76feSBryan Drewery return (ret); 91452cb76feSBryan Drewery } 91552cb76feSBryan Drewery 9163aa4b42aSBaptiste Daroussin int 9173aa4b42aSBaptiste Daroussin main(__unused int argc, char *argv[]) 9183aa4b42aSBaptiste Daroussin { 9193aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 920*5212e8baSBryan Drewery const char *pkgarg; 921*5212e8baSBryan Drewery bool bootstrap_only, force, yes; 922*5212e8baSBryan Drewery 923*5212e8baSBryan Drewery bootstrap_only = false; 924*5212e8baSBryan Drewery force = false; 925*5212e8baSBryan Drewery pkgarg = NULL; 926*5212e8baSBryan Drewery yes = false; 9273aa4b42aSBaptiste Daroussin 9283aa4b42aSBaptiste Daroussin snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 9293aa4b42aSBaptiste Daroussin getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 9303aa4b42aSBaptiste Daroussin 931*5212e8baSBryan Drewery if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 932*5212e8baSBryan Drewery bootstrap_only = true; 933*5212e8baSBryan Drewery if (argc == 3 && strcmp(argv[2], "-f") == 0) 934*5212e8baSBryan Drewery force = true; 935*5212e8baSBryan Drewery } 936*5212e8baSBryan Drewery 937*5212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 938e18ad51cSAlexander Kabaev /* 939d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 940ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 941ecfed9f2SMatthew Seaman * when that argument is given as argv[1]. 942ecfed9f2SMatthew Seaman */ 943d8f9490cSMatthew Seaman if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 944e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 945ecfed9f2SMatthew Seaman 94652cb76feSBryan Drewery config_init(); 94752cb76feSBryan Drewery 948*5212e8baSBryan Drewery if (argc > 1 && strcmp(argv[1], "add") == 0) { 949*5212e8baSBryan Drewery if (argc > 2 && strcmp(argv[2], "-f") == 0) { 950*5212e8baSBryan Drewery force = true; 951*5212e8baSBryan Drewery pkgarg = argv[3]; 952*5212e8baSBryan Drewery } else 953*5212e8baSBryan Drewery pkgarg = argv[2]; 954*5212e8baSBryan Drewery if (pkgarg == NULL) { 955*5212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 956*5212e8baSBryan Drewery exit(EXIT_FAILURE); 957*5212e8baSBryan Drewery } 958*5212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 959*5212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 960*5212e8baSBryan Drewery exit(EXIT_FAILURE); 961*5212e8baSBryan Drewery } 962*5212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 963b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 964b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 965b70213b5SBaptiste Daroussin } 966ecfed9f2SMatthew Seaman /* 967e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 968e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 969e18ad51cSAlexander Kabaev * tucked in there already. 970e18ad51cSAlexander Kabaev */ 9719950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 9729950eceeSBaptiste Daroussin if (!yes) { 973e18ad51cSAlexander Kabaev printf("%s", confirmation_message); 974204ea792SBaptiste Daroussin if (!isatty(fileno(stdin))) 9753a480126SBaptiste Daroussin exit(EXIT_FAILURE); 976204ea792SBaptiste Daroussin 977204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 978e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 979e18ad51cSAlexander Kabaev } 980*5212e8baSBryan Drewery if (bootstrap_pkg(force) != 0) 981a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 9829950eceeSBaptiste Daroussin config_finish(); 983c3e8a27aSBryan Drewery 984*5212e8baSBryan Drewery if (bootstrap_only) 985c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 986*5212e8baSBryan Drewery } else if (bootstrap_only) { 987*5212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 988c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 989c3e8a27aSBryan Drewery } 9903aa4b42aSBaptiste Daroussin 9913aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 9923aa4b42aSBaptiste Daroussin 993a6454741SBaptiste Daroussin /* NOT REACHED */ 9943b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 9953aa4b42aSBaptiste Daroussin } 996