13aa4b42aSBaptiste Daroussin /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 40ad5dbacSBaptiste Daroussin * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org> 5f12db248SBryan Drewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 63aa4b42aSBaptiste Daroussin * All rights reserved. 73aa4b42aSBaptiste Daroussin * 83aa4b42aSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 93aa4b42aSBaptiste Daroussin * modification, are permitted provided that the following conditions 103aa4b42aSBaptiste Daroussin * are met: 113aa4b42aSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 123aa4b42aSBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 133aa4b42aSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 143aa4b42aSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 153aa4b42aSBaptiste Daroussin * documentation and/or other materials provided with the distribution. 163aa4b42aSBaptiste Daroussin * 173aa4b42aSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 183aa4b42aSBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 193aa4b42aSBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203aa4b42aSBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 213aa4b42aSBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 223aa4b42aSBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 233aa4b42aSBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243aa4b42aSBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253aa4b42aSBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 263aa4b42aSBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 273aa4b42aSBaptiste Daroussin * SUCH DAMAGE. 283aa4b42aSBaptiste Daroussin */ 293aa4b42aSBaptiste Daroussin 303aa4b42aSBaptiste Daroussin #include <sys/param.h> 31f12db248SBryan Drewery #include <sys/queue.h> 32f12db248SBryan Drewery #include <sys/types.h> 333b05c2a8SBaptiste Daroussin #include <sys/wait.h> 343aa4b42aSBaptiste Daroussin 353aa4b42aSBaptiste Daroussin #include <archive.h> 363aa4b42aSBaptiste Daroussin #include <archive_entry.h> 375862580dSKyle Evans #include <assert.h> 38f12db248SBryan Drewery #include <dirent.h> 393aa4b42aSBaptiste Daroussin #include <err.h> 403aa4b42aSBaptiste Daroussin #include <errno.h> 41b70213b5SBaptiste Daroussin #include <fcntl.h> 423b05c2a8SBaptiste Daroussin #include <fetch.h> 43ae994fdcSBaptiste Daroussin #include <getopt.h> 4456d11d4aSStefan Eßer #include <libutil.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> 508a7d859eSBaptiste Daroussin #include <ucl.h> 51f12db248SBryan Drewery 522629e90dSKyle Evans #include "pkg.h" 533aa4b42aSBaptiste Daroussin 5429aaa961SBaptiste Daroussin #include "dns_utils.h" 559950eceeSBaptiste Daroussin #include "config.h" 56b2654064SBaptiste Daroussin #include "hash.h" 573aa4b42aSBaptiste Daroussin 583d0a0ddaSKyle Evans #define PKGSIGN_MARKER "$PKGSIGN:" 593d0a0ddaSKyle Evans 605862580dSKyle Evans static const struct pkgsign_impl { 615862580dSKyle Evans const char *pi_name; 625862580dSKyle Evans const struct pkgsign_ops *pi_ops; 635862580dSKyle Evans } pkgsign_builtins[] = { 645862580dSKyle Evans { 655862580dSKyle Evans .pi_name = "rsa", 665862580dSKyle Evans .pi_ops = &pkgsign_rsa, 675862580dSKyle Evans }, 683d0a0ddaSKyle Evans { 693d0a0ddaSKyle Evans .pi_name = "ecc", 703d0a0ddaSKyle Evans .pi_ops = &pkgsign_ecc, 713d0a0ddaSKyle Evans }, 723d0a0ddaSKyle Evans { 733d0a0ddaSKyle Evans .pi_name = "ecdsa", 743d0a0ddaSKyle Evans .pi_ops = &pkgsign_ecc, 753d0a0ddaSKyle Evans }, 763d0a0ddaSKyle Evans { 773d0a0ddaSKyle Evans .pi_name = "eddsa", 783d0a0ddaSKyle Evans .pi_ops = &pkgsign_ecc, 793d0a0ddaSKyle Evans }, 805862580dSKyle Evans }; 815862580dSKyle Evans 82f12db248SBryan Drewery typedef enum { 83f12db248SBryan Drewery HASH_UNKNOWN, 84f12db248SBryan Drewery HASH_SHA256, 85f12db248SBryan Drewery } hash_t; 86f12db248SBryan Drewery 87f12db248SBryan Drewery struct fingerprint { 88f12db248SBryan Drewery hash_t type; 89516aaf7cSBryan Drewery char *name; 90f12db248SBryan Drewery char hash[BUFSIZ]; 91f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 92f12db248SBryan Drewery }; 93f12db248SBryan Drewery 940cd9513aSEd Maste static const char *bootstrap_name = "pkg.pkg"; 95a2aac2f5SBaptiste Daroussin 96f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 97f12db248SBryan Drewery 98e9ad2964SBrooks Davis static int debug; 99e9ad2964SBrooks Davis 1003aa4b42aSBaptiste Daroussin static int 1015862580dSKyle Evans pkgsign_new(const char *name, struct pkgsign_ctx **ctx) 1025862580dSKyle Evans { 1035862580dSKyle Evans const struct pkgsign_impl *impl; 1045862580dSKyle Evans const struct pkgsign_ops *ops; 1055862580dSKyle Evans struct pkgsign_ctx *nctx; 1065862580dSKyle Evans size_t ctx_size; 1075862580dSKyle Evans int ret; 1085862580dSKyle Evans 1095862580dSKyle Evans assert(*ctx == NULL); 1105862580dSKyle Evans ops = NULL; 1115862580dSKyle Evans for (size_t i = 0; i < nitems(pkgsign_builtins); i++) { 1125862580dSKyle Evans impl = &pkgsign_builtins[i]; 1135862580dSKyle Evans 1145862580dSKyle Evans if (strcmp(name, impl->pi_name) == 0) { 1155862580dSKyle Evans ops = impl->pi_ops; 1165862580dSKyle Evans break; 1175862580dSKyle Evans } 1185862580dSKyle Evans } 1195862580dSKyle Evans 1205862580dSKyle Evans if (ops == NULL) 1215862580dSKyle Evans return (ENOENT); 1225862580dSKyle Evans 1235862580dSKyle Evans ctx_size = ops->pkgsign_ctx_size; 1245862580dSKyle Evans if (ctx_size == 0) 1255862580dSKyle Evans ctx_size = sizeof(*nctx); 1265862580dSKyle Evans assert(ctx_size >= sizeof(*nctx)); 1275862580dSKyle Evans 1285862580dSKyle Evans nctx = calloc(1, ctx_size); 1295862580dSKyle Evans if (nctx == NULL) 1305862580dSKyle Evans err(EXIT_FAILURE, "calloc"); 1315862580dSKyle Evans nctx->impl = impl; 1325862580dSKyle Evans 1335862580dSKyle Evans ret = 0; 1345862580dSKyle Evans if (ops->pkgsign_new != NULL) 1355862580dSKyle Evans ret = (*ops->pkgsign_new)(name, nctx); 1365862580dSKyle Evans 1375862580dSKyle Evans if (ret != 0) { 1385862580dSKyle Evans free(nctx); 1395862580dSKyle Evans return (ret); 1405862580dSKyle Evans } 1415862580dSKyle Evans 1425862580dSKyle Evans *ctx = nctx; 1435862580dSKyle Evans return (0); 1445862580dSKyle Evans } 1455862580dSKyle Evans 1465862580dSKyle Evans static bool 1475862580dSKyle Evans pkgsign_verify_cert(const struct pkgsign_ctx *ctx, int fd, const char *sigfile, 1485862580dSKyle Evans const unsigned char *key, int keylen, unsigned char *sig, int siglen) 1495862580dSKyle Evans { 1505862580dSKyle Evans 1515862580dSKyle Evans return ((*ctx->impl->pi_ops->pkgsign_verify_cert)(ctx, fd, sigfile, 1525862580dSKyle Evans key, keylen, sig, siglen)); 1535862580dSKyle Evans } 1545862580dSKyle Evans 1552e065d74SKyle Evans static bool 1562e065d74SKyle Evans pkgsign_verify_data(const struct pkgsign_ctx *ctx, const char *data, 1572e065d74SKyle Evans size_t datasz, const char *sigfile, const unsigned char *key, int keylen, 1582e065d74SKyle Evans unsigned char *sig, int siglen) 1592e065d74SKyle Evans { 1602e065d74SKyle Evans 1612e065d74SKyle Evans return ((*ctx->impl->pi_ops->pkgsign_verify_data)(ctx, data, datasz, 1622e065d74SKyle Evans sigfile, key, keylen, sig, siglen)); 1632e065d74SKyle Evans } 1642e065d74SKyle Evans 1652e065d74SKyle Evans 1665862580dSKyle Evans static int 1673aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 1683aa4b42aSBaptiste Daroussin { 1693aa4b42aSBaptiste Daroussin struct archive *a; 1703aa4b42aSBaptiste Daroussin struct archive_entry *ae; 1713aa4b42aSBaptiste Daroussin char *end; 1723aa4b42aSBaptiste Daroussin int ret, r; 1733aa4b42aSBaptiste Daroussin 174a6454741SBaptiste Daroussin ret = -1; 1753aa4b42aSBaptiste Daroussin a = archive_read_new(); 176a6454741SBaptiste Daroussin if (a == NULL) { 177a6454741SBaptiste Daroussin warn("archive_read_new"); 178a6454741SBaptiste Daroussin return (ret); 179a6454741SBaptiste Daroussin } 180ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1813aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1823aa4b42aSBaptiste Daroussin 183a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 184a6454741SBaptiste Daroussin warn("lseek"); 185a6454741SBaptiste Daroussin goto cleanup; 186a6454741SBaptiste Daroussin } 1873aa4b42aSBaptiste Daroussin 1883aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 189a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1903aa4b42aSBaptiste Daroussin goto cleanup; 1913aa4b42aSBaptiste Daroussin } 1923aa4b42aSBaptiste Daroussin 1933aa4b42aSBaptiste Daroussin ae = NULL; 1943aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1953aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1963aa4b42aSBaptiste Daroussin if (end == NULL) 1973aa4b42aSBaptiste Daroussin continue; 1983aa4b42aSBaptiste Daroussin 1993aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 2003aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 2013aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 2023aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 2033aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 204a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 2053aa4b42aSBaptiste Daroussin break; 2063aa4b42aSBaptiste Daroussin } 2073aa4b42aSBaptiste Daroussin } 2083aa4b42aSBaptiste Daroussin 209a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 210a6454741SBaptiste Daroussin ret = 0; 211a6454741SBaptiste Daroussin else 2124622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 2134622bc4eSGavin Atkinson archive_error_string(a)); 2143aa4b42aSBaptiste Daroussin 2153aa4b42aSBaptiste Daroussin cleanup: 216ff75c36aSBaptiste Daroussin archive_read_free(a); 2173b05c2a8SBaptiste Daroussin return (ret); 2183aa4b42aSBaptiste Daroussin 2193aa4b42aSBaptiste Daroussin } 2203aa4b42aSBaptiste Daroussin 2213aa4b42aSBaptiste Daroussin static int 2225212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 2233aa4b42aSBaptiste Daroussin { 2243aa4b42aSBaptiste Daroussin int pstat; 2253aa4b42aSBaptiste Daroussin pid_t pid; 2263aa4b42aSBaptiste Daroussin 2273aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 2283aa4b42aSBaptiste Daroussin case -1: 2293aa4b42aSBaptiste Daroussin return (-1); 2303aa4b42aSBaptiste Daroussin case 0: 2315212e8baSBryan Drewery if (force) 2325212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 2335212e8baSBryan Drewery (char *)NULL); 2345212e8baSBryan Drewery else 2355212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 2365212e8baSBryan Drewery (char *)NULL); 2373b05c2a8SBaptiste Daroussin _exit(1); 2383aa4b42aSBaptiste Daroussin default: 2393aa4b42aSBaptiste Daroussin break; 2403aa4b42aSBaptiste Daroussin } 2413aa4b42aSBaptiste Daroussin 242a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 2433aa4b42aSBaptiste Daroussin if (errno != EINTR) 2443aa4b42aSBaptiste Daroussin return (-1); 2453aa4b42aSBaptiste Daroussin 246a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 2473aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 248a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 249a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 250a6454741SBaptiste Daroussin return (pstat); 2513aa4b42aSBaptiste Daroussin } 2523aa4b42aSBaptiste Daroussin 2533aa4b42aSBaptiste Daroussin static int 254dc458158SBaptiste Daroussin fetch_to_fd(struct repository *repo, const char *url, char *path, const char *fetchOpts) 2553aa4b42aSBaptiste Daroussin { 25629aaa961SBaptiste Daroussin struct url *u; 25729aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 258a6454741SBaptiste Daroussin struct url_stat st; 259f12db248SBryan Drewery FILE *remote; 260f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 261f12db248SBryan Drewery int fd; 262f12db248SBryan Drewery int retry, max_retry; 263cc36fe49SBaptiste Daroussin ssize_t r; 264f12db248SBryan Drewery char buf[10240]; 265f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 2663aa4b42aSBaptiste Daroussin 26729aaa961SBaptiste Daroussin max_retry = 3; 26829aaa961SBaptiste Daroussin current = mirrors = NULL; 269f12db248SBryan Drewery remote = NULL; 2703aa4b42aSBaptiste Daroussin 271f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2723aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2733b05c2a8SBaptiste Daroussin return (-1); 2743aa4b42aSBaptiste Daroussin } 2753aa4b42aSBaptiste Daroussin 27629aaa961SBaptiste Daroussin retry = max_retry; 27729aaa961SBaptiste Daroussin 27879fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 27979fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 28079fe80efSBaptiste Daroussin return (-1); 28179fe80efSBaptiste Daroussin } 28279fe80efSBaptiste Daroussin 28329aaa961SBaptiste Daroussin while (remote == NULL) { 28429aaa961SBaptiste Daroussin if (retry == max_retry) { 2859950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 286dc458158SBaptiste Daroussin repo->mirror_type == MIRROR_SRV) { 28729aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 28829aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 28929aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 29029aaa961SBaptiste Daroussin current = mirrors; 29129aaa961SBaptiste Daroussin } 29229aaa961SBaptiste Daroussin } 29329aaa961SBaptiste Daroussin 29435e07a7aSBaptiste Daroussin if (mirrors != NULL) { 29529aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 29635e07a7aSBaptiste Daroussin u->port = current->port; 29735e07a7aSBaptiste Daroussin } 29829aaa961SBaptiste Daroussin 299ae994fdcSBaptiste Daroussin remote = fetchXGet(u, &st, fetchOpts); 30029aaa961SBaptiste Daroussin if (remote == NULL) { 30129aaa961SBaptiste Daroussin --retry; 30229aaa961SBaptiste Daroussin if (retry <= 0) 30329aaa961SBaptiste Daroussin goto fetchfail; 30460b92ba9SJohn Hood if (mirrors != NULL) { 30529aaa961SBaptiste Daroussin current = current->next; 30629aaa961SBaptiste Daroussin if (current == NULL) 30729aaa961SBaptiste Daroussin current = mirrors; 30829aaa961SBaptiste Daroussin } 30929aaa961SBaptiste Daroussin } 31029aaa961SBaptiste Daroussin } 311a6454741SBaptiste Daroussin 312cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 3133aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 3143aa4b42aSBaptiste Daroussin warn("write()"); 315f12db248SBryan Drewery goto fetchfail; 3163aa4b42aSBaptiste Daroussin } 317cc36fe49SBaptiste Daroussin } 3183aa4b42aSBaptiste Daroussin 319cc36fe49SBaptiste Daroussin if (r != 0) { 320cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 321cc36fe49SBaptiste Daroussin goto fetchfail; 3223aa4b42aSBaptiste Daroussin } 3233aa4b42aSBaptiste Daroussin 324a6454741SBaptiste Daroussin if (ferror(remote)) 325a6454741SBaptiste Daroussin goto fetchfail; 3263aa4b42aSBaptiste Daroussin 327f12db248SBryan Drewery goto cleanup; 328f12db248SBryan Drewery 329f12db248SBryan Drewery fetchfail: 330f12db248SBryan Drewery if (fd != -1) { 331f12db248SBryan Drewery close(fd); 332f12db248SBryan Drewery fd = -1; 333f12db248SBryan Drewery unlink(path); 334f12db248SBryan Drewery } 335f12db248SBryan Drewery 336f12db248SBryan Drewery cleanup: 337f12db248SBryan Drewery if (remote != NULL) 338f12db248SBryan Drewery fclose(remote); 339f12db248SBryan Drewery 340f12db248SBryan Drewery return fd; 341f12db248SBryan Drewery } 342f12db248SBryan Drewery 343f12db248SBryan Drewery static struct fingerprint * 3448a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 345f12db248SBryan Drewery { 346b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 3478a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 3488a7d859eSBaptiste Daroussin const char *function, *fp, *key; 349f12db248SBryan Drewery struct fingerprint *f; 350f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 351f12db248SBryan Drewery 352f12db248SBryan Drewery function = fp = NULL; 353f12db248SBryan Drewery 3548a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 3558a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 3568a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 3578a7d859eSBaptiste Daroussin continue; 3588a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 3598a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 360f12db248SBryan Drewery continue; 361f12db248SBryan Drewery } 3628a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 3638a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 364f12db248SBryan Drewery continue; 365f12db248SBryan Drewery } 366f12db248SBryan Drewery } 367f12db248SBryan Drewery 368f12db248SBryan Drewery if (fp == NULL || function == NULL) 369f12db248SBryan Drewery return (NULL); 370f12db248SBryan Drewery 371f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 372f12db248SBryan Drewery fct = HASH_SHA256; 373f12db248SBryan Drewery 374f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 375d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 376f12db248SBryan Drewery return (NULL); 377f12db248SBryan Drewery } 378f12db248SBryan Drewery 379f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 380f12db248SBryan Drewery f->type = fct; 381f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 382f12db248SBryan Drewery 383f12db248SBryan Drewery return (f); 384f12db248SBryan Drewery } 385f12db248SBryan Drewery 386516aaf7cSBryan Drewery static void 387516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 388516aaf7cSBryan Drewery { 389d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 390516aaf7cSBryan Drewery 391d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 392516aaf7cSBryan Drewery free(fingerprint->name); 393516aaf7cSBryan Drewery free(fingerprint); 394516aaf7cSBryan Drewery } 395516aaf7cSBryan Drewery free(list); 396516aaf7cSBryan Drewery } 397516aaf7cSBryan Drewery 398f12db248SBryan Drewery static struct fingerprint * 399f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 400f12db248SBryan Drewery { 4018a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 4028a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 403f12db248SBryan Drewery struct fingerprint *f; 404f12db248SBryan Drewery char path[MAXPATHLEN]; 405f12db248SBryan Drewery 406f12db248SBryan Drewery f = NULL; 407f12db248SBryan Drewery 408f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 409f12db248SBryan Drewery 4108a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 4118a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 4128a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 4138a7d859eSBaptiste Daroussin ucl_parser_free(p); 414f12db248SBryan Drewery return (NULL); 4158a7d859eSBaptiste Daroussin } 416f12db248SBryan Drewery 4178a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 418f12db248SBryan Drewery 4198a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 4208a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 421f12db248SBryan Drewery 4228a7d859eSBaptiste Daroussin if (f != NULL) 423516aaf7cSBryan Drewery f->name = strdup(filename); 424f12db248SBryan Drewery 425b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 4268a7d859eSBaptiste Daroussin ucl_parser_free(p); 427f12db248SBryan Drewery 428f12db248SBryan Drewery return (f); 429f12db248SBryan Drewery } 430f12db248SBryan Drewery 431f12db248SBryan Drewery static struct fingerprint_list * 432f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 433f12db248SBryan Drewery { 434f12db248SBryan Drewery DIR *d; 435f12db248SBryan Drewery struct dirent *ent; 436f12db248SBryan Drewery struct fingerprint *finger; 437f12db248SBryan Drewery struct fingerprint_list *fingerprints; 438f12db248SBryan Drewery 439f12db248SBryan Drewery *count = 0; 440f12db248SBryan Drewery 441f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 442f12db248SBryan Drewery if (fingerprints == NULL) 443f12db248SBryan Drewery return (NULL); 444f12db248SBryan Drewery STAILQ_INIT(fingerprints); 445f12db248SBryan Drewery 44692947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 44792947daaSBaptiste Daroussin free(fingerprints); 44892947daaSBaptiste Daroussin 449f12db248SBryan Drewery return (NULL); 45092947daaSBaptiste Daroussin } 451f12db248SBryan Drewery 452f12db248SBryan Drewery while ((ent = readdir(d))) { 453f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 454f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 455f12db248SBryan Drewery continue; 456f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 457f12db248SBryan Drewery if (finger != NULL) { 458f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 459f12db248SBryan Drewery ++(*count); 460f12db248SBryan Drewery } 461f12db248SBryan Drewery } 462f12db248SBryan Drewery 463f12db248SBryan Drewery closedir(d); 464f12db248SBryan Drewery 465f12db248SBryan Drewery return (fingerprints); 466f12db248SBryan Drewery } 467f12db248SBryan Drewery 4682ecfc040SKyle Evans char * 4692ecfc040SKyle Evans pkg_read_fd(int fd, size_t *osz) 4702ecfc040SKyle Evans { 4712ecfc040SKyle Evans char *obuf; 4722ecfc040SKyle Evans char buf[4096]; 4732ecfc040SKyle Evans FILE *fp; 4742ecfc040SKyle Evans ssize_t r; 4752ecfc040SKyle Evans 4762ecfc040SKyle Evans obuf = NULL; 4772ecfc040SKyle Evans *osz = 0; 4782ecfc040SKyle Evans fp = open_memstream(&obuf, osz); 4792ecfc040SKyle Evans if (fp == NULL) 4802ecfc040SKyle Evans err(EXIT_FAILURE, "open_memstream()"); 4812ecfc040SKyle Evans 4822ecfc040SKyle Evans while ((r = read(fd, buf, sizeof(buf))) >0) { 4832ecfc040SKyle Evans fwrite(buf, 1, r, fp); 4842ecfc040SKyle Evans } 4852ecfc040SKyle Evans 4862ecfc040SKyle Evans if (ferror(fp)) 4872ecfc040SKyle Evans errx(EXIT_FAILURE, "reading file"); 4882ecfc040SKyle Evans 4892ecfc040SKyle Evans fclose(fp); 4902ecfc040SKyle Evans 4912ecfc040SKyle Evans return (obuf); 4922ecfc040SKyle Evans } 4932ecfc040SKyle Evans 4943d0a0ddaSKyle Evans /* 4953d0a0ddaSKyle Evans * Returns a copy of the signature type stored on the heap, and advances *bufp 4963d0a0ddaSKyle Evans * past the type. 4973d0a0ddaSKyle Evans */ 4983d0a0ddaSKyle Evans static char * 4993d0a0ddaSKyle Evans parse_sigtype(char **bufp, size_t *bufszp) 5003d0a0ddaSKyle Evans { 5013d0a0ddaSKyle Evans char *buf = *bufp; 5023d0a0ddaSKyle Evans char *endp; 5033d0a0ddaSKyle Evans char *sigtype; 5043d0a0ddaSKyle Evans size_t bufsz = *bufszp; 5053d0a0ddaSKyle Evans 5063d0a0ddaSKyle Evans if (bufsz <= sizeof(PKGSIGN_MARKER) - 1 || 5073d0a0ddaSKyle Evans strncmp(buf, PKGSIGN_MARKER, sizeof(PKGSIGN_MARKER) - 1) != 0) 5083d0a0ddaSKyle Evans goto dflt; 5093d0a0ddaSKyle Evans 5103d0a0ddaSKyle Evans buf += sizeof(PKGSIGN_MARKER) - 1; 5113d0a0ddaSKyle Evans endp = strchr(buf, '$'); 5123d0a0ddaSKyle Evans if (endp == NULL) 5133d0a0ddaSKyle Evans goto dflt; 5143d0a0ddaSKyle Evans 5153d0a0ddaSKyle Evans sigtype = strndup(buf, endp - buf); 5163d0a0ddaSKyle Evans *bufp = endp + 1; 5173d0a0ddaSKyle Evans *bufszp -= *bufp - buf; 5183d0a0ddaSKyle Evans 5193d0a0ddaSKyle Evans return (sigtype); 5203d0a0ddaSKyle Evans dflt: 5213d0a0ddaSKyle Evans return (strdup("rsa")); 5223d0a0ddaSKyle Evans } 5233d0a0ddaSKyle Evans 52461acb458SBaptiste Daroussin static struct pubkey * 52561acb458SBaptiste Daroussin read_pubkey(int fd) 52661acb458SBaptiste Daroussin { 52761acb458SBaptiste Daroussin struct pubkey *pk; 5283d0a0ddaSKyle Evans char *osigb, *sigb, *sigtype; 529cc9a8a11SBaptiste Daroussin size_t sigsz; 53061acb458SBaptiste Daroussin 53161acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 53261acb458SBaptiste Daroussin warn("lseek"); 53361acb458SBaptiste Daroussin return (NULL); 53461acb458SBaptiste Daroussin } 53561acb458SBaptiste Daroussin 5363d0a0ddaSKyle Evans osigb = sigb = pkg_read_fd(fd, &sigsz); 5373d0a0ddaSKyle Evans sigtype = parse_sigtype(&sigb, &sigsz); 53861acb458SBaptiste Daroussin 53961acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 540cc9a8a11SBaptiste Daroussin pk->siglen = sigsz; 54161acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 542cc9a8a11SBaptiste Daroussin memcpy(pk->sig, sigb, pk->siglen); 5433d0a0ddaSKyle Evans pk->sigtype = sigtype; 5443d0a0ddaSKyle Evans free(osigb); 54561acb458SBaptiste Daroussin 54661acb458SBaptiste Daroussin return (pk); 54761acb458SBaptiste Daroussin } 54861acb458SBaptiste Daroussin 549f12db248SBryan Drewery static struct sig_cert * 550f12db248SBryan Drewery parse_cert(int fd) { 551f12db248SBryan Drewery int my_fd; 552f12db248SBryan Drewery struct sig_cert *sc; 5533d0a0ddaSKyle Evans FILE *fp, *sigfp, *certfp, *tmpfp, *typefp; 554f12db248SBryan Drewery char *line; 5553d0a0ddaSKyle Evans char *sig, *cert, *type; 5563d0a0ddaSKyle Evans size_t linecap, sigsz, certsz, typesz; 557f12db248SBryan Drewery ssize_t linelen; 5583d0a0ddaSKyle Evans bool end_seen; 559f12db248SBryan Drewery 560f12db248SBryan Drewery sc = NULL; 561f12db248SBryan Drewery line = NULL; 562f12db248SBryan Drewery linecap = 0; 5633d0a0ddaSKyle Evans sig = cert = type = NULL; 5643d0a0ddaSKyle Evans sigfp = certfp = tmpfp = typefp = NULL; 565f12db248SBryan Drewery 566f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 567f12db248SBryan Drewery warn("lseek"); 568f12db248SBryan Drewery return (NULL); 569f12db248SBryan Drewery } 570f12db248SBryan Drewery 571f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 572f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 573f12db248SBryan Drewery warnx("dup"); 574f12db248SBryan Drewery return (NULL); 575f12db248SBryan Drewery } 576f12db248SBryan Drewery 577f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 578f12db248SBryan Drewery warn("fdopen"); 579f12db248SBryan Drewery close(my_fd); 580f12db248SBryan Drewery return (NULL); 581f12db248SBryan Drewery } 582f12db248SBryan Drewery 5833d0a0ddaSKyle Evans sigsz = certsz = typesz = 0; 584cc9a8a11SBaptiste Daroussin sigfp = open_memstream(&sig, &sigsz); 585cc9a8a11SBaptiste Daroussin if (sigfp == NULL) 586cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 587cc9a8a11SBaptiste Daroussin certfp = open_memstream(&cert, &certsz); 588cc9a8a11SBaptiste Daroussin if (certfp == NULL) 589cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 5903d0a0ddaSKyle Evans typefp = open_memstream(&type, &typesz); 5913d0a0ddaSKyle Evans if (typefp == NULL) 5923d0a0ddaSKyle Evans err(EXIT_FAILURE, "open_memstream()"); 593f12db248SBryan Drewery 5943d0a0ddaSKyle Evans end_seen = false; 595f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 596f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 597cc9a8a11SBaptiste Daroussin tmpfp = sigfp; 598f12db248SBryan Drewery continue; 5993d0a0ddaSKyle Evans } else if (strcmp(line, "TYPE\n") == 0) { 6003d0a0ddaSKyle Evans tmpfp = typefp; 6013d0a0ddaSKyle Evans continue; 602f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 603cc9a8a11SBaptiste Daroussin tmpfp = certfp; 604f12db248SBryan Drewery continue; 605f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 6063d0a0ddaSKyle Evans end_seen = true; 607f12db248SBryan Drewery break; 608f12db248SBryan Drewery } 609cc9a8a11SBaptiste Daroussin if (tmpfp != NULL) 610cc9a8a11SBaptiste Daroussin fwrite(line, 1, linelen, tmpfp); 611f12db248SBryan Drewery } 612f12db248SBryan Drewery 613f12db248SBryan Drewery fclose(fp); 614cc9a8a11SBaptiste Daroussin fclose(sigfp); 615cc9a8a11SBaptiste Daroussin fclose(certfp); 6163d0a0ddaSKyle Evans fclose(typefp); 617f12db248SBryan Drewery 618f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 619cc9a8a11SBaptiste Daroussin sc->siglen = sigsz -1; /* Trim out unrelated trailing newline */ 620cc9a8a11SBaptiste Daroussin sc->sig = sig; 621f12db248SBryan Drewery 6223d0a0ddaSKyle Evans if (typesz == 0) { 6233d0a0ddaSKyle Evans sc->type = strdup("rsa"); 6243d0a0ddaSKyle Evans free(type); 6253d0a0ddaSKyle Evans } else { 6263d0a0ddaSKyle Evans assert(type[typesz - 1] == '\n'); 6273d0a0ddaSKyle Evans type[typesz - 1] = '\0'; 6283d0a0ddaSKyle Evans sc->type = type; 6293d0a0ddaSKyle Evans } 6303d0a0ddaSKyle Evans 6313d0a0ddaSKyle Evans /* 6323d0a0ddaSKyle Evans * cert could be DER-encoded rather than PEM, so strip off any trailing 6333d0a0ddaSKyle Evans * END marker if we ran over it. 6343d0a0ddaSKyle Evans */ 6353d0a0ddaSKyle Evans if (!end_seen && certsz > 4 && 6363d0a0ddaSKyle Evans strcmp(&cert[certsz - 4], "END\n") == 0) 6373d0a0ddaSKyle Evans certsz -= 4; 638cc9a8a11SBaptiste Daroussin sc->certlen = certsz; 639cc9a8a11SBaptiste Daroussin sc->cert = cert; 640f12db248SBryan Drewery 641f12db248SBryan Drewery return (sc); 642f12db248SBryan Drewery } 643f12db248SBryan Drewery 644f12db248SBryan Drewery static bool 645dc458158SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig, struct repository *r) 64661acb458SBaptiste Daroussin { 64761acb458SBaptiste Daroussin struct pubkey *pk; 6482e065d74SKyle Evans char *data; 6495862580dSKyle Evans struct pkgsign_ctx *sctx; 6502e065d74SKyle Evans size_t datasz; 65161acb458SBaptiste Daroussin bool ret; 652dc458158SBaptiste Daroussin const char *pubkey; 65361acb458SBaptiste Daroussin 65461acb458SBaptiste Daroussin pk = NULL; 6555862580dSKyle Evans sctx = NULL; 6562e065d74SKyle Evans data = NULL; 65761acb458SBaptiste Daroussin ret = false; 658dc458158SBaptiste Daroussin 659dc458158SBaptiste Daroussin if (r != NULL) { 660dc458158SBaptiste Daroussin if (r->pubkey == NULL) { 661dc458158SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined for %s", r->name); 66261acb458SBaptiste Daroussin goto cleanup; 66361acb458SBaptiste Daroussin } 664dc458158SBaptiste Daroussin pubkey = r->pubkey; 665dc458158SBaptiste Daroussin } else { 666dc458158SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 667*c1557708SMark Johnston warnx("No CONFIG_PUBKEY defined"); 668dc458158SBaptiste Daroussin goto cleanup; 669dc458158SBaptiste Daroussin } 670dc458158SBaptiste Daroussin } 67161acb458SBaptiste Daroussin 67261acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 67361acb458SBaptiste Daroussin warnx("Error reading signature"); 67461acb458SBaptiste Daroussin goto cleanup; 67561acb458SBaptiste Daroussin } 67661acb458SBaptiste Daroussin 6772e065d74SKyle Evans if (lseek(fd_pkg, 0, SEEK_SET) == -1) { 6782e065d74SKyle Evans warn("lseek"); 6792e065d74SKyle Evans goto cleanup; 6802e065d74SKyle Evans } 6812e065d74SKyle Evans 6823d0a0ddaSKyle Evans if (strcmp(pk->sigtype, "rsa") == 0) { 6832e065d74SKyle Evans /* Future types shouldn't do this. */ 6842e065d74SKyle Evans if ((data = sha256_fd(fd_pkg)) == NULL) { 6852e065d74SKyle Evans warnx("Error creating SHA256 hash for package"); 6862e065d74SKyle Evans goto cleanup; 6872e065d74SKyle Evans } 6882e065d74SKyle Evans 6892e065d74SKyle Evans datasz = strlen(data); 6903d0a0ddaSKyle Evans } else { 6913d0a0ddaSKyle Evans if ((data = pkg_read_fd(fd_pkg, &datasz)) == NULL) { 6923d0a0ddaSKyle Evans warnx("Failed to read package data"); 6933d0a0ddaSKyle Evans goto cleanup; 6943d0a0ddaSKyle Evans } 6953d0a0ddaSKyle Evans } 6962e065d74SKyle Evans 6973d0a0ddaSKyle Evans if (pkgsign_new(pk->sigtype, &sctx) != 0) { 6983d0a0ddaSKyle Evans warnx("Failed to fetch '%s' signer", pk->sigtype); 6995862580dSKyle Evans goto cleanup; 7005862580dSKyle Evans } 7015862580dSKyle Evans 70261acb458SBaptiste Daroussin /* Verify the signature. */ 703dc458158SBaptiste Daroussin printf("Verifying signature with public key %s.a.. ", r->pubkey); 704dc458158SBaptiste Daroussin if (pkgsign_verify_data(sctx, data, datasz, r->pubkey, NULL, 0, pk->sig, 70561acb458SBaptiste Daroussin pk->siglen) == false) { 70661acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 70761acb458SBaptiste Daroussin goto cleanup; 70861acb458SBaptiste Daroussin } 70961acb458SBaptiste Daroussin 71061acb458SBaptiste Daroussin ret = true; 71161acb458SBaptiste Daroussin 71261acb458SBaptiste Daroussin cleanup: 7132e065d74SKyle Evans free(data); 71461acb458SBaptiste Daroussin if (pk) { 71561acb458SBaptiste Daroussin free(pk->sig); 71661acb458SBaptiste Daroussin free(pk); 71761acb458SBaptiste Daroussin } 71861acb458SBaptiste Daroussin 71961acb458SBaptiste Daroussin return (ret); 72061acb458SBaptiste Daroussin } 72161acb458SBaptiste Daroussin 72261acb458SBaptiste Daroussin static bool 723dc458158SBaptiste Daroussin verify_signature(int fd_pkg, int fd_sig, struct repository *r) 724f12db248SBryan Drewery { 725f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 726f12db248SBryan Drewery struct fingerprint *fingerprint; 727f12db248SBryan Drewery struct sig_cert *sc; 7285862580dSKyle Evans struct pkgsign_ctx *sctx; 729f12db248SBryan Drewery bool ret; 730f12db248SBryan Drewery int trusted_count, revoked_count; 731f12db248SBryan Drewery const char *fingerprints; 732f12db248SBryan Drewery char path[MAXPATHLEN]; 733e5dd5bfaSBaptiste Daroussin char *hash; 734f12db248SBryan Drewery 735e5dd5bfaSBaptiste Daroussin hash = NULL; 736516aaf7cSBryan Drewery sc = NULL; 7375862580dSKyle Evans sctx = NULL; 738f12db248SBryan Drewery trusted = revoked = NULL; 739f12db248SBryan Drewery ret = false; 740f12db248SBryan Drewery 741f12db248SBryan Drewery /* Read and parse fingerprints. */ 742dc458158SBaptiste Daroussin if (r != NULL) { 743dc458158SBaptiste Daroussin if (r->fingerprints == NULL) { 744dc458158SBaptiste Daroussin warnx("No FINGERPRINTS defined for %s", r->name); 745f12db248SBryan Drewery goto cleanup; 746f12db248SBryan Drewery } 747dc458158SBaptiste Daroussin fingerprints = r->fingerprints; 748dc458158SBaptiste Daroussin } else { 749dc458158SBaptiste Daroussin if (config_string(FINGERPRINTS, &fingerprints) != 0) { 750dc458158SBaptiste Daroussin warnx("No FINGERPRINTS defined"); 751dc458158SBaptiste Daroussin goto cleanup; 752dc458158SBaptiste Daroussin } 753dc458158SBaptiste Daroussin } 754f12db248SBryan Drewery 755f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 756f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 757f12db248SBryan Drewery warnx("Error loading trusted certificates"); 758f12db248SBryan Drewery goto cleanup; 759f12db248SBryan Drewery } 760f12db248SBryan Drewery 761f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 762f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 763f12db248SBryan Drewery goto cleanup; 764f12db248SBryan Drewery } 765f12db248SBryan Drewery 766f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 767f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 768f12db248SBryan Drewery warnx("Error loading revoked certificates"); 769f12db248SBryan Drewery goto cleanup; 770f12db248SBryan Drewery } 771f12db248SBryan Drewery 772f12db248SBryan Drewery /* Read certificate and signature in. */ 773f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 774f12db248SBryan Drewery warnx("Error parsing certificate"); 775f12db248SBryan Drewery goto cleanup; 776f12db248SBryan Drewery } 777f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 778f12db248SBryan Drewery sc->trusted = false; 779f12db248SBryan Drewery 780f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 781e5dd5bfaSBaptiste Daroussin hash = sha256_buf(sc->cert, sc->certlen); 782f12db248SBryan Drewery 783f12db248SBryan Drewery /* Check if this hash is revoked */ 784f12db248SBryan Drewery if (revoked != NULL) { 785f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 786f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 787516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 788516aaf7cSBryan Drewery "revoked certificate %s\n", 789516aaf7cSBryan Drewery fingerprint->name); 790f12db248SBryan Drewery goto cleanup; 791f12db248SBryan Drewery } 792f12db248SBryan Drewery } 793f12db248SBryan Drewery } 794f12db248SBryan Drewery 795f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 796f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 797f12db248SBryan Drewery sc->trusted = true; 798516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 799f12db248SBryan Drewery break; 800f12db248SBryan Drewery } 801f12db248SBryan Drewery } 802f12db248SBryan Drewery 803f12db248SBryan Drewery if (sc->trusted == false) { 804516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 805f12db248SBryan Drewery "package's certificate\n"); 806f12db248SBryan Drewery goto cleanup; 807f12db248SBryan Drewery } 808f12db248SBryan Drewery 8093d0a0ddaSKyle Evans if (pkgsign_new(sc->type, &sctx) != 0) { 8105862580dSKyle Evans fprintf(stderr, "Failed to fetch 'rsa' signer\n"); 8115862580dSKyle Evans goto cleanup; 8125862580dSKyle Evans } 8135862580dSKyle Evans 814f12db248SBryan Drewery /* Verify the signature. */ 815516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 8165862580dSKyle Evans if (pkgsign_verify_cert(sctx, fd_pkg, NULL, sc->cert, sc->certlen, 8175862580dSKyle Evans sc->sig, sc->siglen) == false) { 818f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 819f12db248SBryan Drewery goto cleanup; 820f12db248SBryan Drewery } 821f12db248SBryan Drewery 822f12db248SBryan Drewery ret = true; 823f12db248SBryan Drewery 824f12db248SBryan Drewery cleanup: 825e5dd5bfaSBaptiste Daroussin free(hash); 826516aaf7cSBryan Drewery if (trusted) 827516aaf7cSBryan Drewery free_fingerprint_list(trusted); 828516aaf7cSBryan Drewery if (revoked) 829516aaf7cSBryan Drewery free_fingerprint_list(revoked); 830f12db248SBryan Drewery if (sc) { 831f12db248SBryan Drewery free(sc->cert); 832f12db248SBryan Drewery free(sc->sig); 833516aaf7cSBryan Drewery free(sc->name); 834f12db248SBryan Drewery free(sc); 835f12db248SBryan Drewery } 836f12db248SBryan Drewery 837f12db248SBryan Drewery return (ret); 838f12db248SBryan Drewery } 839f12db248SBryan Drewery 840f12db248SBryan Drewery static int 841dc458158SBaptiste Daroussin bootstrap_pkg(bool force, const char *fetchOpts, struct repository *repo) 842f12db248SBryan Drewery { 843f12db248SBryan Drewery int fd_pkg, fd_sig; 844f12db248SBryan Drewery int ret; 845f12db248SBryan Drewery char url[MAXPATHLEN]; 846f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 847f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 848f12db248SBryan Drewery const char *packagesite; 849f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 850f12db248SBryan Drewery 851f12db248SBryan Drewery fd_sig = -1; 852f12db248SBryan Drewery ret = -1; 853f12db248SBryan Drewery 854dc458158SBaptiste Daroussin printf("Bootstrapping pkg from %s, please wait...\n", repo->url); 855f12db248SBryan Drewery 856f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 857f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 858f12db248SBryan Drewery no A record. */ 859dc458158SBaptiste Daroussin packagesite = repo->url; 860f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 861f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 862f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 863f12db248SBryan Drewery 864a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s", packagesite, bootstrap_name); 865a2aac2f5SBaptiste Daroussin snprintf(tmppkg, MAXPATHLEN, "%s/%s.XXXXXX", 866a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 867a2aac2f5SBaptiste Daroussin bootstrap_name); 8680cd9513aSEd Maste if ((fd_pkg = fetch_to_fd(repo, url, tmppkg, fetchOpts)) == -1) 869f12db248SBryan Drewery goto fetchfail; 870f12db248SBryan Drewery 871dc458158SBaptiste Daroussin if (repo->signature_type == SIGNATURE_FINGERPRINT) { 872a2aac2f5SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX", 873a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 874a2aac2f5SBaptiste Daroussin bootstrap_name); 875a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig", 876a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 877f12db248SBryan Drewery 878dc458158SBaptiste Daroussin if ((fd_sig = fetch_to_fd(repo, url, tmpsig, fetchOpts)) == -1) { 87961acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 88061acb458SBaptiste Daroussin "available.\n"); 881f12db248SBryan Drewery goto fetchfail; 882f12db248SBryan Drewery } 883f12db248SBryan Drewery 884dc458158SBaptiste Daroussin if (verify_signature(fd_pkg, fd_sig, repo) == false) 885f12db248SBryan Drewery goto cleanup; 886dc458158SBaptiste Daroussin } else if (repo->signature_type == SIGNATURE_PUBKEY) { 88761acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 888a2aac2f5SBaptiste Daroussin "%s/%s.pubkeysig.XXXXXX", 889a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 890a2aac2f5SBaptiste Daroussin bootstrap_name); 891a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.pubkeysig", 892dc458158SBaptiste Daroussin repo->url, bootstrap_name); 89361acb458SBaptiste Daroussin 894dc458158SBaptiste Daroussin if ((fd_sig = fetch_to_fd(repo, url, tmpsig, fetchOpts)) == -1) { 89561acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 89661acb458SBaptiste Daroussin "available.\n"); 89761acb458SBaptiste Daroussin goto fetchfail; 89861acb458SBaptiste Daroussin } 89961acb458SBaptiste Daroussin 900dc458158SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig, repo) == false) 90161acb458SBaptiste Daroussin goto cleanup; 902f12db248SBryan Drewery } 903f12db248SBryan Drewery 904f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9055212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 9063aa4b42aSBaptiste Daroussin 907a6454741SBaptiste Daroussin goto cleanup; 908a6454741SBaptiste Daroussin 909a6454741SBaptiste Daroussin fetchfail: 9100cd9513aSEd Maste warnx("Error fetching %s: %s", url, fetchLastErrString); 911a10f71c5STom Jones if (fetchLastErrCode == FETCH_RESOLV) { 912a10f71c5STom Jones fprintf(stderr, "Address resolution failed for %s.\n", packagesite); 913a10f71c5STom Jones } else { 9144ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 9154ff9a7efSBryan Drewery "your system.\n"); 916a10f71c5STom Jones } 917a6454741SBaptiste Daroussin 9183aa4b42aSBaptiste Daroussin cleanup: 919f12db248SBryan Drewery if (fd_sig != -1) { 920f12db248SBryan Drewery close(fd_sig); 921f12db248SBryan Drewery unlink(tmpsig); 922f12db248SBryan Drewery } 92392947daaSBaptiste Daroussin 92492947daaSBaptiste Daroussin if (fd_pkg != -1) { 925f12db248SBryan Drewery close(fd_pkg); 9263aa4b42aSBaptiste Daroussin unlink(tmppkg); 92792947daaSBaptiste Daroussin } 9283aa4b42aSBaptiste Daroussin 929a6454741SBaptiste Daroussin return (ret); 9303aa4b42aSBaptiste Daroussin } 9313aa4b42aSBaptiste Daroussin 932e18ad51cSAlexander Kabaev static const char confirmation_message[] = 933e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 934e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 935e18ad51cSAlexander Kabaev 936e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 937575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 9381efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 939e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 940575c4095SBaptiste Daroussin 941ae994fdcSBaptiste Daroussin static const char args_bootstrap_message[] = 942ae994fdcSBaptiste Daroussin "Too many arguments\n" 943ae994fdcSBaptiste Daroussin "Usage: pkg [-4|-6] bootstrap [-f] [-y]\n"; 944ae994fdcSBaptiste Daroussin 945ae994fdcSBaptiste Daroussin static const char args_add_message[] = 946ae994fdcSBaptiste Daroussin "Too many arguments\n" 947f5c847aeSEd Maste "Usage: pkg add [-f] [-y] {pkg.pkg}\n"; 948ae994fdcSBaptiste Daroussin 949e18ad51cSAlexander Kabaev static int 950e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 951e18ad51cSAlexander Kabaev { 952e18ad51cSAlexander Kabaev int ret, c; 953e18ad51cSAlexander Kabaev 95467c9f60eSPoul-Henning Kamp fflush(stdout); 955e18ad51cSAlexander Kabaev c = getchar(); 956e18ad51cSAlexander Kabaev 957e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 958e18ad51cSAlexander Kabaev ret = 1; 959e18ad51cSAlexander Kabaev else 960e18ad51cSAlexander Kabaev ret = 0; 961e18ad51cSAlexander Kabaev 962e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 963e18ad51cSAlexander Kabaev c = getchar(); 964e18ad51cSAlexander Kabaev 965e18ad51cSAlexander Kabaev return (ret); 966e18ad51cSAlexander Kabaev } 967e18ad51cSAlexander Kabaev 96852cb76feSBryan Drewery static int 9695212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 97052cb76feSBryan Drewery { 97152cb76feSBryan Drewery char path[MAXPATHLEN]; 97252cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 97352cb76feSBryan Drewery const char *signature_type; 97452cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 97552cb76feSBryan Drewery 97652cb76feSBryan Drewery fd_sig = -1; 97752cb76feSBryan Drewery ret = -1; 97852cb76feSBryan Drewery 97952cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 98052cb76feSBryan Drewery if (fd_pkg == -1) 98152cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 98252cb76feSBryan Drewery 98352cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 98452cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 98592947daaSBaptiste Daroussin goto cleanup; 98652cb76feSBryan Drewery } 98752cb76feSBryan Drewery if (signature_type != NULL && 98848f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 98961acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 99048f92706SXin LI 99152cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 99252cb76feSBryan Drewery 99352cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 99461acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 99561acb458SBaptiste Daroussin "available.\n"); 99652cb76feSBryan Drewery goto cleanup; 99752cb76feSBryan Drewery } 99852cb76feSBryan Drewery 999dc458158SBaptiste Daroussin if (verify_signature(fd_pkg, fd_sig, NULL) == false) 100052cb76feSBryan Drewery goto cleanup; 100161acb458SBaptiste Daroussin 100261acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 100361acb458SBaptiste Daroussin 100461acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 100561acb458SBaptiste Daroussin 100661acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 100761acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 100861acb458SBaptiste Daroussin "available.\n"); 100961acb458SBaptiste Daroussin goto cleanup; 101061acb458SBaptiste Daroussin } 101161acb458SBaptiste Daroussin 1012dc458158SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig, NULL) == false) 101361acb458SBaptiste Daroussin goto cleanup; 101461acb458SBaptiste Daroussin 101561acb458SBaptiste Daroussin } else { 101661acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 101761acb458SBaptiste Daroussin "bootstrapping.", signature_type); 101861acb458SBaptiste Daroussin goto cleanup; 101961acb458SBaptiste Daroussin } 102052cb76feSBryan Drewery } 102152cb76feSBryan Drewery 102252cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 10235212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 102452cb76feSBryan Drewery 102552cb76feSBryan Drewery cleanup: 102652cb76feSBryan Drewery close(fd_pkg); 102752cb76feSBryan Drewery if (fd_sig != -1) 102852cb76feSBryan Drewery close(fd_sig); 102952cb76feSBryan Drewery 103052cb76feSBryan Drewery return (ret); 103152cb76feSBryan Drewery } 103252cb76feSBryan Drewery 103340b9f924SKyle Evans #define PKG_NAME "pkg" 103440b9f924SKyle Evans #define PKG_DEVEL_NAME PKG_NAME "-devel" 103540b9f924SKyle Evans #define PKG_PKG PKG_NAME "." 103640b9f924SKyle Evans 103740b9f924SKyle Evans static bool 103840b9f924SKyle Evans pkg_is_pkg_pkg(const char *pkg) 103940b9f924SKyle Evans { 1040c96b4d87SGleb Smirnoff char *vstart, *basename; 104140b9f924SKyle Evans size_t namelen; 104240b9f924SKyle Evans 1043c96b4d87SGleb Smirnoff /* Strip path. */ 1044c96b4d87SGleb Smirnoff if ((basename = strrchr(pkg, '/')) != NULL) 1045c96b4d87SGleb Smirnoff pkg = basename + 1; 1046c96b4d87SGleb Smirnoff 104740b9f924SKyle Evans /* 104840b9f924SKyle Evans * Chop off the final "-" (version delimiter) and check the name that 104940b9f924SKyle Evans * precedes it. If we didn't have a version delimiter, it must be the 105040b9f924SKyle Evans * pkg.$archive short form but we'll check it anyways. pkg-devel short 105140b9f924SKyle Evans * form will look like a pkg archive with 'devel' version, but that's 105240b9f924SKyle Evans * OK. We otherwise assumed that non-pkg packages will always have a 105340b9f924SKyle Evans * version component. 105440b9f924SKyle Evans */ 105540b9f924SKyle Evans vstart = strrchr(pkg, '-'); 105640b9f924SKyle Evans if (vstart == NULL) { 105740b9f924SKyle Evans return (strlen(pkg) > sizeof(PKG_PKG) - 1 && 105840b9f924SKyle Evans strncmp(pkg, PKG_PKG, sizeof(PKG_PKG) - 1) == 0); 105940b9f924SKyle Evans } 106040b9f924SKyle Evans 106140b9f924SKyle Evans namelen = vstart - pkg; 106240b9f924SKyle Evans if (namelen == sizeof(PKG_NAME) - 1 && 106340b9f924SKyle Evans strncmp(pkg, PKG_NAME, sizeof(PKG_NAME) - 1) == 0) 106440b9f924SKyle Evans return (true); 106540b9f924SKyle Evans if (namelen == sizeof(PKG_DEVEL_NAME) - 1 && 106640b9f924SKyle Evans strncmp(pkg, PKG_DEVEL_NAME, sizeof(PKG_DEVEL_NAME) - 1) == 0) 106740b9f924SKyle Evans return (true); 106840b9f924SKyle Evans return (false); 106940b9f924SKyle Evans } 107040b9f924SKyle Evans 10713aa4b42aSBaptiste Daroussin int 107246b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10733aa4b42aSBaptiste Daroussin { 10743aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 107518418e19SKyle Evans const char *pkgarg, *repo_name; 1076ae994fdcSBaptiste Daroussin bool activation_test, add_pkg, bootstrap_only, force, yes; 1077ae994fdcSBaptiste Daroussin signed char ch; 1078ae994fdcSBaptiste Daroussin const char *fetchOpts; 1079ae994fdcSBaptiste Daroussin char *command; 1080dc458158SBaptiste Daroussin struct repositories *repositories; 10815212e8baSBryan Drewery 1082ae994fdcSBaptiste Daroussin activation_test = false; 1083ae994fdcSBaptiste Daroussin add_pkg = false; 10845212e8baSBryan Drewery bootstrap_only = false; 1085ae994fdcSBaptiste Daroussin command = NULL; 1086ae994fdcSBaptiste Daroussin fetchOpts = ""; 10875212e8baSBryan Drewery force = false; 10885212e8baSBryan Drewery pkgarg = NULL; 108918418e19SKyle Evans repo_name = NULL; 10905212e8baSBryan Drewery yes = false; 10913aa4b42aSBaptiste Daroussin 1092ae994fdcSBaptiste Daroussin struct option longopts[] = { 1093e9ad2964SBrooks Davis { "debug", no_argument, NULL, 'd' }, 1094ae994fdcSBaptiste Daroussin { "force", no_argument, NULL, 'f' }, 1095ae994fdcSBaptiste Daroussin { "only-ipv4", no_argument, NULL, '4' }, 1096ae994fdcSBaptiste Daroussin { "only-ipv6", no_argument, NULL, '6' }, 1097ae994fdcSBaptiste Daroussin { "yes", no_argument, NULL, 'y' }, 1098ae994fdcSBaptiste Daroussin { NULL, 0, NULL, 0 }, 1099ae994fdcSBaptiste Daroussin }; 1100ae994fdcSBaptiste Daroussin 110156d11d4aSStefan Eßer snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase()); 11023aa4b42aSBaptiste Daroussin 1103e9ad2964SBrooks Davis while ((ch = getopt_long(argc, argv, "-:dfr::yN46", longopts, NULL)) != -1) { 1104ae994fdcSBaptiste Daroussin switch (ch) { 1105e9ad2964SBrooks Davis case 'd': 1106e9ad2964SBrooks Davis debug++; 1107e9ad2964SBrooks Davis break; 1108ae994fdcSBaptiste Daroussin case 'f': 1109ae994fdcSBaptiste Daroussin force = true; 1110ae994fdcSBaptiste Daroussin break; 1111ae994fdcSBaptiste Daroussin case 'N': 1112ae994fdcSBaptiste Daroussin activation_test = true; 1113ae994fdcSBaptiste Daroussin break; 1114ae994fdcSBaptiste Daroussin case 'y': 1115ae994fdcSBaptiste Daroussin yes = true; 1116ae994fdcSBaptiste Daroussin break; 1117ae994fdcSBaptiste Daroussin case '4': 1118ae994fdcSBaptiste Daroussin fetchOpts = "4"; 1119ae994fdcSBaptiste Daroussin break; 1120ae994fdcSBaptiste Daroussin case '6': 1121ae994fdcSBaptiste Daroussin fetchOpts = "6"; 1122ae994fdcSBaptiste Daroussin break; 112318418e19SKyle Evans case 'r': 112418418e19SKyle Evans /* 112518418e19SKyle Evans * The repository can only be specified for an explicit 112618418e19SKyle Evans * bootstrap request at this time, so that we don't 112718418e19SKyle Evans * confuse the user if they're trying to use a verb that 112818418e19SKyle Evans * has some other conflicting meaning but we need to 112918418e19SKyle Evans * bootstrap. 113018418e19SKyle Evans * 113118418e19SKyle Evans * For that reason, we specify that -r has an optional 113218418e19SKyle Evans * argument above and process the next index ourselves. 113318418e19SKyle Evans * This is mostly significant because getopt(3) will 113418418e19SKyle Evans * otherwise eat the next argument, which could be 113518418e19SKyle Evans * something we need to try and make sense of. 113618418e19SKyle Evans * 113718418e19SKyle Evans * At worst this gets us false positives that we ignore 113818418e19SKyle Evans * in other contexts, and we have to do a little fudging 113918418e19SKyle Evans * in order to support separating -r from the reponame 114018418e19SKyle Evans * with a space since it's not actually optional in 114118418e19SKyle Evans * the bootstrap/add sense. 114218418e19SKyle Evans */ 114318418e19SKyle Evans if (add_pkg || bootstrap_only) { 114418418e19SKyle Evans if (optarg != NULL) { 114518418e19SKyle Evans repo_name = optarg; 114618418e19SKyle Evans } else if (optind < argc) { 114718418e19SKyle Evans repo_name = argv[optind]; 114818418e19SKyle Evans } 114918418e19SKyle Evans 115018418e19SKyle Evans if (repo_name == NULL || *repo_name == '\0') { 115118418e19SKyle Evans fprintf(stderr, 115218418e19SKyle Evans "Must specify a repository with -r!\n"); 115318418e19SKyle Evans exit(EXIT_FAILURE); 115418418e19SKyle Evans } 115518418e19SKyle Evans 115618418e19SKyle Evans if (optarg == NULL) { 115718418e19SKyle Evans /* Advance past repo name. */ 115818418e19SKyle Evans optreset = 1; 115918418e19SKyle Evans optind++; 116018418e19SKyle Evans } 116118418e19SKyle Evans } 116218418e19SKyle Evans break; 1163ae994fdcSBaptiste Daroussin case 1: 1164ae994fdcSBaptiste Daroussin // Non-option arguments, first one is the command 1165ae994fdcSBaptiste Daroussin if (command == NULL) { 1166ae994fdcSBaptiste Daroussin command = argv[optind-1]; 1167ae994fdcSBaptiste Daroussin if (strcmp(command, "add") == 0) { 1168ae994fdcSBaptiste Daroussin add_pkg = true; 1169ae994fdcSBaptiste Daroussin } 1170ae994fdcSBaptiste Daroussin else if (strcmp(command, "bootstrap") == 0) { 11715212e8baSBryan Drewery bootstrap_only = true; 1172ae994fdcSBaptiste Daroussin } 1173ae994fdcSBaptiste Daroussin } 1174ae994fdcSBaptiste Daroussin // bootstrap doesn't accept other arguments 1175ae994fdcSBaptiste Daroussin else if (bootstrap_only) { 1176ae994fdcSBaptiste Daroussin fprintf(stderr, args_bootstrap_message); 1177ca7f7593SKyle Evans exit(EXIT_FAILURE); 1178ca7f7593SKyle Evans } 1179ae994fdcSBaptiste Daroussin else if (add_pkg && pkgarg != NULL) { 118040b9f924SKyle Evans /* 118140b9f924SKyle Evans * Additional arguments also means it's not a 118240b9f924SKyle Evans * local bootstrap request. 118340b9f924SKyle Evans */ 118440b9f924SKyle Evans add_pkg = false; 1185ca7f7593SKyle Evans } 1186ae994fdcSBaptiste Daroussin else if (add_pkg) { 118740b9f924SKyle Evans /* 118840b9f924SKyle Evans * If it's not a request for pkg or pkg-devel, 118940b9f924SKyle Evans * then we must assume they were trying to 119040b9f924SKyle Evans * install some other local package and we 119140b9f924SKyle Evans * should try to bootstrap from the repo. 119240b9f924SKyle Evans */ 119340b9f924SKyle Evans if (!pkg_is_pkg_pkg(argv[optind-1])) { 119440b9f924SKyle Evans add_pkg = false; 119540b9f924SKyle Evans } else { 1196ae994fdcSBaptiste Daroussin pkgarg = argv[optind-1]; 1197ae994fdcSBaptiste Daroussin } 119840b9f924SKyle Evans } 1199ae994fdcSBaptiste Daroussin break; 1200ae994fdcSBaptiste Daroussin default: 1201ae994fdcSBaptiste Daroussin break; 1202ae994fdcSBaptiste Daroussin } 12035212e8baSBryan Drewery } 1204e9ad2964SBrooks Davis if (debug > 1) 1205e9ad2964SBrooks Davis fetchDebug = 1; 12065212e8baSBryan Drewery 12075212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1208dc458158SBaptiste Daroussin struct repository *repo; 1209dc458158SBaptiste Daroussin int ret = 0; 1210e18ad51cSAlexander Kabaev /* 1211d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1212ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1213990878b0SGordon Bergling * when that option is passed. 1214ecfed9f2SMatthew Seaman */ 1215ae994fdcSBaptiste Daroussin if (activation_test) 1216e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1217ecfed9f2SMatthew Seaman 121818418e19SKyle Evans config_init(repo_name); 121952cb76feSBryan Drewery 1220ae994fdcSBaptiste Daroussin if (add_pkg) { 12215212e8baSBryan Drewery if (pkgarg == NULL) { 1222f5c847aeSEd Maste fprintf(stderr, "Path to pkg.pkg required\n"); 12235212e8baSBryan Drewery exit(EXIT_FAILURE); 12245212e8baSBryan Drewery } 12255212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 12265212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 12275212e8baSBryan Drewery exit(EXIT_FAILURE); 12285212e8baSBryan Drewery } 12295212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1230b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1231b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1232b70213b5SBaptiste Daroussin } 1233ecfed9f2SMatthew Seaman /* 1234e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1235e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1236e18ad51cSAlexander Kabaev * tucked in there already. 1237e18ad51cSAlexander Kabaev */ 1238ae994fdcSBaptiste Daroussin if (!yes) 12399950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 12409950eceeSBaptiste Daroussin if (!yes) { 1241575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1242e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 12433a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1244575c4095SBaptiste Daroussin } 1245204ea792SBaptiste Daroussin 1246575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1247204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1248e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1249e18ad51cSAlexander Kabaev } 1250dc458158SBaptiste Daroussin repositories = config_get_repositories(); 1251dc458158SBaptiste Daroussin STAILQ_FOREACH(repo, repositories, next) { 1252dc458158SBaptiste Daroussin if ((ret = bootstrap_pkg(force, fetchOpts, repo)) == 0) 1253dc458158SBaptiste Daroussin break; 1254dc458158SBaptiste Daroussin } 1255dc458158SBaptiste Daroussin if (ret != 0) 1256a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 12579950eceeSBaptiste Daroussin config_finish(); 1258c3e8a27aSBryan Drewery 12595212e8baSBryan Drewery if (bootstrap_only) 1260c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 12615212e8baSBryan Drewery } else if (bootstrap_only) { 12625212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1263c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1264c3e8a27aSBryan Drewery } 12653aa4b42aSBaptiste Daroussin 12663aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 12673aa4b42aSBaptiste Daroussin 1268a6454741SBaptiste Daroussin /* NOT REACHED */ 12693b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 12703aa4b42aSBaptiste Daroussin } 1271