13aa4b42aSBaptiste Daroussin /*- 29950eceeSBaptiste Daroussin * Copyright (c) 2012-2013 Baptiste Daroussin <bapt@FreeBSD.org> 3*f12db248SBryan 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> 32*f12db248SBryan Drewery #include <sys/queue.h> 33*f12db248SBryan Drewery #include <sys/types.h> 34*f12db248SBryan Drewery #include <sys/sbuf.h> 353b05c2a8SBaptiste Daroussin #include <sys/wait.h> 363aa4b42aSBaptiste Daroussin 37*f12db248SBryan Drewery #define _WITH_GETLINE 383aa4b42aSBaptiste Daroussin #include <archive.h> 393aa4b42aSBaptiste Daroussin #include <archive_entry.h> 40*f12db248SBryan 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> 52*f12db248SBryan Drewery #include <yaml.h> 53*f12db248SBryan Drewery 54*f12db248SBryan Drewery #include <openssl/err.h> 55*f12db248SBryan Drewery #include <openssl/ssl.h> 563aa4b42aSBaptiste Daroussin 5729aaa961SBaptiste Daroussin #include "dns_utils.h" 589950eceeSBaptiste Daroussin #include "config.h" 593aa4b42aSBaptiste Daroussin 60*f12db248SBryan Drewery struct sig_cert { 61*f12db248SBryan Drewery unsigned char *sig; 62*f12db248SBryan Drewery int siglen; 63*f12db248SBryan Drewery unsigned char *cert; 64*f12db248SBryan Drewery int certlen; 65*f12db248SBryan Drewery bool trusted; 66*f12db248SBryan Drewery }; 67*f12db248SBryan Drewery 68*f12db248SBryan Drewery typedef enum { 69*f12db248SBryan Drewery HASH_UNKNOWN, 70*f12db248SBryan Drewery HASH_SHA256, 71*f12db248SBryan Drewery } hash_t; 72*f12db248SBryan Drewery 73*f12db248SBryan Drewery struct fingerprint { 74*f12db248SBryan Drewery hash_t type; 75*f12db248SBryan Drewery char hash[BUFSIZ]; 76*f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 77*f12db248SBryan Drewery }; 78*f12db248SBryan Drewery 79*f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 80*f12db248SBryan Drewery 813aa4b42aSBaptiste Daroussin static int 823aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 833aa4b42aSBaptiste Daroussin { 843aa4b42aSBaptiste Daroussin struct archive *a; 853aa4b42aSBaptiste Daroussin struct archive_entry *ae; 863aa4b42aSBaptiste Daroussin char *end; 873aa4b42aSBaptiste Daroussin int ret, r; 883aa4b42aSBaptiste Daroussin 89a6454741SBaptiste Daroussin ret = -1; 903aa4b42aSBaptiste Daroussin a = archive_read_new(); 91a6454741SBaptiste Daroussin if (a == NULL) { 92a6454741SBaptiste Daroussin warn("archive_read_new"); 93a6454741SBaptiste Daroussin return (ret); 94a6454741SBaptiste Daroussin } 95ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 963aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 973aa4b42aSBaptiste Daroussin 98a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 99a6454741SBaptiste Daroussin warn("lseek"); 100a6454741SBaptiste Daroussin goto cleanup; 101a6454741SBaptiste Daroussin } 1023aa4b42aSBaptiste Daroussin 1033aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 104a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1053aa4b42aSBaptiste Daroussin goto cleanup; 1063aa4b42aSBaptiste Daroussin } 1073aa4b42aSBaptiste Daroussin 1083aa4b42aSBaptiste Daroussin ae = NULL; 1093aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1103aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1113aa4b42aSBaptiste Daroussin if (end == NULL) 1123aa4b42aSBaptiste Daroussin continue; 1133aa4b42aSBaptiste Daroussin 1143aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1153aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1163aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1173aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1183aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 119a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1203aa4b42aSBaptiste Daroussin break; 1213aa4b42aSBaptiste Daroussin } 1223aa4b42aSBaptiste Daroussin } 1233aa4b42aSBaptiste Daroussin 124a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 125a6454741SBaptiste Daroussin ret = 0; 126a6454741SBaptiste Daroussin else 1273aa4b42aSBaptiste Daroussin warnx("fail to extract pkg-static"); 1283aa4b42aSBaptiste Daroussin 1293aa4b42aSBaptiste Daroussin cleanup: 130ff75c36aSBaptiste Daroussin archive_read_free(a); 1313b05c2a8SBaptiste Daroussin return (ret); 1323aa4b42aSBaptiste Daroussin 1333aa4b42aSBaptiste Daroussin } 1343aa4b42aSBaptiste Daroussin 1353aa4b42aSBaptiste Daroussin static int 1363aa4b42aSBaptiste Daroussin install_pkg_static(char *path, char *pkgpath) 1373aa4b42aSBaptiste Daroussin { 1383aa4b42aSBaptiste Daroussin int pstat; 1393aa4b42aSBaptiste Daroussin pid_t pid; 1403aa4b42aSBaptiste Daroussin 1413aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1423aa4b42aSBaptiste Daroussin case -1: 1433aa4b42aSBaptiste Daroussin return (-1); 1443aa4b42aSBaptiste Daroussin case 0: 145a6454741SBaptiste Daroussin execl(path, "pkg-static", "add", pkgpath, (char *)NULL); 1463b05c2a8SBaptiste Daroussin _exit(1); 1473aa4b42aSBaptiste Daroussin default: 1483aa4b42aSBaptiste Daroussin break; 1493aa4b42aSBaptiste Daroussin } 1503aa4b42aSBaptiste Daroussin 151a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1523aa4b42aSBaptiste Daroussin if (errno != EINTR) 1533aa4b42aSBaptiste Daroussin return (-1); 1543aa4b42aSBaptiste Daroussin 155a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1563aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 157a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 158a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 159a6454741SBaptiste Daroussin return (pstat); 1603aa4b42aSBaptiste Daroussin } 1613aa4b42aSBaptiste Daroussin 1623aa4b42aSBaptiste Daroussin static int 163*f12db248SBryan Drewery fetch_to_fd(const char *url, char *path) 1643aa4b42aSBaptiste Daroussin { 16529aaa961SBaptiste Daroussin struct url *u; 16629aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 167a6454741SBaptiste Daroussin struct url_stat st; 168*f12db248SBryan Drewery FILE *remote; 169*f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 170*f12db248SBryan Drewery int fd; 171*f12db248SBryan Drewery int retry, max_retry; 1723aa4b42aSBaptiste Daroussin off_t done, r; 173*f12db248SBryan Drewery time_t now, last; 174*f12db248SBryan Drewery char buf[10240]; 175*f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 176*f12db248SBryan Drewery static const char *mirror_type = NULL; 1773aa4b42aSBaptiste Daroussin 1783aa4b42aSBaptiste Daroussin done = 0; 179a6454741SBaptiste Daroussin last = 0; 18029aaa961SBaptiste Daroussin max_retry = 3; 18129aaa961SBaptiste Daroussin current = mirrors = NULL; 182*f12db248SBryan Drewery remote = NULL; 1833aa4b42aSBaptiste Daroussin 184*f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 185*f12db248SBryan Drewery != 0) { 1869950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 1879950eceeSBaptiste Daroussin return (-1); 1889950eceeSBaptiste Daroussin } 18962940ea9SBryan Drewery 190*f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 1913aa4b42aSBaptiste Daroussin warn("mkstemp()"); 1923b05c2a8SBaptiste Daroussin return (-1); 1933aa4b42aSBaptiste Daroussin } 1943aa4b42aSBaptiste Daroussin 19529aaa961SBaptiste Daroussin retry = max_retry; 19629aaa961SBaptiste Daroussin 19729aaa961SBaptiste Daroussin u = fetchParseURL(url); 19829aaa961SBaptiste Daroussin while (remote == NULL) { 19929aaa961SBaptiste Daroussin if (retry == max_retry) { 2009950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2019950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 20229aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 20329aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 20429aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 20529aaa961SBaptiste Daroussin current = mirrors; 20629aaa961SBaptiste Daroussin } 20729aaa961SBaptiste Daroussin } 20829aaa961SBaptiste Daroussin 20935e07a7aSBaptiste Daroussin if (mirrors != NULL) { 21029aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 21135e07a7aSBaptiste Daroussin u->port = current->port; 21235e07a7aSBaptiste Daroussin } 21329aaa961SBaptiste Daroussin 21429aaa961SBaptiste Daroussin remote = fetchXGet(u, &st, ""); 21529aaa961SBaptiste Daroussin if (remote == NULL) { 21629aaa961SBaptiste Daroussin --retry; 21729aaa961SBaptiste Daroussin if (retry <= 0) 21829aaa961SBaptiste Daroussin goto fetchfail; 21929aaa961SBaptiste Daroussin if (mirrors == NULL) { 2203aa4b42aSBaptiste Daroussin sleep(1); 22129aaa961SBaptiste Daroussin } else { 22229aaa961SBaptiste Daroussin current = current->next; 22329aaa961SBaptiste Daroussin if (current == NULL) 22429aaa961SBaptiste Daroussin current = mirrors; 22529aaa961SBaptiste Daroussin } 22629aaa961SBaptiste Daroussin } 22729aaa961SBaptiste Daroussin } 228a6454741SBaptiste Daroussin 229a6454741SBaptiste Daroussin if (remote == NULL) 230a6454741SBaptiste Daroussin goto fetchfail; 2313aa4b42aSBaptiste Daroussin 2323aa4b42aSBaptiste Daroussin while (done < st.size) { 2333aa4b42aSBaptiste Daroussin if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) 2343aa4b42aSBaptiste Daroussin break; 2353aa4b42aSBaptiste Daroussin 2363aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2373aa4b42aSBaptiste Daroussin warn("write()"); 238*f12db248SBryan Drewery goto fetchfail; 2393aa4b42aSBaptiste Daroussin } 2403aa4b42aSBaptiste Daroussin 2413aa4b42aSBaptiste Daroussin done += r; 2423aa4b42aSBaptiste Daroussin now = time(NULL); 243a6454741SBaptiste Daroussin if (now > last || done == st.size) 2443aa4b42aSBaptiste Daroussin last = now; 2453aa4b42aSBaptiste Daroussin } 2463aa4b42aSBaptiste Daroussin 247a6454741SBaptiste Daroussin if (ferror(remote)) 248a6454741SBaptiste Daroussin goto fetchfail; 2493aa4b42aSBaptiste Daroussin 250*f12db248SBryan Drewery goto cleanup; 251*f12db248SBryan Drewery 252*f12db248SBryan Drewery fetchfail: 253*f12db248SBryan Drewery if (fd != -1) { 254*f12db248SBryan Drewery close(fd); 255*f12db248SBryan Drewery fd = -1; 256*f12db248SBryan Drewery unlink(path); 257*f12db248SBryan Drewery } 258*f12db248SBryan Drewery 259*f12db248SBryan Drewery cleanup: 260*f12db248SBryan Drewery if (remote != NULL) 261*f12db248SBryan Drewery fclose(remote); 262*f12db248SBryan Drewery 263*f12db248SBryan Drewery return fd; 264*f12db248SBryan Drewery } 265*f12db248SBryan Drewery 266*f12db248SBryan Drewery static struct fingerprint * 267*f12db248SBryan Drewery parse_fingerprint(yaml_document_t *doc, yaml_node_t *node) 268*f12db248SBryan Drewery { 269*f12db248SBryan Drewery yaml_node_pair_t *pair; 270*f12db248SBryan Drewery yaml_char_t *function, *fp; 271*f12db248SBryan Drewery struct fingerprint *f; 272*f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 273*f12db248SBryan Drewery 274*f12db248SBryan Drewery function = fp = NULL; 275*f12db248SBryan Drewery 276*f12db248SBryan Drewery pair = node->data.mapping.pairs.start; 277*f12db248SBryan Drewery while (pair < node->data.mapping.pairs.top) { 278*f12db248SBryan Drewery yaml_node_t *key = yaml_document_get_node(doc, pair->key); 279*f12db248SBryan Drewery yaml_node_t *val = yaml_document_get_node(doc, pair->value); 280*f12db248SBryan Drewery 281*f12db248SBryan Drewery if (key->data.scalar.length <= 0) { 282*f12db248SBryan Drewery ++pair; 283*f12db248SBryan Drewery continue; 284*f12db248SBryan Drewery } 285*f12db248SBryan Drewery 286*f12db248SBryan Drewery if (val->type != YAML_SCALAR_NODE) { 287*f12db248SBryan Drewery ++pair; 288*f12db248SBryan Drewery continue; 289*f12db248SBryan Drewery } 290*f12db248SBryan Drewery 291*f12db248SBryan Drewery if (strcasecmp(key->data.scalar.value, "function") == 0) 292*f12db248SBryan Drewery function = val->data.scalar.value; 293*f12db248SBryan Drewery else if (strcasecmp(key->data.scalar.value, "fingerprint") 294*f12db248SBryan Drewery == 0) 295*f12db248SBryan Drewery fp = val->data.scalar.value; 296*f12db248SBryan Drewery 297*f12db248SBryan Drewery ++pair; 298*f12db248SBryan Drewery continue; 299*f12db248SBryan Drewery } 300*f12db248SBryan Drewery 301*f12db248SBryan Drewery if (fp == NULL || function == NULL) 302*f12db248SBryan Drewery return (NULL); 303*f12db248SBryan Drewery 304*f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 305*f12db248SBryan Drewery fct = HASH_SHA256; 306*f12db248SBryan Drewery 307*f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 308*f12db248SBryan Drewery fprintf(stderr, "Unsupported hashing function: %s\n", function); 309*f12db248SBryan Drewery return (NULL); 310*f12db248SBryan Drewery } 311*f12db248SBryan Drewery 312*f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 313*f12db248SBryan Drewery f->type = fct; 314*f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 315*f12db248SBryan Drewery 316*f12db248SBryan Drewery return (f); 317*f12db248SBryan Drewery } 318*f12db248SBryan Drewery 319*f12db248SBryan Drewery static struct fingerprint * 320*f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 321*f12db248SBryan Drewery { 322*f12db248SBryan Drewery yaml_parser_t parser; 323*f12db248SBryan Drewery yaml_document_t doc; 324*f12db248SBryan Drewery yaml_node_t *node; 325*f12db248SBryan Drewery FILE *fp; 326*f12db248SBryan Drewery struct fingerprint *f; 327*f12db248SBryan Drewery char path[MAXPATHLEN]; 328*f12db248SBryan Drewery 329*f12db248SBryan Drewery f = NULL; 330*f12db248SBryan Drewery 331*f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 332*f12db248SBryan Drewery 333*f12db248SBryan Drewery if ((fp = fopen(path, "r")) == NULL) 334*f12db248SBryan Drewery return (NULL); 335*f12db248SBryan Drewery 336*f12db248SBryan Drewery yaml_parser_initialize(&parser); 337*f12db248SBryan Drewery yaml_parser_set_input_file(&parser, fp); 338*f12db248SBryan Drewery yaml_parser_load(&parser, &doc); 339*f12db248SBryan Drewery 340*f12db248SBryan Drewery node = yaml_document_get_root_node(&doc); 341*f12db248SBryan Drewery if (node == NULL || node->type != YAML_MAPPING_NODE) 342*f12db248SBryan Drewery goto out; 343*f12db248SBryan Drewery 344*f12db248SBryan Drewery f = parse_fingerprint(&doc, node); 345*f12db248SBryan Drewery 346*f12db248SBryan Drewery out: 347*f12db248SBryan Drewery yaml_document_delete(&doc); 348*f12db248SBryan Drewery yaml_parser_delete(&parser); 349*f12db248SBryan Drewery fclose(fp); 350*f12db248SBryan Drewery 351*f12db248SBryan Drewery return (f); 352*f12db248SBryan Drewery } 353*f12db248SBryan Drewery 354*f12db248SBryan Drewery static struct fingerprint_list * 355*f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 356*f12db248SBryan Drewery { 357*f12db248SBryan Drewery DIR *d; 358*f12db248SBryan Drewery struct dirent *ent; 359*f12db248SBryan Drewery struct fingerprint *finger; 360*f12db248SBryan Drewery struct fingerprint_list *fingerprints; 361*f12db248SBryan Drewery 362*f12db248SBryan Drewery *count = 0; 363*f12db248SBryan Drewery 364*f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 365*f12db248SBryan Drewery if (fingerprints == NULL) 366*f12db248SBryan Drewery return (NULL); 367*f12db248SBryan Drewery STAILQ_INIT(fingerprints); 368*f12db248SBryan Drewery 369*f12db248SBryan Drewery if ((d = opendir(path)) == NULL) 370*f12db248SBryan Drewery return (NULL); 371*f12db248SBryan Drewery 372*f12db248SBryan Drewery while ((ent = readdir(d))) { 373*f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 374*f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 375*f12db248SBryan Drewery continue; 376*f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 377*f12db248SBryan Drewery if (finger != NULL) { 378*f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 379*f12db248SBryan Drewery ++(*count); 380*f12db248SBryan Drewery } 381*f12db248SBryan Drewery } 382*f12db248SBryan Drewery 383*f12db248SBryan Drewery closedir(d); 384*f12db248SBryan Drewery 385*f12db248SBryan Drewery return (fingerprints); 386*f12db248SBryan Drewery } 387*f12db248SBryan Drewery 388*f12db248SBryan Drewery static void 389*f12db248SBryan Drewery sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 390*f12db248SBryan Drewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 391*f12db248SBryan Drewery { 392*f12db248SBryan Drewery int i; 393*f12db248SBryan Drewery 394*f12db248SBryan Drewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 395*f12db248SBryan Drewery sprintf(out + (i * 2), "%02x", hash[i]); 396*f12db248SBryan Drewery 397*f12db248SBryan Drewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 398*f12db248SBryan Drewery } 399*f12db248SBryan Drewery 400*f12db248SBryan Drewery static void 401*f12db248SBryan Drewery sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 402*f12db248SBryan Drewery { 403*f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 404*f12db248SBryan Drewery SHA256_CTX sha256; 405*f12db248SBryan Drewery 406*f12db248SBryan Drewery out[0] = '\0'; 407*f12db248SBryan Drewery 408*f12db248SBryan Drewery SHA256_Init(&sha256); 409*f12db248SBryan Drewery SHA256_Update(&sha256, buf, len); 410*f12db248SBryan Drewery SHA256_Final(hash, &sha256); 411*f12db248SBryan Drewery sha256_hash(hash, out); 412*f12db248SBryan Drewery } 413*f12db248SBryan Drewery 414*f12db248SBryan Drewery static int 415*f12db248SBryan Drewery sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 416*f12db248SBryan Drewery { 417*f12db248SBryan Drewery int my_fd; 418*f12db248SBryan Drewery FILE *fp; 419*f12db248SBryan Drewery char buffer[BUFSIZ]; 420*f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 421*f12db248SBryan Drewery size_t r; 422*f12db248SBryan Drewery int ret; 423*f12db248SBryan Drewery SHA256_CTX sha256; 424*f12db248SBryan Drewery 425*f12db248SBryan Drewery my_fd = -1; 426*f12db248SBryan Drewery fp = NULL; 427*f12db248SBryan Drewery r = 0; 428*f12db248SBryan Drewery ret = 1; 429*f12db248SBryan Drewery 430*f12db248SBryan Drewery out[0] = '\0'; 431*f12db248SBryan Drewery 432*f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 433*f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 434*f12db248SBryan Drewery warnx("dup"); 435*f12db248SBryan Drewery goto cleanup; 436*f12db248SBryan Drewery } 437*f12db248SBryan Drewery 438*f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 439*f12db248SBryan Drewery warnx("fdopen"); 440*f12db248SBryan Drewery goto cleanup; 441*f12db248SBryan Drewery } 442*f12db248SBryan Drewery 443*f12db248SBryan Drewery SHA256_Init(&sha256); 444*f12db248SBryan Drewery 445*f12db248SBryan Drewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 446*f12db248SBryan Drewery SHA256_Update(&sha256, buffer, r); 447*f12db248SBryan Drewery 448*f12db248SBryan Drewery if (ferror(fp) != 0) { 449*f12db248SBryan Drewery warnx("fread"); 450*f12db248SBryan Drewery goto cleanup; 451*f12db248SBryan Drewery } 452*f12db248SBryan Drewery 453*f12db248SBryan Drewery SHA256_Final(hash, &sha256); 454*f12db248SBryan Drewery sha256_hash(hash, out); 455*f12db248SBryan Drewery ret = 0; 456*f12db248SBryan Drewery 457*f12db248SBryan Drewery cleanup: 458*f12db248SBryan Drewery if (fp != NULL) 459*f12db248SBryan Drewery fclose(fp); 460*f12db248SBryan Drewery else if (my_fd != -1) 461*f12db248SBryan Drewery close(my_fd); 462*f12db248SBryan Drewery (void)lseek(fd, 0, SEEK_SET); 463*f12db248SBryan Drewery 464*f12db248SBryan Drewery return (ret); 465*f12db248SBryan Drewery } 466*f12db248SBryan Drewery 467*f12db248SBryan Drewery static EVP_PKEY * 468*f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 469*f12db248SBryan Drewery { 470*f12db248SBryan Drewery EVP_PKEY *pkey; 471*f12db248SBryan Drewery BIO *bp; 472*f12db248SBryan Drewery char errbuf[1024]; 473*f12db248SBryan Drewery 474*f12db248SBryan Drewery bp = BIO_new_mem_buf((void *)cert, certlen); 475*f12db248SBryan Drewery 476*f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 477*f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 478*f12db248SBryan Drewery 479*f12db248SBryan Drewery BIO_free(bp); 480*f12db248SBryan Drewery 481*f12db248SBryan Drewery return (pkey); 482*f12db248SBryan Drewery } 483*f12db248SBryan Drewery 484*f12db248SBryan Drewery static bool 485*f12db248SBryan Drewery rsa_verify_cert(int fd, const unsigned char *key, int keylen, 486*f12db248SBryan Drewery unsigned char *sig, int siglen) 487*f12db248SBryan Drewery { 488*f12db248SBryan Drewery EVP_MD_CTX *mdctx; 489*f12db248SBryan Drewery EVP_PKEY *pkey; 490*f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 491*f12db248SBryan Drewery char errbuf[1024]; 492*f12db248SBryan Drewery bool ret; 493*f12db248SBryan Drewery 494*f12db248SBryan Drewery pkey = NULL; 495*f12db248SBryan Drewery mdctx = NULL; 496*f12db248SBryan Drewery ret = false; 497*f12db248SBryan Drewery 498*f12db248SBryan Drewery /* Compute SHA256 of the package. */ 499*f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 500*f12db248SBryan Drewery warn("lseek"); 501*f12db248SBryan Drewery goto cleanup; 502*f12db248SBryan Drewery } 503*f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 504*f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 505*f12db248SBryan Drewery goto cleanup; 506*f12db248SBryan Drewery } 507*f12db248SBryan Drewery 508*f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 509*f12db248SBryan Drewery warnx("Error reading public key"); 510*f12db248SBryan Drewery goto cleanup; 511*f12db248SBryan Drewery } 512*f12db248SBryan Drewery 513*f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 514*f12db248SBryan Drewery printf("Verifying signature... "); 515*f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 516*f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 517*f12db248SBryan Drewery goto error; 518*f12db248SBryan Drewery } 519*f12db248SBryan Drewery 520*f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 521*f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 522*f12db248SBryan Drewery goto error; 523*f12db248SBryan Drewery } 524*f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 525*f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 526*f12db248SBryan Drewery goto error; 527*f12db248SBryan Drewery } 528*f12db248SBryan Drewery 529*f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 530*f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 531*f12db248SBryan Drewery goto error; 532*f12db248SBryan Drewery } 533*f12db248SBryan Drewery 534*f12db248SBryan Drewery ret = true; 535*f12db248SBryan Drewery printf("done\n"); 536*f12db248SBryan Drewery goto cleanup; 537*f12db248SBryan Drewery 538*f12db248SBryan Drewery error: 539*f12db248SBryan Drewery printf("failed\n"); 540*f12db248SBryan Drewery 541*f12db248SBryan Drewery cleanup: 542*f12db248SBryan Drewery if (pkey) 543*f12db248SBryan Drewery EVP_PKEY_free(pkey); 544*f12db248SBryan Drewery if (mdctx) 545*f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 546*f12db248SBryan Drewery ERR_free_strings(); 547*f12db248SBryan Drewery 548*f12db248SBryan Drewery return (ret); 549*f12db248SBryan Drewery } 550*f12db248SBryan Drewery 551*f12db248SBryan Drewery static struct sig_cert * 552*f12db248SBryan Drewery parse_cert(int fd) { 553*f12db248SBryan Drewery int my_fd; 554*f12db248SBryan Drewery struct sig_cert *sc; 555*f12db248SBryan Drewery FILE *fp; 556*f12db248SBryan Drewery struct sbuf *buf, *sig, *cert; 557*f12db248SBryan Drewery char *line; 558*f12db248SBryan Drewery size_t linecap; 559*f12db248SBryan Drewery ssize_t linelen; 560*f12db248SBryan Drewery 561*f12db248SBryan Drewery my_fd = -1; 562*f12db248SBryan Drewery sc = NULL; 563*f12db248SBryan Drewery line = NULL; 564*f12db248SBryan Drewery linecap = 0; 565*f12db248SBryan Drewery 566*f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 567*f12db248SBryan Drewery warn("lseek"); 568*f12db248SBryan Drewery return (NULL); 569*f12db248SBryan Drewery } 570*f12db248SBryan Drewery 571*f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 572*f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 573*f12db248SBryan Drewery warnx("dup"); 574*f12db248SBryan Drewery return (NULL); 575*f12db248SBryan Drewery } 576*f12db248SBryan Drewery 577*f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 578*f12db248SBryan Drewery warn("fdopen"); 579*f12db248SBryan Drewery close(my_fd); 580*f12db248SBryan Drewery return (NULL); 581*f12db248SBryan Drewery } 582*f12db248SBryan Drewery 583*f12db248SBryan Drewery sig = sbuf_new_auto(); 584*f12db248SBryan Drewery cert = sbuf_new_auto(); 585*f12db248SBryan Drewery 586*f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 587*f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 588*f12db248SBryan Drewery buf = sig; 589*f12db248SBryan Drewery continue; 590*f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 591*f12db248SBryan Drewery buf = cert; 592*f12db248SBryan Drewery continue; 593*f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 594*f12db248SBryan Drewery break; 595*f12db248SBryan Drewery } 596*f12db248SBryan Drewery if (buf != NULL) 597*f12db248SBryan Drewery sbuf_bcat(buf, line, linelen); 598*f12db248SBryan Drewery } 599*f12db248SBryan Drewery 600*f12db248SBryan Drewery fclose(fp); 601*f12db248SBryan Drewery 602*f12db248SBryan Drewery /* Trim out unrelated trailing newline */ 603*f12db248SBryan Drewery sbuf_setpos(sig, sbuf_len(sig) - 1); 604*f12db248SBryan Drewery 605*f12db248SBryan Drewery sbuf_finish(sig); 606*f12db248SBryan Drewery sbuf_finish(cert); 607*f12db248SBryan Drewery 608*f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 609*f12db248SBryan Drewery sc->siglen = sbuf_len(sig); 610*f12db248SBryan Drewery sc->sig = calloc(1, sc->siglen); 611*f12db248SBryan Drewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 612*f12db248SBryan Drewery 613*f12db248SBryan Drewery sc->certlen = sbuf_len(cert); 614*f12db248SBryan Drewery sc->cert = strdup(sbuf_data(cert)); 615*f12db248SBryan Drewery 616*f12db248SBryan Drewery sbuf_delete(sig); 617*f12db248SBryan Drewery sbuf_delete(cert); 618*f12db248SBryan Drewery 619*f12db248SBryan Drewery return (sc); 620*f12db248SBryan Drewery } 621*f12db248SBryan Drewery 622*f12db248SBryan Drewery static bool 623*f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 624*f12db248SBryan Drewery { 625*f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 626*f12db248SBryan Drewery struct fingerprint *fingerprint; 627*f12db248SBryan Drewery struct sig_cert *sc; 628*f12db248SBryan Drewery bool ret; 629*f12db248SBryan Drewery int trusted_count, revoked_count; 630*f12db248SBryan Drewery const char *fingerprints; 631*f12db248SBryan Drewery char path[MAXPATHLEN]; 632*f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 633*f12db248SBryan Drewery 634*f12db248SBryan Drewery trusted = revoked = NULL; 635*f12db248SBryan Drewery ret = false; 636*f12db248SBryan Drewery 637*f12db248SBryan Drewery /* Read and parse fingerprints. */ 638*f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 639*f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 640*f12db248SBryan Drewery goto cleanup; 641*f12db248SBryan Drewery } 642*f12db248SBryan Drewery 643*f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 644*f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 645*f12db248SBryan Drewery warnx("Error loading trusted certificates"); 646*f12db248SBryan Drewery goto cleanup; 647*f12db248SBryan Drewery } 648*f12db248SBryan Drewery 649*f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 650*f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 651*f12db248SBryan Drewery goto cleanup; 652*f12db248SBryan Drewery } 653*f12db248SBryan Drewery 654*f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 655*f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 656*f12db248SBryan Drewery warnx("Error loading revoked certificates"); 657*f12db248SBryan Drewery goto cleanup; 658*f12db248SBryan Drewery } 659*f12db248SBryan Drewery 660*f12db248SBryan Drewery /* Read certificate and signature in. */ 661*f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 662*f12db248SBryan Drewery warnx("Error parsing certificate"); 663*f12db248SBryan Drewery goto cleanup; 664*f12db248SBryan Drewery } 665*f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 666*f12db248SBryan Drewery sc->trusted = false; 667*f12db248SBryan Drewery 668*f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 669*f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 670*f12db248SBryan Drewery 671*f12db248SBryan Drewery /* Check if this hash is revoked */ 672*f12db248SBryan Drewery if (revoked != NULL) { 673*f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 674*f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 675*f12db248SBryan Drewery fprintf(stderr, "The certificate has been " 676*f12db248SBryan Drewery "revoked\n"); 677*f12db248SBryan Drewery goto cleanup; 678*f12db248SBryan Drewery } 679*f12db248SBryan Drewery } 680*f12db248SBryan Drewery } 681*f12db248SBryan Drewery 682*f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 683*f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 684*f12db248SBryan Drewery sc->trusted = true; 685*f12db248SBryan Drewery break; 686*f12db248SBryan Drewery } 687*f12db248SBryan Drewery } 688*f12db248SBryan Drewery 689*f12db248SBryan Drewery if (sc->trusted == false) { 690*f12db248SBryan Drewery fprintf(stderr, "No trusted certificate found matching " 691*f12db248SBryan Drewery "package's certificate\n"); 692*f12db248SBryan Drewery goto cleanup; 693*f12db248SBryan Drewery } 694*f12db248SBryan Drewery 695*f12db248SBryan Drewery /* Verify the signature. */ 696*f12db248SBryan Drewery if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig, 697*f12db248SBryan Drewery sc->siglen) == false) { 698*f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 699*f12db248SBryan Drewery goto cleanup; 700*f12db248SBryan Drewery } 701*f12db248SBryan Drewery 702*f12db248SBryan Drewery ret = true; 703*f12db248SBryan Drewery 704*f12db248SBryan Drewery cleanup: 705*f12db248SBryan Drewery if (trusted) { 706*f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) 707*f12db248SBryan Drewery free(fingerprint); 708*f12db248SBryan Drewery free(trusted); 709*f12db248SBryan Drewery } 710*f12db248SBryan Drewery if (revoked) { 711*f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) 712*f12db248SBryan Drewery free(fingerprint); 713*f12db248SBryan Drewery free(revoked); 714*f12db248SBryan Drewery } 715*f12db248SBryan Drewery if (sc) { 716*f12db248SBryan Drewery if (sc->cert) 717*f12db248SBryan Drewery free(sc->cert); 718*f12db248SBryan Drewery if (sc->sig) 719*f12db248SBryan Drewery free(sc->sig); 720*f12db248SBryan Drewery free(sc); 721*f12db248SBryan Drewery } 722*f12db248SBryan Drewery 723*f12db248SBryan Drewery return (ret); 724*f12db248SBryan Drewery } 725*f12db248SBryan Drewery 726*f12db248SBryan Drewery static int 727*f12db248SBryan Drewery bootstrap_pkg(void) 728*f12db248SBryan Drewery { 729*f12db248SBryan Drewery FILE *config; 730*f12db248SBryan Drewery int fd_pkg, fd_sig; 731*f12db248SBryan Drewery int ret; 732*f12db248SBryan Drewery char *site; 733*f12db248SBryan Drewery char url[MAXPATHLEN]; 734*f12db248SBryan Drewery char conf[MAXPATHLEN]; 735*f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 736*f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 737*f12db248SBryan Drewery const char *packagesite; 738*f12db248SBryan Drewery const char *signature_type; 739*f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 740*f12db248SBryan Drewery 741*f12db248SBryan Drewery fd_sig = -1; 742*f12db248SBryan Drewery ret = -1; 743*f12db248SBryan Drewery config = NULL; 744*f12db248SBryan Drewery 745*f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 746*f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 747*f12db248SBryan Drewery return (-1); 748*f12db248SBryan Drewery } 749*f12db248SBryan Drewery 750*f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 751*f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 752*f12db248SBryan Drewery return (-1); 753*f12db248SBryan Drewery } 754*f12db248SBryan Drewery 755*f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 756*f12db248SBryan Drewery 757*f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 758*f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 759*f12db248SBryan Drewery no A record. */ 760*f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 761*f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 762*f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 763*f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 764*f12db248SBryan Drewery 765*f12db248SBryan Drewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 766*f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 767*f12db248SBryan Drewery 768*f12db248SBryan Drewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 769*f12db248SBryan Drewery goto fetchfail; 770*f12db248SBryan Drewery 771*f12db248SBryan Drewery if (signature_type != NULL && 772*f12db248SBryan Drewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 773*f12db248SBryan Drewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 774*f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 775*f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 776*f12db248SBryan Drewery packagesite); 777*f12db248SBryan Drewery 778*f12db248SBryan Drewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 779*f12db248SBryan Drewery fprintf(stderr, "Signature for pkg not available.\n"); 780*f12db248SBryan Drewery goto fetchfail; 781*f12db248SBryan Drewery } 782*f12db248SBryan Drewery 783*f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 784*f12db248SBryan Drewery goto cleanup; 785*f12db248SBryan Drewery } 786*f12db248SBryan Drewery 787*f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 7883aa4b42aSBaptiste Daroussin ret = install_pkg_static(pkgstatic, tmppkg); 7893aa4b42aSBaptiste Daroussin 7902fe3761eSBaptiste Daroussin snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf", 7912fe3761eSBaptiste Daroussin getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 7922fe3761eSBaptiste Daroussin 7932fe3761eSBaptiste Daroussin if (access(conf, R_OK) == -1) { 7942fe3761eSBaptiste Daroussin site = strrchr(url, '/'); 7952fe3761eSBaptiste Daroussin if (site == NULL) 7962fe3761eSBaptiste Daroussin goto cleanup; 7972fe3761eSBaptiste Daroussin site[0] = '\0'; 7982fe3761eSBaptiste Daroussin site = strrchr(url, '/'); 7992fe3761eSBaptiste Daroussin if (site == NULL) 8002fe3761eSBaptiste Daroussin goto cleanup; 8012fe3761eSBaptiste Daroussin site[0] = '\0'; 8022fe3761eSBaptiste Daroussin 8032fe3761eSBaptiste Daroussin config = fopen(conf, "w+"); 8042fe3761eSBaptiste Daroussin if (config == NULL) 8052fe3761eSBaptiste Daroussin goto cleanup; 806514ead92SBaptiste Daroussin fprintf(config, "packagesite: %s\n", url); 8072fe3761eSBaptiste Daroussin fclose(config); 8082fe3761eSBaptiste Daroussin } 8092fe3761eSBaptiste Daroussin 810a6454741SBaptiste Daroussin goto cleanup; 811a6454741SBaptiste Daroussin 812a6454741SBaptiste Daroussin fetchfail: 813a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 8144ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 8154ff9a7efSBryan Drewery "your system.\n"); 8164ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 8174ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 818a6454741SBaptiste Daroussin 8193aa4b42aSBaptiste Daroussin cleanup: 820*f12db248SBryan Drewery if (fd_sig != -1) { 821*f12db248SBryan Drewery close(fd_sig); 822*f12db248SBryan Drewery unlink(tmpsig); 823*f12db248SBryan Drewery } 824*f12db248SBryan Drewery close(fd_pkg); 8253aa4b42aSBaptiste Daroussin unlink(tmppkg); 8263aa4b42aSBaptiste Daroussin 827a6454741SBaptiste Daroussin return (ret); 8283aa4b42aSBaptiste Daroussin } 8293aa4b42aSBaptiste Daroussin 830e18ad51cSAlexander Kabaev static const char confirmation_message[] = 831e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 832e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 833e18ad51cSAlexander Kabaev 834e18ad51cSAlexander Kabaev static int 835e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 836e18ad51cSAlexander Kabaev { 837e18ad51cSAlexander Kabaev int ret, c; 838e18ad51cSAlexander Kabaev 839e18ad51cSAlexander Kabaev c = getchar(); 840e18ad51cSAlexander Kabaev 841e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 842e18ad51cSAlexander Kabaev ret = 1; 843e18ad51cSAlexander Kabaev else 844e18ad51cSAlexander Kabaev ret = 0; 845e18ad51cSAlexander Kabaev 846e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 847e18ad51cSAlexander Kabaev c = getchar(); 848e18ad51cSAlexander Kabaev 849e18ad51cSAlexander Kabaev return (ret); 850e18ad51cSAlexander Kabaev } 851e18ad51cSAlexander Kabaev 8523aa4b42aSBaptiste Daroussin int 8533aa4b42aSBaptiste Daroussin main(__unused int argc, char *argv[]) 8543aa4b42aSBaptiste Daroussin { 8553aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 856b70213b5SBaptiste Daroussin char pkgstatic[MAXPATHLEN]; 8579950eceeSBaptiste Daroussin bool yes = false; 858b70213b5SBaptiste Daroussin int fd, ret; 8593aa4b42aSBaptiste Daroussin 8603aa4b42aSBaptiste Daroussin snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 8613aa4b42aSBaptiste Daroussin getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 8623aa4b42aSBaptiste Daroussin 863e18ad51cSAlexander Kabaev if (access(pkgpath, X_OK) == -1) { 864e18ad51cSAlexander Kabaev /* 865d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 866ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 867ecfed9f2SMatthew Seaman * when that argument is given as argv[1]. 868ecfed9f2SMatthew Seaman */ 869d8f9490cSMatthew Seaman if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 870e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 871ecfed9f2SMatthew Seaman 872b70213b5SBaptiste Daroussin if (argc > 2 && strcmp(argv[1], "add") == 0 && 873b70213b5SBaptiste Daroussin access(argv[2], R_OK) == 0) { 874b70213b5SBaptiste Daroussin fd = open(argv[2], O_RDONLY); 875b70213b5SBaptiste Daroussin if (fd == -1) 876b70213b5SBaptiste Daroussin err(EXIT_FAILURE, "Unable to open %s", argv[2]); 877b70213b5SBaptiste Daroussin 878b70213b5SBaptiste Daroussin if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0) 879b70213b5SBaptiste Daroussin ret = install_pkg_static(pkgstatic, argv[2]); 880b70213b5SBaptiste Daroussin close(fd); 881b70213b5SBaptiste Daroussin if (ret != 0) 882b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 883b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 884b70213b5SBaptiste Daroussin } 885ecfed9f2SMatthew Seaman /* 886e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 887e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 888e18ad51cSAlexander Kabaev * tucked in there already. 889e18ad51cSAlexander Kabaev */ 8909950eceeSBaptiste Daroussin config_init(); 8919950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 8929950eceeSBaptiste Daroussin if (!yes) { 893e18ad51cSAlexander Kabaev printf("%s", confirmation_message); 894204ea792SBaptiste Daroussin if (!isatty(fileno(stdin))) 8953a480126SBaptiste Daroussin exit(EXIT_FAILURE); 896204ea792SBaptiste Daroussin 897204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 898e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 899e18ad51cSAlexander Kabaev } 900a6454741SBaptiste Daroussin if (bootstrap_pkg() != 0) 901a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 9029950eceeSBaptiste Daroussin config_finish(); 903e18ad51cSAlexander Kabaev } 9043aa4b42aSBaptiste Daroussin 9053aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 9063aa4b42aSBaptiste Daroussin 907a6454741SBaptiste Daroussin /* NOT REACHED */ 9083b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 9093aa4b42aSBaptiste Daroussin } 910