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 94e9ad2964SBrooks Davis static int debug; 95e9ad2964SBrooks Davis 963aa4b42aSBaptiste Daroussin static int 973aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 983aa4b42aSBaptiste Daroussin { 993aa4b42aSBaptiste Daroussin struct archive *a; 1003aa4b42aSBaptiste Daroussin struct archive_entry *ae; 1013aa4b42aSBaptiste Daroussin char *end; 1023aa4b42aSBaptiste Daroussin int ret, r; 1033aa4b42aSBaptiste Daroussin 104a6454741SBaptiste Daroussin ret = -1; 1053aa4b42aSBaptiste Daroussin a = archive_read_new(); 106a6454741SBaptiste Daroussin if (a == NULL) { 107a6454741SBaptiste Daroussin warn("archive_read_new"); 108a6454741SBaptiste Daroussin return (ret); 109a6454741SBaptiste Daroussin } 110ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1113aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1123aa4b42aSBaptiste Daroussin 113a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 114a6454741SBaptiste Daroussin warn("lseek"); 115a6454741SBaptiste Daroussin goto cleanup; 116a6454741SBaptiste Daroussin } 1173aa4b42aSBaptiste Daroussin 1183aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 119a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1203aa4b42aSBaptiste Daroussin goto cleanup; 1213aa4b42aSBaptiste Daroussin } 1223aa4b42aSBaptiste Daroussin 1233aa4b42aSBaptiste Daroussin ae = NULL; 1243aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1253aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1263aa4b42aSBaptiste Daroussin if (end == NULL) 1273aa4b42aSBaptiste Daroussin continue; 1283aa4b42aSBaptiste Daroussin 1293aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1303aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1313aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1323aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1333aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 134a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1353aa4b42aSBaptiste Daroussin break; 1363aa4b42aSBaptiste Daroussin } 1373aa4b42aSBaptiste Daroussin } 1383aa4b42aSBaptiste Daroussin 139a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 140a6454741SBaptiste Daroussin ret = 0; 141a6454741SBaptiste Daroussin else 1424622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1434622bc4eSGavin Atkinson archive_error_string(a)); 1443aa4b42aSBaptiste Daroussin 1453aa4b42aSBaptiste Daroussin cleanup: 146ff75c36aSBaptiste Daroussin archive_read_free(a); 1473b05c2a8SBaptiste Daroussin return (ret); 1483aa4b42aSBaptiste Daroussin 1493aa4b42aSBaptiste Daroussin } 1503aa4b42aSBaptiste Daroussin 1513aa4b42aSBaptiste Daroussin static int 1525212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1533aa4b42aSBaptiste Daroussin { 1543aa4b42aSBaptiste Daroussin int pstat; 1553aa4b42aSBaptiste Daroussin pid_t pid; 1563aa4b42aSBaptiste Daroussin 1573aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1583aa4b42aSBaptiste Daroussin case -1: 1593aa4b42aSBaptiste Daroussin return (-1); 1603aa4b42aSBaptiste Daroussin case 0: 1615212e8baSBryan Drewery if (force) 1625212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 1635212e8baSBryan Drewery (char *)NULL); 1645212e8baSBryan Drewery else 1655212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 1665212e8baSBryan Drewery (char *)NULL); 1673b05c2a8SBaptiste Daroussin _exit(1); 1683aa4b42aSBaptiste Daroussin default: 1693aa4b42aSBaptiste Daroussin break; 1703aa4b42aSBaptiste Daroussin } 1713aa4b42aSBaptiste Daroussin 172a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1733aa4b42aSBaptiste Daroussin if (errno != EINTR) 1743aa4b42aSBaptiste Daroussin return (-1); 1753aa4b42aSBaptiste Daroussin 176a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1773aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 178a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 179a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 180a6454741SBaptiste Daroussin return (pstat); 1813aa4b42aSBaptiste Daroussin } 1823aa4b42aSBaptiste Daroussin 1833aa4b42aSBaptiste Daroussin static int 184ae994fdcSBaptiste Daroussin fetch_to_fd(const char *url, char *path, const char *fetchOpts) 1853aa4b42aSBaptiste Daroussin { 18629aaa961SBaptiste Daroussin struct url *u; 18729aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 188a6454741SBaptiste Daroussin struct url_stat st; 189f12db248SBryan Drewery FILE *remote; 190f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 191f12db248SBryan Drewery int fd; 192f12db248SBryan Drewery int retry, max_retry; 193cc36fe49SBaptiste Daroussin ssize_t r; 194f12db248SBryan Drewery char buf[10240]; 195f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 196f12db248SBryan Drewery static const char *mirror_type = NULL; 1973aa4b42aSBaptiste Daroussin 19829aaa961SBaptiste Daroussin max_retry = 3; 19929aaa961SBaptiste Daroussin current = mirrors = NULL; 200f12db248SBryan Drewery remote = NULL; 2013aa4b42aSBaptiste Daroussin 202f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 203f12db248SBryan Drewery != 0) { 2049950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 2059950eceeSBaptiste Daroussin return (-1); 2069950eceeSBaptiste Daroussin } 20762940ea9SBryan Drewery 208f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2093aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2103b05c2a8SBaptiste Daroussin return (-1); 2113aa4b42aSBaptiste Daroussin } 2123aa4b42aSBaptiste Daroussin 21329aaa961SBaptiste Daroussin retry = max_retry; 21429aaa961SBaptiste Daroussin 21579fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 21679fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 21779fe80efSBaptiste Daroussin return (-1); 21879fe80efSBaptiste Daroussin } 21979fe80efSBaptiste Daroussin 22029aaa961SBaptiste Daroussin while (remote == NULL) { 22129aaa961SBaptiste Daroussin if (retry == max_retry) { 2229950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2239950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 22429aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 22529aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 22629aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 22729aaa961SBaptiste Daroussin current = mirrors; 22829aaa961SBaptiste Daroussin } 22929aaa961SBaptiste Daroussin } 23029aaa961SBaptiste Daroussin 23135e07a7aSBaptiste Daroussin if (mirrors != NULL) { 23229aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 23335e07a7aSBaptiste Daroussin u->port = current->port; 23435e07a7aSBaptiste Daroussin } 23529aaa961SBaptiste Daroussin 236ae994fdcSBaptiste Daroussin remote = fetchXGet(u, &st, fetchOpts); 23729aaa961SBaptiste Daroussin if (remote == NULL) { 23829aaa961SBaptiste Daroussin --retry; 23929aaa961SBaptiste Daroussin if (retry <= 0) 24029aaa961SBaptiste Daroussin goto fetchfail; 24160b92ba9SJohn Hood if (mirrors != NULL) { 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; 597cc9a8a11SBaptiste Daroussin char *sigb; 598cc9a8a11SBaptiste Daroussin size_t sigsz; 599cc9a8a11SBaptiste 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 608cc9a8a11SBaptiste Daroussin sigsz = 0; 609cc9a8a11SBaptiste Daroussin sigb = NULL; 610cc9a8a11SBaptiste Daroussin sig = open_memstream(&sigb, &sigsz); 611cc9a8a11SBaptiste Daroussin if (sig == NULL) 612cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 61361acb458SBaptiste Daroussin 61461acb458SBaptiste Daroussin while ((r = read(fd, buf, sizeof(buf))) >0) { 615cc9a8a11SBaptiste Daroussin fwrite(buf, 1, r, sig); 61661acb458SBaptiste Daroussin } 61761acb458SBaptiste Daroussin 618cc9a8a11SBaptiste Daroussin fclose(sig); 61961acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 620cc9a8a11SBaptiste Daroussin pk->siglen = sigsz; 62161acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 622cc9a8a11SBaptiste Daroussin memcpy(pk->sig, sigb, pk->siglen); 623cc9a8a11SBaptiste 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; 632cc9a8a11SBaptiste Daroussin FILE *fp, *sigfp, *certfp, *tmpfp; 633f12db248SBryan Drewery char *line; 634cc9a8a11SBaptiste Daroussin char *sig, *cert; 635cc9a8a11SBaptiste 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; 641cc9a8a11SBaptiste Daroussin sig = cert = NULL; 642cc9a8a11SBaptiste 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 661cc9a8a11SBaptiste Daroussin sigsz = certsz = 0; 662cc9a8a11SBaptiste Daroussin sigfp = open_memstream(&sig, &sigsz); 663cc9a8a11SBaptiste Daroussin if (sigfp == NULL) 664cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 665cc9a8a11SBaptiste Daroussin certfp = open_memstream(&cert, &certsz); 666cc9a8a11SBaptiste Daroussin if (certfp == NULL) 667cc9a8a11SBaptiste 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) { 671cc9a8a11SBaptiste Daroussin tmpfp = sigfp; 672f12db248SBryan Drewery continue; 673f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 674cc9a8a11SBaptiste Daroussin tmpfp = certfp; 675f12db248SBryan Drewery continue; 676f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 677f12db248SBryan Drewery break; 678f12db248SBryan Drewery } 679cc9a8a11SBaptiste Daroussin if (tmpfp != NULL) 680cc9a8a11SBaptiste Daroussin fwrite(line, 1, linelen, tmpfp); 681f12db248SBryan Drewery } 682f12db248SBryan Drewery 683f12db248SBryan Drewery fclose(fp); 684cc9a8a11SBaptiste Daroussin fclose(sigfp); 685cc9a8a11SBaptiste Daroussin fclose(certfp); 686f12db248SBryan Drewery 687f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 688cc9a8a11SBaptiste Daroussin sc->siglen = sigsz -1; /* Trim out unrelated trailing newline */ 689cc9a8a11SBaptiste Daroussin sc->sig = sig; 690f12db248SBryan Drewery 691cc9a8a11SBaptiste Daroussin sc->certlen = certsz; 692cc9a8a11SBaptiste 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 105940b9f924SKyle Evans #define PKG_NAME "pkg" 106040b9f924SKyle Evans #define PKG_DEVEL_NAME PKG_NAME "-devel" 106140b9f924SKyle Evans #define PKG_PKG PKG_NAME "." 106240b9f924SKyle Evans 106340b9f924SKyle Evans static bool 106440b9f924SKyle Evans pkg_is_pkg_pkg(const char *pkg) 106540b9f924SKyle Evans { 1066c96b4d87SGleb Smirnoff char *vstart, *basename; 106740b9f924SKyle Evans size_t namelen; 106840b9f924SKyle Evans 1069c96b4d87SGleb Smirnoff /* Strip path. */ 1070c96b4d87SGleb Smirnoff if ((basename = strrchr(pkg, '/')) != NULL) 1071c96b4d87SGleb Smirnoff pkg = basename + 1; 1072c96b4d87SGleb Smirnoff 107340b9f924SKyle Evans /* 107440b9f924SKyle Evans * Chop off the final "-" (version delimiter) and check the name that 107540b9f924SKyle Evans * precedes it. If we didn't have a version delimiter, it must be the 107640b9f924SKyle Evans * pkg.$archive short form but we'll check it anyways. pkg-devel short 107740b9f924SKyle Evans * form will look like a pkg archive with 'devel' version, but that's 107840b9f924SKyle Evans * OK. We otherwise assumed that non-pkg packages will always have a 107940b9f924SKyle Evans * version component. 108040b9f924SKyle Evans */ 108140b9f924SKyle Evans vstart = strrchr(pkg, '-'); 108240b9f924SKyle Evans if (vstart == NULL) { 108340b9f924SKyle Evans return (strlen(pkg) > sizeof(PKG_PKG) - 1 && 108440b9f924SKyle Evans strncmp(pkg, PKG_PKG, sizeof(PKG_PKG) - 1) == 0); 108540b9f924SKyle Evans } 108640b9f924SKyle Evans 108740b9f924SKyle Evans namelen = vstart - pkg; 108840b9f924SKyle Evans if (namelen == sizeof(PKG_NAME) - 1 && 108940b9f924SKyle Evans strncmp(pkg, PKG_NAME, sizeof(PKG_NAME) - 1) == 0) 109040b9f924SKyle Evans return (true); 109140b9f924SKyle Evans if (namelen == sizeof(PKG_DEVEL_NAME) - 1 && 109240b9f924SKyle Evans strncmp(pkg, PKG_DEVEL_NAME, sizeof(PKG_DEVEL_NAME) - 1) == 0) 109340b9f924SKyle Evans return (true); 109440b9f924SKyle Evans return (false); 109540b9f924SKyle Evans } 109640b9f924SKyle Evans 10973aa4b42aSBaptiste Daroussin int 109846b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10993aa4b42aSBaptiste Daroussin { 11003aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 110118418e19SKyle Evans const char *pkgarg, *repo_name; 1102ae994fdcSBaptiste Daroussin bool activation_test, add_pkg, bootstrap_only, force, yes; 1103ae994fdcSBaptiste Daroussin signed char ch; 1104ae994fdcSBaptiste Daroussin const char *fetchOpts; 1105ae994fdcSBaptiste Daroussin char *command; 11065212e8baSBryan Drewery 1107ae994fdcSBaptiste Daroussin activation_test = false; 1108ae994fdcSBaptiste Daroussin add_pkg = false; 11095212e8baSBryan Drewery bootstrap_only = false; 1110ae994fdcSBaptiste Daroussin command = NULL; 1111ae994fdcSBaptiste Daroussin fetchOpts = ""; 11125212e8baSBryan Drewery force = false; 11135212e8baSBryan Drewery pkgarg = NULL; 111418418e19SKyle Evans repo_name = NULL; 11155212e8baSBryan Drewery yes = false; 11163aa4b42aSBaptiste Daroussin 1117ae994fdcSBaptiste Daroussin struct option longopts[] = { 1118e9ad2964SBrooks Davis { "debug", no_argument, NULL, 'd' }, 1119ae994fdcSBaptiste Daroussin { "force", no_argument, NULL, 'f' }, 1120ae994fdcSBaptiste Daroussin { "only-ipv4", no_argument, NULL, '4' }, 1121ae994fdcSBaptiste Daroussin { "only-ipv6", no_argument, NULL, '6' }, 1122ae994fdcSBaptiste Daroussin { "yes", no_argument, NULL, 'y' }, 1123ae994fdcSBaptiste Daroussin { NULL, 0, NULL, 0 }, 1124ae994fdcSBaptiste Daroussin }; 1125ae994fdcSBaptiste Daroussin 112656d11d4aSStefan Eßer snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase()); 11273aa4b42aSBaptiste Daroussin 1128e9ad2964SBrooks Davis while ((ch = getopt_long(argc, argv, "-:dfr::yN46", longopts, NULL)) != -1) { 1129ae994fdcSBaptiste Daroussin switch (ch) { 1130e9ad2964SBrooks Davis case 'd': 1131e9ad2964SBrooks Davis debug++; 1132e9ad2964SBrooks Davis break; 1133ae994fdcSBaptiste Daroussin case 'f': 1134ae994fdcSBaptiste Daroussin force = true; 1135ae994fdcSBaptiste Daroussin break; 1136ae994fdcSBaptiste Daroussin case 'N': 1137ae994fdcSBaptiste Daroussin activation_test = true; 1138ae994fdcSBaptiste Daroussin break; 1139ae994fdcSBaptiste Daroussin case 'y': 1140ae994fdcSBaptiste Daroussin yes = true; 1141ae994fdcSBaptiste Daroussin break; 1142ae994fdcSBaptiste Daroussin case '4': 1143ae994fdcSBaptiste Daroussin fetchOpts = "4"; 1144ae994fdcSBaptiste Daroussin break; 1145ae994fdcSBaptiste Daroussin case '6': 1146ae994fdcSBaptiste Daroussin fetchOpts = "6"; 1147ae994fdcSBaptiste Daroussin break; 114818418e19SKyle Evans case 'r': 114918418e19SKyle Evans /* 115018418e19SKyle Evans * The repository can only be specified for an explicit 115118418e19SKyle Evans * bootstrap request at this time, so that we don't 115218418e19SKyle Evans * confuse the user if they're trying to use a verb that 115318418e19SKyle Evans * has some other conflicting meaning but we need to 115418418e19SKyle Evans * bootstrap. 115518418e19SKyle Evans * 115618418e19SKyle Evans * For that reason, we specify that -r has an optional 115718418e19SKyle Evans * argument above and process the next index ourselves. 115818418e19SKyle Evans * This is mostly significant because getopt(3) will 115918418e19SKyle Evans * otherwise eat the next argument, which could be 116018418e19SKyle Evans * something we need to try and make sense of. 116118418e19SKyle Evans * 116218418e19SKyle Evans * At worst this gets us false positives that we ignore 116318418e19SKyle Evans * in other contexts, and we have to do a little fudging 116418418e19SKyle Evans * in order to support separating -r from the reponame 116518418e19SKyle Evans * with a space since it's not actually optional in 116618418e19SKyle Evans * the bootstrap/add sense. 116718418e19SKyle Evans */ 116818418e19SKyle Evans if (add_pkg || bootstrap_only) { 116918418e19SKyle Evans if (optarg != NULL) { 117018418e19SKyle Evans repo_name = optarg; 117118418e19SKyle Evans } else if (optind < argc) { 117218418e19SKyle Evans repo_name = argv[optind]; 117318418e19SKyle Evans } 117418418e19SKyle Evans 117518418e19SKyle Evans if (repo_name == NULL || *repo_name == '\0') { 117618418e19SKyle Evans fprintf(stderr, 117718418e19SKyle Evans "Must specify a repository with -r!\n"); 117818418e19SKyle Evans exit(EXIT_FAILURE); 117918418e19SKyle Evans } 118018418e19SKyle Evans 118118418e19SKyle Evans if (optarg == NULL) { 118218418e19SKyle Evans /* Advance past repo name. */ 118318418e19SKyle Evans optreset = 1; 118418418e19SKyle Evans optind++; 118518418e19SKyle Evans } 118618418e19SKyle Evans } 118718418e19SKyle Evans break; 1188ae994fdcSBaptiste Daroussin case 1: 1189ae994fdcSBaptiste Daroussin // Non-option arguments, first one is the command 1190ae994fdcSBaptiste Daroussin if (command == NULL) { 1191ae994fdcSBaptiste Daroussin command = argv[optind-1]; 1192ae994fdcSBaptiste Daroussin if (strcmp(command, "add") == 0) { 1193ae994fdcSBaptiste Daroussin add_pkg = true; 1194ae994fdcSBaptiste Daroussin } 1195ae994fdcSBaptiste Daroussin else if (strcmp(command, "bootstrap") == 0) { 11965212e8baSBryan Drewery bootstrap_only = true; 1197ae994fdcSBaptiste Daroussin } 1198ae994fdcSBaptiste Daroussin } 1199ae994fdcSBaptiste Daroussin // bootstrap doesn't accept other arguments 1200ae994fdcSBaptiste Daroussin else if (bootstrap_only) { 1201ae994fdcSBaptiste Daroussin fprintf(stderr, args_bootstrap_message); 1202ca7f7593SKyle Evans exit(EXIT_FAILURE); 1203ca7f7593SKyle Evans } 1204ae994fdcSBaptiste Daroussin else if (add_pkg && pkgarg != NULL) { 120540b9f924SKyle Evans /* 120640b9f924SKyle Evans * Additional arguments also means it's not a 120740b9f924SKyle Evans * local bootstrap request. 120840b9f924SKyle Evans */ 120940b9f924SKyle Evans add_pkg = false; 1210ca7f7593SKyle Evans } 1211ae994fdcSBaptiste Daroussin else if (add_pkg) { 121240b9f924SKyle Evans /* 121340b9f924SKyle Evans * If it's not a request for pkg or pkg-devel, 121440b9f924SKyle Evans * then we must assume they were trying to 121540b9f924SKyle Evans * install some other local package and we 121640b9f924SKyle Evans * should try to bootstrap from the repo. 121740b9f924SKyle Evans */ 121840b9f924SKyle Evans if (!pkg_is_pkg_pkg(argv[optind-1])) { 121940b9f924SKyle Evans add_pkg = false; 122040b9f924SKyle Evans } else { 1221ae994fdcSBaptiste Daroussin pkgarg = argv[optind-1]; 1222ae994fdcSBaptiste Daroussin } 122340b9f924SKyle Evans } 1224ae994fdcSBaptiste Daroussin break; 1225ae994fdcSBaptiste Daroussin default: 1226ae994fdcSBaptiste Daroussin break; 1227ae994fdcSBaptiste Daroussin } 12285212e8baSBryan Drewery } 1229e9ad2964SBrooks Davis if (debug > 1) 1230e9ad2964SBrooks Davis fetchDebug = 1; 12315212e8baSBryan Drewery 12325212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1233e18ad51cSAlexander Kabaev /* 1234d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1235ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1236*990878b0SGordon Bergling * when that option is passed. 1237ecfed9f2SMatthew Seaman */ 1238ae994fdcSBaptiste Daroussin if (activation_test) 1239e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1240ecfed9f2SMatthew Seaman 124118418e19SKyle Evans config_init(repo_name); 124252cb76feSBryan Drewery 1243ae994fdcSBaptiste Daroussin if (add_pkg) { 12445212e8baSBryan Drewery if (pkgarg == NULL) { 12455212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 12465212e8baSBryan Drewery exit(EXIT_FAILURE); 12475212e8baSBryan Drewery } 12485212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 12495212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 12505212e8baSBryan Drewery exit(EXIT_FAILURE); 12515212e8baSBryan Drewery } 12525212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1253b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1254b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1255b70213b5SBaptiste Daroussin } 1256ecfed9f2SMatthew Seaman /* 1257e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1258e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1259e18ad51cSAlexander Kabaev * tucked in there already. 1260e18ad51cSAlexander Kabaev */ 1261ae994fdcSBaptiste Daroussin if (!yes) 12629950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 12639950eceeSBaptiste Daroussin if (!yes) { 1264575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1265e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 12663a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1267575c4095SBaptiste Daroussin } 1268204ea792SBaptiste Daroussin 1269575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1270204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1271e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1272e18ad51cSAlexander Kabaev } 1273ae994fdcSBaptiste Daroussin if (bootstrap_pkg(force, fetchOpts) != 0) 1274a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 12759950eceeSBaptiste Daroussin config_finish(); 1276c3e8a27aSBryan Drewery 12775212e8baSBryan Drewery if (bootstrap_only) 1278c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 12795212e8baSBryan Drewery } else if (bootstrap_only) { 12805212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1281c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1282c3e8a27aSBryan Drewery } 12833aa4b42aSBaptiste Daroussin 12843aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 12853aa4b42aSBaptiste Daroussin 1286a6454741SBaptiste Daroussin /* NOT REACHED */ 12873b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 12883aa4b42aSBaptiste Daroussin } 1289