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" 593aa4b42aSBaptiste Daroussin 60f12db248SBryan Drewery struct sig_cert { 61516aaf7cSBryan Drewery char *name; 62f12db248SBryan Drewery unsigned char *sig; 63f12db248SBryan Drewery int siglen; 64f12db248SBryan Drewery unsigned char *cert; 65f12db248SBryan Drewery int certlen; 66f12db248SBryan Drewery bool trusted; 67f12db248SBryan Drewery }; 68f12db248SBryan Drewery 6961acb458SBaptiste Daroussin struct pubkey { 7061acb458SBaptiste Daroussin unsigned char *sig; 7161acb458SBaptiste Daroussin int siglen; 7261acb458SBaptiste Daroussin }; 7361acb458SBaptiste Daroussin 74f12db248SBryan Drewery typedef enum { 75f12db248SBryan Drewery HASH_UNKNOWN, 76f12db248SBryan Drewery HASH_SHA256, 77f12db248SBryan Drewery } hash_t; 78f12db248SBryan Drewery 79f12db248SBryan Drewery struct fingerprint { 80f12db248SBryan Drewery hash_t type; 81516aaf7cSBryan Drewery char *name; 82f12db248SBryan Drewery char hash[BUFSIZ]; 83f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 84f12db248SBryan Drewery }; 85f12db248SBryan Drewery 86a2aac2f5SBaptiste Daroussin static const char *bootstrap_names [] = { 87c244b1d8SBaptiste Daroussin "pkg.pkg", 88a2aac2f5SBaptiste Daroussin "pkg.txz", 89a2aac2f5SBaptiste Daroussin NULL 90a2aac2f5SBaptiste Daroussin }; 91a2aac2f5SBaptiste Daroussin 92f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 93f12db248SBryan Drewery 943aa4b42aSBaptiste Daroussin static int 953aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 963aa4b42aSBaptiste Daroussin { 973aa4b42aSBaptiste Daroussin struct archive *a; 983aa4b42aSBaptiste Daroussin struct archive_entry *ae; 993aa4b42aSBaptiste Daroussin char *end; 1003aa4b42aSBaptiste Daroussin int ret, r; 1013aa4b42aSBaptiste Daroussin 102a6454741SBaptiste Daroussin ret = -1; 1033aa4b42aSBaptiste Daroussin a = archive_read_new(); 104a6454741SBaptiste Daroussin if (a == NULL) { 105a6454741SBaptiste Daroussin warn("archive_read_new"); 106a6454741SBaptiste Daroussin return (ret); 107a6454741SBaptiste Daroussin } 108ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1093aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1103aa4b42aSBaptiste Daroussin 111a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 112a6454741SBaptiste Daroussin warn("lseek"); 113a6454741SBaptiste Daroussin goto cleanup; 114a6454741SBaptiste Daroussin } 1153aa4b42aSBaptiste Daroussin 1163aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 117a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1183aa4b42aSBaptiste Daroussin goto cleanup; 1193aa4b42aSBaptiste Daroussin } 1203aa4b42aSBaptiste Daroussin 1213aa4b42aSBaptiste Daroussin ae = NULL; 1223aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1233aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1243aa4b42aSBaptiste Daroussin if (end == NULL) 1253aa4b42aSBaptiste Daroussin continue; 1263aa4b42aSBaptiste Daroussin 1273aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1283aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1293aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1303aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1313aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 132a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1333aa4b42aSBaptiste Daroussin break; 1343aa4b42aSBaptiste Daroussin } 1353aa4b42aSBaptiste Daroussin } 1363aa4b42aSBaptiste Daroussin 137a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 138a6454741SBaptiste Daroussin ret = 0; 139a6454741SBaptiste Daroussin else 1404622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1414622bc4eSGavin Atkinson archive_error_string(a)); 1423aa4b42aSBaptiste Daroussin 1433aa4b42aSBaptiste Daroussin cleanup: 144ff75c36aSBaptiste Daroussin archive_read_free(a); 1453b05c2a8SBaptiste Daroussin return (ret); 1463aa4b42aSBaptiste Daroussin 1473aa4b42aSBaptiste Daroussin } 1483aa4b42aSBaptiste Daroussin 1493aa4b42aSBaptiste Daroussin static int 1505212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1513aa4b42aSBaptiste Daroussin { 1523aa4b42aSBaptiste Daroussin int pstat; 1533aa4b42aSBaptiste Daroussin pid_t pid; 1543aa4b42aSBaptiste Daroussin 1553aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1563aa4b42aSBaptiste Daroussin case -1: 1573aa4b42aSBaptiste Daroussin return (-1); 1583aa4b42aSBaptiste Daroussin case 0: 1595212e8baSBryan Drewery if (force) 1605212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 1615212e8baSBryan Drewery (char *)NULL); 1625212e8baSBryan Drewery else 1635212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 1645212e8baSBryan Drewery (char *)NULL); 1653b05c2a8SBaptiste Daroussin _exit(1); 1663aa4b42aSBaptiste Daroussin default: 1673aa4b42aSBaptiste Daroussin break; 1683aa4b42aSBaptiste Daroussin } 1693aa4b42aSBaptiste Daroussin 170a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1713aa4b42aSBaptiste Daroussin if (errno != EINTR) 1723aa4b42aSBaptiste Daroussin return (-1); 1733aa4b42aSBaptiste Daroussin 174a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1753aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 176a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 177a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 178a6454741SBaptiste Daroussin return (pstat); 1793aa4b42aSBaptiste Daroussin } 1803aa4b42aSBaptiste Daroussin 1813aa4b42aSBaptiste Daroussin static int 182ae994fdcSBaptiste Daroussin fetch_to_fd(const char *url, char *path, const char *fetchOpts) 1833aa4b42aSBaptiste Daroussin { 18429aaa961SBaptiste Daroussin struct url *u; 18529aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 186a6454741SBaptiste Daroussin struct url_stat st; 187f12db248SBryan Drewery FILE *remote; 188f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 189f12db248SBryan Drewery int fd; 190f12db248SBryan Drewery int retry, max_retry; 191cc36fe49SBaptiste Daroussin ssize_t r; 192f12db248SBryan Drewery char buf[10240]; 193f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 194f12db248SBryan Drewery static const char *mirror_type = NULL; 1953aa4b42aSBaptiste Daroussin 19629aaa961SBaptiste Daroussin max_retry = 3; 19729aaa961SBaptiste Daroussin current = mirrors = NULL; 198f12db248SBryan Drewery remote = NULL; 1993aa4b42aSBaptiste Daroussin 200f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 201f12db248SBryan Drewery != 0) { 2029950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 2039950eceeSBaptiste Daroussin return (-1); 2049950eceeSBaptiste Daroussin } 20562940ea9SBryan Drewery 206f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2073aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2083b05c2a8SBaptiste Daroussin return (-1); 2093aa4b42aSBaptiste Daroussin } 2103aa4b42aSBaptiste Daroussin 21129aaa961SBaptiste Daroussin retry = max_retry; 21229aaa961SBaptiste Daroussin 21379fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 21479fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 21579fe80efSBaptiste Daroussin return (-1); 21679fe80efSBaptiste Daroussin } 21779fe80efSBaptiste Daroussin 21829aaa961SBaptiste Daroussin while (remote == NULL) { 21929aaa961SBaptiste Daroussin if (retry == max_retry) { 2209950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2219950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 22229aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 22329aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 22429aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 22529aaa961SBaptiste Daroussin current = mirrors; 22629aaa961SBaptiste Daroussin } 22729aaa961SBaptiste Daroussin } 22829aaa961SBaptiste Daroussin 22935e07a7aSBaptiste Daroussin if (mirrors != NULL) { 23029aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 23135e07a7aSBaptiste Daroussin u->port = current->port; 23235e07a7aSBaptiste Daroussin } 23329aaa961SBaptiste Daroussin 234ae994fdcSBaptiste Daroussin remote = fetchXGet(u, &st, fetchOpts); 23529aaa961SBaptiste Daroussin if (remote == NULL) { 23629aaa961SBaptiste Daroussin --retry; 23729aaa961SBaptiste Daroussin if (retry <= 0) 23829aaa961SBaptiste Daroussin goto fetchfail; 23929aaa961SBaptiste Daroussin if (mirrors == NULL) { 2403aa4b42aSBaptiste Daroussin sleep(1); 24129aaa961SBaptiste Daroussin } else { 24229aaa961SBaptiste Daroussin current = current->next; 24329aaa961SBaptiste Daroussin if (current == NULL) 24429aaa961SBaptiste Daroussin current = mirrors; 24529aaa961SBaptiste Daroussin } 24629aaa961SBaptiste Daroussin } 24729aaa961SBaptiste Daroussin } 248a6454741SBaptiste Daroussin 249cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 2503aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2513aa4b42aSBaptiste Daroussin warn("write()"); 252f12db248SBryan Drewery goto fetchfail; 2533aa4b42aSBaptiste Daroussin } 254cc36fe49SBaptiste Daroussin } 2553aa4b42aSBaptiste Daroussin 256cc36fe49SBaptiste Daroussin if (r != 0) { 257cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 258cc36fe49SBaptiste Daroussin goto fetchfail; 2593aa4b42aSBaptiste Daroussin } 2603aa4b42aSBaptiste Daroussin 261a6454741SBaptiste Daroussin if (ferror(remote)) 262a6454741SBaptiste Daroussin goto fetchfail; 2633aa4b42aSBaptiste Daroussin 264f12db248SBryan Drewery goto cleanup; 265f12db248SBryan Drewery 266f12db248SBryan Drewery fetchfail: 267f12db248SBryan Drewery if (fd != -1) { 268f12db248SBryan Drewery close(fd); 269f12db248SBryan Drewery fd = -1; 270f12db248SBryan Drewery unlink(path); 271f12db248SBryan Drewery } 272f12db248SBryan Drewery 273f12db248SBryan Drewery cleanup: 274f12db248SBryan Drewery if (remote != NULL) 275f12db248SBryan Drewery fclose(remote); 276f12db248SBryan Drewery 277f12db248SBryan Drewery return fd; 278f12db248SBryan Drewery } 279f12db248SBryan Drewery 280f12db248SBryan Drewery static struct fingerprint * 2818a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 282f12db248SBryan Drewery { 283b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 2848a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 2858a7d859eSBaptiste Daroussin const char *function, *fp, *key; 286f12db248SBryan Drewery struct fingerprint *f; 287f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 288f12db248SBryan Drewery 289f12db248SBryan Drewery function = fp = NULL; 290f12db248SBryan Drewery 2918a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 2928a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 2938a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 2948a7d859eSBaptiste Daroussin continue; 2958a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 2968a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 297f12db248SBryan Drewery continue; 298f12db248SBryan Drewery } 2998a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 3008a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 301f12db248SBryan Drewery continue; 302f12db248SBryan Drewery } 303f12db248SBryan Drewery } 304f12db248SBryan Drewery 305f12db248SBryan Drewery if (fp == NULL || function == NULL) 306f12db248SBryan Drewery return (NULL); 307f12db248SBryan Drewery 308f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 309f12db248SBryan Drewery fct = HASH_SHA256; 310f12db248SBryan Drewery 311f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 312d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 313f12db248SBryan Drewery return (NULL); 314f12db248SBryan Drewery } 315f12db248SBryan Drewery 316f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 317f12db248SBryan Drewery f->type = fct; 318f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 319f12db248SBryan Drewery 320f12db248SBryan Drewery return (f); 321f12db248SBryan Drewery } 322f12db248SBryan Drewery 323516aaf7cSBryan Drewery static void 324516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 325516aaf7cSBryan Drewery { 326d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 327516aaf7cSBryan Drewery 328d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 329516aaf7cSBryan Drewery free(fingerprint->name); 330516aaf7cSBryan Drewery free(fingerprint); 331516aaf7cSBryan Drewery } 332516aaf7cSBryan Drewery free(list); 333516aaf7cSBryan Drewery } 334516aaf7cSBryan Drewery 335f12db248SBryan Drewery static struct fingerprint * 336f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 337f12db248SBryan Drewery { 3388a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 3398a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 340f12db248SBryan Drewery struct fingerprint *f; 341f12db248SBryan Drewery char path[MAXPATHLEN]; 342f12db248SBryan Drewery 343f12db248SBryan Drewery f = NULL; 344f12db248SBryan Drewery 345f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 346f12db248SBryan Drewery 3478a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 3488a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 3498a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 3508a7d859eSBaptiste Daroussin ucl_parser_free(p); 351f12db248SBryan Drewery return (NULL); 3528a7d859eSBaptiste Daroussin } 353f12db248SBryan Drewery 3548a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 355f12db248SBryan Drewery 3568a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 3578a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 358f12db248SBryan Drewery 3598a7d859eSBaptiste Daroussin if (f != NULL) 360516aaf7cSBryan Drewery f->name = strdup(filename); 361f12db248SBryan Drewery 362b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 3638a7d859eSBaptiste Daroussin ucl_parser_free(p); 364f12db248SBryan Drewery 365f12db248SBryan Drewery return (f); 366f12db248SBryan Drewery } 367f12db248SBryan Drewery 368f12db248SBryan Drewery static struct fingerprint_list * 369f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 370f12db248SBryan Drewery { 371f12db248SBryan Drewery DIR *d; 372f12db248SBryan Drewery struct dirent *ent; 373f12db248SBryan Drewery struct fingerprint *finger; 374f12db248SBryan Drewery struct fingerprint_list *fingerprints; 375f12db248SBryan Drewery 376f12db248SBryan Drewery *count = 0; 377f12db248SBryan Drewery 378f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 379f12db248SBryan Drewery if (fingerprints == NULL) 380f12db248SBryan Drewery return (NULL); 381f12db248SBryan Drewery STAILQ_INIT(fingerprints); 382f12db248SBryan Drewery 38392947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 38492947daaSBaptiste Daroussin free(fingerprints); 38592947daaSBaptiste Daroussin 386f12db248SBryan Drewery return (NULL); 38792947daaSBaptiste Daroussin } 388f12db248SBryan Drewery 389f12db248SBryan Drewery while ((ent = readdir(d))) { 390f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 391f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 392f12db248SBryan Drewery continue; 393f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 394f12db248SBryan Drewery if (finger != NULL) { 395f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 396f12db248SBryan Drewery ++(*count); 397f12db248SBryan Drewery } 398f12db248SBryan Drewery } 399f12db248SBryan Drewery 400f12db248SBryan Drewery closedir(d); 401f12db248SBryan Drewery 402f12db248SBryan Drewery return (fingerprints); 403f12db248SBryan Drewery } 404f12db248SBryan Drewery 405f12db248SBryan Drewery static void 406f12db248SBryan Drewery sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 407f12db248SBryan Drewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 408f12db248SBryan Drewery { 409f12db248SBryan Drewery int i; 410f12db248SBryan Drewery 411f12db248SBryan Drewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 412f12db248SBryan Drewery sprintf(out + (i * 2), "%02x", hash[i]); 413f12db248SBryan Drewery 414f12db248SBryan Drewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 415f12db248SBryan Drewery } 416f12db248SBryan Drewery 417f12db248SBryan Drewery static void 418f12db248SBryan Drewery sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 419f12db248SBryan Drewery { 420f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 421f12db248SBryan Drewery SHA256_CTX sha256; 422f12db248SBryan Drewery 423f12db248SBryan Drewery out[0] = '\0'; 424f12db248SBryan Drewery 425f12db248SBryan Drewery SHA256_Init(&sha256); 426f12db248SBryan Drewery SHA256_Update(&sha256, buf, len); 427f12db248SBryan Drewery SHA256_Final(hash, &sha256); 428f12db248SBryan Drewery sha256_hash(hash, out); 429f12db248SBryan Drewery } 430f12db248SBryan Drewery 431f12db248SBryan Drewery static int 432f12db248SBryan Drewery sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 433f12db248SBryan Drewery { 434f12db248SBryan Drewery int my_fd; 435f12db248SBryan Drewery FILE *fp; 436f12db248SBryan Drewery char buffer[BUFSIZ]; 437f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 438f12db248SBryan Drewery size_t r; 439f12db248SBryan Drewery int ret; 440f12db248SBryan Drewery SHA256_CTX sha256; 441f12db248SBryan Drewery 442f12db248SBryan Drewery fp = NULL; 443f12db248SBryan Drewery ret = 1; 444f12db248SBryan Drewery 445f12db248SBryan Drewery out[0] = '\0'; 446f12db248SBryan Drewery 447f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 448f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 449f12db248SBryan Drewery warnx("dup"); 450f12db248SBryan Drewery goto cleanup; 451f12db248SBryan Drewery } 452f12db248SBryan Drewery 453f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 454f12db248SBryan Drewery warnx("fdopen"); 455f12db248SBryan Drewery goto cleanup; 456f12db248SBryan Drewery } 457f12db248SBryan Drewery 458f12db248SBryan Drewery SHA256_Init(&sha256); 459f12db248SBryan Drewery 460f12db248SBryan Drewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 461f12db248SBryan Drewery SHA256_Update(&sha256, buffer, r); 462f12db248SBryan Drewery 463f12db248SBryan Drewery if (ferror(fp) != 0) { 464f12db248SBryan Drewery warnx("fread"); 465f12db248SBryan Drewery goto cleanup; 466f12db248SBryan Drewery } 467f12db248SBryan Drewery 468f12db248SBryan Drewery SHA256_Final(hash, &sha256); 469f12db248SBryan Drewery sha256_hash(hash, out); 470f12db248SBryan Drewery ret = 0; 471f12db248SBryan Drewery 472f12db248SBryan Drewery cleanup: 473f12db248SBryan Drewery if (fp != NULL) 474f12db248SBryan Drewery fclose(fp); 475f12db248SBryan Drewery else if (my_fd != -1) 476f12db248SBryan Drewery close(my_fd); 477f12db248SBryan Drewery (void)lseek(fd, 0, SEEK_SET); 478f12db248SBryan Drewery 479f12db248SBryan Drewery return (ret); 480f12db248SBryan Drewery } 481f12db248SBryan Drewery 482f12db248SBryan Drewery static EVP_PKEY * 48361acb458SBaptiste Daroussin load_public_key_file(const char *file) 48461acb458SBaptiste Daroussin { 48561acb458SBaptiste Daroussin EVP_PKEY *pkey; 48661acb458SBaptiste Daroussin BIO *bp; 48761acb458SBaptiste Daroussin char errbuf[1024]; 48861acb458SBaptiste Daroussin 48961acb458SBaptiste Daroussin bp = BIO_new_file(file, "r"); 49061acb458SBaptiste Daroussin if (!bp) 49161acb458SBaptiste Daroussin errx(EXIT_FAILURE, "Unable to read %s", file); 49261acb458SBaptiste Daroussin 49361acb458SBaptiste Daroussin if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 49461acb458SBaptiste Daroussin warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); 49561acb458SBaptiste Daroussin 49661acb458SBaptiste Daroussin BIO_free(bp); 49761acb458SBaptiste Daroussin 49861acb458SBaptiste Daroussin return (pkey); 49961acb458SBaptiste Daroussin } 50061acb458SBaptiste Daroussin 50161acb458SBaptiste Daroussin static EVP_PKEY * 502f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 503f12db248SBryan Drewery { 504f12db248SBryan Drewery EVP_PKEY *pkey; 505f12db248SBryan Drewery BIO *bp; 506f12db248SBryan Drewery char errbuf[1024]; 507f12db248SBryan Drewery 508c2788c07SBryan Drewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 509f12db248SBryan Drewery 510f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 511f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 512f12db248SBryan Drewery 513f12db248SBryan Drewery BIO_free(bp); 514f12db248SBryan Drewery 515f12db248SBryan Drewery return (pkey); 516f12db248SBryan Drewery } 517f12db248SBryan Drewery 518f12db248SBryan Drewery static bool 51961acb458SBaptiste Daroussin rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, 52061acb458SBaptiste Daroussin int keylen, unsigned char *sig, int siglen) 521f12db248SBryan Drewery { 522f12db248SBryan Drewery EVP_MD_CTX *mdctx; 523f12db248SBryan Drewery EVP_PKEY *pkey; 524f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 525f12db248SBryan Drewery char errbuf[1024]; 526f12db248SBryan Drewery bool ret; 527f12db248SBryan Drewery 528f12db248SBryan Drewery pkey = NULL; 529f12db248SBryan Drewery mdctx = NULL; 530f12db248SBryan Drewery ret = false; 531f12db248SBryan Drewery 53261acb458SBaptiste Daroussin SSL_load_error_strings(); 53361acb458SBaptiste Daroussin 534f12db248SBryan Drewery /* Compute SHA256 of the package. */ 535f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 536f12db248SBryan Drewery warn("lseek"); 537f12db248SBryan Drewery goto cleanup; 538f12db248SBryan Drewery } 539f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 540f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 541f12db248SBryan Drewery goto cleanup; 542f12db248SBryan Drewery } 543f12db248SBryan Drewery 54461acb458SBaptiste Daroussin if (sigfile != NULL) { 54561acb458SBaptiste Daroussin if ((pkey = load_public_key_file(sigfile)) == NULL) { 54661acb458SBaptiste Daroussin warnx("Error reading public key"); 54761acb458SBaptiste Daroussin goto cleanup; 54861acb458SBaptiste Daroussin } 54961acb458SBaptiste Daroussin } else { 550f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 551f12db248SBryan Drewery warnx("Error reading public key"); 552f12db248SBryan Drewery goto cleanup; 553f12db248SBryan Drewery } 55461acb458SBaptiste Daroussin } 555f12db248SBryan Drewery 556f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 557f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 558f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 559f12db248SBryan Drewery goto error; 560f12db248SBryan Drewery } 561f12db248SBryan Drewery 562f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 5634c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 564f12db248SBryan Drewery goto error; 565f12db248SBryan Drewery } 566f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 5674c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 568f12db248SBryan Drewery goto error; 569f12db248SBryan Drewery } 570f12db248SBryan Drewery 571f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 5724c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 573f12db248SBryan Drewery goto error; 574f12db248SBryan Drewery } 575f12db248SBryan Drewery 576f12db248SBryan Drewery ret = true; 577f12db248SBryan Drewery printf("done\n"); 578f12db248SBryan Drewery goto cleanup; 579f12db248SBryan Drewery 580f12db248SBryan Drewery error: 581f12db248SBryan Drewery printf("failed\n"); 582f12db248SBryan Drewery 583f12db248SBryan Drewery cleanup: 584f12db248SBryan Drewery if (pkey) 585f12db248SBryan Drewery EVP_PKEY_free(pkey); 586f12db248SBryan Drewery if (mdctx) 587f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 588f12db248SBryan Drewery ERR_free_strings(); 589f12db248SBryan Drewery 590f12db248SBryan Drewery return (ret); 591f12db248SBryan Drewery } 592f12db248SBryan Drewery 59361acb458SBaptiste Daroussin static struct pubkey * 59461acb458SBaptiste Daroussin read_pubkey(int fd) 59561acb458SBaptiste Daroussin { 59661acb458SBaptiste Daroussin struct pubkey *pk; 597*cc9a8a11SBaptiste Daroussin char *sigb; 598*cc9a8a11SBaptiste Daroussin size_t sigsz; 599*cc9a8a11SBaptiste Daroussin FILE *sig; 60061acb458SBaptiste Daroussin char buf[4096]; 60161acb458SBaptiste Daroussin int r; 60261acb458SBaptiste Daroussin 60361acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 60461acb458SBaptiste Daroussin warn("lseek"); 60561acb458SBaptiste Daroussin return (NULL); 60661acb458SBaptiste Daroussin } 60761acb458SBaptiste Daroussin 608*cc9a8a11SBaptiste Daroussin sigsz = 0; 609*cc9a8a11SBaptiste Daroussin sigb = NULL; 610*cc9a8a11SBaptiste Daroussin sig = open_memstream(&sigb, &sigsz); 611*cc9a8a11SBaptiste Daroussin if (sig == NULL) 612*cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 61361acb458SBaptiste Daroussin 61461acb458SBaptiste Daroussin while ((r = read(fd, buf, sizeof(buf))) >0) { 615*cc9a8a11SBaptiste Daroussin fwrite(buf, 1, r, sig); 61661acb458SBaptiste Daroussin } 61761acb458SBaptiste Daroussin 618*cc9a8a11SBaptiste Daroussin fclose(sig); 61961acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 620*cc9a8a11SBaptiste Daroussin pk->siglen = sigsz; 62161acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 622*cc9a8a11SBaptiste Daroussin memcpy(pk->sig, sigb, pk->siglen); 623*cc9a8a11SBaptiste Daroussin free(sigb); 62461acb458SBaptiste Daroussin 62561acb458SBaptiste Daroussin return (pk); 62661acb458SBaptiste Daroussin } 62761acb458SBaptiste Daroussin 628f12db248SBryan Drewery static struct sig_cert * 629f12db248SBryan Drewery parse_cert(int fd) { 630f12db248SBryan Drewery int my_fd; 631f12db248SBryan Drewery struct sig_cert *sc; 632*cc9a8a11SBaptiste Daroussin FILE *fp, *sigfp, *certfp, *tmpfp; 633f12db248SBryan Drewery char *line; 634*cc9a8a11SBaptiste Daroussin char *sig, *cert; 635*cc9a8a11SBaptiste Daroussin size_t linecap, sigsz, certsz; 636f12db248SBryan Drewery ssize_t linelen; 637f12db248SBryan Drewery 638f12db248SBryan Drewery sc = NULL; 639f12db248SBryan Drewery line = NULL; 640f12db248SBryan Drewery linecap = 0; 641*cc9a8a11SBaptiste Daroussin sig = cert = NULL; 642*cc9a8a11SBaptiste Daroussin sigfp = certfp = tmpfp = NULL; 643f12db248SBryan Drewery 644f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 645f12db248SBryan Drewery warn("lseek"); 646f12db248SBryan Drewery return (NULL); 647f12db248SBryan Drewery } 648f12db248SBryan Drewery 649f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 650f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 651f12db248SBryan Drewery warnx("dup"); 652f12db248SBryan Drewery return (NULL); 653f12db248SBryan Drewery } 654f12db248SBryan Drewery 655f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 656f12db248SBryan Drewery warn("fdopen"); 657f12db248SBryan Drewery close(my_fd); 658f12db248SBryan Drewery return (NULL); 659f12db248SBryan Drewery } 660f12db248SBryan Drewery 661*cc9a8a11SBaptiste Daroussin sigsz = certsz = 0; 662*cc9a8a11SBaptiste Daroussin sigfp = open_memstream(&sig, &sigsz); 663*cc9a8a11SBaptiste Daroussin if (sigfp == NULL) 664*cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 665*cc9a8a11SBaptiste Daroussin certfp = open_memstream(&cert, &certsz); 666*cc9a8a11SBaptiste Daroussin if (certfp == NULL) 667*cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 668f12db248SBryan Drewery 669f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 670f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 671*cc9a8a11SBaptiste Daroussin tmpfp = sigfp; 672f12db248SBryan Drewery continue; 673f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 674*cc9a8a11SBaptiste Daroussin tmpfp = certfp; 675f12db248SBryan Drewery continue; 676f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 677f12db248SBryan Drewery break; 678f12db248SBryan Drewery } 679*cc9a8a11SBaptiste Daroussin if (tmpfp != NULL) 680*cc9a8a11SBaptiste Daroussin fwrite(line, 1, linelen, tmpfp); 681f12db248SBryan Drewery } 682f12db248SBryan Drewery 683f12db248SBryan Drewery fclose(fp); 684*cc9a8a11SBaptiste Daroussin fclose(sigfp); 685*cc9a8a11SBaptiste Daroussin fclose(certfp); 686f12db248SBryan Drewery 687f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 688*cc9a8a11SBaptiste Daroussin sc->siglen = sigsz -1; /* Trim out unrelated trailing newline */ 689*cc9a8a11SBaptiste Daroussin sc->sig = sig; 690f12db248SBryan Drewery 691*cc9a8a11SBaptiste Daroussin sc->certlen = certsz; 692*cc9a8a11SBaptiste Daroussin sc->cert = cert; 693f12db248SBryan Drewery 694f12db248SBryan Drewery return (sc); 695f12db248SBryan Drewery } 696f12db248SBryan Drewery 697f12db248SBryan Drewery static bool 69861acb458SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig) 69961acb458SBaptiste Daroussin { 70061acb458SBaptiste Daroussin struct pubkey *pk; 70161acb458SBaptiste Daroussin const char *pubkey; 70261acb458SBaptiste Daroussin bool ret; 70361acb458SBaptiste Daroussin 70461acb458SBaptiste Daroussin pk = NULL; 70561acb458SBaptiste Daroussin pubkey = NULL; 70661acb458SBaptiste Daroussin ret = false; 70761acb458SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 70861acb458SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined"); 70961acb458SBaptiste Daroussin goto cleanup; 71061acb458SBaptiste Daroussin } 71161acb458SBaptiste Daroussin 71261acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 71361acb458SBaptiste Daroussin warnx("Error reading signature"); 71461acb458SBaptiste Daroussin goto cleanup; 71561acb458SBaptiste Daroussin } 71661acb458SBaptiste Daroussin 71761acb458SBaptiste Daroussin /* Verify the signature. */ 71861acb458SBaptiste Daroussin printf("Verifying signature with public key %s... ", pubkey); 71961acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, 72061acb458SBaptiste Daroussin pk->siglen) == false) { 72161acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 72261acb458SBaptiste Daroussin goto cleanup; 72361acb458SBaptiste Daroussin } 72461acb458SBaptiste Daroussin 72561acb458SBaptiste Daroussin ret = true; 72661acb458SBaptiste Daroussin 72761acb458SBaptiste Daroussin cleanup: 72861acb458SBaptiste Daroussin if (pk) { 72961acb458SBaptiste Daroussin free(pk->sig); 73061acb458SBaptiste Daroussin free(pk); 73161acb458SBaptiste Daroussin } 73261acb458SBaptiste Daroussin 73361acb458SBaptiste Daroussin return (ret); 73461acb458SBaptiste Daroussin } 73561acb458SBaptiste Daroussin 73661acb458SBaptiste Daroussin static bool 737f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 738f12db248SBryan Drewery { 739f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 740f12db248SBryan Drewery struct fingerprint *fingerprint; 741f12db248SBryan Drewery struct sig_cert *sc; 742f12db248SBryan Drewery bool ret; 743f12db248SBryan Drewery int trusted_count, revoked_count; 744f12db248SBryan Drewery const char *fingerprints; 745f12db248SBryan Drewery char path[MAXPATHLEN]; 746f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 747f12db248SBryan Drewery 748516aaf7cSBryan Drewery sc = NULL; 749f12db248SBryan Drewery trusted = revoked = NULL; 750f12db248SBryan Drewery ret = false; 751f12db248SBryan Drewery 752f12db248SBryan Drewery /* Read and parse fingerprints. */ 753f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 754f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 755f12db248SBryan Drewery goto cleanup; 756f12db248SBryan Drewery } 757f12db248SBryan Drewery 758f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 759f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 760f12db248SBryan Drewery warnx("Error loading trusted certificates"); 761f12db248SBryan Drewery goto cleanup; 762f12db248SBryan Drewery } 763f12db248SBryan Drewery 764f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 765f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 766f12db248SBryan Drewery goto cleanup; 767f12db248SBryan Drewery } 768f12db248SBryan Drewery 769f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 770f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 771f12db248SBryan Drewery warnx("Error loading revoked certificates"); 772f12db248SBryan Drewery goto cleanup; 773f12db248SBryan Drewery } 774f12db248SBryan Drewery 775f12db248SBryan Drewery /* Read certificate and signature in. */ 776f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 777f12db248SBryan Drewery warnx("Error parsing certificate"); 778f12db248SBryan Drewery goto cleanup; 779f12db248SBryan Drewery } 780f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 781f12db248SBryan Drewery sc->trusted = false; 782f12db248SBryan Drewery 783f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 784f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 785f12db248SBryan Drewery 786f12db248SBryan Drewery /* Check if this hash is revoked */ 787f12db248SBryan Drewery if (revoked != NULL) { 788f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 789f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 790516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 791516aaf7cSBryan Drewery "revoked certificate %s\n", 792516aaf7cSBryan Drewery fingerprint->name); 793f12db248SBryan Drewery goto cleanup; 794f12db248SBryan Drewery } 795f12db248SBryan Drewery } 796f12db248SBryan Drewery } 797f12db248SBryan Drewery 798f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 799f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 800f12db248SBryan Drewery sc->trusted = true; 801516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 802f12db248SBryan Drewery break; 803f12db248SBryan Drewery } 804f12db248SBryan Drewery } 805f12db248SBryan Drewery 806f12db248SBryan Drewery if (sc->trusted == false) { 807516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 808f12db248SBryan Drewery "package's certificate\n"); 809f12db248SBryan Drewery goto cleanup; 810f12db248SBryan Drewery } 811f12db248SBryan Drewery 812f12db248SBryan Drewery /* Verify the signature. */ 813516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 81461acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, 815f12db248SBryan Drewery sc->siglen) == false) { 816f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 817f12db248SBryan Drewery goto cleanup; 818f12db248SBryan Drewery } 819f12db248SBryan Drewery 820f12db248SBryan Drewery ret = true; 821f12db248SBryan Drewery 822f12db248SBryan Drewery cleanup: 823516aaf7cSBryan Drewery if (trusted) 824516aaf7cSBryan Drewery free_fingerprint_list(trusted); 825516aaf7cSBryan Drewery if (revoked) 826516aaf7cSBryan Drewery free_fingerprint_list(revoked); 827f12db248SBryan Drewery if (sc) { 828f12db248SBryan Drewery free(sc->cert); 829f12db248SBryan Drewery free(sc->sig); 830516aaf7cSBryan Drewery free(sc->name); 831f12db248SBryan Drewery free(sc); 832f12db248SBryan Drewery } 833f12db248SBryan Drewery 834f12db248SBryan Drewery return (ret); 835f12db248SBryan Drewery } 836f12db248SBryan Drewery 837f12db248SBryan Drewery static int 838ae994fdcSBaptiste Daroussin bootstrap_pkg(bool force, const char *fetchOpts) 839f12db248SBryan Drewery { 840f12db248SBryan Drewery int fd_pkg, fd_sig; 841f12db248SBryan Drewery int ret; 842f12db248SBryan Drewery char url[MAXPATHLEN]; 843f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 844f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 845f12db248SBryan Drewery const char *packagesite; 846f12db248SBryan Drewery const char *signature_type; 847f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 848a2aac2f5SBaptiste Daroussin const char *bootstrap_name; 849f12db248SBryan Drewery 850f12db248SBryan Drewery fd_sig = -1; 851f12db248SBryan Drewery ret = -1; 852f12db248SBryan Drewery 853f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 854f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 855f12db248SBryan Drewery return (-1); 856f12db248SBryan Drewery } 857f12db248SBryan Drewery 858f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 859f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 860f12db248SBryan Drewery return (-1); 861f12db248SBryan Drewery } 862f12db248SBryan Drewery 863f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 864f12db248SBryan Drewery 865f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 866f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 867f12db248SBryan Drewery no A record. */ 868f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 869f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 870f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 871a2aac2f5SBaptiste Daroussin for (int j = 0; bootstrap_names[j] != NULL; j++) { 872a2aac2f5SBaptiste Daroussin bootstrap_name = bootstrap_names[j]; 873f12db248SBryan Drewery 874a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s", packagesite, bootstrap_name); 875a2aac2f5SBaptiste Daroussin snprintf(tmppkg, MAXPATHLEN, "%s/%s.XXXXXX", 876a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 877a2aac2f5SBaptiste Daroussin bootstrap_name); 878a2aac2f5SBaptiste Daroussin if ((fd_pkg = fetch_to_fd(url, tmppkg, fetchOpts)) != -1) 879a2aac2f5SBaptiste Daroussin break; 880a2aac2f5SBaptiste Daroussin bootstrap_name = NULL; 881a2aac2f5SBaptiste Daroussin } 882a2aac2f5SBaptiste Daroussin if (bootstrap_name == NULL) 883f12db248SBryan Drewery goto fetchfail; 884f12db248SBryan Drewery 885f12db248SBryan Drewery if (signature_type != NULL && 88648f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 88761acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 88848f92706SXin LI 889a2aac2f5SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX", 890a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 891a2aac2f5SBaptiste Daroussin bootstrap_name); 892a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig", 893a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 894f12db248SBryan Drewery 895ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 89661acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 89761acb458SBaptiste Daroussin "available.\n"); 898f12db248SBryan Drewery goto fetchfail; 899f12db248SBryan Drewery } 900f12db248SBryan Drewery 901f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 902f12db248SBryan Drewery goto cleanup; 90361acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 90461acb458SBaptiste Daroussin 90561acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 906a2aac2f5SBaptiste Daroussin "%s/%s.pubkeysig.XXXXXX", 907a2aac2f5SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, 908a2aac2f5SBaptiste Daroussin bootstrap_name); 909a2aac2f5SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/%s.pubkeysig", 910a2aac2f5SBaptiste Daroussin packagesite, bootstrap_name); 91161acb458SBaptiste Daroussin 912ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 91361acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 91461acb458SBaptiste Daroussin "available.\n"); 91561acb458SBaptiste Daroussin goto fetchfail; 91661acb458SBaptiste Daroussin } 91761acb458SBaptiste Daroussin 91861acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 91961acb458SBaptiste Daroussin goto cleanup; 92061acb458SBaptiste Daroussin } else { 92161acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 92261acb458SBaptiste Daroussin "bootstrapping.", signature_type); 92361acb458SBaptiste Daroussin goto cleanup; 92461acb458SBaptiste Daroussin } 925f12db248SBryan Drewery } 926f12db248SBryan Drewery 927f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9285212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 9293aa4b42aSBaptiste Daroussin 930a6454741SBaptiste Daroussin goto cleanup; 931a6454741SBaptiste Daroussin 932a6454741SBaptiste Daroussin fetchfail: 933a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 934a10f71c5STom Jones if (fetchLastErrCode == FETCH_RESOLV) { 935a10f71c5STom Jones fprintf(stderr, "Address resolution failed for %s.\n", packagesite); 936a10f71c5STom Jones fprintf(stderr, "Consider changing PACKAGESITE.\n"); 937a10f71c5STom Jones } else { 9384ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 9394ff9a7efSBryan Drewery "your system.\n"); 9404ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 9414ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 942a10f71c5STom Jones } 943a6454741SBaptiste Daroussin 9443aa4b42aSBaptiste Daroussin cleanup: 945f12db248SBryan Drewery if (fd_sig != -1) { 946f12db248SBryan Drewery close(fd_sig); 947f12db248SBryan Drewery unlink(tmpsig); 948f12db248SBryan Drewery } 94992947daaSBaptiste Daroussin 95092947daaSBaptiste Daroussin if (fd_pkg != -1) { 951f12db248SBryan Drewery close(fd_pkg); 9523aa4b42aSBaptiste Daroussin unlink(tmppkg); 95392947daaSBaptiste Daroussin } 9543aa4b42aSBaptiste Daroussin 955a6454741SBaptiste Daroussin return (ret); 9563aa4b42aSBaptiste Daroussin } 9573aa4b42aSBaptiste Daroussin 958e18ad51cSAlexander Kabaev static const char confirmation_message[] = 959e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 960e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 961e18ad51cSAlexander Kabaev 962e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 963575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 9641efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 965e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 966575c4095SBaptiste Daroussin 967ae994fdcSBaptiste Daroussin static const char args_bootstrap_message[] = 968ae994fdcSBaptiste Daroussin "Too many arguments\n" 969ae994fdcSBaptiste Daroussin "Usage: pkg [-4|-6] bootstrap [-f] [-y]\n"; 970ae994fdcSBaptiste Daroussin 971ae994fdcSBaptiste Daroussin static const char args_add_message[] = 972ae994fdcSBaptiste Daroussin "Too many arguments\n" 973ae994fdcSBaptiste Daroussin "Usage: pkg add [-f] [-y] {pkg.txz}\n"; 974ae994fdcSBaptiste Daroussin 975e18ad51cSAlexander Kabaev static int 976e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 977e18ad51cSAlexander Kabaev { 978e18ad51cSAlexander Kabaev int ret, c; 979e18ad51cSAlexander Kabaev 98067c9f60eSPoul-Henning Kamp fflush(stdout); 981e18ad51cSAlexander Kabaev c = getchar(); 982e18ad51cSAlexander Kabaev 983e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 984e18ad51cSAlexander Kabaev ret = 1; 985e18ad51cSAlexander Kabaev else 986e18ad51cSAlexander Kabaev ret = 0; 987e18ad51cSAlexander Kabaev 988e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 989e18ad51cSAlexander Kabaev c = getchar(); 990e18ad51cSAlexander Kabaev 991e18ad51cSAlexander Kabaev return (ret); 992e18ad51cSAlexander Kabaev } 993e18ad51cSAlexander Kabaev 99452cb76feSBryan Drewery static int 9955212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 99652cb76feSBryan Drewery { 99752cb76feSBryan Drewery char path[MAXPATHLEN]; 99852cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 99952cb76feSBryan Drewery const char *signature_type; 100052cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 100152cb76feSBryan Drewery 100252cb76feSBryan Drewery fd_sig = -1; 100352cb76feSBryan Drewery ret = -1; 100452cb76feSBryan Drewery 100552cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 100652cb76feSBryan Drewery if (fd_pkg == -1) 100752cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 100852cb76feSBryan Drewery 100952cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 101052cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 101192947daaSBaptiste Daroussin goto cleanup; 101252cb76feSBryan Drewery } 101352cb76feSBryan Drewery if (signature_type != NULL && 101448f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 101561acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 101648f92706SXin LI 101752cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 101852cb76feSBryan Drewery 101952cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 102061acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 102161acb458SBaptiste Daroussin "available.\n"); 102252cb76feSBryan Drewery goto cleanup; 102352cb76feSBryan Drewery } 102452cb76feSBryan Drewery 102552cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 102652cb76feSBryan Drewery goto cleanup; 102761acb458SBaptiste Daroussin 102861acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 102961acb458SBaptiste Daroussin 103061acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 103161acb458SBaptiste Daroussin 103261acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 103361acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 103461acb458SBaptiste Daroussin "available.\n"); 103561acb458SBaptiste Daroussin goto cleanup; 103661acb458SBaptiste Daroussin } 103761acb458SBaptiste Daroussin 103861acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 103961acb458SBaptiste Daroussin goto cleanup; 104061acb458SBaptiste Daroussin 104161acb458SBaptiste Daroussin } else { 104261acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 104361acb458SBaptiste Daroussin "bootstrapping.", signature_type); 104461acb458SBaptiste Daroussin goto cleanup; 104561acb458SBaptiste Daroussin } 104652cb76feSBryan Drewery } 104752cb76feSBryan Drewery 104852cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 10495212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 105052cb76feSBryan Drewery 105152cb76feSBryan Drewery cleanup: 105252cb76feSBryan Drewery close(fd_pkg); 105352cb76feSBryan Drewery if (fd_sig != -1) 105452cb76feSBryan Drewery close(fd_sig); 105552cb76feSBryan Drewery 105652cb76feSBryan Drewery return (ret); 105752cb76feSBryan Drewery } 105852cb76feSBryan Drewery 10593aa4b42aSBaptiste Daroussin int 106046b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10613aa4b42aSBaptiste Daroussin { 10623aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 106318418e19SKyle Evans const char *pkgarg, *repo_name; 1064ae994fdcSBaptiste Daroussin bool activation_test, add_pkg, bootstrap_only, force, yes; 1065ae994fdcSBaptiste Daroussin signed char ch; 1066ae994fdcSBaptiste Daroussin const char *fetchOpts; 1067ae994fdcSBaptiste Daroussin char *command; 10685212e8baSBryan Drewery 1069ae994fdcSBaptiste Daroussin activation_test = false; 1070ae994fdcSBaptiste Daroussin add_pkg = false; 10715212e8baSBryan Drewery bootstrap_only = false; 1072ae994fdcSBaptiste Daroussin command = NULL; 1073ae994fdcSBaptiste Daroussin fetchOpts = ""; 10745212e8baSBryan Drewery force = false; 10755212e8baSBryan Drewery pkgarg = NULL; 107618418e19SKyle Evans repo_name = NULL; 10775212e8baSBryan Drewery yes = false; 10783aa4b42aSBaptiste Daroussin 1079ae994fdcSBaptiste Daroussin struct option longopts[] = { 1080ae994fdcSBaptiste Daroussin { "force", no_argument, NULL, 'f' }, 1081ae994fdcSBaptiste Daroussin { "only-ipv4", no_argument, NULL, '4' }, 1082ae994fdcSBaptiste Daroussin { "only-ipv6", no_argument, NULL, '6' }, 1083ae994fdcSBaptiste Daroussin { "yes", no_argument, NULL, 'y' }, 1084ae994fdcSBaptiste Daroussin { NULL, 0, NULL, 0 }, 1085ae994fdcSBaptiste Daroussin }; 1086ae994fdcSBaptiste Daroussin 108756d11d4aSStefan Eßer snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase()); 10883aa4b42aSBaptiste Daroussin 108918418e19SKyle Evans while ((ch = getopt_long(argc, argv, "-:fr::yN46", longopts, NULL)) != -1) { 1090ae994fdcSBaptiste Daroussin switch (ch) { 1091ae994fdcSBaptiste Daroussin case 'f': 1092ae994fdcSBaptiste Daroussin force = true; 1093ae994fdcSBaptiste Daroussin break; 1094ae994fdcSBaptiste Daroussin case 'N': 1095ae994fdcSBaptiste Daroussin activation_test = true; 1096ae994fdcSBaptiste Daroussin break; 1097ae994fdcSBaptiste Daroussin case 'y': 1098ae994fdcSBaptiste Daroussin yes = true; 1099ae994fdcSBaptiste Daroussin break; 1100ae994fdcSBaptiste Daroussin case '4': 1101ae994fdcSBaptiste Daroussin fetchOpts = "4"; 1102ae994fdcSBaptiste Daroussin break; 1103ae994fdcSBaptiste Daroussin case '6': 1104ae994fdcSBaptiste Daroussin fetchOpts = "6"; 1105ae994fdcSBaptiste Daroussin break; 110618418e19SKyle Evans case 'r': 110718418e19SKyle Evans /* 110818418e19SKyle Evans * The repository can only be specified for an explicit 110918418e19SKyle Evans * bootstrap request at this time, so that we don't 111018418e19SKyle Evans * confuse the user if they're trying to use a verb that 111118418e19SKyle Evans * has some other conflicting meaning but we need to 111218418e19SKyle Evans * bootstrap. 111318418e19SKyle Evans * 111418418e19SKyle Evans * For that reason, we specify that -r has an optional 111518418e19SKyle Evans * argument above and process the next index ourselves. 111618418e19SKyle Evans * This is mostly significant because getopt(3) will 111718418e19SKyle Evans * otherwise eat the next argument, which could be 111818418e19SKyle Evans * something we need to try and make sense of. 111918418e19SKyle Evans * 112018418e19SKyle Evans * At worst this gets us false positives that we ignore 112118418e19SKyle Evans * in other contexts, and we have to do a little fudging 112218418e19SKyle Evans * in order to support separating -r from the reponame 112318418e19SKyle Evans * with a space since it's not actually optional in 112418418e19SKyle Evans * the bootstrap/add sense. 112518418e19SKyle Evans */ 112618418e19SKyle Evans if (add_pkg || bootstrap_only) { 112718418e19SKyle Evans if (optarg != NULL) { 112818418e19SKyle Evans repo_name = optarg; 112918418e19SKyle Evans } else if (optind < argc) { 113018418e19SKyle Evans repo_name = argv[optind]; 113118418e19SKyle Evans } 113218418e19SKyle Evans 113318418e19SKyle Evans if (repo_name == NULL || *repo_name == '\0') { 113418418e19SKyle Evans fprintf(stderr, 113518418e19SKyle Evans "Must specify a repository with -r!\n"); 113618418e19SKyle Evans exit(EXIT_FAILURE); 113718418e19SKyle Evans } 113818418e19SKyle Evans 113918418e19SKyle Evans if (optarg == NULL) { 114018418e19SKyle Evans /* Advance past repo name. */ 114118418e19SKyle Evans optreset = 1; 114218418e19SKyle Evans optind++; 114318418e19SKyle Evans } 114418418e19SKyle Evans } 114518418e19SKyle Evans break; 1146ae994fdcSBaptiste Daroussin case 1: 1147ae994fdcSBaptiste Daroussin // Non-option arguments, first one is the command 1148ae994fdcSBaptiste Daroussin if (command == NULL) { 1149ae994fdcSBaptiste Daroussin command = argv[optind-1]; 1150ae994fdcSBaptiste Daroussin if (strcmp(command, "add") == 0) { 1151ae994fdcSBaptiste Daroussin add_pkg = true; 1152ae994fdcSBaptiste Daroussin } 1153ae994fdcSBaptiste Daroussin else if (strcmp(command, "bootstrap") == 0) { 11545212e8baSBryan Drewery bootstrap_only = true; 1155ae994fdcSBaptiste Daroussin } 1156ae994fdcSBaptiste Daroussin } 1157ae994fdcSBaptiste Daroussin // bootstrap doesn't accept other arguments 1158ae994fdcSBaptiste Daroussin else if (bootstrap_only) { 1159ae994fdcSBaptiste Daroussin fprintf(stderr, args_bootstrap_message); 1160ca7f7593SKyle Evans exit(EXIT_FAILURE); 1161ca7f7593SKyle Evans } 1162ae994fdcSBaptiste Daroussin // For add, we accept exactly one further argument 1163ae994fdcSBaptiste Daroussin else if (add_pkg && pkgarg != NULL) { 1164ae994fdcSBaptiste Daroussin fprintf(stderr, args_add_message); 1165ca7f7593SKyle Evans exit(EXIT_FAILURE); 1166ca7f7593SKyle Evans } 1167ae994fdcSBaptiste Daroussin else if (add_pkg) { 1168ae994fdcSBaptiste Daroussin pkgarg = argv[optind-1]; 1169ae994fdcSBaptiste Daroussin } 1170ae994fdcSBaptiste Daroussin break; 1171ae994fdcSBaptiste Daroussin default: 1172ae994fdcSBaptiste Daroussin break; 1173ae994fdcSBaptiste Daroussin } 11745212e8baSBryan Drewery } 11755212e8baSBryan Drewery 11765212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1177e18ad51cSAlexander Kabaev /* 1178d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1179ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1180ae994fdcSBaptiste Daroussin * when that that option is passed. 1181ecfed9f2SMatthew Seaman */ 1182ae994fdcSBaptiste Daroussin if (activation_test) 1183e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1184ecfed9f2SMatthew Seaman 118518418e19SKyle Evans config_init(repo_name); 118652cb76feSBryan Drewery 1187ae994fdcSBaptiste Daroussin if (add_pkg) { 11885212e8baSBryan Drewery if (pkgarg == NULL) { 11895212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 11905212e8baSBryan Drewery exit(EXIT_FAILURE); 11915212e8baSBryan Drewery } 11925212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 11935212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 11945212e8baSBryan Drewery exit(EXIT_FAILURE); 11955212e8baSBryan Drewery } 11965212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1197b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1198b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1199b70213b5SBaptiste Daroussin } 1200ecfed9f2SMatthew Seaman /* 1201e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1202e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1203e18ad51cSAlexander Kabaev * tucked in there already. 1204e18ad51cSAlexander Kabaev */ 1205ae994fdcSBaptiste Daroussin if (!yes) 12069950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 12079950eceeSBaptiste Daroussin if (!yes) { 1208575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1209e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 12103a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1211575c4095SBaptiste Daroussin } 1212204ea792SBaptiste Daroussin 1213575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1214204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1215e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1216e18ad51cSAlexander Kabaev } 1217ae994fdcSBaptiste Daroussin if (bootstrap_pkg(force, fetchOpts) != 0) 1218a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 12199950eceeSBaptiste Daroussin config_finish(); 1220c3e8a27aSBryan Drewery 12215212e8baSBryan Drewery if (bootstrap_only) 1222c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 12235212e8baSBryan Drewery } else if (bootstrap_only) { 12245212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1225c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1226c3e8a27aSBryan Drewery } 12273aa4b42aSBaptiste Daroussin 12283aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 12293aa4b42aSBaptiste Daroussin 1230a6454741SBaptiste Daroussin /* NOT REACHED */ 12313b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 12323aa4b42aSBaptiste Daroussin } 1233