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 585862580dSKyle Evans static const struct pkgsign_impl { 595862580dSKyle Evans const char *pi_name; 605862580dSKyle Evans const struct pkgsign_ops *pi_ops; 615862580dSKyle Evans } pkgsign_builtins[] = { 625862580dSKyle Evans { 635862580dSKyle Evans .pi_name = "rsa", 645862580dSKyle Evans .pi_ops = &pkgsign_rsa, 655862580dSKyle Evans }, 665862580dSKyle Evans }; 675862580dSKyle Evans 68f12db248SBryan Drewery typedef enum { 69f12db248SBryan Drewery HASH_UNKNOWN, 70f12db248SBryan Drewery HASH_SHA256, 71f12db248SBryan Drewery } hash_t; 72f12db248SBryan Drewery 73f12db248SBryan Drewery struct fingerprint { 74f12db248SBryan Drewery hash_t type; 75516aaf7cSBryan Drewery char *name; 76f12db248SBryan Drewery char hash[BUFSIZ]; 77f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 78f12db248SBryan Drewery }; 79f12db248SBryan Drewery 80a2aac2f5SBaptiste Daroussin static const char *bootstrap_names [] = { 81c244b1d8SBaptiste Daroussin "pkg.pkg", 82a2aac2f5SBaptiste Daroussin "pkg.txz", 83a2aac2f5SBaptiste Daroussin NULL 84a2aac2f5SBaptiste Daroussin }; 85a2aac2f5SBaptiste Daroussin 86f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 87f12db248SBryan Drewery 88e9ad2964SBrooks Davis static int debug; 89e9ad2964SBrooks Davis 903aa4b42aSBaptiste Daroussin static int 915862580dSKyle Evans pkgsign_new(const char *name, struct pkgsign_ctx **ctx) 925862580dSKyle Evans { 935862580dSKyle Evans const struct pkgsign_impl *impl; 945862580dSKyle Evans const struct pkgsign_ops *ops; 955862580dSKyle Evans struct pkgsign_ctx *nctx; 965862580dSKyle Evans size_t ctx_size; 975862580dSKyle Evans int ret; 985862580dSKyle Evans 995862580dSKyle Evans assert(*ctx == NULL); 1005862580dSKyle Evans ops = NULL; 1015862580dSKyle Evans for (size_t i = 0; i < nitems(pkgsign_builtins); i++) { 1025862580dSKyle Evans impl = &pkgsign_builtins[i]; 1035862580dSKyle Evans 1045862580dSKyle Evans if (strcmp(name, impl->pi_name) == 0) { 1055862580dSKyle Evans ops = impl->pi_ops; 1065862580dSKyle Evans break; 1075862580dSKyle Evans } 1085862580dSKyle Evans } 1095862580dSKyle Evans 1105862580dSKyle Evans if (ops == NULL) 1115862580dSKyle Evans return (ENOENT); 1125862580dSKyle Evans 1135862580dSKyle Evans ctx_size = ops->pkgsign_ctx_size; 1145862580dSKyle Evans if (ctx_size == 0) 1155862580dSKyle Evans ctx_size = sizeof(*nctx); 1165862580dSKyle Evans assert(ctx_size >= sizeof(*nctx)); 1175862580dSKyle Evans 1185862580dSKyle Evans nctx = calloc(1, ctx_size); 1195862580dSKyle Evans if (nctx == NULL) 1205862580dSKyle Evans err(EXIT_FAILURE, "calloc"); 1215862580dSKyle Evans nctx->impl = impl; 1225862580dSKyle Evans 1235862580dSKyle Evans ret = 0; 1245862580dSKyle Evans if (ops->pkgsign_new != NULL) 1255862580dSKyle Evans ret = (*ops->pkgsign_new)(name, nctx); 1265862580dSKyle Evans 1275862580dSKyle Evans if (ret != 0) { 1285862580dSKyle Evans free(nctx); 1295862580dSKyle Evans return (ret); 1305862580dSKyle Evans } 1315862580dSKyle Evans 1325862580dSKyle Evans *ctx = nctx; 1335862580dSKyle Evans return (0); 1345862580dSKyle Evans } 1355862580dSKyle Evans 1365862580dSKyle Evans static bool 1375862580dSKyle Evans pkgsign_verify_cert(const struct pkgsign_ctx *ctx, int fd, const char *sigfile, 1385862580dSKyle Evans const unsigned char *key, int keylen, unsigned char *sig, int siglen) 1395862580dSKyle Evans { 1405862580dSKyle Evans 1415862580dSKyle Evans return ((*ctx->impl->pi_ops->pkgsign_verify_cert)(ctx, fd, sigfile, 1425862580dSKyle Evans key, keylen, sig, siglen)); 1435862580dSKyle Evans } 1445862580dSKyle Evans 1455862580dSKyle Evans static int 1463aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 1473aa4b42aSBaptiste Daroussin { 1483aa4b42aSBaptiste Daroussin struct archive *a; 1493aa4b42aSBaptiste Daroussin struct archive_entry *ae; 1503aa4b42aSBaptiste Daroussin char *end; 1513aa4b42aSBaptiste Daroussin int ret, r; 1523aa4b42aSBaptiste Daroussin 153a6454741SBaptiste Daroussin ret = -1; 1543aa4b42aSBaptiste Daroussin a = archive_read_new(); 155a6454741SBaptiste Daroussin if (a == NULL) { 156a6454741SBaptiste Daroussin warn("archive_read_new"); 157a6454741SBaptiste Daroussin return (ret); 158a6454741SBaptiste Daroussin } 159ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1603aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1613aa4b42aSBaptiste Daroussin 162a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 163a6454741SBaptiste Daroussin warn("lseek"); 164a6454741SBaptiste Daroussin goto cleanup; 165a6454741SBaptiste Daroussin } 1663aa4b42aSBaptiste Daroussin 1673aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 168a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1693aa4b42aSBaptiste Daroussin goto cleanup; 1703aa4b42aSBaptiste Daroussin } 1713aa4b42aSBaptiste Daroussin 1723aa4b42aSBaptiste Daroussin ae = NULL; 1733aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1743aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1753aa4b42aSBaptiste Daroussin if (end == NULL) 1763aa4b42aSBaptiste Daroussin continue; 1773aa4b42aSBaptiste Daroussin 1783aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1793aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1803aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1813aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1823aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 183a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1843aa4b42aSBaptiste Daroussin break; 1853aa4b42aSBaptiste Daroussin } 1863aa4b42aSBaptiste Daroussin } 1873aa4b42aSBaptiste Daroussin 188a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 189a6454741SBaptiste Daroussin ret = 0; 190a6454741SBaptiste Daroussin else 1914622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1924622bc4eSGavin Atkinson archive_error_string(a)); 1933aa4b42aSBaptiste Daroussin 1943aa4b42aSBaptiste Daroussin cleanup: 195ff75c36aSBaptiste Daroussin archive_read_free(a); 1963b05c2a8SBaptiste Daroussin return (ret); 1973aa4b42aSBaptiste Daroussin 1983aa4b42aSBaptiste Daroussin } 1993aa4b42aSBaptiste Daroussin 2003aa4b42aSBaptiste Daroussin static int 2015212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 2023aa4b42aSBaptiste Daroussin { 2033aa4b42aSBaptiste Daroussin int pstat; 2043aa4b42aSBaptiste Daroussin pid_t pid; 2053aa4b42aSBaptiste Daroussin 2063aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 2073aa4b42aSBaptiste Daroussin case -1: 2083aa4b42aSBaptiste Daroussin return (-1); 2093aa4b42aSBaptiste Daroussin case 0: 2105212e8baSBryan Drewery if (force) 2115212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 2125212e8baSBryan Drewery (char *)NULL); 2135212e8baSBryan Drewery else 2145212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 2155212e8baSBryan Drewery (char *)NULL); 2163b05c2a8SBaptiste Daroussin _exit(1); 2173aa4b42aSBaptiste Daroussin default: 2183aa4b42aSBaptiste Daroussin break; 2193aa4b42aSBaptiste Daroussin } 2203aa4b42aSBaptiste Daroussin 221a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 2223aa4b42aSBaptiste Daroussin if (errno != EINTR) 2233aa4b42aSBaptiste Daroussin return (-1); 2243aa4b42aSBaptiste Daroussin 225a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 2263aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 227a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 228a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 229a6454741SBaptiste Daroussin return (pstat); 2303aa4b42aSBaptiste Daroussin } 2313aa4b42aSBaptiste Daroussin 2323aa4b42aSBaptiste Daroussin static int 233ae994fdcSBaptiste Daroussin fetch_to_fd(const char *url, char *path, const char *fetchOpts) 2343aa4b42aSBaptiste Daroussin { 23529aaa961SBaptiste Daroussin struct url *u; 23629aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 237a6454741SBaptiste Daroussin struct url_stat st; 238f12db248SBryan Drewery FILE *remote; 239f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 240f12db248SBryan Drewery int fd; 241f12db248SBryan Drewery int retry, max_retry; 242cc36fe49SBaptiste Daroussin ssize_t r; 243f12db248SBryan Drewery char buf[10240]; 244f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 245f12db248SBryan Drewery static const char *mirror_type = NULL; 2463aa4b42aSBaptiste Daroussin 24729aaa961SBaptiste Daroussin max_retry = 3; 24829aaa961SBaptiste Daroussin current = mirrors = NULL; 249f12db248SBryan Drewery remote = NULL; 2503aa4b42aSBaptiste Daroussin 251f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 252f12db248SBryan Drewery != 0) { 2539950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 2549950eceeSBaptiste Daroussin return (-1); 2559950eceeSBaptiste Daroussin } 25662940ea9SBryan Drewery 257f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2583aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2593b05c2a8SBaptiste Daroussin return (-1); 2603aa4b42aSBaptiste Daroussin } 2613aa4b42aSBaptiste Daroussin 26229aaa961SBaptiste Daroussin retry = max_retry; 26329aaa961SBaptiste Daroussin 26479fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 26579fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 26679fe80efSBaptiste Daroussin return (-1); 26779fe80efSBaptiste Daroussin } 26879fe80efSBaptiste Daroussin 26929aaa961SBaptiste Daroussin while (remote == NULL) { 27029aaa961SBaptiste Daroussin if (retry == max_retry) { 2719950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2729950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 27329aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 27429aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 27529aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 27629aaa961SBaptiste Daroussin current = mirrors; 27729aaa961SBaptiste Daroussin } 27829aaa961SBaptiste Daroussin } 27929aaa961SBaptiste Daroussin 28035e07a7aSBaptiste Daroussin if (mirrors != NULL) { 28129aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 28235e07a7aSBaptiste Daroussin u->port = current->port; 28335e07a7aSBaptiste Daroussin } 28429aaa961SBaptiste Daroussin 285ae994fdcSBaptiste Daroussin remote = fetchXGet(u, &st, fetchOpts); 28629aaa961SBaptiste Daroussin if (remote == NULL) { 28729aaa961SBaptiste Daroussin --retry; 28829aaa961SBaptiste Daroussin if (retry <= 0) 28929aaa961SBaptiste Daroussin goto fetchfail; 29060b92ba9SJohn Hood if (mirrors != NULL) { 29129aaa961SBaptiste Daroussin current = current->next; 29229aaa961SBaptiste Daroussin if (current == NULL) 29329aaa961SBaptiste Daroussin current = mirrors; 29429aaa961SBaptiste Daroussin } 29529aaa961SBaptiste Daroussin } 29629aaa961SBaptiste Daroussin } 297a6454741SBaptiste Daroussin 298cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 2993aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 3003aa4b42aSBaptiste Daroussin warn("write()"); 301f12db248SBryan Drewery goto fetchfail; 3023aa4b42aSBaptiste Daroussin } 303cc36fe49SBaptiste Daroussin } 3043aa4b42aSBaptiste Daroussin 305cc36fe49SBaptiste Daroussin if (r != 0) { 306cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 307cc36fe49SBaptiste Daroussin goto fetchfail; 3083aa4b42aSBaptiste Daroussin } 3093aa4b42aSBaptiste Daroussin 310a6454741SBaptiste Daroussin if (ferror(remote)) 311a6454741SBaptiste Daroussin goto fetchfail; 3123aa4b42aSBaptiste Daroussin 313f12db248SBryan Drewery goto cleanup; 314f12db248SBryan Drewery 315f12db248SBryan Drewery fetchfail: 316f12db248SBryan Drewery if (fd != -1) { 317f12db248SBryan Drewery close(fd); 318f12db248SBryan Drewery fd = -1; 319f12db248SBryan Drewery unlink(path); 320f12db248SBryan Drewery } 321f12db248SBryan Drewery 322f12db248SBryan Drewery cleanup: 323f12db248SBryan Drewery if (remote != NULL) 324f12db248SBryan Drewery fclose(remote); 325f12db248SBryan Drewery 326f12db248SBryan Drewery return fd; 327f12db248SBryan Drewery } 328f12db248SBryan Drewery 329f12db248SBryan Drewery static struct fingerprint * 3308a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 331f12db248SBryan Drewery { 332b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 3338a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 3348a7d859eSBaptiste Daroussin const char *function, *fp, *key; 335f12db248SBryan Drewery struct fingerprint *f; 336f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 337f12db248SBryan Drewery 338f12db248SBryan Drewery function = fp = NULL; 339f12db248SBryan Drewery 3408a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 3418a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 3428a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 3438a7d859eSBaptiste Daroussin continue; 3448a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 3458a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 346f12db248SBryan Drewery continue; 347f12db248SBryan Drewery } 3488a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 3498a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 350f12db248SBryan Drewery continue; 351f12db248SBryan Drewery } 352f12db248SBryan Drewery } 353f12db248SBryan Drewery 354f12db248SBryan Drewery if (fp == NULL || function == NULL) 355f12db248SBryan Drewery return (NULL); 356f12db248SBryan Drewery 357f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 358f12db248SBryan Drewery fct = HASH_SHA256; 359f12db248SBryan Drewery 360f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 361d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 362f12db248SBryan Drewery return (NULL); 363f12db248SBryan Drewery } 364f12db248SBryan Drewery 365f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 366f12db248SBryan Drewery f->type = fct; 367f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 368f12db248SBryan Drewery 369f12db248SBryan Drewery return (f); 370f12db248SBryan Drewery } 371f12db248SBryan Drewery 372516aaf7cSBryan Drewery static void 373516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 374516aaf7cSBryan Drewery { 375d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 376516aaf7cSBryan Drewery 377d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 378516aaf7cSBryan Drewery free(fingerprint->name); 379516aaf7cSBryan Drewery free(fingerprint); 380516aaf7cSBryan Drewery } 381516aaf7cSBryan Drewery free(list); 382516aaf7cSBryan Drewery } 383516aaf7cSBryan Drewery 384f12db248SBryan Drewery static struct fingerprint * 385f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 386f12db248SBryan Drewery { 3878a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 3888a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 389f12db248SBryan Drewery struct fingerprint *f; 390f12db248SBryan Drewery char path[MAXPATHLEN]; 391f12db248SBryan Drewery 392f12db248SBryan Drewery f = NULL; 393f12db248SBryan Drewery 394f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 395f12db248SBryan Drewery 3968a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 3978a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 3988a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 3998a7d859eSBaptiste Daroussin ucl_parser_free(p); 400f12db248SBryan Drewery return (NULL); 4018a7d859eSBaptiste Daroussin } 402f12db248SBryan Drewery 4038a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 404f12db248SBryan Drewery 4058a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 4068a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 407f12db248SBryan Drewery 4088a7d859eSBaptiste Daroussin if (f != NULL) 409516aaf7cSBryan Drewery f->name = strdup(filename); 410f12db248SBryan Drewery 411b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 4128a7d859eSBaptiste Daroussin ucl_parser_free(p); 413f12db248SBryan Drewery 414f12db248SBryan Drewery return (f); 415f12db248SBryan Drewery } 416f12db248SBryan Drewery 417f12db248SBryan Drewery static struct fingerprint_list * 418f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 419f12db248SBryan Drewery { 420f12db248SBryan Drewery DIR *d; 421f12db248SBryan Drewery struct dirent *ent; 422f12db248SBryan Drewery struct fingerprint *finger; 423f12db248SBryan Drewery struct fingerprint_list *fingerprints; 424f12db248SBryan Drewery 425f12db248SBryan Drewery *count = 0; 426f12db248SBryan Drewery 427f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 428f12db248SBryan Drewery if (fingerprints == NULL) 429f12db248SBryan Drewery return (NULL); 430f12db248SBryan Drewery STAILQ_INIT(fingerprints); 431f12db248SBryan Drewery 43292947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 43392947daaSBaptiste Daroussin free(fingerprints); 43492947daaSBaptiste Daroussin 435f12db248SBryan Drewery return (NULL); 43692947daaSBaptiste Daroussin } 437f12db248SBryan Drewery 438f12db248SBryan Drewery while ((ent = readdir(d))) { 439f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 440f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 441f12db248SBryan Drewery continue; 442f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 443f12db248SBryan Drewery if (finger != NULL) { 444f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 445f12db248SBryan Drewery ++(*count); 446f12db248SBryan Drewery } 447f12db248SBryan Drewery } 448f12db248SBryan Drewery 449f12db248SBryan Drewery closedir(d); 450f12db248SBryan Drewery 451f12db248SBryan Drewery return (fingerprints); 452f12db248SBryan Drewery } 453f12db248SBryan Drewery 454*2ecfc040SKyle Evans char * 455*2ecfc040SKyle Evans pkg_read_fd(int fd, size_t *osz) 456*2ecfc040SKyle Evans { 457*2ecfc040SKyle Evans char *obuf; 458*2ecfc040SKyle Evans char buf[4096]; 459*2ecfc040SKyle Evans FILE *fp; 460*2ecfc040SKyle Evans ssize_t r; 461*2ecfc040SKyle Evans 462*2ecfc040SKyle Evans obuf = NULL; 463*2ecfc040SKyle Evans *osz = 0; 464*2ecfc040SKyle Evans fp = open_memstream(&obuf, osz); 465*2ecfc040SKyle Evans if (fp == NULL) 466*2ecfc040SKyle Evans err(EXIT_FAILURE, "open_memstream()"); 467*2ecfc040SKyle Evans 468*2ecfc040SKyle Evans while ((r = read(fd, buf, sizeof(buf))) >0) { 469*2ecfc040SKyle Evans fwrite(buf, 1, r, fp); 470*2ecfc040SKyle Evans } 471*2ecfc040SKyle Evans 472*2ecfc040SKyle Evans if (ferror(fp)) 473*2ecfc040SKyle Evans errx(EXIT_FAILURE, "reading file"); 474*2ecfc040SKyle Evans 475*2ecfc040SKyle Evans fclose(fp); 476*2ecfc040SKyle Evans 477*2ecfc040SKyle Evans return (obuf); 478*2ecfc040SKyle Evans } 479*2ecfc040SKyle Evans 48061acb458SBaptiste Daroussin static struct pubkey * 48161acb458SBaptiste Daroussin read_pubkey(int fd) 48261acb458SBaptiste Daroussin { 48361acb458SBaptiste Daroussin struct pubkey *pk; 484cc9a8a11SBaptiste Daroussin char *sigb; 485cc9a8a11SBaptiste Daroussin size_t sigsz; 48661acb458SBaptiste Daroussin 48761acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 48861acb458SBaptiste Daroussin warn("lseek"); 48961acb458SBaptiste Daroussin return (NULL); 49061acb458SBaptiste Daroussin } 49161acb458SBaptiste Daroussin 492*2ecfc040SKyle Evans sigb = pkg_read_fd(fd, &sigsz); 49361acb458SBaptiste Daroussin 49461acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 495cc9a8a11SBaptiste Daroussin pk->siglen = sigsz; 49661acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 497cc9a8a11SBaptiste Daroussin memcpy(pk->sig, sigb, pk->siglen); 498cc9a8a11SBaptiste Daroussin free(sigb); 49961acb458SBaptiste Daroussin 50061acb458SBaptiste Daroussin return (pk); 50161acb458SBaptiste Daroussin } 50261acb458SBaptiste Daroussin 503f12db248SBryan Drewery static struct sig_cert * 504f12db248SBryan Drewery parse_cert(int fd) { 505f12db248SBryan Drewery int my_fd; 506f12db248SBryan Drewery struct sig_cert *sc; 507cc9a8a11SBaptiste Daroussin FILE *fp, *sigfp, *certfp, *tmpfp; 508f12db248SBryan Drewery char *line; 509cc9a8a11SBaptiste Daroussin char *sig, *cert; 510cc9a8a11SBaptiste Daroussin size_t linecap, sigsz, certsz; 511f12db248SBryan Drewery ssize_t linelen; 512f12db248SBryan Drewery 513f12db248SBryan Drewery sc = NULL; 514f12db248SBryan Drewery line = NULL; 515f12db248SBryan Drewery linecap = 0; 516cc9a8a11SBaptiste Daroussin sig = cert = NULL; 517cc9a8a11SBaptiste Daroussin sigfp = certfp = tmpfp = NULL; 518f12db248SBryan Drewery 519f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 520f12db248SBryan Drewery warn("lseek"); 521f12db248SBryan Drewery return (NULL); 522f12db248SBryan Drewery } 523f12db248SBryan Drewery 524f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 525f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 526f12db248SBryan Drewery warnx("dup"); 527f12db248SBryan Drewery return (NULL); 528f12db248SBryan Drewery } 529f12db248SBryan Drewery 530f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 531f12db248SBryan Drewery warn("fdopen"); 532f12db248SBryan Drewery close(my_fd); 533f12db248SBryan Drewery return (NULL); 534f12db248SBryan Drewery } 535f12db248SBryan Drewery 536cc9a8a11SBaptiste Daroussin sigsz = certsz = 0; 537cc9a8a11SBaptiste Daroussin sigfp = open_memstream(&sig, &sigsz); 538cc9a8a11SBaptiste Daroussin if (sigfp == NULL) 539cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 540cc9a8a11SBaptiste Daroussin certfp = open_memstream(&cert, &certsz); 541cc9a8a11SBaptiste Daroussin if (certfp == NULL) 542cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 543f12db248SBryan Drewery 544f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 545f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 546cc9a8a11SBaptiste Daroussin tmpfp = sigfp; 547f12db248SBryan Drewery continue; 548f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 549cc9a8a11SBaptiste Daroussin tmpfp = certfp; 550f12db248SBryan Drewery continue; 551f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 552f12db248SBryan Drewery break; 553f12db248SBryan Drewery } 554cc9a8a11SBaptiste Daroussin if (tmpfp != NULL) 555cc9a8a11SBaptiste Daroussin fwrite(line, 1, linelen, tmpfp); 556f12db248SBryan Drewery } 557f12db248SBryan Drewery 558f12db248SBryan Drewery fclose(fp); 559cc9a8a11SBaptiste Daroussin fclose(sigfp); 560cc9a8a11SBaptiste Daroussin fclose(certfp); 561f12db248SBryan Drewery 562f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 563cc9a8a11SBaptiste Daroussin sc->siglen = sigsz -1; /* Trim out unrelated trailing newline */ 564cc9a8a11SBaptiste Daroussin sc->sig = sig; 565f12db248SBryan Drewery 566cc9a8a11SBaptiste Daroussin sc->certlen = certsz; 567cc9a8a11SBaptiste Daroussin sc->cert = cert; 568f12db248SBryan Drewery 569f12db248SBryan Drewery return (sc); 570f12db248SBryan Drewery } 571f12db248SBryan Drewery 572f12db248SBryan Drewery static bool 57361acb458SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig) 57461acb458SBaptiste Daroussin { 57561acb458SBaptiste Daroussin struct pubkey *pk; 57661acb458SBaptiste Daroussin const char *pubkey; 5775862580dSKyle Evans struct pkgsign_ctx *sctx; 57861acb458SBaptiste Daroussin bool ret; 57961acb458SBaptiste Daroussin 58061acb458SBaptiste Daroussin pk = NULL; 58161acb458SBaptiste Daroussin pubkey = NULL; 5825862580dSKyle Evans sctx = NULL; 58361acb458SBaptiste Daroussin ret = false; 58461acb458SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 58561acb458SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined"); 58661acb458SBaptiste Daroussin goto cleanup; 58761acb458SBaptiste Daroussin } 58861acb458SBaptiste Daroussin 58961acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 59061acb458SBaptiste Daroussin warnx("Error reading signature"); 59161acb458SBaptiste Daroussin goto cleanup; 59261acb458SBaptiste Daroussin } 59361acb458SBaptiste Daroussin 5945862580dSKyle Evans if (pkgsign_new("rsa", &sctx) != 0) { 5955862580dSKyle Evans warnx("Failed to fetch 'rsa' signer"); 5965862580dSKyle Evans goto cleanup; 5975862580dSKyle Evans } 5985862580dSKyle Evans 59961acb458SBaptiste Daroussin /* Verify the signature. */ 60061acb458SBaptiste Daroussin printf("Verifying signature with public key %s... ", pubkey); 6015862580dSKyle Evans if (pkgsign_verify_cert(sctx, fd_pkg, pubkey, NULL, 0, pk->sig, 60261acb458SBaptiste Daroussin pk->siglen) == false) { 60361acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 60461acb458SBaptiste Daroussin goto cleanup; 60561acb458SBaptiste Daroussin } 60661acb458SBaptiste Daroussin 60761acb458SBaptiste Daroussin ret = true; 60861acb458SBaptiste Daroussin 60961acb458SBaptiste Daroussin cleanup: 61061acb458SBaptiste Daroussin if (pk) { 61161acb458SBaptiste Daroussin free(pk->sig); 61261acb458SBaptiste Daroussin free(pk); 61361acb458SBaptiste Daroussin } 61461acb458SBaptiste Daroussin 61561acb458SBaptiste Daroussin return (ret); 61661acb458SBaptiste Daroussin } 61761acb458SBaptiste Daroussin 61861acb458SBaptiste Daroussin static bool 619f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 620f12db248SBryan Drewery { 621f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 622f12db248SBryan Drewery struct fingerprint *fingerprint; 623f12db248SBryan Drewery struct sig_cert *sc; 6245862580dSKyle Evans struct pkgsign_ctx *sctx; 625f12db248SBryan Drewery bool ret; 626f12db248SBryan Drewery int trusted_count, revoked_count; 627f12db248SBryan Drewery const char *fingerprints; 628f12db248SBryan Drewery char path[MAXPATHLEN]; 629e5dd5bfaSBaptiste Daroussin char *hash; 630f12db248SBryan Drewery 631e5dd5bfaSBaptiste Daroussin hash = NULL; 632516aaf7cSBryan Drewery sc = NULL; 6335862580dSKyle Evans sctx = NULL; 634f12db248SBryan Drewery trusted = revoked = NULL; 635f12db248SBryan Drewery ret = false; 636f12db248SBryan Drewery 637f12db248SBryan Drewery /* Read and parse fingerprints. */ 638f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 639f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 640f12db248SBryan Drewery goto cleanup; 641f12db248SBryan Drewery } 642f12db248SBryan Drewery 643f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 644f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 645f12db248SBryan Drewery warnx("Error loading trusted certificates"); 646f12db248SBryan Drewery goto cleanup; 647f12db248SBryan Drewery } 648f12db248SBryan Drewery 649f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 650f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 651f12db248SBryan Drewery goto cleanup; 652f12db248SBryan Drewery } 653f12db248SBryan Drewery 654f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 655f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 656f12db248SBryan Drewery warnx("Error loading revoked certificates"); 657f12db248SBryan Drewery goto cleanup; 658f12db248SBryan Drewery } 659f12db248SBryan Drewery 660f12db248SBryan Drewery /* Read certificate and signature in. */ 661f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 662f12db248SBryan Drewery warnx("Error parsing certificate"); 663f12db248SBryan Drewery goto cleanup; 664f12db248SBryan Drewery } 665f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 666f12db248SBryan Drewery sc->trusted = false; 667f12db248SBryan Drewery 668f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 669e5dd5bfaSBaptiste Daroussin hash = sha256_buf(sc->cert, sc->certlen); 670f12db248SBryan Drewery 671f12db248SBryan Drewery /* Check if this hash is revoked */ 672f12db248SBryan Drewery if (revoked != NULL) { 673f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 674f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 675516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 676516aaf7cSBryan Drewery "revoked certificate %s\n", 677516aaf7cSBryan Drewery fingerprint->name); 678f12db248SBryan Drewery goto cleanup; 679f12db248SBryan Drewery } 680f12db248SBryan Drewery } 681f12db248SBryan Drewery } 682f12db248SBryan Drewery 683f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 684f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 685f12db248SBryan Drewery sc->trusted = true; 686516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 687f12db248SBryan Drewery break; 688f12db248SBryan Drewery } 689f12db248SBryan Drewery } 690f12db248SBryan Drewery 691f12db248SBryan Drewery if (sc->trusted == false) { 692516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 693f12db248SBryan Drewery "package's certificate\n"); 694f12db248SBryan Drewery goto cleanup; 695f12db248SBryan Drewery } 696f12db248SBryan Drewery 6975862580dSKyle Evans if (pkgsign_new("rsa", &sctx) != 0) { 6985862580dSKyle Evans fprintf(stderr, "Failed to fetch 'rsa' signer\n"); 6995862580dSKyle Evans goto cleanup; 7005862580dSKyle Evans } 7015862580dSKyle Evans 702f12db248SBryan Drewery /* Verify the signature. */ 703516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 7045862580dSKyle Evans if (pkgsign_verify_cert(sctx, fd_pkg, NULL, sc->cert, sc->certlen, 7055862580dSKyle Evans sc->sig, sc->siglen) == false) { 706f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 707f12db248SBryan Drewery goto cleanup; 708f12db248SBryan Drewery } 709f12db248SBryan Drewery 710f12db248SBryan Drewery ret = true; 711f12db248SBryan Drewery 712f12db248SBryan Drewery cleanup: 713e5dd5bfaSBaptiste Daroussin free(hash); 714516aaf7cSBryan Drewery if (trusted) 715516aaf7cSBryan Drewery free_fingerprint_list(trusted); 716516aaf7cSBryan Drewery if (revoked) 717516aaf7cSBryan Drewery free_fingerprint_list(revoked); 718f12db248SBryan Drewery if (sc) { 719f12db248SBryan Drewery free(sc->cert); 720f12db248SBryan Drewery free(sc->sig); 721516aaf7cSBryan Drewery free(sc->name); 722f12db248SBryan Drewery free(sc); 723f12db248SBryan Drewery } 724f12db248SBryan Drewery 725f12db248SBryan Drewery return (ret); 726f12db248SBryan Drewery } 727f12db248SBryan Drewery 728f12db248SBryan Drewery static int 729ae994fdcSBaptiste Daroussin bootstrap_pkg(bool force, const char *fetchOpts) 730f12db248SBryan Drewery { 731f12db248SBryan Drewery int fd_pkg, fd_sig; 732f12db248SBryan Drewery int ret; 733f12db248SBryan Drewery char url[MAXPATHLEN]; 734f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 735f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 736f12db248SBryan Drewery const char *packagesite; 737f12db248SBryan Drewery const char *signature_type; 738f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 739a2aac2f5SBaptiste Daroussin const char *bootstrap_name; 740f12db248SBryan Drewery 741f12db248SBryan Drewery fd_sig = -1; 742f12db248SBryan Drewery ret = -1; 743f12db248SBryan Drewery 744f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 745f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 746f12db248SBryan Drewery return (-1); 747f12db248SBryan Drewery } 748f12db248SBryan Drewery 749f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 750f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 751f12db248SBryan Drewery return (-1); 752f12db248SBryan Drewery } 753f12db248SBryan Drewery 754f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 755f12db248SBryan Drewery 756f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 757f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 758f12db248SBryan Drewery no A record. */ 759f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 760f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 761f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 762a2aac2f5SBaptiste Daroussin for (int j = 0; bootstrap_names[j] != NULL; j++) { 763a2aac2f5SBaptiste Daroussin bootstrap_name = bootstrap_names[j]; 764f12db248SBryan Drewery 765a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s", packagesite, bootstrap_name); 766a2aac2f5SBaptiste Daroussin snprintf(tmppkg, MAXPATHLEN, "%s/%s.XXXXXX", 767a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 768a2aac2f5SBaptiste Daroussin bootstrap_name); 769a2aac2f5SBaptiste Daroussin if ((fd_pkg = fetch_to_fd(url, tmppkg, fetchOpts)) != -1) 770a2aac2f5SBaptiste Daroussin break; 771a2aac2f5SBaptiste Daroussin bootstrap_name = NULL; 772a2aac2f5SBaptiste Daroussin } 773a2aac2f5SBaptiste Daroussin if (bootstrap_name == NULL) 774f12db248SBryan Drewery goto fetchfail; 775f12db248SBryan Drewery 776f12db248SBryan Drewery if (signature_type != NULL && 77748f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 77861acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 77948f92706SXin LI 780a2aac2f5SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX", 781a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 782a2aac2f5SBaptiste Daroussin bootstrap_name); 783a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig", 784a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 785f12db248SBryan Drewery 786ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 78761acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 78861acb458SBaptiste Daroussin "available.\n"); 789f12db248SBryan Drewery goto fetchfail; 790f12db248SBryan Drewery } 791f12db248SBryan Drewery 792f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 793f12db248SBryan Drewery goto cleanup; 79461acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 79561acb458SBaptiste Daroussin 79661acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 797a2aac2f5SBaptiste Daroussin "%s/%s.pubkeysig.XXXXXX", 798a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 799a2aac2f5SBaptiste Daroussin bootstrap_name); 800a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.pubkeysig", 801a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 80261acb458SBaptiste Daroussin 803ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 80461acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 80561acb458SBaptiste Daroussin "available.\n"); 80661acb458SBaptiste Daroussin goto fetchfail; 80761acb458SBaptiste Daroussin } 80861acb458SBaptiste Daroussin 80961acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 81061acb458SBaptiste Daroussin goto cleanup; 81161acb458SBaptiste Daroussin } else { 81261acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 81361acb458SBaptiste Daroussin "bootstrapping.", signature_type); 81461acb458SBaptiste Daroussin goto cleanup; 81561acb458SBaptiste Daroussin } 816f12db248SBryan Drewery } 817f12db248SBryan Drewery 818f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 8195212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 8203aa4b42aSBaptiste Daroussin 821a6454741SBaptiste Daroussin goto cleanup; 822a6454741SBaptiste Daroussin 823a6454741SBaptiste Daroussin fetchfail: 824be924340SEd Maste for (int j = 0; bootstrap_names[j] != NULL; j++) { 825be924340SEd Maste warnx("Attempted to fetch %s/Latest/%s", packagesite, 826be924340SEd Maste bootstrap_names[j]); 827be924340SEd Maste } 828be924340SEd Maste warnx("Error: %s", fetchLastErrString); 829a10f71c5STom Jones if (fetchLastErrCode == FETCH_RESOLV) { 830a10f71c5STom Jones fprintf(stderr, "Address resolution failed for %s.\n", packagesite); 831a10f71c5STom Jones fprintf(stderr, "Consider changing PACKAGESITE.\n"); 832a10f71c5STom Jones } else { 8334ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 8344ff9a7efSBryan Drewery "your system.\n"); 8354ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 8364ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 837a10f71c5STom Jones } 838a6454741SBaptiste Daroussin 8393aa4b42aSBaptiste Daroussin cleanup: 840f12db248SBryan Drewery if (fd_sig != -1) { 841f12db248SBryan Drewery close(fd_sig); 842f12db248SBryan Drewery unlink(tmpsig); 843f12db248SBryan Drewery } 84492947daaSBaptiste Daroussin 84592947daaSBaptiste Daroussin if (fd_pkg != -1) { 846f12db248SBryan Drewery close(fd_pkg); 8473aa4b42aSBaptiste Daroussin unlink(tmppkg); 84892947daaSBaptiste Daroussin } 8493aa4b42aSBaptiste Daroussin 850a6454741SBaptiste Daroussin return (ret); 8513aa4b42aSBaptiste Daroussin } 8523aa4b42aSBaptiste Daroussin 853e18ad51cSAlexander Kabaev static const char confirmation_message[] = 854e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 855e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 856e18ad51cSAlexander Kabaev 857e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 858575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 8591efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 860e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 861575c4095SBaptiste Daroussin 862ae994fdcSBaptiste Daroussin static const char args_bootstrap_message[] = 863ae994fdcSBaptiste Daroussin "Too many arguments\n" 864ae994fdcSBaptiste Daroussin "Usage: pkg [-4|-6] bootstrap [-f] [-y]\n"; 865ae994fdcSBaptiste Daroussin 866ae994fdcSBaptiste Daroussin static const char args_add_message[] = 867ae994fdcSBaptiste Daroussin "Too many arguments\n" 868f5c847aeSEd Maste "Usage: pkg add [-f] [-y] {pkg.pkg}\n"; 869ae994fdcSBaptiste Daroussin 870e18ad51cSAlexander Kabaev static int 871e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 872e18ad51cSAlexander Kabaev { 873e18ad51cSAlexander Kabaev int ret, c; 874e18ad51cSAlexander Kabaev 87567c9f60eSPoul-Henning Kamp fflush(stdout); 876e18ad51cSAlexander Kabaev c = getchar(); 877e18ad51cSAlexander Kabaev 878e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 879e18ad51cSAlexander Kabaev ret = 1; 880e18ad51cSAlexander Kabaev else 881e18ad51cSAlexander Kabaev ret = 0; 882e18ad51cSAlexander Kabaev 883e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 884e18ad51cSAlexander Kabaev c = getchar(); 885e18ad51cSAlexander Kabaev 886e18ad51cSAlexander Kabaev return (ret); 887e18ad51cSAlexander Kabaev } 888e18ad51cSAlexander Kabaev 88952cb76feSBryan Drewery static int 8905212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 89152cb76feSBryan Drewery { 89252cb76feSBryan Drewery char path[MAXPATHLEN]; 89352cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 89452cb76feSBryan Drewery const char *signature_type; 89552cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 89652cb76feSBryan Drewery 89752cb76feSBryan Drewery fd_sig = -1; 89852cb76feSBryan Drewery ret = -1; 89952cb76feSBryan Drewery 90052cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 90152cb76feSBryan Drewery if (fd_pkg == -1) 90252cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 90352cb76feSBryan Drewery 90452cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 90552cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 90692947daaSBaptiste Daroussin goto cleanup; 90752cb76feSBryan Drewery } 90852cb76feSBryan Drewery if (signature_type != NULL && 90948f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 91061acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 91148f92706SXin LI 91252cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 91352cb76feSBryan Drewery 91452cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 91561acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 91661acb458SBaptiste Daroussin "available.\n"); 91752cb76feSBryan Drewery goto cleanup; 91852cb76feSBryan Drewery } 91952cb76feSBryan Drewery 92052cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 92152cb76feSBryan Drewery goto cleanup; 92261acb458SBaptiste Daroussin 92361acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 92461acb458SBaptiste Daroussin 92561acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 92661acb458SBaptiste Daroussin 92761acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 92861acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 92961acb458SBaptiste Daroussin "available.\n"); 93061acb458SBaptiste Daroussin goto cleanup; 93161acb458SBaptiste Daroussin } 93261acb458SBaptiste Daroussin 93361acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 93461acb458SBaptiste Daroussin goto cleanup; 93561acb458SBaptiste Daroussin 93661acb458SBaptiste Daroussin } else { 93761acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 93861acb458SBaptiste Daroussin "bootstrapping.", signature_type); 93961acb458SBaptiste Daroussin goto cleanup; 94061acb458SBaptiste Daroussin } 94152cb76feSBryan Drewery } 94252cb76feSBryan Drewery 94352cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9445212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 94552cb76feSBryan Drewery 94652cb76feSBryan Drewery cleanup: 94752cb76feSBryan Drewery close(fd_pkg); 94852cb76feSBryan Drewery if (fd_sig != -1) 94952cb76feSBryan Drewery close(fd_sig); 95052cb76feSBryan Drewery 95152cb76feSBryan Drewery return (ret); 95252cb76feSBryan Drewery } 95352cb76feSBryan Drewery 95440b9f924SKyle Evans #define PKG_NAME "pkg" 95540b9f924SKyle Evans #define PKG_DEVEL_NAME PKG_NAME "-devel" 95640b9f924SKyle Evans #define PKG_PKG PKG_NAME "." 95740b9f924SKyle Evans 95840b9f924SKyle Evans static bool 95940b9f924SKyle Evans pkg_is_pkg_pkg(const char *pkg) 96040b9f924SKyle Evans { 961c96b4d87SGleb Smirnoff char *vstart, *basename; 96240b9f924SKyle Evans size_t namelen; 96340b9f924SKyle Evans 964c96b4d87SGleb Smirnoff /* Strip path. */ 965c96b4d87SGleb Smirnoff if ((basename = strrchr(pkg, '/')) != NULL) 966c96b4d87SGleb Smirnoff pkg = basename + 1; 967c96b4d87SGleb Smirnoff 96840b9f924SKyle Evans /* 96940b9f924SKyle Evans * Chop off the final "-" (version delimiter) and check the name that 97040b9f924SKyle Evans * precedes it. If we didn't have a version delimiter, it must be the 97140b9f924SKyle Evans * pkg.$archive short form but we'll check it anyways. pkg-devel short 97240b9f924SKyle Evans * form will look like a pkg archive with 'devel' version, but that's 97340b9f924SKyle Evans * OK. We otherwise assumed that non-pkg packages will always have a 97440b9f924SKyle Evans * version component. 97540b9f924SKyle Evans */ 97640b9f924SKyle Evans vstart = strrchr(pkg, '-'); 97740b9f924SKyle Evans if (vstart == NULL) { 97840b9f924SKyle Evans return (strlen(pkg) > sizeof(PKG_PKG) - 1 && 97940b9f924SKyle Evans strncmp(pkg, PKG_PKG, sizeof(PKG_PKG) - 1) == 0); 98040b9f924SKyle Evans } 98140b9f924SKyle Evans 98240b9f924SKyle Evans namelen = vstart - pkg; 98340b9f924SKyle Evans if (namelen == sizeof(PKG_NAME) - 1 && 98440b9f924SKyle Evans strncmp(pkg, PKG_NAME, sizeof(PKG_NAME) - 1) == 0) 98540b9f924SKyle Evans return (true); 98640b9f924SKyle Evans if (namelen == sizeof(PKG_DEVEL_NAME) - 1 && 98740b9f924SKyle Evans strncmp(pkg, PKG_DEVEL_NAME, sizeof(PKG_DEVEL_NAME) - 1) == 0) 98840b9f924SKyle Evans return (true); 98940b9f924SKyle Evans return (false); 99040b9f924SKyle Evans } 99140b9f924SKyle Evans 9923aa4b42aSBaptiste Daroussin int 99346b67edeSBaptiste Daroussin main(int argc, char *argv[]) 9943aa4b42aSBaptiste Daroussin { 9953aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 99618418e19SKyle Evans const char *pkgarg, *repo_name; 997ae994fdcSBaptiste Daroussin bool activation_test, add_pkg, bootstrap_only, force, yes; 998ae994fdcSBaptiste Daroussin signed char ch; 999ae994fdcSBaptiste Daroussin const char *fetchOpts; 1000ae994fdcSBaptiste Daroussin char *command; 10015212e8baSBryan Drewery 1002ae994fdcSBaptiste Daroussin activation_test = false; 1003ae994fdcSBaptiste Daroussin add_pkg = false; 10045212e8baSBryan Drewery bootstrap_only = false; 1005ae994fdcSBaptiste Daroussin command = NULL; 1006ae994fdcSBaptiste Daroussin fetchOpts = ""; 10075212e8baSBryan Drewery force = false; 10085212e8baSBryan Drewery pkgarg = NULL; 100918418e19SKyle Evans repo_name = NULL; 10105212e8baSBryan Drewery yes = false; 10113aa4b42aSBaptiste Daroussin 1012ae994fdcSBaptiste Daroussin struct option longopts[] = { 1013e9ad2964SBrooks Davis { "debug", no_argument, NULL, 'd' }, 1014ae994fdcSBaptiste Daroussin { "force", no_argument, NULL, 'f' }, 1015ae994fdcSBaptiste Daroussin { "only-ipv4", no_argument, NULL, '4' }, 1016ae994fdcSBaptiste Daroussin { "only-ipv6", no_argument, NULL, '6' }, 1017ae994fdcSBaptiste Daroussin { "yes", no_argument, NULL, 'y' }, 1018ae994fdcSBaptiste Daroussin { NULL, 0, NULL, 0 }, 1019ae994fdcSBaptiste Daroussin }; 1020ae994fdcSBaptiste Daroussin 102156d11d4aSStefan Eßer snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase()); 10223aa4b42aSBaptiste Daroussin 1023e9ad2964SBrooks Davis while ((ch = getopt_long(argc, argv, "-:dfr::yN46", longopts, NULL)) != -1) { 1024ae994fdcSBaptiste Daroussin switch (ch) { 1025e9ad2964SBrooks Davis case 'd': 1026e9ad2964SBrooks Davis debug++; 1027e9ad2964SBrooks Davis break; 1028ae994fdcSBaptiste Daroussin case 'f': 1029ae994fdcSBaptiste Daroussin force = true; 1030ae994fdcSBaptiste Daroussin break; 1031ae994fdcSBaptiste Daroussin case 'N': 1032ae994fdcSBaptiste Daroussin activation_test = true; 1033ae994fdcSBaptiste Daroussin break; 1034ae994fdcSBaptiste Daroussin case 'y': 1035ae994fdcSBaptiste Daroussin yes = true; 1036ae994fdcSBaptiste Daroussin break; 1037ae994fdcSBaptiste Daroussin case '4': 1038ae994fdcSBaptiste Daroussin fetchOpts = "4"; 1039ae994fdcSBaptiste Daroussin break; 1040ae994fdcSBaptiste Daroussin case '6': 1041ae994fdcSBaptiste Daroussin fetchOpts = "6"; 1042ae994fdcSBaptiste Daroussin break; 104318418e19SKyle Evans case 'r': 104418418e19SKyle Evans /* 104518418e19SKyle Evans * The repository can only be specified for an explicit 104618418e19SKyle Evans * bootstrap request at this time, so that we don't 104718418e19SKyle Evans * confuse the user if they're trying to use a verb that 104818418e19SKyle Evans * has some other conflicting meaning but we need to 104918418e19SKyle Evans * bootstrap. 105018418e19SKyle Evans * 105118418e19SKyle Evans * For that reason, we specify that -r has an optional 105218418e19SKyle Evans * argument above and process the next index ourselves. 105318418e19SKyle Evans * This is mostly significant because getopt(3) will 105418418e19SKyle Evans * otherwise eat the next argument, which could be 105518418e19SKyle Evans * something we need to try and make sense of. 105618418e19SKyle Evans * 105718418e19SKyle Evans * At worst this gets us false positives that we ignore 105818418e19SKyle Evans * in other contexts, and we have to do a little fudging 105918418e19SKyle Evans * in order to support separating -r from the reponame 106018418e19SKyle Evans * with a space since it's not actually optional in 106118418e19SKyle Evans * the bootstrap/add sense. 106218418e19SKyle Evans */ 106318418e19SKyle Evans if (add_pkg || bootstrap_only) { 106418418e19SKyle Evans if (optarg != NULL) { 106518418e19SKyle Evans repo_name = optarg; 106618418e19SKyle Evans } else if (optind < argc) { 106718418e19SKyle Evans repo_name = argv[optind]; 106818418e19SKyle Evans } 106918418e19SKyle Evans 107018418e19SKyle Evans if (repo_name == NULL || *repo_name == '\0') { 107118418e19SKyle Evans fprintf(stderr, 107218418e19SKyle Evans "Must specify a repository with -r!\n"); 107318418e19SKyle Evans exit(EXIT_FAILURE); 107418418e19SKyle Evans } 107518418e19SKyle Evans 107618418e19SKyle Evans if (optarg == NULL) { 107718418e19SKyle Evans /* Advance past repo name. */ 107818418e19SKyle Evans optreset = 1; 107918418e19SKyle Evans optind++; 108018418e19SKyle Evans } 108118418e19SKyle Evans } 108218418e19SKyle Evans break; 1083ae994fdcSBaptiste Daroussin case 1: 1084ae994fdcSBaptiste Daroussin // Non-option arguments, first one is the command 1085ae994fdcSBaptiste Daroussin if (command == NULL) { 1086ae994fdcSBaptiste Daroussin command = argv[optind-1]; 1087ae994fdcSBaptiste Daroussin if (strcmp(command, "add") == 0) { 1088ae994fdcSBaptiste Daroussin add_pkg = true; 1089ae994fdcSBaptiste Daroussin } 1090ae994fdcSBaptiste Daroussin else if (strcmp(command, "bootstrap") == 0) { 10915212e8baSBryan Drewery bootstrap_only = true; 1092ae994fdcSBaptiste Daroussin } 1093ae994fdcSBaptiste Daroussin } 1094ae994fdcSBaptiste Daroussin // bootstrap doesn't accept other arguments 1095ae994fdcSBaptiste Daroussin else if (bootstrap_only) { 1096ae994fdcSBaptiste Daroussin fprintf(stderr, args_bootstrap_message); 1097ca7f7593SKyle Evans exit(EXIT_FAILURE); 1098ca7f7593SKyle Evans } 1099ae994fdcSBaptiste Daroussin else if (add_pkg && pkgarg != NULL) { 110040b9f924SKyle Evans /* 110140b9f924SKyle Evans * Additional arguments also means it's not a 110240b9f924SKyle Evans * local bootstrap request. 110340b9f924SKyle Evans */ 110440b9f924SKyle Evans add_pkg = false; 1105ca7f7593SKyle Evans } 1106ae994fdcSBaptiste Daroussin else if (add_pkg) { 110740b9f924SKyle Evans /* 110840b9f924SKyle Evans * If it's not a request for pkg or pkg-devel, 110940b9f924SKyle Evans * then we must assume they were trying to 111040b9f924SKyle Evans * install some other local package and we 111140b9f924SKyle Evans * should try to bootstrap from the repo. 111240b9f924SKyle Evans */ 111340b9f924SKyle Evans if (!pkg_is_pkg_pkg(argv[optind-1])) { 111440b9f924SKyle Evans add_pkg = false; 111540b9f924SKyle Evans } else { 1116ae994fdcSBaptiste Daroussin pkgarg = argv[optind-1]; 1117ae994fdcSBaptiste Daroussin } 111840b9f924SKyle Evans } 1119ae994fdcSBaptiste Daroussin break; 1120ae994fdcSBaptiste Daroussin default: 1121ae994fdcSBaptiste Daroussin break; 1122ae994fdcSBaptiste Daroussin } 11235212e8baSBryan Drewery } 1124e9ad2964SBrooks Davis if (debug > 1) 1125e9ad2964SBrooks Davis fetchDebug = 1; 11265212e8baSBryan Drewery 11275212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1128e18ad51cSAlexander Kabaev /* 1129d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1130ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1131990878b0SGordon Bergling * when that option is passed. 1132ecfed9f2SMatthew Seaman */ 1133ae994fdcSBaptiste Daroussin if (activation_test) 1134e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1135ecfed9f2SMatthew Seaman 113618418e19SKyle Evans config_init(repo_name); 113752cb76feSBryan Drewery 1138ae994fdcSBaptiste Daroussin if (add_pkg) { 11395212e8baSBryan Drewery if (pkgarg == NULL) { 1140f5c847aeSEd Maste fprintf(stderr, "Path to pkg.pkg required\n"); 11415212e8baSBryan Drewery exit(EXIT_FAILURE); 11425212e8baSBryan Drewery } 11435212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 11445212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 11455212e8baSBryan Drewery exit(EXIT_FAILURE); 11465212e8baSBryan Drewery } 11475212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1148b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1149b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1150b70213b5SBaptiste Daroussin } 1151ecfed9f2SMatthew Seaman /* 1152e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1153e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1154e18ad51cSAlexander Kabaev * tucked in there already. 1155e18ad51cSAlexander Kabaev */ 1156ae994fdcSBaptiste Daroussin if (!yes) 11579950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 11589950eceeSBaptiste Daroussin if (!yes) { 1159575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1160e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 11613a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1162575c4095SBaptiste Daroussin } 1163204ea792SBaptiste Daroussin 1164575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1165204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1166e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1167e18ad51cSAlexander Kabaev } 1168ae994fdcSBaptiste Daroussin if (bootstrap_pkg(force, fetchOpts) != 0) 1169a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 11709950eceeSBaptiste Daroussin config_finish(); 1171c3e8a27aSBryan Drewery 11725212e8baSBryan Drewery if (bootstrap_only) 1173c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 11745212e8baSBryan Drewery } else if (bootstrap_only) { 11755212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1176c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1177c3e8a27aSBryan Drewery } 11783aa4b42aSBaptiste Daroussin 11793aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 11803aa4b42aSBaptiste Daroussin 1181a6454741SBaptiste Daroussin /* NOT REACHED */ 11823b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 11833aa4b42aSBaptiste Daroussin } 1184