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> 36f12db248SBryan Drewery #include <sys/sbuf.h> 373b05c2a8SBaptiste Daroussin #include <sys/wait.h> 383aa4b42aSBaptiste Daroussin 393aa4b42aSBaptiste Daroussin #include <archive.h> 403aa4b42aSBaptiste Daroussin #include <archive_entry.h> 41f12db248SBryan Drewery #include <dirent.h> 423aa4b42aSBaptiste Daroussin #include <err.h> 433aa4b42aSBaptiste Daroussin #include <errno.h> 44b70213b5SBaptiste Daroussin #include <fcntl.h> 453b05c2a8SBaptiste Daroussin #include <fetch.h> 46ae994fdcSBaptiste Daroussin #include <getopt.h> 4756d11d4aSStefan Eßer #include <libutil.h> 48a6454741SBaptiste Daroussin #include <paths.h> 499950eceeSBaptiste Daroussin #include <stdbool.h> 503aa4b42aSBaptiste Daroussin #include <stdlib.h> 513aa4b42aSBaptiste Daroussin #include <stdio.h> 523aa4b42aSBaptiste Daroussin #include <string.h> 538a7d859eSBaptiste Daroussin #include <ucl.h> 54f12db248SBryan Drewery 55f12db248SBryan Drewery #include <openssl/err.h> 56f12db248SBryan Drewery #include <openssl/ssl.h> 573aa4b42aSBaptiste Daroussin 5829aaa961SBaptiste Daroussin #include "dns_utils.h" 599950eceeSBaptiste Daroussin #include "config.h" 603aa4b42aSBaptiste Daroussin 61f12db248SBryan Drewery struct sig_cert { 62516aaf7cSBryan Drewery char *name; 63f12db248SBryan Drewery unsigned char *sig; 64f12db248SBryan Drewery int siglen; 65f12db248SBryan Drewery unsigned char *cert; 66f12db248SBryan Drewery int certlen; 67f12db248SBryan Drewery bool trusted; 68f12db248SBryan Drewery }; 69f12db248SBryan Drewery 7061acb458SBaptiste Daroussin struct pubkey { 7161acb458SBaptiste Daroussin unsigned char *sig; 7261acb458SBaptiste Daroussin int siglen; 7361acb458SBaptiste Daroussin }; 7461acb458SBaptiste Daroussin 75f12db248SBryan Drewery typedef enum { 76f12db248SBryan Drewery HASH_UNKNOWN, 77f12db248SBryan Drewery HASH_SHA256, 78f12db248SBryan Drewery } hash_t; 79f12db248SBryan Drewery 80f12db248SBryan Drewery struct fingerprint { 81f12db248SBryan Drewery hash_t type; 82516aaf7cSBryan Drewery char *name; 83f12db248SBryan Drewery char hash[BUFSIZ]; 84f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 85f12db248SBryan Drewery }; 86f12db248SBryan Drewery 87f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 88f12db248SBryan Drewery 893aa4b42aSBaptiste Daroussin static int 903aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 913aa4b42aSBaptiste Daroussin { 923aa4b42aSBaptiste Daroussin struct archive *a; 933aa4b42aSBaptiste Daroussin struct archive_entry *ae; 943aa4b42aSBaptiste Daroussin char *end; 953aa4b42aSBaptiste Daroussin int ret, r; 963aa4b42aSBaptiste Daroussin 97a6454741SBaptiste Daroussin ret = -1; 983aa4b42aSBaptiste Daroussin a = archive_read_new(); 99a6454741SBaptiste Daroussin if (a == NULL) { 100a6454741SBaptiste Daroussin warn("archive_read_new"); 101a6454741SBaptiste Daroussin return (ret); 102a6454741SBaptiste Daroussin } 103ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1043aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1053aa4b42aSBaptiste Daroussin 106a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 107a6454741SBaptiste Daroussin warn("lseek"); 108a6454741SBaptiste Daroussin goto cleanup; 109a6454741SBaptiste Daroussin } 1103aa4b42aSBaptiste Daroussin 1113aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 112a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1133aa4b42aSBaptiste Daroussin goto cleanup; 1143aa4b42aSBaptiste Daroussin } 1153aa4b42aSBaptiste Daroussin 1163aa4b42aSBaptiste Daroussin ae = NULL; 1173aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1183aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1193aa4b42aSBaptiste Daroussin if (end == NULL) 1203aa4b42aSBaptiste Daroussin continue; 1213aa4b42aSBaptiste Daroussin 1223aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1233aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1243aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1253aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1263aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 127a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1283aa4b42aSBaptiste Daroussin break; 1293aa4b42aSBaptiste Daroussin } 1303aa4b42aSBaptiste Daroussin } 1313aa4b42aSBaptiste Daroussin 132a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 133a6454741SBaptiste Daroussin ret = 0; 134a6454741SBaptiste Daroussin else 1354622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1364622bc4eSGavin Atkinson archive_error_string(a)); 1373aa4b42aSBaptiste Daroussin 1383aa4b42aSBaptiste Daroussin cleanup: 139ff75c36aSBaptiste Daroussin archive_read_free(a); 1403b05c2a8SBaptiste Daroussin return (ret); 1413aa4b42aSBaptiste Daroussin 1423aa4b42aSBaptiste Daroussin } 1433aa4b42aSBaptiste Daroussin 1443aa4b42aSBaptiste Daroussin static int 1455212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1463aa4b42aSBaptiste Daroussin { 1473aa4b42aSBaptiste Daroussin int pstat; 1483aa4b42aSBaptiste Daroussin pid_t pid; 1493aa4b42aSBaptiste Daroussin 1503aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1513aa4b42aSBaptiste Daroussin case -1: 1523aa4b42aSBaptiste Daroussin return (-1); 1533aa4b42aSBaptiste Daroussin case 0: 1545212e8baSBryan Drewery if (force) 1555212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 1565212e8baSBryan Drewery (char *)NULL); 1575212e8baSBryan Drewery else 1585212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 1595212e8baSBryan Drewery (char *)NULL); 1603b05c2a8SBaptiste Daroussin _exit(1); 1613aa4b42aSBaptiste Daroussin default: 1623aa4b42aSBaptiste Daroussin break; 1633aa4b42aSBaptiste Daroussin } 1643aa4b42aSBaptiste Daroussin 165a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1663aa4b42aSBaptiste Daroussin if (errno != EINTR) 1673aa4b42aSBaptiste Daroussin return (-1); 1683aa4b42aSBaptiste Daroussin 169a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1703aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 171a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 172a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 173a6454741SBaptiste Daroussin return (pstat); 1743aa4b42aSBaptiste Daroussin } 1753aa4b42aSBaptiste Daroussin 1763aa4b42aSBaptiste Daroussin static int 177ae994fdcSBaptiste Daroussin fetch_to_fd(const char *url, char *path, const char *fetchOpts) 1783aa4b42aSBaptiste Daroussin { 17929aaa961SBaptiste Daroussin struct url *u; 18029aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 181a6454741SBaptiste Daroussin struct url_stat st; 182f12db248SBryan Drewery FILE *remote; 183f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 184f12db248SBryan Drewery int fd; 185f12db248SBryan Drewery int retry, max_retry; 186cc36fe49SBaptiste Daroussin ssize_t r; 187f12db248SBryan Drewery char buf[10240]; 188f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 189f12db248SBryan Drewery static const char *mirror_type = NULL; 1903aa4b42aSBaptiste Daroussin 19129aaa961SBaptiste Daroussin max_retry = 3; 19229aaa961SBaptiste Daroussin current = mirrors = NULL; 193f12db248SBryan Drewery remote = NULL; 1943aa4b42aSBaptiste Daroussin 195f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 196f12db248SBryan Drewery != 0) { 1979950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 1989950eceeSBaptiste Daroussin return (-1); 1999950eceeSBaptiste Daroussin } 20062940ea9SBryan Drewery 201f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2023aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2033b05c2a8SBaptiste Daroussin return (-1); 2043aa4b42aSBaptiste Daroussin } 2053aa4b42aSBaptiste Daroussin 20629aaa961SBaptiste Daroussin retry = max_retry; 20729aaa961SBaptiste Daroussin 20879fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 20979fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 21079fe80efSBaptiste Daroussin return (-1); 21179fe80efSBaptiste Daroussin } 21279fe80efSBaptiste Daroussin 21329aaa961SBaptiste Daroussin while (remote == NULL) { 21429aaa961SBaptiste Daroussin if (retry == max_retry) { 2159950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2169950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 21729aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 21829aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 21929aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 22029aaa961SBaptiste Daroussin current = mirrors; 22129aaa961SBaptiste Daroussin } 22229aaa961SBaptiste Daroussin } 22329aaa961SBaptiste Daroussin 22435e07a7aSBaptiste Daroussin if (mirrors != NULL) { 22529aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 22635e07a7aSBaptiste Daroussin u->port = current->port; 22735e07a7aSBaptiste Daroussin } 22829aaa961SBaptiste Daroussin 229ae994fdcSBaptiste Daroussin remote = fetchXGet(u, &st, fetchOpts); 23029aaa961SBaptiste Daroussin if (remote == NULL) { 23129aaa961SBaptiste Daroussin --retry; 23229aaa961SBaptiste Daroussin if (retry <= 0) 23329aaa961SBaptiste Daroussin goto fetchfail; 23429aaa961SBaptiste Daroussin if (mirrors == NULL) { 2353aa4b42aSBaptiste Daroussin sleep(1); 23629aaa961SBaptiste Daroussin } else { 23729aaa961SBaptiste Daroussin current = current->next; 23829aaa961SBaptiste Daroussin if (current == NULL) 23929aaa961SBaptiste Daroussin current = mirrors; 24029aaa961SBaptiste Daroussin } 24129aaa961SBaptiste Daroussin } 24229aaa961SBaptiste Daroussin } 243a6454741SBaptiste Daroussin 244cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 2453aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2463aa4b42aSBaptiste Daroussin warn("write()"); 247f12db248SBryan Drewery goto fetchfail; 2483aa4b42aSBaptiste Daroussin } 249cc36fe49SBaptiste Daroussin } 2503aa4b42aSBaptiste Daroussin 251cc36fe49SBaptiste Daroussin if (r != 0) { 252cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 253cc36fe49SBaptiste Daroussin goto fetchfail; 2543aa4b42aSBaptiste Daroussin } 2553aa4b42aSBaptiste Daroussin 256a6454741SBaptiste Daroussin if (ferror(remote)) 257a6454741SBaptiste Daroussin goto fetchfail; 2583aa4b42aSBaptiste Daroussin 259f12db248SBryan Drewery goto cleanup; 260f12db248SBryan Drewery 261f12db248SBryan Drewery fetchfail: 262f12db248SBryan Drewery if (fd != -1) { 263f12db248SBryan Drewery close(fd); 264f12db248SBryan Drewery fd = -1; 265f12db248SBryan Drewery unlink(path); 266f12db248SBryan Drewery } 267f12db248SBryan Drewery 268f12db248SBryan Drewery cleanup: 269f12db248SBryan Drewery if (remote != NULL) 270f12db248SBryan Drewery fclose(remote); 271f12db248SBryan Drewery 272f12db248SBryan Drewery return fd; 273f12db248SBryan Drewery } 274f12db248SBryan Drewery 275f12db248SBryan Drewery static struct fingerprint * 2768a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 277f12db248SBryan Drewery { 278b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 2798a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 2808a7d859eSBaptiste Daroussin const char *function, *fp, *key; 281f12db248SBryan Drewery struct fingerprint *f; 282f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 283f12db248SBryan Drewery 284f12db248SBryan Drewery function = fp = NULL; 285f12db248SBryan Drewery 2868a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 2878a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 2888a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 2898a7d859eSBaptiste Daroussin continue; 2908a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 2918a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 292f12db248SBryan Drewery continue; 293f12db248SBryan Drewery } 2948a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 2958a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 296f12db248SBryan Drewery continue; 297f12db248SBryan Drewery } 298f12db248SBryan Drewery } 299f12db248SBryan Drewery 300f12db248SBryan Drewery if (fp == NULL || function == NULL) 301f12db248SBryan Drewery return (NULL); 302f12db248SBryan Drewery 303f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 304f12db248SBryan Drewery fct = HASH_SHA256; 305f12db248SBryan Drewery 306f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 307d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 308f12db248SBryan Drewery return (NULL); 309f12db248SBryan Drewery } 310f12db248SBryan Drewery 311f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 312f12db248SBryan Drewery f->type = fct; 313f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 314f12db248SBryan Drewery 315f12db248SBryan Drewery return (f); 316f12db248SBryan Drewery } 317f12db248SBryan Drewery 318516aaf7cSBryan Drewery static void 319516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 320516aaf7cSBryan Drewery { 321d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 322516aaf7cSBryan Drewery 323d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 324516aaf7cSBryan Drewery free(fingerprint->name); 325516aaf7cSBryan Drewery free(fingerprint); 326516aaf7cSBryan Drewery } 327516aaf7cSBryan Drewery free(list); 328516aaf7cSBryan Drewery } 329516aaf7cSBryan Drewery 330f12db248SBryan Drewery static struct fingerprint * 331f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 332f12db248SBryan Drewery { 3338a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 3348a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 335f12db248SBryan Drewery struct fingerprint *f; 336f12db248SBryan Drewery char path[MAXPATHLEN]; 337f12db248SBryan Drewery 338f12db248SBryan Drewery f = NULL; 339f12db248SBryan Drewery 340f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 341f12db248SBryan Drewery 3428a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 3438a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 3448a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 3458a7d859eSBaptiste Daroussin ucl_parser_free(p); 346f12db248SBryan Drewery return (NULL); 3478a7d859eSBaptiste Daroussin } 348f12db248SBryan Drewery 3498a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 350f12db248SBryan Drewery 3518a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 3528a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 353f12db248SBryan Drewery 3548a7d859eSBaptiste Daroussin if (f != NULL) 355516aaf7cSBryan Drewery f->name = strdup(filename); 356f12db248SBryan Drewery 357b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 3588a7d859eSBaptiste Daroussin ucl_parser_free(p); 359f12db248SBryan Drewery 360f12db248SBryan Drewery return (f); 361f12db248SBryan Drewery } 362f12db248SBryan Drewery 363f12db248SBryan Drewery static struct fingerprint_list * 364f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 365f12db248SBryan Drewery { 366f12db248SBryan Drewery DIR *d; 367f12db248SBryan Drewery struct dirent *ent; 368f12db248SBryan Drewery struct fingerprint *finger; 369f12db248SBryan Drewery struct fingerprint_list *fingerprints; 370f12db248SBryan Drewery 371f12db248SBryan Drewery *count = 0; 372f12db248SBryan Drewery 373f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 374f12db248SBryan Drewery if (fingerprints == NULL) 375f12db248SBryan Drewery return (NULL); 376f12db248SBryan Drewery STAILQ_INIT(fingerprints); 377f12db248SBryan Drewery 37892947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 37992947daaSBaptiste Daroussin free(fingerprints); 38092947daaSBaptiste Daroussin 381f12db248SBryan Drewery return (NULL); 38292947daaSBaptiste Daroussin } 383f12db248SBryan Drewery 384f12db248SBryan Drewery while ((ent = readdir(d))) { 385f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 386f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 387f12db248SBryan Drewery continue; 388f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 389f12db248SBryan Drewery if (finger != NULL) { 390f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 391f12db248SBryan Drewery ++(*count); 392f12db248SBryan Drewery } 393f12db248SBryan Drewery } 394f12db248SBryan Drewery 395f12db248SBryan Drewery closedir(d); 396f12db248SBryan Drewery 397f12db248SBryan Drewery return (fingerprints); 398f12db248SBryan Drewery } 399f12db248SBryan Drewery 400f12db248SBryan Drewery static void 401f12db248SBryan Drewery sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 402f12db248SBryan Drewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 403f12db248SBryan Drewery { 404f12db248SBryan Drewery int i; 405f12db248SBryan Drewery 406f12db248SBryan Drewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 407f12db248SBryan Drewery sprintf(out + (i * 2), "%02x", hash[i]); 408f12db248SBryan Drewery 409f12db248SBryan Drewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 410f12db248SBryan Drewery } 411f12db248SBryan Drewery 412f12db248SBryan Drewery static void 413f12db248SBryan Drewery sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 414f12db248SBryan Drewery { 415f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 416f12db248SBryan Drewery SHA256_CTX sha256; 417f12db248SBryan Drewery 418f12db248SBryan Drewery out[0] = '\0'; 419f12db248SBryan Drewery 420f12db248SBryan Drewery SHA256_Init(&sha256); 421f12db248SBryan Drewery SHA256_Update(&sha256, buf, len); 422f12db248SBryan Drewery SHA256_Final(hash, &sha256); 423f12db248SBryan Drewery sha256_hash(hash, out); 424f12db248SBryan Drewery } 425f12db248SBryan Drewery 426f12db248SBryan Drewery static int 427f12db248SBryan Drewery sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 428f12db248SBryan Drewery { 429f12db248SBryan Drewery int my_fd; 430f12db248SBryan Drewery FILE *fp; 431f12db248SBryan Drewery char buffer[BUFSIZ]; 432f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 433f12db248SBryan Drewery size_t r; 434f12db248SBryan Drewery int ret; 435f12db248SBryan Drewery SHA256_CTX sha256; 436f12db248SBryan Drewery 437f12db248SBryan Drewery my_fd = -1; 438f12db248SBryan Drewery fp = NULL; 439f12db248SBryan Drewery r = 0; 440f12db248SBryan Drewery ret = 1; 441f12db248SBryan Drewery 442f12db248SBryan Drewery out[0] = '\0'; 443f12db248SBryan Drewery 444f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 445f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 446f12db248SBryan Drewery warnx("dup"); 447f12db248SBryan Drewery goto cleanup; 448f12db248SBryan Drewery } 449f12db248SBryan Drewery 450f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 451f12db248SBryan Drewery warnx("fdopen"); 452f12db248SBryan Drewery goto cleanup; 453f12db248SBryan Drewery } 454f12db248SBryan Drewery 455f12db248SBryan Drewery SHA256_Init(&sha256); 456f12db248SBryan Drewery 457f12db248SBryan Drewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 458f12db248SBryan Drewery SHA256_Update(&sha256, buffer, r); 459f12db248SBryan Drewery 460f12db248SBryan Drewery if (ferror(fp) != 0) { 461f12db248SBryan Drewery warnx("fread"); 462f12db248SBryan Drewery goto cleanup; 463f12db248SBryan Drewery } 464f12db248SBryan Drewery 465f12db248SBryan Drewery SHA256_Final(hash, &sha256); 466f12db248SBryan Drewery sha256_hash(hash, out); 467f12db248SBryan Drewery ret = 0; 468f12db248SBryan Drewery 469f12db248SBryan Drewery cleanup: 470f12db248SBryan Drewery if (fp != NULL) 471f12db248SBryan Drewery fclose(fp); 472f12db248SBryan Drewery else if (my_fd != -1) 473f12db248SBryan Drewery close(my_fd); 474f12db248SBryan Drewery (void)lseek(fd, 0, SEEK_SET); 475f12db248SBryan Drewery 476f12db248SBryan Drewery return (ret); 477f12db248SBryan Drewery } 478f12db248SBryan Drewery 479f12db248SBryan Drewery static EVP_PKEY * 48061acb458SBaptiste Daroussin load_public_key_file(const char *file) 48161acb458SBaptiste Daroussin { 48261acb458SBaptiste Daroussin EVP_PKEY *pkey; 48361acb458SBaptiste Daroussin BIO *bp; 48461acb458SBaptiste Daroussin char errbuf[1024]; 48561acb458SBaptiste Daroussin 48661acb458SBaptiste Daroussin bp = BIO_new_file(file, "r"); 48761acb458SBaptiste Daroussin if (!bp) 48861acb458SBaptiste Daroussin errx(EXIT_FAILURE, "Unable to read %s", file); 48961acb458SBaptiste Daroussin 49061acb458SBaptiste Daroussin if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 49161acb458SBaptiste Daroussin warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); 49261acb458SBaptiste Daroussin 49361acb458SBaptiste Daroussin BIO_free(bp); 49461acb458SBaptiste Daroussin 49561acb458SBaptiste Daroussin return (pkey); 49661acb458SBaptiste Daroussin } 49761acb458SBaptiste Daroussin 49861acb458SBaptiste Daroussin static EVP_PKEY * 499f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 500f12db248SBryan Drewery { 501f12db248SBryan Drewery EVP_PKEY *pkey; 502f12db248SBryan Drewery BIO *bp; 503f12db248SBryan Drewery char errbuf[1024]; 504f12db248SBryan Drewery 505c2788c07SBryan Drewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 506f12db248SBryan Drewery 507f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 508f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 509f12db248SBryan Drewery 510f12db248SBryan Drewery BIO_free(bp); 511f12db248SBryan Drewery 512f12db248SBryan Drewery return (pkey); 513f12db248SBryan Drewery } 514f12db248SBryan Drewery 515f12db248SBryan Drewery static bool 51661acb458SBaptiste Daroussin rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, 51761acb458SBaptiste Daroussin int keylen, unsigned char *sig, int siglen) 518f12db248SBryan Drewery { 519f12db248SBryan Drewery EVP_MD_CTX *mdctx; 520f12db248SBryan Drewery EVP_PKEY *pkey; 521f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 522f12db248SBryan Drewery char errbuf[1024]; 523f12db248SBryan Drewery bool ret; 524f12db248SBryan Drewery 525f12db248SBryan Drewery pkey = NULL; 526f12db248SBryan Drewery mdctx = NULL; 527f12db248SBryan Drewery ret = false; 528f12db248SBryan Drewery 52961acb458SBaptiste Daroussin SSL_load_error_strings(); 53061acb458SBaptiste Daroussin 531f12db248SBryan Drewery /* Compute SHA256 of the package. */ 532f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 533f12db248SBryan Drewery warn("lseek"); 534f12db248SBryan Drewery goto cleanup; 535f12db248SBryan Drewery } 536f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 537f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 538f12db248SBryan Drewery goto cleanup; 539f12db248SBryan Drewery } 540f12db248SBryan Drewery 54161acb458SBaptiste Daroussin if (sigfile != NULL) { 54261acb458SBaptiste Daroussin if ((pkey = load_public_key_file(sigfile)) == NULL) { 54361acb458SBaptiste Daroussin warnx("Error reading public key"); 54461acb458SBaptiste Daroussin goto cleanup; 54561acb458SBaptiste Daroussin } 54661acb458SBaptiste Daroussin } else { 547f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 548f12db248SBryan Drewery warnx("Error reading public key"); 549f12db248SBryan Drewery goto cleanup; 550f12db248SBryan Drewery } 55161acb458SBaptiste Daroussin } 552f12db248SBryan Drewery 553f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 554f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 555f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 556f12db248SBryan Drewery goto error; 557f12db248SBryan Drewery } 558f12db248SBryan Drewery 559f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 5604c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 561f12db248SBryan Drewery goto error; 562f12db248SBryan Drewery } 563f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 5644c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 565f12db248SBryan Drewery goto error; 566f12db248SBryan Drewery } 567f12db248SBryan Drewery 568f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 5694c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 570f12db248SBryan Drewery goto error; 571f12db248SBryan Drewery } 572f12db248SBryan Drewery 573f12db248SBryan Drewery ret = true; 574f12db248SBryan Drewery printf("done\n"); 575f12db248SBryan Drewery goto cleanup; 576f12db248SBryan Drewery 577f12db248SBryan Drewery error: 578f12db248SBryan Drewery printf("failed\n"); 579f12db248SBryan Drewery 580f12db248SBryan Drewery cleanup: 581f12db248SBryan Drewery if (pkey) 582f12db248SBryan Drewery EVP_PKEY_free(pkey); 583f12db248SBryan Drewery if (mdctx) 584f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 585f12db248SBryan Drewery ERR_free_strings(); 586f12db248SBryan Drewery 587f12db248SBryan Drewery return (ret); 588f12db248SBryan Drewery } 589f12db248SBryan Drewery 59061acb458SBaptiste Daroussin static struct pubkey * 59161acb458SBaptiste Daroussin read_pubkey(int fd) 59261acb458SBaptiste Daroussin { 59361acb458SBaptiste Daroussin struct pubkey *pk; 59461acb458SBaptiste Daroussin struct sbuf *sig; 59561acb458SBaptiste Daroussin char buf[4096]; 59661acb458SBaptiste Daroussin int r; 59761acb458SBaptiste Daroussin 59861acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 59961acb458SBaptiste Daroussin warn("lseek"); 60061acb458SBaptiste Daroussin return (NULL); 60161acb458SBaptiste Daroussin } 60261acb458SBaptiste Daroussin 60361acb458SBaptiste Daroussin sig = sbuf_new_auto(); 60461acb458SBaptiste Daroussin 60561acb458SBaptiste Daroussin while ((r = read(fd, buf, sizeof(buf))) >0) { 60661acb458SBaptiste Daroussin sbuf_bcat(sig, buf, r); 60761acb458SBaptiste Daroussin } 60861acb458SBaptiste Daroussin 60961acb458SBaptiste Daroussin sbuf_finish(sig); 61061acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 61161acb458SBaptiste Daroussin pk->siglen = sbuf_len(sig); 61261acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 61361acb458SBaptiste Daroussin memcpy(pk->sig, sbuf_data(sig), pk->siglen); 61461acb458SBaptiste Daroussin sbuf_delete(sig); 61561acb458SBaptiste Daroussin 61661acb458SBaptiste Daroussin return (pk); 61761acb458SBaptiste Daroussin } 61861acb458SBaptiste Daroussin 619f12db248SBryan Drewery static struct sig_cert * 620f12db248SBryan Drewery parse_cert(int fd) { 621f12db248SBryan Drewery int my_fd; 622f12db248SBryan Drewery struct sig_cert *sc; 623f12db248SBryan Drewery FILE *fp; 624f12db248SBryan Drewery struct sbuf *buf, *sig, *cert; 625f12db248SBryan Drewery char *line; 626f12db248SBryan Drewery size_t linecap; 627f12db248SBryan Drewery ssize_t linelen; 628f12db248SBryan Drewery 629c2788c07SBryan Drewery buf = NULL; 630f12db248SBryan Drewery my_fd = -1; 631f12db248SBryan Drewery sc = NULL; 632f12db248SBryan Drewery line = NULL; 633f12db248SBryan Drewery linecap = 0; 634f12db248SBryan Drewery 635f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 636f12db248SBryan Drewery warn("lseek"); 637f12db248SBryan Drewery return (NULL); 638f12db248SBryan Drewery } 639f12db248SBryan Drewery 640f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 641f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 642f12db248SBryan Drewery warnx("dup"); 643f12db248SBryan Drewery return (NULL); 644f12db248SBryan Drewery } 645f12db248SBryan Drewery 646f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 647f12db248SBryan Drewery warn("fdopen"); 648f12db248SBryan Drewery close(my_fd); 649f12db248SBryan Drewery return (NULL); 650f12db248SBryan Drewery } 651f12db248SBryan Drewery 652f12db248SBryan Drewery sig = sbuf_new_auto(); 653f12db248SBryan Drewery cert = sbuf_new_auto(); 654f12db248SBryan Drewery 655f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 656f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 657f12db248SBryan Drewery buf = sig; 658f12db248SBryan Drewery continue; 659f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 660f12db248SBryan Drewery buf = cert; 661f12db248SBryan Drewery continue; 662f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 663f12db248SBryan Drewery break; 664f12db248SBryan Drewery } 665f12db248SBryan Drewery if (buf != NULL) 666f12db248SBryan Drewery sbuf_bcat(buf, line, linelen); 667f12db248SBryan Drewery } 668f12db248SBryan Drewery 669f12db248SBryan Drewery fclose(fp); 670f12db248SBryan Drewery 671f12db248SBryan Drewery /* Trim out unrelated trailing newline */ 672f12db248SBryan Drewery sbuf_setpos(sig, sbuf_len(sig) - 1); 673f12db248SBryan Drewery 674f12db248SBryan Drewery sbuf_finish(sig); 675f12db248SBryan Drewery sbuf_finish(cert); 676f12db248SBryan Drewery 677f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 678f12db248SBryan Drewery sc->siglen = sbuf_len(sig); 679f12db248SBryan Drewery sc->sig = calloc(1, sc->siglen); 680f12db248SBryan Drewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 681f12db248SBryan Drewery 682f12db248SBryan Drewery sc->certlen = sbuf_len(cert); 683f12db248SBryan Drewery sc->cert = strdup(sbuf_data(cert)); 684f12db248SBryan Drewery 685f12db248SBryan Drewery sbuf_delete(sig); 686f12db248SBryan Drewery sbuf_delete(cert); 687f12db248SBryan Drewery 688f12db248SBryan Drewery return (sc); 689f12db248SBryan Drewery } 690f12db248SBryan Drewery 691f12db248SBryan Drewery static bool 69261acb458SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig) 69361acb458SBaptiste Daroussin { 69461acb458SBaptiste Daroussin struct pubkey *pk; 69561acb458SBaptiste Daroussin const char *pubkey; 69661acb458SBaptiste Daroussin bool ret; 69761acb458SBaptiste Daroussin 69861acb458SBaptiste Daroussin pk = NULL; 69961acb458SBaptiste Daroussin pubkey = NULL; 70061acb458SBaptiste Daroussin ret = false; 70161acb458SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 70261acb458SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined"); 70361acb458SBaptiste Daroussin goto cleanup; 70461acb458SBaptiste Daroussin } 70561acb458SBaptiste Daroussin 70661acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 70761acb458SBaptiste Daroussin warnx("Error reading signature"); 70861acb458SBaptiste Daroussin goto cleanup; 70961acb458SBaptiste Daroussin } 71061acb458SBaptiste Daroussin 71161acb458SBaptiste Daroussin /* Verify the signature. */ 71261acb458SBaptiste Daroussin printf("Verifying signature with public key %s... ", pubkey); 71361acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, 71461acb458SBaptiste Daroussin pk->siglen) == false) { 71561acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 71661acb458SBaptiste Daroussin goto cleanup; 71761acb458SBaptiste Daroussin } 71861acb458SBaptiste Daroussin 71961acb458SBaptiste Daroussin ret = true; 72061acb458SBaptiste Daroussin 72161acb458SBaptiste Daroussin cleanup: 72261acb458SBaptiste Daroussin if (pk) { 72361acb458SBaptiste Daroussin free(pk->sig); 72461acb458SBaptiste Daroussin free(pk); 72561acb458SBaptiste Daroussin } 72661acb458SBaptiste Daroussin 72761acb458SBaptiste Daroussin return (ret); 72861acb458SBaptiste Daroussin } 72961acb458SBaptiste Daroussin 73061acb458SBaptiste Daroussin static bool 731f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 732f12db248SBryan Drewery { 733f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 734f12db248SBryan Drewery struct fingerprint *fingerprint; 735f12db248SBryan Drewery struct sig_cert *sc; 736f12db248SBryan Drewery bool ret; 737f12db248SBryan Drewery int trusted_count, revoked_count; 738f12db248SBryan Drewery const char *fingerprints; 739f12db248SBryan Drewery char path[MAXPATHLEN]; 740f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 741f12db248SBryan Drewery 742516aaf7cSBryan Drewery sc = NULL; 743f12db248SBryan Drewery trusted = revoked = NULL; 744f12db248SBryan Drewery ret = false; 745f12db248SBryan Drewery 746f12db248SBryan Drewery /* Read and parse fingerprints. */ 747f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 748f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 749f12db248SBryan Drewery goto cleanup; 750f12db248SBryan Drewery } 751f12db248SBryan Drewery 752f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 753f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 754f12db248SBryan Drewery warnx("Error loading trusted certificates"); 755f12db248SBryan Drewery goto cleanup; 756f12db248SBryan Drewery } 757f12db248SBryan Drewery 758f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 759f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 760f12db248SBryan Drewery goto cleanup; 761f12db248SBryan Drewery } 762f12db248SBryan Drewery 763f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 764f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 765f12db248SBryan Drewery warnx("Error loading revoked certificates"); 766f12db248SBryan Drewery goto cleanup; 767f12db248SBryan Drewery } 768f12db248SBryan Drewery 769f12db248SBryan Drewery /* Read certificate and signature in. */ 770f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 771f12db248SBryan Drewery warnx("Error parsing certificate"); 772f12db248SBryan Drewery goto cleanup; 773f12db248SBryan Drewery } 774f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 775f12db248SBryan Drewery sc->trusted = false; 776f12db248SBryan Drewery 777f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 778f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 779f12db248SBryan Drewery 780f12db248SBryan Drewery /* Check if this hash is revoked */ 781f12db248SBryan Drewery if (revoked != NULL) { 782f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 783f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 784516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 785516aaf7cSBryan Drewery "revoked certificate %s\n", 786516aaf7cSBryan Drewery fingerprint->name); 787f12db248SBryan Drewery goto cleanup; 788f12db248SBryan Drewery } 789f12db248SBryan Drewery } 790f12db248SBryan Drewery } 791f12db248SBryan Drewery 792f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 793f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 794f12db248SBryan Drewery sc->trusted = true; 795516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 796f12db248SBryan Drewery break; 797f12db248SBryan Drewery } 798f12db248SBryan Drewery } 799f12db248SBryan Drewery 800f12db248SBryan Drewery if (sc->trusted == false) { 801516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 802f12db248SBryan Drewery "package's certificate\n"); 803f12db248SBryan Drewery goto cleanup; 804f12db248SBryan Drewery } 805f12db248SBryan Drewery 806f12db248SBryan Drewery /* Verify the signature. */ 807516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 80861acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, 809f12db248SBryan Drewery sc->siglen) == false) { 810f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 811f12db248SBryan Drewery goto cleanup; 812f12db248SBryan Drewery } 813f12db248SBryan Drewery 814f12db248SBryan Drewery ret = true; 815f12db248SBryan Drewery 816f12db248SBryan Drewery cleanup: 817516aaf7cSBryan Drewery if (trusted) 818516aaf7cSBryan Drewery free_fingerprint_list(trusted); 819516aaf7cSBryan Drewery if (revoked) 820516aaf7cSBryan Drewery free_fingerprint_list(revoked); 821f12db248SBryan Drewery if (sc) { 822f12db248SBryan Drewery free(sc->cert); 823f12db248SBryan Drewery free(sc->sig); 824516aaf7cSBryan Drewery free(sc->name); 825f12db248SBryan Drewery free(sc); 826f12db248SBryan Drewery } 827f12db248SBryan Drewery 828f12db248SBryan Drewery return (ret); 829f12db248SBryan Drewery } 830f12db248SBryan Drewery 831f12db248SBryan Drewery static int 832ae994fdcSBaptiste Daroussin bootstrap_pkg(bool force, const char *fetchOpts) 833f12db248SBryan Drewery { 834f12db248SBryan Drewery int fd_pkg, fd_sig; 835f12db248SBryan Drewery int ret; 836f12db248SBryan Drewery char url[MAXPATHLEN]; 837f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 838f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 839f12db248SBryan Drewery const char *packagesite; 840f12db248SBryan Drewery const char *signature_type; 841f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 842f12db248SBryan Drewery 843f12db248SBryan Drewery fd_sig = -1; 844f12db248SBryan Drewery ret = -1; 845f12db248SBryan Drewery 846f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 847f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 848f12db248SBryan Drewery return (-1); 849f12db248SBryan Drewery } 850f12db248SBryan Drewery 851f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 852f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 853f12db248SBryan Drewery return (-1); 854f12db248SBryan Drewery } 855f12db248SBryan Drewery 856f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 857f12db248SBryan Drewery 858f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 859f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 860f12db248SBryan Drewery no A record. */ 861f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 862f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 863f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 864f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 865f12db248SBryan Drewery 866f12db248SBryan Drewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 867f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 868f12db248SBryan Drewery 869ae994fdcSBaptiste Daroussin if ((fd_pkg = fetch_to_fd(url, tmppkg, fetchOpts)) == -1) 870f12db248SBryan Drewery goto fetchfail; 871f12db248SBryan Drewery 872f12db248SBryan Drewery if (signature_type != NULL && 87348f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 87461acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 87548f92706SXin LI 876f12db248SBryan Drewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 877f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 878f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 879f12db248SBryan Drewery packagesite); 880f12db248SBryan Drewery 881ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 88261acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 88361acb458SBaptiste Daroussin "available.\n"); 884f12db248SBryan Drewery goto fetchfail; 885f12db248SBryan Drewery } 886f12db248SBryan Drewery 887f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 888f12db248SBryan Drewery goto cleanup; 88961acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 89061acb458SBaptiste Daroussin 89161acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 89261acb458SBaptiste Daroussin "%s/pkg.txz.pubkeysig.XXXXXX", 89361acb458SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 89461acb458SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", 89561acb458SBaptiste Daroussin packagesite); 89661acb458SBaptiste Daroussin 897ae994fdcSBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) { 89861acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 89961acb458SBaptiste Daroussin "available.\n"); 90061acb458SBaptiste Daroussin goto fetchfail; 90161acb458SBaptiste Daroussin } 90261acb458SBaptiste Daroussin 90361acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 90461acb458SBaptiste Daroussin goto cleanup; 90561acb458SBaptiste Daroussin } else { 90661acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 90761acb458SBaptiste Daroussin "bootstrapping.", signature_type); 90861acb458SBaptiste Daroussin goto cleanup; 90961acb458SBaptiste Daroussin } 910f12db248SBryan Drewery } 911f12db248SBryan Drewery 912f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9135212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 9143aa4b42aSBaptiste Daroussin 915a6454741SBaptiste Daroussin goto cleanup; 916a6454741SBaptiste Daroussin 917a6454741SBaptiste Daroussin fetchfail: 918a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 919a10f71c5STom Jones if (fetchLastErrCode == FETCH_RESOLV) { 920a10f71c5STom Jones fprintf(stderr, "Address resolution failed for %s.\n", packagesite); 921a10f71c5STom Jones fprintf(stderr, "Consider changing PACKAGESITE.\n"); 922a10f71c5STom Jones } else { 9234ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 9244ff9a7efSBryan Drewery "your system.\n"); 9254ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 9264ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 927a10f71c5STom Jones } 928a6454741SBaptiste Daroussin 9293aa4b42aSBaptiste Daroussin cleanup: 930f12db248SBryan Drewery if (fd_sig != -1) { 931f12db248SBryan Drewery close(fd_sig); 932f12db248SBryan Drewery unlink(tmpsig); 933f12db248SBryan Drewery } 93492947daaSBaptiste Daroussin 93592947daaSBaptiste Daroussin if (fd_pkg != -1) { 936f12db248SBryan Drewery close(fd_pkg); 9373aa4b42aSBaptiste Daroussin unlink(tmppkg); 93892947daaSBaptiste Daroussin } 9393aa4b42aSBaptiste Daroussin 940a6454741SBaptiste Daroussin return (ret); 9413aa4b42aSBaptiste Daroussin } 9423aa4b42aSBaptiste Daroussin 943e18ad51cSAlexander Kabaev static const char confirmation_message[] = 944e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 945e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 946e18ad51cSAlexander Kabaev 947e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 948575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 9491efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 950e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 951575c4095SBaptiste Daroussin 952ae994fdcSBaptiste Daroussin static const char args_bootstrap_message[] = 953ae994fdcSBaptiste Daroussin "Too many arguments\n" 954ae994fdcSBaptiste Daroussin "Usage: pkg [-4|-6] bootstrap [-f] [-y]\n"; 955ae994fdcSBaptiste Daroussin 956ae994fdcSBaptiste Daroussin static const char args_add_message[] = 957ae994fdcSBaptiste Daroussin "Too many arguments\n" 958ae994fdcSBaptiste Daroussin "Usage: pkg add [-f] [-y] {pkg.txz}\n"; 959ae994fdcSBaptiste Daroussin 960e18ad51cSAlexander Kabaev static int 961e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 962e18ad51cSAlexander Kabaev { 963e18ad51cSAlexander Kabaev int ret, c; 964e18ad51cSAlexander Kabaev 96567c9f60eSPoul-Henning Kamp fflush(stdout); 966e18ad51cSAlexander Kabaev c = getchar(); 967e18ad51cSAlexander Kabaev 968e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 969e18ad51cSAlexander Kabaev ret = 1; 970e18ad51cSAlexander Kabaev else 971e18ad51cSAlexander Kabaev ret = 0; 972e18ad51cSAlexander Kabaev 973e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 974e18ad51cSAlexander Kabaev c = getchar(); 975e18ad51cSAlexander Kabaev 976e18ad51cSAlexander Kabaev return (ret); 977e18ad51cSAlexander Kabaev } 978e18ad51cSAlexander Kabaev 97952cb76feSBryan Drewery static int 9805212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 98152cb76feSBryan Drewery { 98252cb76feSBryan Drewery char path[MAXPATHLEN]; 98352cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 98452cb76feSBryan Drewery const char *signature_type; 98552cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 98652cb76feSBryan Drewery 98752cb76feSBryan Drewery fd_sig = -1; 98852cb76feSBryan Drewery ret = -1; 98952cb76feSBryan Drewery 99052cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 99152cb76feSBryan Drewery if (fd_pkg == -1) 99252cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 99352cb76feSBryan Drewery 99452cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 99552cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 99692947daaSBaptiste Daroussin goto cleanup; 99752cb76feSBryan Drewery } 99852cb76feSBryan Drewery if (signature_type != NULL && 99948f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 100061acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 100148f92706SXin LI 100252cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 100352cb76feSBryan Drewery 100452cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 100561acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 100661acb458SBaptiste Daroussin "available.\n"); 100752cb76feSBryan Drewery goto cleanup; 100852cb76feSBryan Drewery } 100952cb76feSBryan Drewery 101052cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 101152cb76feSBryan Drewery goto cleanup; 101261acb458SBaptiste Daroussin 101361acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 101461acb458SBaptiste Daroussin 101561acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 101661acb458SBaptiste Daroussin 101761acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 101861acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 101961acb458SBaptiste Daroussin "available.\n"); 102061acb458SBaptiste Daroussin goto cleanup; 102161acb458SBaptiste Daroussin } 102261acb458SBaptiste Daroussin 102361acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 102461acb458SBaptiste Daroussin goto cleanup; 102561acb458SBaptiste Daroussin 102661acb458SBaptiste Daroussin } else { 102761acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 102861acb458SBaptiste Daroussin "bootstrapping.", signature_type); 102961acb458SBaptiste Daroussin goto cleanup; 103061acb458SBaptiste Daroussin } 103152cb76feSBryan Drewery } 103252cb76feSBryan Drewery 103352cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 10345212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 103552cb76feSBryan Drewery 103652cb76feSBryan Drewery cleanup: 103752cb76feSBryan Drewery close(fd_pkg); 103852cb76feSBryan Drewery if (fd_sig != -1) 103952cb76feSBryan Drewery close(fd_sig); 104052cb76feSBryan Drewery 104152cb76feSBryan Drewery return (ret); 104252cb76feSBryan Drewery } 104352cb76feSBryan Drewery 10443aa4b42aSBaptiste Daroussin int 104546b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10463aa4b42aSBaptiste Daroussin { 10473aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 1048*18418e19SKyle Evans const char *pkgarg, *repo_name; 1049ae994fdcSBaptiste Daroussin bool activation_test, add_pkg, bootstrap_only, force, yes; 1050ae994fdcSBaptiste Daroussin signed char ch; 1051ae994fdcSBaptiste Daroussin const char *fetchOpts; 1052ae994fdcSBaptiste Daroussin char *command; 10535212e8baSBryan Drewery 1054ae994fdcSBaptiste Daroussin activation_test = false; 1055ae994fdcSBaptiste Daroussin add_pkg = false; 10565212e8baSBryan Drewery bootstrap_only = false; 1057ae994fdcSBaptiste Daroussin command = NULL; 1058ae994fdcSBaptiste Daroussin fetchOpts = ""; 10595212e8baSBryan Drewery force = false; 10605212e8baSBryan Drewery pkgarg = NULL; 1061*18418e19SKyle Evans repo_name = NULL; 10625212e8baSBryan Drewery yes = false; 10633aa4b42aSBaptiste Daroussin 1064ae994fdcSBaptiste Daroussin struct option longopts[] = { 1065ae994fdcSBaptiste Daroussin { "force", no_argument, NULL, 'f' }, 1066ae994fdcSBaptiste Daroussin { "only-ipv4", no_argument, NULL, '4' }, 1067ae994fdcSBaptiste Daroussin { "only-ipv6", no_argument, NULL, '6' }, 1068ae994fdcSBaptiste Daroussin { "yes", no_argument, NULL, 'y' }, 1069ae994fdcSBaptiste Daroussin { NULL, 0, NULL, 0 }, 1070ae994fdcSBaptiste Daroussin }; 1071ae994fdcSBaptiste Daroussin 107256d11d4aSStefan Eßer snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase()); 10733aa4b42aSBaptiste Daroussin 1074*18418e19SKyle Evans while ((ch = getopt_long(argc, argv, "-:fr::yN46", longopts, NULL)) != -1) { 1075ae994fdcSBaptiste Daroussin switch (ch) { 1076ae994fdcSBaptiste Daroussin case 'f': 1077ae994fdcSBaptiste Daroussin force = true; 1078ae994fdcSBaptiste Daroussin break; 1079ae994fdcSBaptiste Daroussin case 'N': 1080ae994fdcSBaptiste Daroussin activation_test = true; 1081ae994fdcSBaptiste Daroussin break; 1082ae994fdcSBaptiste Daroussin case 'y': 1083ae994fdcSBaptiste Daroussin yes = true; 1084ae994fdcSBaptiste Daroussin break; 1085ae994fdcSBaptiste Daroussin case '4': 1086ae994fdcSBaptiste Daroussin fetchOpts = "4"; 1087ae994fdcSBaptiste Daroussin break; 1088ae994fdcSBaptiste Daroussin case '6': 1089ae994fdcSBaptiste Daroussin fetchOpts = "6"; 1090ae994fdcSBaptiste Daroussin break; 1091*18418e19SKyle Evans case 'r': 1092*18418e19SKyle Evans /* 1093*18418e19SKyle Evans * The repository can only be specified for an explicit 1094*18418e19SKyle Evans * bootstrap request at this time, so that we don't 1095*18418e19SKyle Evans * confuse the user if they're trying to use a verb that 1096*18418e19SKyle Evans * has some other conflicting meaning but we need to 1097*18418e19SKyle Evans * bootstrap. 1098*18418e19SKyle Evans * 1099*18418e19SKyle Evans * For that reason, we specify that -r has an optional 1100*18418e19SKyle Evans * argument above and process the next index ourselves. 1101*18418e19SKyle Evans * This is mostly significant because getopt(3) will 1102*18418e19SKyle Evans * otherwise eat the next argument, which could be 1103*18418e19SKyle Evans * something we need to try and make sense of. 1104*18418e19SKyle Evans * 1105*18418e19SKyle Evans * At worst this gets us false positives that we ignore 1106*18418e19SKyle Evans * in other contexts, and we have to do a little fudging 1107*18418e19SKyle Evans * in order to support separating -r from the reponame 1108*18418e19SKyle Evans * with a space since it's not actually optional in 1109*18418e19SKyle Evans * the bootstrap/add sense. 1110*18418e19SKyle Evans */ 1111*18418e19SKyle Evans if (add_pkg || bootstrap_only) { 1112*18418e19SKyle Evans if (optarg != NULL) { 1113*18418e19SKyle Evans repo_name = optarg; 1114*18418e19SKyle Evans } else if (optind < argc) { 1115*18418e19SKyle Evans repo_name = argv[optind]; 1116*18418e19SKyle Evans } 1117*18418e19SKyle Evans 1118*18418e19SKyle Evans if (repo_name == NULL || *repo_name == '\0') { 1119*18418e19SKyle Evans fprintf(stderr, 1120*18418e19SKyle Evans "Must specify a repository with -r!\n"); 1121*18418e19SKyle Evans exit(EXIT_FAILURE); 1122*18418e19SKyle Evans } 1123*18418e19SKyle Evans 1124*18418e19SKyle Evans if (optarg == NULL) { 1125*18418e19SKyle Evans /* Advance past repo name. */ 1126*18418e19SKyle Evans optreset = 1; 1127*18418e19SKyle Evans optind++; 1128*18418e19SKyle Evans } 1129*18418e19SKyle Evans } 1130*18418e19SKyle Evans break; 1131ae994fdcSBaptiste Daroussin case 1: 1132ae994fdcSBaptiste Daroussin // Non-option arguments, first one is the command 1133ae994fdcSBaptiste Daroussin if (command == NULL) { 1134ae994fdcSBaptiste Daroussin command = argv[optind-1]; 1135ae994fdcSBaptiste Daroussin if (strcmp(command, "add") == 0) { 1136ae994fdcSBaptiste Daroussin add_pkg = true; 1137ae994fdcSBaptiste Daroussin } 1138ae994fdcSBaptiste Daroussin else if (strcmp(command, "bootstrap") == 0) { 11395212e8baSBryan Drewery bootstrap_only = true; 1140ae994fdcSBaptiste Daroussin } 1141ae994fdcSBaptiste Daroussin } 1142ae994fdcSBaptiste Daroussin // bootstrap doesn't accept other arguments 1143ae994fdcSBaptiste Daroussin else if (bootstrap_only) { 1144ae994fdcSBaptiste Daroussin fprintf(stderr, args_bootstrap_message); 1145ca7f7593SKyle Evans exit(EXIT_FAILURE); 1146ca7f7593SKyle Evans } 1147ae994fdcSBaptiste Daroussin // For add, we accept exactly one further argument 1148ae994fdcSBaptiste Daroussin else if (add_pkg && pkgarg != NULL) { 1149ae994fdcSBaptiste Daroussin fprintf(stderr, args_add_message); 1150ca7f7593SKyle Evans exit(EXIT_FAILURE); 1151ca7f7593SKyle Evans } 1152ae994fdcSBaptiste Daroussin else if (add_pkg) { 1153ae994fdcSBaptiste Daroussin pkgarg = argv[optind-1]; 1154ae994fdcSBaptiste Daroussin } 1155ae994fdcSBaptiste Daroussin break; 1156ae994fdcSBaptiste Daroussin default: 1157ae994fdcSBaptiste Daroussin break; 1158ae994fdcSBaptiste Daroussin } 11595212e8baSBryan Drewery } 11605212e8baSBryan Drewery 11615212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1162e18ad51cSAlexander Kabaev /* 1163d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1164ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1165ae994fdcSBaptiste Daroussin * when that that option is passed. 1166ecfed9f2SMatthew Seaman */ 1167ae994fdcSBaptiste Daroussin if (activation_test) 1168e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1169ecfed9f2SMatthew Seaman 1170*18418e19SKyle Evans config_init(repo_name); 117152cb76feSBryan Drewery 1172ae994fdcSBaptiste Daroussin if (add_pkg) { 11735212e8baSBryan Drewery if (pkgarg == NULL) { 11745212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 11755212e8baSBryan Drewery exit(EXIT_FAILURE); 11765212e8baSBryan Drewery } 11775212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 11785212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 11795212e8baSBryan Drewery exit(EXIT_FAILURE); 11805212e8baSBryan Drewery } 11815212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1182b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1183b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1184b70213b5SBaptiste Daroussin } 1185ecfed9f2SMatthew Seaman /* 1186e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1187e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1188e18ad51cSAlexander Kabaev * tucked in there already. 1189e18ad51cSAlexander Kabaev */ 1190ae994fdcSBaptiste Daroussin if (!yes) 11919950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 11929950eceeSBaptiste Daroussin if (!yes) { 1193575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1194e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 11953a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1196575c4095SBaptiste Daroussin } 1197204ea792SBaptiste Daroussin 1198575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1199204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1200e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1201e18ad51cSAlexander Kabaev } 1202ae994fdcSBaptiste Daroussin if (bootstrap_pkg(force, fetchOpts) != 0) 1203a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 12049950eceeSBaptiste Daroussin config_finish(); 1205c3e8a27aSBryan Drewery 12065212e8baSBryan Drewery if (bootstrap_only) 1207c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 12085212e8baSBryan Drewery } else if (bootstrap_only) { 12095212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1210c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1211c3e8a27aSBryan Drewery } 12123aa4b42aSBaptiste Daroussin 12133aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 12143aa4b42aSBaptiste Daroussin 1215a6454741SBaptiste Daroussin /* NOT REACHED */ 12163b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 12173aa4b42aSBaptiste Daroussin } 1218