13aa4b42aSBaptiste Daroussin /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 313aa4b42aSBaptiste Daroussin __FBSDID("$FreeBSD$"); 323aa4b42aSBaptiste Daroussin 333aa4b42aSBaptiste Daroussin #include <sys/param.h> 34f12db248SBryan Drewery #include <sys/queue.h> 35f12db248SBryan Drewery #include <sys/types.h> 363b05c2a8SBaptiste Daroussin #include <sys/wait.h> 373aa4b42aSBaptiste Daroussin 383aa4b42aSBaptiste Daroussin #include <archive.h> 393aa4b42aSBaptiste Daroussin #include <archive_entry.h> 40f12db248SBryan Drewery #include <dirent.h> 413aa4b42aSBaptiste Daroussin #include <err.h> 423aa4b42aSBaptiste Daroussin #include <errno.h> 43b70213b5SBaptiste Daroussin #include <fcntl.h> 443b05c2a8SBaptiste Daroussin #include <fetch.h> 45ae994fdcSBaptiste Daroussin #include <getopt.h> 4656d11d4aSStefan Eßer #include <libutil.h> 47a6454741SBaptiste Daroussin #include <paths.h> 489950eceeSBaptiste Daroussin #include <stdbool.h> 493aa4b42aSBaptiste Daroussin #include <stdlib.h> 503aa4b42aSBaptiste Daroussin #include <stdio.h> 513aa4b42aSBaptiste Daroussin #include <string.h> 528a7d859eSBaptiste Daroussin #include <ucl.h> 53f12db248SBryan Drewery 54f12db248SBryan Drewery #include <openssl/err.h> 55f12db248SBryan Drewery #include <openssl/ssl.h> 563aa4b42aSBaptiste Daroussin 5729aaa961SBaptiste Daroussin #include "dns_utils.h" 589950eceeSBaptiste Daroussin #include "config.h" 59*b2654064SBaptiste Daroussin #include "hash.h" 603aa4b42aSBaptiste Daroussin 61f12db248SBryan Drewery struct sig_cert { 62516aaf7cSBryan Drewery char *name; 63f12db248SBryan Drewery unsigned char *sig; 64f12db248SBryan Drewery int siglen; 65f12db248SBryan Drewery unsigned char *cert; 66f12db248SBryan Drewery int certlen; 67f12db248SBryan Drewery bool trusted; 68f12db248SBryan Drewery }; 69f12db248SBryan Drewery 7061acb458SBaptiste Daroussin struct pubkey { 7161acb458SBaptiste Daroussin unsigned char *sig; 7261acb458SBaptiste Daroussin int siglen; 7361acb458SBaptiste Daroussin }; 7461acb458SBaptiste Daroussin 75f12db248SBryan Drewery typedef enum { 76f12db248SBryan Drewery HASH_UNKNOWN, 77f12db248SBryan Drewery HASH_SHA256, 78f12db248SBryan Drewery } hash_t; 79f12db248SBryan Drewery 80f12db248SBryan Drewery struct fingerprint { 81f12db248SBryan Drewery hash_t type; 82516aaf7cSBryan Drewery char *name; 83f12db248SBryan Drewery char hash[BUFSIZ]; 84f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 85f12db248SBryan Drewery }; 86f12db248SBryan Drewery 87a2aac2f5SBaptiste Daroussin static const char *bootstrap_names [] = { 88c244b1d8SBaptiste Daroussin "pkg.pkg", 89a2aac2f5SBaptiste Daroussin "pkg.txz", 90a2aac2f5SBaptiste Daroussin NULL 91a2aac2f5SBaptiste Daroussin }; 92a2aac2f5SBaptiste Daroussin 93f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 94f12db248SBryan Drewery 95e9ad2964SBrooks Davis static int debug; 96e9ad2964SBrooks Davis 973aa4b42aSBaptiste Daroussin static int 983aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 993aa4b42aSBaptiste Daroussin { 1003aa4b42aSBaptiste Daroussin struct archive *a; 1013aa4b42aSBaptiste Daroussin struct archive_entry *ae; 1023aa4b42aSBaptiste Daroussin char *end; 1033aa4b42aSBaptiste Daroussin int ret, r; 1043aa4b42aSBaptiste Daroussin 105a6454741SBaptiste Daroussin ret = -1; 1063aa4b42aSBaptiste Daroussin a = archive_read_new(); 107a6454741SBaptiste Daroussin if (a == NULL) { 108a6454741SBaptiste Daroussin warn("archive_read_new"); 109a6454741SBaptiste Daroussin return (ret); 110a6454741SBaptiste Daroussin } 111ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1123aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1133aa4b42aSBaptiste Daroussin 114a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 115a6454741SBaptiste Daroussin warn("lseek"); 116a6454741SBaptiste Daroussin goto cleanup; 117a6454741SBaptiste Daroussin } 1183aa4b42aSBaptiste Daroussin 1193aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 120a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1213aa4b42aSBaptiste Daroussin goto cleanup; 1223aa4b42aSBaptiste Daroussin } 1233aa4b42aSBaptiste Daroussin 1243aa4b42aSBaptiste Daroussin ae = NULL; 1253aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1263aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1273aa4b42aSBaptiste Daroussin if (end == NULL) 1283aa4b42aSBaptiste Daroussin continue; 1293aa4b42aSBaptiste Daroussin 1303aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1313aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1323aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1333aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1343aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 135a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1363aa4b42aSBaptiste Daroussin break; 1373aa4b42aSBaptiste Daroussin } 1383aa4b42aSBaptiste Daroussin } 1393aa4b42aSBaptiste Daroussin 140a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 141a6454741SBaptiste Daroussin ret = 0; 142a6454741SBaptiste Daroussin else 1434622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1444622bc4eSGavin Atkinson archive_error_string(a)); 1453aa4b42aSBaptiste Daroussin 1463aa4b42aSBaptiste Daroussin cleanup: 147ff75c36aSBaptiste Daroussin archive_read_free(a); 1483b05c2a8SBaptiste Daroussin return (ret); 1493aa4b42aSBaptiste Daroussin 1503aa4b42aSBaptiste Daroussin } 1513aa4b42aSBaptiste Daroussin 1523aa4b42aSBaptiste Daroussin static int 1535212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1543aa4b42aSBaptiste Daroussin { 1553aa4b42aSBaptiste Daroussin int pstat; 1563aa4b42aSBaptiste Daroussin pid_t pid; 1573aa4b42aSBaptiste Daroussin 1583aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1593aa4b42aSBaptiste Daroussin case -1: 1603aa4b42aSBaptiste Daroussin return (-1); 1613aa4b42aSBaptiste Daroussin case 0: 1625212e8baSBryan Drewery if (force) 1635212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 1645212e8baSBryan Drewery (char *)NULL); 1655212e8baSBryan Drewery else 1665212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 1675212e8baSBryan Drewery (char *)NULL); 1683b05c2a8SBaptiste Daroussin _exit(1); 1693aa4b42aSBaptiste Daroussin default: 1703aa4b42aSBaptiste Daroussin break; 1713aa4b42aSBaptiste Daroussin } 1723aa4b42aSBaptiste Daroussin 173a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1743aa4b42aSBaptiste Daroussin if (errno != EINTR) 1753aa4b42aSBaptiste Daroussin return (-1); 1763aa4b42aSBaptiste Daroussin 177a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1783aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 179a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 180a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 181a6454741SBaptiste Daroussin return (pstat); 1823aa4b42aSBaptiste Daroussin } 1833aa4b42aSBaptiste Daroussin 1843aa4b42aSBaptiste Daroussin static int 185ae994fdcSBaptiste Daroussin fetch_to_fd(const char *url, char *path, const char *fetchOpts) 1863aa4b42aSBaptiste Daroussin { 18729aaa961SBaptiste Daroussin struct url *u; 18829aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 189a6454741SBaptiste Daroussin struct url_stat st; 190f12db248SBryan Drewery FILE *remote; 191f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 192f12db248SBryan Drewery int fd; 193f12db248SBryan Drewery int retry, max_retry; 194cc36fe49SBaptiste Daroussin ssize_t r; 195f12db248SBryan Drewery char buf[10240]; 196f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 197f12db248SBryan Drewery static const char *mirror_type = NULL; 1983aa4b42aSBaptiste Daroussin 19929aaa961SBaptiste Daroussin max_retry = 3; 20029aaa961SBaptiste Daroussin current = mirrors = NULL; 201f12db248SBryan Drewery remote = NULL; 2023aa4b42aSBaptiste Daroussin 203f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 204f12db248SBryan Drewery != 0) { 2059950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 2069950eceeSBaptiste Daroussin return (-1); 2079950eceeSBaptiste Daroussin } 20862940ea9SBryan Drewery 209f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2103aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2113b05c2a8SBaptiste Daroussin return (-1); 2123aa4b42aSBaptiste Daroussin } 2133aa4b42aSBaptiste Daroussin 21429aaa961SBaptiste Daroussin retry = max_retry; 21529aaa961SBaptiste Daroussin 21679fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 21779fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 21879fe80efSBaptiste Daroussin return (-1); 21979fe80efSBaptiste Daroussin } 22079fe80efSBaptiste Daroussin 22129aaa961SBaptiste Daroussin while (remote == NULL) { 22229aaa961SBaptiste Daroussin if (retry == max_retry) { 2239950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2249950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 22529aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 22629aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 22729aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 22829aaa961SBaptiste Daroussin current = mirrors; 22929aaa961SBaptiste Daroussin } 23029aaa961SBaptiste Daroussin } 23129aaa961SBaptiste Daroussin 23235e07a7aSBaptiste Daroussin if (mirrors != NULL) { 23329aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 23435e07a7aSBaptiste Daroussin u->port = current->port; 23535e07a7aSBaptiste Daroussin } 23629aaa961SBaptiste Daroussin 237ae994fdcSBaptiste Daroussin remote = fetchXGet(u, &st, fetchOpts); 23829aaa961SBaptiste Daroussin if (remote == NULL) { 23929aaa961SBaptiste Daroussin --retry; 24029aaa961SBaptiste Daroussin if (retry <= 0) 24129aaa961SBaptiste Daroussin goto fetchfail; 24260b92ba9SJohn Hood if (mirrors != NULL) { 24329aaa961SBaptiste Daroussin current = current->next; 24429aaa961SBaptiste Daroussin if (current == NULL) 24529aaa961SBaptiste Daroussin current = mirrors; 24629aaa961SBaptiste Daroussin } 24729aaa961SBaptiste Daroussin } 24829aaa961SBaptiste Daroussin } 249a6454741SBaptiste Daroussin 250cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 2513aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2523aa4b42aSBaptiste Daroussin warn("write()"); 253f12db248SBryan Drewery goto fetchfail; 2543aa4b42aSBaptiste Daroussin } 255cc36fe49SBaptiste Daroussin } 2563aa4b42aSBaptiste Daroussin 257cc36fe49SBaptiste Daroussin if (r != 0) { 258cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 259cc36fe49SBaptiste Daroussin goto fetchfail; 2603aa4b42aSBaptiste Daroussin } 2613aa4b42aSBaptiste Daroussin 262a6454741SBaptiste Daroussin if (ferror(remote)) 263a6454741SBaptiste Daroussin goto fetchfail; 2643aa4b42aSBaptiste Daroussin 265f12db248SBryan Drewery goto cleanup; 266f12db248SBryan Drewery 267f12db248SBryan Drewery fetchfail: 268f12db248SBryan Drewery if (fd != -1) { 269f12db248SBryan Drewery close(fd); 270f12db248SBryan Drewery fd = -1; 271f12db248SBryan Drewery unlink(path); 272f12db248SBryan Drewery } 273f12db248SBryan Drewery 274f12db248SBryan Drewery cleanup: 275f12db248SBryan Drewery if (remote != NULL) 276f12db248SBryan Drewery fclose(remote); 277f12db248SBryan Drewery 278f12db248SBryan Drewery return fd; 279f12db248SBryan Drewery } 280f12db248SBryan Drewery 281f12db248SBryan Drewery static struct fingerprint * 2828a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 283f12db248SBryan Drewery { 284b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 2858a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 2868a7d859eSBaptiste Daroussin const char *function, *fp, *key; 287f12db248SBryan Drewery struct fingerprint *f; 288f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 289f12db248SBryan Drewery 290f12db248SBryan Drewery function = fp = NULL; 291f12db248SBryan Drewery 2928a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 2938a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 2948a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 2958a7d859eSBaptiste Daroussin continue; 2968a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 2978a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 298f12db248SBryan Drewery continue; 299f12db248SBryan Drewery } 3008a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 3018a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 302f12db248SBryan Drewery continue; 303f12db248SBryan Drewery } 304f12db248SBryan Drewery } 305f12db248SBryan Drewery 306f12db248SBryan Drewery if (fp == NULL || function == NULL) 307f12db248SBryan Drewery return (NULL); 308f12db248SBryan Drewery 309f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 310f12db248SBryan Drewery fct = HASH_SHA256; 311f12db248SBryan Drewery 312f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 313d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 314f12db248SBryan Drewery return (NULL); 315f12db248SBryan Drewery } 316f12db248SBryan Drewery 317f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 318f12db248SBryan Drewery f->type = fct; 319f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 320f12db248SBryan Drewery 321f12db248SBryan Drewery return (f); 322f12db248SBryan Drewery } 323f12db248SBryan Drewery 324516aaf7cSBryan Drewery static void 325516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 326516aaf7cSBryan Drewery { 327d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 328516aaf7cSBryan Drewery 329d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 330516aaf7cSBryan Drewery free(fingerprint->name); 331516aaf7cSBryan Drewery free(fingerprint); 332516aaf7cSBryan Drewery } 333516aaf7cSBryan Drewery free(list); 334516aaf7cSBryan Drewery } 335516aaf7cSBryan Drewery 336f12db248SBryan Drewery static struct fingerprint * 337f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 338f12db248SBryan Drewery { 3398a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 3408a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 341f12db248SBryan Drewery struct fingerprint *f; 342f12db248SBryan Drewery char path[MAXPATHLEN]; 343f12db248SBryan Drewery 344f12db248SBryan Drewery f = NULL; 345f12db248SBryan Drewery 346f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 347f12db248SBryan Drewery 3488a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 3498a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 3508a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 3518a7d859eSBaptiste Daroussin ucl_parser_free(p); 352f12db248SBryan Drewery return (NULL); 3538a7d859eSBaptiste Daroussin } 354f12db248SBryan Drewery 3558a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 356f12db248SBryan Drewery 3578a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 3588a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 359f12db248SBryan Drewery 3608a7d859eSBaptiste Daroussin if (f != NULL) 361516aaf7cSBryan Drewery f->name = strdup(filename); 362f12db248SBryan Drewery 363b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 3648a7d859eSBaptiste Daroussin ucl_parser_free(p); 365f12db248SBryan Drewery 366f12db248SBryan Drewery return (f); 367f12db248SBryan Drewery } 368f12db248SBryan Drewery 369f12db248SBryan Drewery static struct fingerprint_list * 370f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 371f12db248SBryan Drewery { 372f12db248SBryan Drewery DIR *d; 373f12db248SBryan Drewery struct dirent *ent; 374f12db248SBryan Drewery struct fingerprint *finger; 375f12db248SBryan Drewery struct fingerprint_list *fingerprints; 376f12db248SBryan Drewery 377f12db248SBryan Drewery *count = 0; 378f12db248SBryan Drewery 379f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 380f12db248SBryan Drewery if (fingerprints == NULL) 381f12db248SBryan Drewery return (NULL); 382f12db248SBryan Drewery STAILQ_INIT(fingerprints); 383f12db248SBryan Drewery 38492947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 38592947daaSBaptiste Daroussin free(fingerprints); 38692947daaSBaptiste Daroussin 387f12db248SBryan Drewery return (NULL); 38892947daaSBaptiste Daroussin } 389f12db248SBryan Drewery 390f12db248SBryan Drewery while ((ent = readdir(d))) { 391f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 392f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 393f12db248SBryan Drewery continue; 394f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 395f12db248SBryan Drewery if (finger != NULL) { 396f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 397f12db248SBryan Drewery ++(*count); 398f12db248SBryan Drewery } 399f12db248SBryan Drewery } 400f12db248SBryan Drewery 401f12db248SBryan Drewery closedir(d); 402f12db248SBryan Drewery 403f12db248SBryan Drewery return (fingerprints); 404f12db248SBryan Drewery } 405f12db248SBryan Drewery 406f12db248SBryan Drewery static EVP_PKEY * 40761acb458SBaptiste Daroussin load_public_key_file(const char *file) 40861acb458SBaptiste Daroussin { 40961acb458SBaptiste Daroussin EVP_PKEY *pkey; 41061acb458SBaptiste Daroussin BIO *bp; 41161acb458SBaptiste Daroussin char errbuf[1024]; 41261acb458SBaptiste Daroussin 41361acb458SBaptiste Daroussin bp = BIO_new_file(file, "r"); 41461acb458SBaptiste Daroussin if (!bp) 41561acb458SBaptiste Daroussin errx(EXIT_FAILURE, "Unable to read %s", file); 41661acb458SBaptiste Daroussin 41761acb458SBaptiste Daroussin if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 41861acb458SBaptiste Daroussin warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); 41961acb458SBaptiste Daroussin 42061acb458SBaptiste Daroussin BIO_free(bp); 42161acb458SBaptiste Daroussin 42261acb458SBaptiste Daroussin return (pkey); 42361acb458SBaptiste Daroussin } 42461acb458SBaptiste Daroussin 42561acb458SBaptiste Daroussin static EVP_PKEY * 426f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 427f12db248SBryan Drewery { 428f12db248SBryan Drewery EVP_PKEY *pkey; 429f12db248SBryan Drewery BIO *bp; 430f12db248SBryan Drewery char errbuf[1024]; 431f12db248SBryan Drewery 432c2788c07SBryan Drewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 433f12db248SBryan Drewery 434f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 435f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 436f12db248SBryan Drewery 437f12db248SBryan Drewery BIO_free(bp); 438f12db248SBryan Drewery 439f12db248SBryan Drewery return (pkey); 440f12db248SBryan Drewery } 441f12db248SBryan Drewery 442f12db248SBryan Drewery static bool 44361acb458SBaptiste Daroussin rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, 44461acb458SBaptiste Daroussin int keylen, unsigned char *sig, int siglen) 445f12db248SBryan Drewery { 446f12db248SBryan Drewery EVP_MD_CTX *mdctx; 447f12db248SBryan Drewery EVP_PKEY *pkey; 448f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 449f12db248SBryan Drewery char errbuf[1024]; 450f12db248SBryan Drewery bool ret; 451f12db248SBryan Drewery 452f12db248SBryan Drewery pkey = NULL; 453f12db248SBryan Drewery mdctx = NULL; 454f12db248SBryan Drewery ret = false; 455f12db248SBryan Drewery 45661acb458SBaptiste Daroussin SSL_load_error_strings(); 45761acb458SBaptiste Daroussin 458f12db248SBryan Drewery /* Compute SHA256 of the package. */ 459f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 460f12db248SBryan Drewery warn("lseek"); 461f12db248SBryan Drewery goto cleanup; 462f12db248SBryan Drewery } 463f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 464f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 465f12db248SBryan Drewery goto cleanup; 466f12db248SBryan Drewery } 467f12db248SBryan Drewery 46861acb458SBaptiste Daroussin if (sigfile != NULL) { 46961acb458SBaptiste Daroussin if ((pkey = load_public_key_file(sigfile)) == NULL) { 47061acb458SBaptiste Daroussin warnx("Error reading public key"); 47161acb458SBaptiste Daroussin goto cleanup; 47261acb458SBaptiste Daroussin } 47361acb458SBaptiste Daroussin } else { 474f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 475f12db248SBryan Drewery warnx("Error reading public key"); 476f12db248SBryan Drewery goto cleanup; 477f12db248SBryan Drewery } 47861acb458SBaptiste Daroussin } 479f12db248SBryan Drewery 480f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 481f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 482f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 483f12db248SBryan Drewery goto error; 484f12db248SBryan Drewery } 485f12db248SBryan Drewery 486f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 4874c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 488f12db248SBryan Drewery goto error; 489f12db248SBryan Drewery } 490f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 4914c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 492f12db248SBryan Drewery goto error; 493f12db248SBryan Drewery } 494f12db248SBryan Drewery 495f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 4964c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 497f12db248SBryan Drewery goto error; 498f12db248SBryan Drewery } 499f12db248SBryan Drewery 500f12db248SBryan Drewery ret = true; 501f12db248SBryan Drewery printf("done\n"); 502f12db248SBryan Drewery goto cleanup; 503f12db248SBryan Drewery 504f12db248SBryan Drewery error: 505f12db248SBryan Drewery printf("failed\n"); 506f12db248SBryan Drewery 507f12db248SBryan Drewery cleanup: 508f12db248SBryan Drewery if (pkey) 509f12db248SBryan Drewery EVP_PKEY_free(pkey); 510f12db248SBryan Drewery if (mdctx) 511f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 512f12db248SBryan Drewery ERR_free_strings(); 513f12db248SBryan Drewery 514f12db248SBryan Drewery return (ret); 515f12db248SBryan Drewery } 516f12db248SBryan Drewery 51761acb458SBaptiste Daroussin static struct pubkey * 51861acb458SBaptiste Daroussin read_pubkey(int fd) 51961acb458SBaptiste Daroussin { 52061acb458SBaptiste Daroussin struct pubkey *pk; 521cc9a8a11SBaptiste Daroussin char *sigb; 522cc9a8a11SBaptiste Daroussin size_t sigsz; 523cc9a8a11SBaptiste Daroussin FILE *sig; 52461acb458SBaptiste Daroussin char buf[4096]; 52561acb458SBaptiste Daroussin int r; 52661acb458SBaptiste Daroussin 52761acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 52861acb458SBaptiste Daroussin warn("lseek"); 52961acb458SBaptiste Daroussin return (NULL); 53061acb458SBaptiste Daroussin } 53161acb458SBaptiste Daroussin 532cc9a8a11SBaptiste Daroussin sigsz = 0; 533cc9a8a11SBaptiste Daroussin sigb = NULL; 534cc9a8a11SBaptiste Daroussin sig = open_memstream(&sigb, &sigsz); 535cc9a8a11SBaptiste Daroussin if (sig == NULL) 536cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 53761acb458SBaptiste Daroussin 53861acb458SBaptiste Daroussin while ((r = read(fd, buf, sizeof(buf))) >0) { 539cc9a8a11SBaptiste Daroussin fwrite(buf, 1, r, sig); 54061acb458SBaptiste Daroussin } 54161acb458SBaptiste Daroussin 542cc9a8a11SBaptiste Daroussin fclose(sig); 54361acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 544cc9a8a11SBaptiste Daroussin pk->siglen = sigsz; 54561acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 546cc9a8a11SBaptiste Daroussin memcpy(pk->sig, sigb, pk->siglen); 547cc9a8a11SBaptiste Daroussin free(sigb); 54861acb458SBaptiste Daroussin 54961acb458SBaptiste Daroussin return (pk); 55061acb458SBaptiste Daroussin } 55161acb458SBaptiste Daroussin 552f12db248SBryan Drewery static struct sig_cert * 553f12db248SBryan Drewery parse_cert(int fd) { 554f12db248SBryan Drewery int my_fd; 555f12db248SBryan Drewery struct sig_cert *sc; 556cc9a8a11SBaptiste Daroussin FILE *fp, *sigfp, *certfp, *tmpfp; 557f12db248SBryan Drewery char *line; 558cc9a8a11SBaptiste Daroussin char *sig, *cert; 559cc9a8a11SBaptiste Daroussin size_t linecap, sigsz, certsz; 560f12db248SBryan Drewery ssize_t linelen; 561f12db248SBryan Drewery 562f12db248SBryan Drewery sc = NULL; 563f12db248SBryan Drewery line = NULL; 564f12db248SBryan Drewery linecap = 0; 565cc9a8a11SBaptiste Daroussin sig = cert = NULL; 566cc9a8a11SBaptiste Daroussin sigfp = certfp = tmpfp = NULL; 567f12db248SBryan Drewery 568f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 569f12db248SBryan Drewery warn("lseek"); 570f12db248SBryan Drewery return (NULL); 571f12db248SBryan Drewery } 572f12db248SBryan Drewery 573f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 574f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 575f12db248SBryan Drewery warnx("dup"); 576f12db248SBryan Drewery return (NULL); 577f12db248SBryan Drewery } 578f12db248SBryan Drewery 579f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 580f12db248SBryan Drewery warn("fdopen"); 581f12db248SBryan Drewery close(my_fd); 582f12db248SBryan Drewery return (NULL); 583f12db248SBryan Drewery } 584f12db248SBryan Drewery 585cc9a8a11SBaptiste Daroussin sigsz = certsz = 0; 586cc9a8a11SBaptiste Daroussin sigfp = open_memstream(&sig, &sigsz); 587cc9a8a11SBaptiste Daroussin if (sigfp == NULL) 588cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 589cc9a8a11SBaptiste Daroussin certfp = open_memstream(&cert, &certsz); 590cc9a8a11SBaptiste Daroussin if (certfp == NULL) 591cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 592f12db248SBryan Drewery 593f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 594f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 595cc9a8a11SBaptiste Daroussin tmpfp = sigfp; 596f12db248SBryan Drewery continue; 597f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 598cc9a8a11SBaptiste Daroussin tmpfp = certfp; 599f12db248SBryan Drewery continue; 600f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 601f12db248SBryan Drewery break; 602f12db248SBryan Drewery } 603cc9a8a11SBaptiste Daroussin if (tmpfp != NULL) 604cc9a8a11SBaptiste Daroussin fwrite(line, 1, linelen, tmpfp); 605f12db248SBryan Drewery } 606f12db248SBryan Drewery 607f12db248SBryan Drewery fclose(fp); 608cc9a8a11SBaptiste Daroussin fclose(sigfp); 609cc9a8a11SBaptiste Daroussin fclose(certfp); 610f12db248SBryan Drewery 611f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 612cc9a8a11SBaptiste Daroussin sc->siglen = sigsz -1; /* Trim out unrelated trailing newline */ 613cc9a8a11SBaptiste Daroussin sc->sig = sig; 614f12db248SBryan Drewery 615cc9a8a11SBaptiste Daroussin sc->certlen = certsz; 616cc9a8a11SBaptiste Daroussin sc->cert = cert; 617f12db248SBryan Drewery 618f12db248SBryan Drewery return (sc); 619f12db248SBryan Drewery } 620f12db248SBryan Drewery 621f12db248SBryan Drewery static bool 62261acb458SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig) 62361acb458SBaptiste Daroussin { 62461acb458SBaptiste Daroussin struct pubkey *pk; 62561acb458SBaptiste Daroussin const char *pubkey; 62661acb458SBaptiste Daroussin bool ret; 62761acb458SBaptiste Daroussin 62861acb458SBaptiste Daroussin pk = NULL; 62961acb458SBaptiste Daroussin pubkey = NULL; 63061acb458SBaptiste Daroussin ret = false; 63161acb458SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 63261acb458SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined"); 63361acb458SBaptiste Daroussin goto cleanup; 63461acb458SBaptiste Daroussin } 63561acb458SBaptiste Daroussin 63661acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 63761acb458SBaptiste Daroussin warnx("Error reading signature"); 63861acb458SBaptiste Daroussin goto cleanup; 63961acb458SBaptiste Daroussin } 64061acb458SBaptiste Daroussin 64161acb458SBaptiste Daroussin /* Verify the signature. */ 64261acb458SBaptiste Daroussin printf("Verifying signature with public key %s... ", pubkey); 64361acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, 64461acb458SBaptiste Daroussin pk->siglen) == false) { 64561acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 64661acb458SBaptiste Daroussin goto cleanup; 64761acb458SBaptiste Daroussin } 64861acb458SBaptiste Daroussin 64961acb458SBaptiste Daroussin ret = true; 65061acb458SBaptiste Daroussin 65161acb458SBaptiste Daroussin cleanup: 65261acb458SBaptiste Daroussin if (pk) { 65361acb458SBaptiste Daroussin free(pk->sig); 65461acb458SBaptiste Daroussin free(pk); 65561acb458SBaptiste Daroussin } 65661acb458SBaptiste Daroussin 65761acb458SBaptiste Daroussin return (ret); 65861acb458SBaptiste Daroussin } 65961acb458SBaptiste Daroussin 66061acb458SBaptiste Daroussin static bool 661f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 662f12db248SBryan Drewery { 663f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 664f12db248SBryan Drewery struct fingerprint *fingerprint; 665f12db248SBryan Drewery struct sig_cert *sc; 666f12db248SBryan Drewery bool ret; 667f12db248SBryan Drewery int trusted_count, revoked_count; 668f12db248SBryan Drewery const char *fingerprints; 669f12db248SBryan Drewery char path[MAXPATHLEN]; 670f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 671f12db248SBryan Drewery 672516aaf7cSBryan Drewery sc = NULL; 673f12db248SBryan Drewery trusted = revoked = NULL; 674f12db248SBryan Drewery ret = false; 675f12db248SBryan Drewery 676f12db248SBryan Drewery /* Read and parse fingerprints. */ 677f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 678f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 679f12db248SBryan Drewery goto cleanup; 680f12db248SBryan Drewery } 681f12db248SBryan Drewery 682f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 683f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 684f12db248SBryan Drewery warnx("Error loading trusted certificates"); 685f12db248SBryan Drewery goto cleanup; 686f12db248SBryan Drewery } 687f12db248SBryan Drewery 688f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 689f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 690f12db248SBryan Drewery goto cleanup; 691f12db248SBryan Drewery } 692f12db248SBryan Drewery 693f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 694f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 695f12db248SBryan Drewery warnx("Error loading revoked certificates"); 696f12db248SBryan Drewery goto cleanup; 697f12db248SBryan Drewery } 698f12db248SBryan Drewery 699f12db248SBryan Drewery /* Read certificate and signature in. */ 700f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 701f12db248SBryan Drewery warnx("Error parsing certificate"); 702f12db248SBryan Drewery goto cleanup; 703f12db248SBryan Drewery } 704f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 705f12db248SBryan Drewery sc->trusted = false; 706f12db248SBryan Drewery 707f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 708f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 709f12db248SBryan Drewery 710f12db248SBryan Drewery /* Check if this hash is revoked */ 711f12db248SBryan Drewery if (revoked != NULL) { 712f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 713f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 714516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 715516aaf7cSBryan Drewery "revoked certificate %s\n", 716516aaf7cSBryan Drewery fingerprint->name); 717f12db248SBryan Drewery goto cleanup; 718f12db248SBryan Drewery } 719f12db248SBryan Drewery } 720f12db248SBryan Drewery } 721f12db248SBryan Drewery 722f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 723f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 724f12db248SBryan Drewery sc->trusted = true; 725516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 726f12db248SBryan Drewery break; 727f12db248SBryan Drewery } 728f12db248SBryan Drewery } 729f12db248SBryan Drewery 730f12db248SBryan Drewery if (sc->trusted == false) { 731516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 732f12db248SBryan Drewery "package's certificate\n"); 733f12db248SBryan Drewery goto cleanup; 734f12db248SBryan Drewery } 735f12db248SBryan Drewery 736f12db248SBryan Drewery /* Verify the signature. */ 737516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 73861acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, 739f12db248SBryan Drewery sc->siglen) == false) { 740f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 741f12db248SBryan Drewery goto cleanup; 742f12db248SBryan Drewery } 743f12db248SBryan Drewery 744f12db248SBryan Drewery ret = true; 745f12db248SBryan Drewery 746f12db248SBryan Drewery cleanup: 747516aaf7cSBryan Drewery if (trusted) 748516aaf7cSBryan Drewery free_fingerprint_list(trusted); 749516aaf7cSBryan Drewery if (revoked) 750516aaf7cSBryan Drewery free_fingerprint_list(revoked); 751f12db248SBryan Drewery if (sc) { 752f12db248SBryan Drewery free(sc->cert); 753f12db248SBryan Drewery free(sc->sig); 754516aaf7cSBryan Drewery free(sc->name); 755f12db248SBryan Drewery free(sc); 756f12db248SBryan Drewery } 757f12db248SBryan Drewery 758f12db248SBryan Drewery return (ret); 759f12db248SBryan Drewery } 760f12db248SBryan Drewery 761f12db248SBryan Drewery static int 762ae994fdcSBaptiste Daroussin bootstrap_pkg(bool force, const char *fetchOpts) 763f12db248SBryan Drewery { 764f12db248SBryan Drewery int fd_pkg, fd_sig; 765f12db248SBryan Drewery int ret; 766f12db248SBryan Drewery char url[MAXPATHLEN]; 767f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 768f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 769f12db248SBryan Drewery const char *packagesite; 770f12db248SBryan Drewery const char *signature_type; 771f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 772a2aac2f5SBaptiste Daroussin const char *bootstrap_name; 773f12db248SBryan Drewery 774f12db248SBryan Drewery fd_sig = -1; 775f12db248SBryan Drewery ret = -1; 776f12db248SBryan Drewery 777f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 778f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 779f12db248SBryan Drewery return (-1); 780f12db248SBryan Drewery } 781f12db248SBryan Drewery 782f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 783f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 784f12db248SBryan Drewery return (-1); 785f12db248SBryan Drewery } 786f12db248SBryan Drewery 787f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 788f12db248SBryan Drewery 789f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 790f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 791f12db248SBryan Drewery no A record. */ 792f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 793f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 794f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 795a2aac2f5SBaptiste Daroussin for (int j = 0; bootstrap_names[j] != NULL; j++) { 796a2aac2f5SBaptiste Daroussin bootstrap_name = bootstrap_names[j]; 797f12db248SBryan Drewery 798a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s", packagesite, bootstrap_name); 799a2aac2f5SBaptiste Daroussin snprintf(tmppkg, MAXPATHLEN, "%s/%s.XXXXXX", 800a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 801a2aac2f5SBaptiste Daroussin bootstrap_name); 802a2aac2f5SBaptiste Daroussin if ((fd_pkg = fetch_to_fd(url, tmppkg, fetchOpts)) != -1) 803a2aac2f5SBaptiste Daroussin break; 804a2aac2f5SBaptiste Daroussin bootstrap_name = NULL; 805a2aac2f5SBaptiste Daroussin } 806a2aac2f5SBaptiste Daroussin if (bootstrap_name == NULL) 807f12db248SBryan Drewery goto fetchfail; 808f12db248SBryan Drewery 809f12db248SBryan Drewery if (signature_type != NULL && 81048f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 81161acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 81248f92706SXin LI 813a2aac2f5SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX", 814a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 815a2aac2f5SBaptiste Daroussin bootstrap_name); 816a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig", 817a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 818f12db248SBryan Drewery 819ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 82061acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 82161acb458SBaptiste Daroussin "available.\n"); 822f12db248SBryan Drewery goto fetchfail; 823f12db248SBryan Drewery } 824f12db248SBryan Drewery 825f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 826f12db248SBryan Drewery goto cleanup; 82761acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 82861acb458SBaptiste Daroussin 82961acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 830a2aac2f5SBaptiste Daroussin "%s/%s.pubkeysig.XXXXXX", 831a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 832a2aac2f5SBaptiste Daroussin bootstrap_name); 833a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.pubkeysig", 834a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 83561acb458SBaptiste Daroussin 836ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 83761acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 83861acb458SBaptiste Daroussin "available.\n"); 83961acb458SBaptiste Daroussin goto fetchfail; 84061acb458SBaptiste Daroussin } 84161acb458SBaptiste Daroussin 84261acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 84361acb458SBaptiste Daroussin goto cleanup; 84461acb458SBaptiste Daroussin } else { 84561acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 84661acb458SBaptiste Daroussin "bootstrapping.", signature_type); 84761acb458SBaptiste Daroussin goto cleanup; 84861acb458SBaptiste Daroussin } 849f12db248SBryan Drewery } 850f12db248SBryan Drewery 851f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 8525212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 8533aa4b42aSBaptiste Daroussin 854a6454741SBaptiste Daroussin goto cleanup; 855a6454741SBaptiste Daroussin 856a6454741SBaptiste Daroussin fetchfail: 857a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 858a10f71c5STom Jones if (fetchLastErrCode == FETCH_RESOLV) { 859a10f71c5STom Jones fprintf(stderr, "Address resolution failed for %s.\n", packagesite); 860a10f71c5STom Jones fprintf(stderr, "Consider changing PACKAGESITE.\n"); 861a10f71c5STom Jones } else { 8624ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 8634ff9a7efSBryan Drewery "your system.\n"); 8644ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 8654ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 866a10f71c5STom Jones } 867a6454741SBaptiste Daroussin 8683aa4b42aSBaptiste Daroussin cleanup: 869f12db248SBryan Drewery if (fd_sig != -1) { 870f12db248SBryan Drewery close(fd_sig); 871f12db248SBryan Drewery unlink(tmpsig); 872f12db248SBryan Drewery } 87392947daaSBaptiste Daroussin 87492947daaSBaptiste Daroussin if (fd_pkg != -1) { 875f12db248SBryan Drewery close(fd_pkg); 8763aa4b42aSBaptiste Daroussin unlink(tmppkg); 87792947daaSBaptiste Daroussin } 8783aa4b42aSBaptiste Daroussin 879a6454741SBaptiste Daroussin return (ret); 8803aa4b42aSBaptiste Daroussin } 8813aa4b42aSBaptiste Daroussin 882e18ad51cSAlexander Kabaev static const char confirmation_message[] = 883e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 884e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 885e18ad51cSAlexander Kabaev 886e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 887575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 8881efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 889e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 890575c4095SBaptiste Daroussin 891ae994fdcSBaptiste Daroussin static const char args_bootstrap_message[] = 892ae994fdcSBaptiste Daroussin "Too many arguments\n" 893ae994fdcSBaptiste Daroussin "Usage: pkg [-4|-6] bootstrap [-f] [-y]\n"; 894ae994fdcSBaptiste Daroussin 895ae994fdcSBaptiste Daroussin static const char args_add_message[] = 896ae994fdcSBaptiste Daroussin "Too many arguments\n" 897ae994fdcSBaptiste Daroussin "Usage: pkg add [-f] [-y] {pkg.txz}\n"; 898ae994fdcSBaptiste Daroussin 899e18ad51cSAlexander Kabaev static int 900e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 901e18ad51cSAlexander Kabaev { 902e18ad51cSAlexander Kabaev int ret, c; 903e18ad51cSAlexander Kabaev 90467c9f60eSPoul-Henning Kamp fflush(stdout); 905e18ad51cSAlexander Kabaev c = getchar(); 906e18ad51cSAlexander Kabaev 907e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 908e18ad51cSAlexander Kabaev ret = 1; 909e18ad51cSAlexander Kabaev else 910e18ad51cSAlexander Kabaev ret = 0; 911e18ad51cSAlexander Kabaev 912e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 913e18ad51cSAlexander Kabaev c = getchar(); 914e18ad51cSAlexander Kabaev 915e18ad51cSAlexander Kabaev return (ret); 916e18ad51cSAlexander Kabaev } 917e18ad51cSAlexander Kabaev 91852cb76feSBryan Drewery static int 9195212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 92052cb76feSBryan Drewery { 92152cb76feSBryan Drewery char path[MAXPATHLEN]; 92252cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 92352cb76feSBryan Drewery const char *signature_type; 92452cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 92552cb76feSBryan Drewery 92652cb76feSBryan Drewery fd_sig = -1; 92752cb76feSBryan Drewery ret = -1; 92852cb76feSBryan Drewery 92952cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 93052cb76feSBryan Drewery if (fd_pkg == -1) 93152cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 93252cb76feSBryan Drewery 93352cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 93452cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 93592947daaSBaptiste Daroussin goto cleanup; 93652cb76feSBryan Drewery } 93752cb76feSBryan Drewery if (signature_type != NULL && 93848f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 93961acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 94048f92706SXin LI 94152cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 94252cb76feSBryan Drewery 94352cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 94461acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 94561acb458SBaptiste Daroussin "available.\n"); 94652cb76feSBryan Drewery goto cleanup; 94752cb76feSBryan Drewery } 94852cb76feSBryan Drewery 94952cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 95052cb76feSBryan Drewery goto cleanup; 95161acb458SBaptiste Daroussin 95261acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 95361acb458SBaptiste Daroussin 95461acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 95561acb458SBaptiste Daroussin 95661acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 95761acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 95861acb458SBaptiste Daroussin "available.\n"); 95961acb458SBaptiste Daroussin goto cleanup; 96061acb458SBaptiste Daroussin } 96161acb458SBaptiste Daroussin 96261acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 96361acb458SBaptiste Daroussin goto cleanup; 96461acb458SBaptiste Daroussin 96561acb458SBaptiste Daroussin } else { 96661acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 96761acb458SBaptiste Daroussin "bootstrapping.", signature_type); 96861acb458SBaptiste Daroussin goto cleanup; 96961acb458SBaptiste Daroussin } 97052cb76feSBryan Drewery } 97152cb76feSBryan Drewery 97252cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9735212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 97452cb76feSBryan Drewery 97552cb76feSBryan Drewery cleanup: 97652cb76feSBryan Drewery close(fd_pkg); 97752cb76feSBryan Drewery if (fd_sig != -1) 97852cb76feSBryan Drewery close(fd_sig); 97952cb76feSBryan Drewery 98052cb76feSBryan Drewery return (ret); 98152cb76feSBryan Drewery } 98252cb76feSBryan Drewery 98340b9f924SKyle Evans #define PKG_NAME "pkg" 98440b9f924SKyle Evans #define PKG_DEVEL_NAME PKG_NAME "-devel" 98540b9f924SKyle Evans #define PKG_PKG PKG_NAME "." 98640b9f924SKyle Evans 98740b9f924SKyle Evans static bool 98840b9f924SKyle Evans pkg_is_pkg_pkg(const char *pkg) 98940b9f924SKyle Evans { 990c96b4d87SGleb Smirnoff char *vstart, *basename; 99140b9f924SKyle Evans size_t namelen; 99240b9f924SKyle Evans 993c96b4d87SGleb Smirnoff /* Strip path. */ 994c96b4d87SGleb Smirnoff if ((basename = strrchr(pkg, '/')) != NULL) 995c96b4d87SGleb Smirnoff pkg = basename + 1; 996c96b4d87SGleb Smirnoff 99740b9f924SKyle Evans /* 99840b9f924SKyle Evans * Chop off the final "-" (version delimiter) and check the name that 99940b9f924SKyle Evans * precedes it. If we didn't have a version delimiter, it must be the 100040b9f924SKyle Evans * pkg.$archive short form but we'll check it anyways. pkg-devel short 100140b9f924SKyle Evans * form will look like a pkg archive with 'devel' version, but that's 100240b9f924SKyle Evans * OK. We otherwise assumed that non-pkg packages will always have a 100340b9f924SKyle Evans * version component. 100440b9f924SKyle Evans */ 100540b9f924SKyle Evans vstart = strrchr(pkg, '-'); 100640b9f924SKyle Evans if (vstart == NULL) { 100740b9f924SKyle Evans return (strlen(pkg) > sizeof(PKG_PKG) - 1 && 100840b9f924SKyle Evans strncmp(pkg, PKG_PKG, sizeof(PKG_PKG) - 1) == 0); 100940b9f924SKyle Evans } 101040b9f924SKyle Evans 101140b9f924SKyle Evans namelen = vstart - pkg; 101240b9f924SKyle Evans if (namelen == sizeof(PKG_NAME) - 1 && 101340b9f924SKyle Evans strncmp(pkg, PKG_NAME, sizeof(PKG_NAME) - 1) == 0) 101440b9f924SKyle Evans return (true); 101540b9f924SKyle Evans if (namelen == sizeof(PKG_DEVEL_NAME) - 1 && 101640b9f924SKyle Evans strncmp(pkg, PKG_DEVEL_NAME, sizeof(PKG_DEVEL_NAME) - 1) == 0) 101740b9f924SKyle Evans return (true); 101840b9f924SKyle Evans return (false); 101940b9f924SKyle Evans } 102040b9f924SKyle Evans 10213aa4b42aSBaptiste Daroussin int 102246b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10233aa4b42aSBaptiste Daroussin { 10243aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 102518418e19SKyle Evans const char *pkgarg, *repo_name; 1026ae994fdcSBaptiste Daroussin bool activation_test, add_pkg, bootstrap_only, force, yes; 1027ae994fdcSBaptiste Daroussin signed char ch; 1028ae994fdcSBaptiste Daroussin const char *fetchOpts; 1029ae994fdcSBaptiste Daroussin char *command; 10305212e8baSBryan Drewery 1031ae994fdcSBaptiste Daroussin activation_test = false; 1032ae994fdcSBaptiste Daroussin add_pkg = false; 10335212e8baSBryan Drewery bootstrap_only = false; 1034ae994fdcSBaptiste Daroussin command = NULL; 1035ae994fdcSBaptiste Daroussin fetchOpts = ""; 10365212e8baSBryan Drewery force = false; 10375212e8baSBryan Drewery pkgarg = NULL; 103818418e19SKyle Evans repo_name = NULL; 10395212e8baSBryan Drewery yes = false; 10403aa4b42aSBaptiste Daroussin 1041ae994fdcSBaptiste Daroussin struct option longopts[] = { 1042e9ad2964SBrooks Davis { "debug", no_argument, NULL, 'd' }, 1043ae994fdcSBaptiste Daroussin { "force", no_argument, NULL, 'f' }, 1044ae994fdcSBaptiste Daroussin { "only-ipv4", no_argument, NULL, '4' }, 1045ae994fdcSBaptiste Daroussin { "only-ipv6", no_argument, NULL, '6' }, 1046ae994fdcSBaptiste Daroussin { "yes", no_argument, NULL, 'y' }, 1047ae994fdcSBaptiste Daroussin { NULL, 0, NULL, 0 }, 1048ae994fdcSBaptiste Daroussin }; 1049ae994fdcSBaptiste Daroussin 105056d11d4aSStefan Eßer snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase()); 10513aa4b42aSBaptiste Daroussin 1052e9ad2964SBrooks Davis while ((ch = getopt_long(argc, argv, "-:dfr::yN46", longopts, NULL)) != -1) { 1053ae994fdcSBaptiste Daroussin switch (ch) { 1054e9ad2964SBrooks Davis case 'd': 1055e9ad2964SBrooks Davis debug++; 1056e9ad2964SBrooks Davis break; 1057ae994fdcSBaptiste Daroussin case 'f': 1058ae994fdcSBaptiste Daroussin force = true; 1059ae994fdcSBaptiste Daroussin break; 1060ae994fdcSBaptiste Daroussin case 'N': 1061ae994fdcSBaptiste Daroussin activation_test = true; 1062ae994fdcSBaptiste Daroussin break; 1063ae994fdcSBaptiste Daroussin case 'y': 1064ae994fdcSBaptiste Daroussin yes = true; 1065ae994fdcSBaptiste Daroussin break; 1066ae994fdcSBaptiste Daroussin case '4': 1067ae994fdcSBaptiste Daroussin fetchOpts = "4"; 1068ae994fdcSBaptiste Daroussin break; 1069ae994fdcSBaptiste Daroussin case '6': 1070ae994fdcSBaptiste Daroussin fetchOpts = "6"; 1071ae994fdcSBaptiste Daroussin break; 107218418e19SKyle Evans case 'r': 107318418e19SKyle Evans /* 107418418e19SKyle Evans * The repository can only be specified for an explicit 107518418e19SKyle Evans * bootstrap request at this time, so that we don't 107618418e19SKyle Evans * confuse the user if they're trying to use a verb that 107718418e19SKyle Evans * has some other conflicting meaning but we need to 107818418e19SKyle Evans * bootstrap. 107918418e19SKyle Evans * 108018418e19SKyle Evans * For that reason, we specify that -r has an optional 108118418e19SKyle Evans * argument above and process the next index ourselves. 108218418e19SKyle Evans * This is mostly significant because getopt(3) will 108318418e19SKyle Evans * otherwise eat the next argument, which could be 108418418e19SKyle Evans * something we need to try and make sense of. 108518418e19SKyle Evans * 108618418e19SKyle Evans * At worst this gets us false positives that we ignore 108718418e19SKyle Evans * in other contexts, and we have to do a little fudging 108818418e19SKyle Evans * in order to support separating -r from the reponame 108918418e19SKyle Evans * with a space since it's not actually optional in 109018418e19SKyle Evans * the bootstrap/add sense. 109118418e19SKyle Evans */ 109218418e19SKyle Evans if (add_pkg || bootstrap_only) { 109318418e19SKyle Evans if (optarg != NULL) { 109418418e19SKyle Evans repo_name = optarg; 109518418e19SKyle Evans } else if (optind < argc) { 109618418e19SKyle Evans repo_name = argv[optind]; 109718418e19SKyle Evans } 109818418e19SKyle Evans 109918418e19SKyle Evans if (repo_name == NULL || *repo_name == '\0') { 110018418e19SKyle Evans fprintf(stderr, 110118418e19SKyle Evans "Must specify a repository with -r!\n"); 110218418e19SKyle Evans exit(EXIT_FAILURE); 110318418e19SKyle Evans } 110418418e19SKyle Evans 110518418e19SKyle Evans if (optarg == NULL) { 110618418e19SKyle Evans /* Advance past repo name. */ 110718418e19SKyle Evans optreset = 1; 110818418e19SKyle Evans optind++; 110918418e19SKyle Evans } 111018418e19SKyle Evans } 111118418e19SKyle Evans break; 1112ae994fdcSBaptiste Daroussin case 1: 1113ae994fdcSBaptiste Daroussin // Non-option arguments, first one is the command 1114ae994fdcSBaptiste Daroussin if (command == NULL) { 1115ae994fdcSBaptiste Daroussin command = argv[optind-1]; 1116ae994fdcSBaptiste Daroussin if (strcmp(command, "add") == 0) { 1117ae994fdcSBaptiste Daroussin add_pkg = true; 1118ae994fdcSBaptiste Daroussin } 1119ae994fdcSBaptiste Daroussin else if (strcmp(command, "bootstrap") == 0) { 11205212e8baSBryan Drewery bootstrap_only = true; 1121ae994fdcSBaptiste Daroussin } 1122ae994fdcSBaptiste Daroussin } 1123ae994fdcSBaptiste Daroussin // bootstrap doesn't accept other arguments 1124ae994fdcSBaptiste Daroussin else if (bootstrap_only) { 1125ae994fdcSBaptiste Daroussin fprintf(stderr, args_bootstrap_message); 1126ca7f7593SKyle Evans exit(EXIT_FAILURE); 1127ca7f7593SKyle Evans } 1128ae994fdcSBaptiste Daroussin else if (add_pkg && pkgarg != NULL) { 112940b9f924SKyle Evans /* 113040b9f924SKyle Evans * Additional arguments also means it's not a 113140b9f924SKyle Evans * local bootstrap request. 113240b9f924SKyle Evans */ 113340b9f924SKyle Evans add_pkg = false; 1134ca7f7593SKyle Evans } 1135ae994fdcSBaptiste Daroussin else if (add_pkg) { 113640b9f924SKyle Evans /* 113740b9f924SKyle Evans * If it's not a request for pkg or pkg-devel, 113840b9f924SKyle Evans * then we must assume they were trying to 113940b9f924SKyle Evans * install some other local package and we 114040b9f924SKyle Evans * should try to bootstrap from the repo. 114140b9f924SKyle Evans */ 114240b9f924SKyle Evans if (!pkg_is_pkg_pkg(argv[optind-1])) { 114340b9f924SKyle Evans add_pkg = false; 114440b9f924SKyle Evans } else { 1145ae994fdcSBaptiste Daroussin pkgarg = argv[optind-1]; 1146ae994fdcSBaptiste Daroussin } 114740b9f924SKyle Evans } 1148ae994fdcSBaptiste Daroussin break; 1149ae994fdcSBaptiste Daroussin default: 1150ae994fdcSBaptiste Daroussin break; 1151ae994fdcSBaptiste Daroussin } 11525212e8baSBryan Drewery } 1153e9ad2964SBrooks Davis if (debug > 1) 1154e9ad2964SBrooks Davis fetchDebug = 1; 11555212e8baSBryan Drewery 11565212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1157e18ad51cSAlexander Kabaev /* 1158d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1159ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1160990878b0SGordon Bergling * when that option is passed. 1161ecfed9f2SMatthew Seaman */ 1162ae994fdcSBaptiste Daroussin if (activation_test) 1163e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1164ecfed9f2SMatthew Seaman 116518418e19SKyle Evans config_init(repo_name); 116652cb76feSBryan Drewery 1167ae994fdcSBaptiste Daroussin if (add_pkg) { 11685212e8baSBryan Drewery if (pkgarg == NULL) { 11695212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 11705212e8baSBryan Drewery exit(EXIT_FAILURE); 11715212e8baSBryan Drewery } 11725212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 11735212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 11745212e8baSBryan Drewery exit(EXIT_FAILURE); 11755212e8baSBryan Drewery } 11765212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1177b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1178b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1179b70213b5SBaptiste Daroussin } 1180ecfed9f2SMatthew Seaman /* 1181e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1182e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1183e18ad51cSAlexander Kabaev * tucked in there already. 1184e18ad51cSAlexander Kabaev */ 1185ae994fdcSBaptiste Daroussin if (!yes) 11869950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 11879950eceeSBaptiste Daroussin if (!yes) { 1188575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1189e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 11903a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1191575c4095SBaptiste Daroussin } 1192204ea792SBaptiste Daroussin 1193575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1194204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1195e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1196e18ad51cSAlexander Kabaev } 1197ae994fdcSBaptiste Daroussin if (bootstrap_pkg(force, fetchOpts) != 0) 1198a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 11999950eceeSBaptiste Daroussin config_finish(); 1200c3e8a27aSBryan Drewery 12015212e8baSBryan Drewery if (bootstrap_only) 1202c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 12035212e8baSBryan Drewery } else if (bootstrap_only) { 12045212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1205c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1206c3e8a27aSBryan Drewery } 12073aa4b42aSBaptiste Daroussin 12083aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 12093aa4b42aSBaptiste Daroussin 1210a6454741SBaptiste Daroussin /* NOT REACHED */ 12113b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 12123aa4b42aSBaptiste Daroussin } 1213