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> 46a6454741SBaptiste Daroussin #include <paths.h> 479950eceeSBaptiste Daroussin #include <stdbool.h> 483aa4b42aSBaptiste Daroussin #include <stdlib.h> 493aa4b42aSBaptiste Daroussin #include <stdio.h> 503aa4b42aSBaptiste Daroussin #include <string.h> 513aa4b42aSBaptiste Daroussin #include <unistd.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 86f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 87f12db248SBryan Drewery 883aa4b42aSBaptiste Daroussin static int 893aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 903aa4b42aSBaptiste Daroussin { 913aa4b42aSBaptiste Daroussin struct archive *a; 923aa4b42aSBaptiste Daroussin struct archive_entry *ae; 933aa4b42aSBaptiste Daroussin char *end; 943aa4b42aSBaptiste Daroussin int ret, r; 953aa4b42aSBaptiste Daroussin 96a6454741SBaptiste Daroussin ret = -1; 973aa4b42aSBaptiste Daroussin a = archive_read_new(); 98a6454741SBaptiste Daroussin if (a == NULL) { 99a6454741SBaptiste Daroussin warn("archive_read_new"); 100a6454741SBaptiste Daroussin return (ret); 101a6454741SBaptiste Daroussin } 102ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1033aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1043aa4b42aSBaptiste Daroussin 105a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 106a6454741SBaptiste Daroussin warn("lseek"); 107a6454741SBaptiste Daroussin goto cleanup; 108a6454741SBaptiste Daroussin } 1093aa4b42aSBaptiste Daroussin 1103aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 111a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1123aa4b42aSBaptiste Daroussin goto cleanup; 1133aa4b42aSBaptiste Daroussin } 1143aa4b42aSBaptiste Daroussin 1153aa4b42aSBaptiste Daroussin ae = NULL; 1163aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1173aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1183aa4b42aSBaptiste Daroussin if (end == NULL) 1193aa4b42aSBaptiste Daroussin continue; 1203aa4b42aSBaptiste Daroussin 1213aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1223aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1233aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1243aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1253aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 126a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1273aa4b42aSBaptiste Daroussin break; 1283aa4b42aSBaptiste Daroussin } 1293aa4b42aSBaptiste Daroussin } 1303aa4b42aSBaptiste Daroussin 131a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 132a6454741SBaptiste Daroussin ret = 0; 133a6454741SBaptiste Daroussin else 1344622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1354622bc4eSGavin Atkinson archive_error_string(a)); 1363aa4b42aSBaptiste Daroussin 1373aa4b42aSBaptiste Daroussin cleanup: 138ff75c36aSBaptiste Daroussin archive_read_free(a); 1393b05c2a8SBaptiste Daroussin return (ret); 1403aa4b42aSBaptiste Daroussin 1413aa4b42aSBaptiste Daroussin } 1423aa4b42aSBaptiste Daroussin 1433aa4b42aSBaptiste Daroussin static int 1445212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1453aa4b42aSBaptiste Daroussin { 1463aa4b42aSBaptiste Daroussin int pstat; 1473aa4b42aSBaptiste Daroussin pid_t pid; 1483aa4b42aSBaptiste Daroussin 1493aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1503aa4b42aSBaptiste Daroussin case -1: 1513aa4b42aSBaptiste Daroussin return (-1); 1523aa4b42aSBaptiste Daroussin case 0: 1535212e8baSBryan Drewery if (force) 1545212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 1555212e8baSBryan Drewery (char *)NULL); 1565212e8baSBryan Drewery else 1575212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 1585212e8baSBryan Drewery (char *)NULL); 1593b05c2a8SBaptiste Daroussin _exit(1); 1603aa4b42aSBaptiste Daroussin default: 1613aa4b42aSBaptiste Daroussin break; 1623aa4b42aSBaptiste Daroussin } 1633aa4b42aSBaptiste Daroussin 164a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1653aa4b42aSBaptiste Daroussin if (errno != EINTR) 1663aa4b42aSBaptiste Daroussin return (-1); 1673aa4b42aSBaptiste Daroussin 168a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1693aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 170a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 171a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 172a6454741SBaptiste Daroussin return (pstat); 1733aa4b42aSBaptiste Daroussin } 1743aa4b42aSBaptiste Daroussin 1753aa4b42aSBaptiste Daroussin static int 176f12db248SBryan Drewery fetch_to_fd(const char *url, char *path) 1773aa4b42aSBaptiste Daroussin { 17829aaa961SBaptiste Daroussin struct url *u; 17929aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 180a6454741SBaptiste Daroussin struct url_stat st; 181f12db248SBryan Drewery FILE *remote; 182f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 183f12db248SBryan Drewery int fd; 184f12db248SBryan Drewery int retry, max_retry; 185cc36fe49SBaptiste Daroussin ssize_t r; 186f12db248SBryan Drewery char buf[10240]; 187f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 188f12db248SBryan Drewery static const char *mirror_type = NULL; 1893aa4b42aSBaptiste Daroussin 19029aaa961SBaptiste Daroussin max_retry = 3; 19129aaa961SBaptiste Daroussin current = mirrors = NULL; 192f12db248SBryan Drewery remote = NULL; 1933aa4b42aSBaptiste Daroussin 194f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 195f12db248SBryan Drewery != 0) { 1969950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 1979950eceeSBaptiste Daroussin return (-1); 1989950eceeSBaptiste Daroussin } 19962940ea9SBryan Drewery 200f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 2013aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2023b05c2a8SBaptiste Daroussin return (-1); 2033aa4b42aSBaptiste Daroussin } 2043aa4b42aSBaptiste Daroussin 20529aaa961SBaptiste Daroussin retry = max_retry; 20629aaa961SBaptiste Daroussin 20779fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 20879fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 20979fe80efSBaptiste Daroussin return (-1); 21079fe80efSBaptiste Daroussin } 21179fe80efSBaptiste Daroussin 21229aaa961SBaptiste Daroussin while (remote == NULL) { 21329aaa961SBaptiste Daroussin if (retry == max_retry) { 2149950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2159950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 21629aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 21729aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 21829aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 21929aaa961SBaptiste Daroussin current = mirrors; 22029aaa961SBaptiste Daroussin } 22129aaa961SBaptiste Daroussin } 22229aaa961SBaptiste Daroussin 22335e07a7aSBaptiste Daroussin if (mirrors != NULL) { 22429aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 22535e07a7aSBaptiste Daroussin u->port = current->port; 22635e07a7aSBaptiste Daroussin } 22729aaa961SBaptiste Daroussin 22829aaa961SBaptiste Daroussin remote = fetchXGet(u, &st, ""); 22929aaa961SBaptiste Daroussin if (remote == NULL) { 23029aaa961SBaptiste Daroussin --retry; 23129aaa961SBaptiste Daroussin if (retry <= 0) 23229aaa961SBaptiste Daroussin goto fetchfail; 23329aaa961SBaptiste Daroussin if (mirrors == NULL) { 2343aa4b42aSBaptiste Daroussin sleep(1); 23529aaa961SBaptiste Daroussin } else { 23629aaa961SBaptiste Daroussin current = current->next; 23729aaa961SBaptiste Daroussin if (current == NULL) 23829aaa961SBaptiste Daroussin current = mirrors; 23929aaa961SBaptiste Daroussin } 24029aaa961SBaptiste Daroussin } 24129aaa961SBaptiste Daroussin } 242a6454741SBaptiste Daroussin 243cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 2443aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2453aa4b42aSBaptiste Daroussin warn("write()"); 246f12db248SBryan Drewery goto fetchfail; 2473aa4b42aSBaptiste Daroussin } 248cc36fe49SBaptiste Daroussin } 2493aa4b42aSBaptiste Daroussin 250cc36fe49SBaptiste Daroussin if (r != 0) { 251cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 252cc36fe49SBaptiste Daroussin goto fetchfail; 2533aa4b42aSBaptiste Daroussin } 2543aa4b42aSBaptiste Daroussin 255a6454741SBaptiste Daroussin if (ferror(remote)) 256a6454741SBaptiste Daroussin goto fetchfail; 2573aa4b42aSBaptiste Daroussin 258f12db248SBryan Drewery goto cleanup; 259f12db248SBryan Drewery 260f12db248SBryan Drewery fetchfail: 261f12db248SBryan Drewery if (fd != -1) { 262f12db248SBryan Drewery close(fd); 263f12db248SBryan Drewery fd = -1; 264f12db248SBryan Drewery unlink(path); 265f12db248SBryan Drewery } 266f12db248SBryan Drewery 267f12db248SBryan Drewery cleanup: 268f12db248SBryan Drewery if (remote != NULL) 269f12db248SBryan Drewery fclose(remote); 270f12db248SBryan Drewery 271f12db248SBryan Drewery return fd; 272f12db248SBryan Drewery } 273f12db248SBryan Drewery 274f12db248SBryan Drewery static struct fingerprint * 2758a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 276f12db248SBryan Drewery { 277b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 2788a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 2798a7d859eSBaptiste Daroussin const char *function, *fp, *key; 280f12db248SBryan Drewery struct fingerprint *f; 281f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 282f12db248SBryan Drewery 283f12db248SBryan Drewery function = fp = NULL; 284f12db248SBryan Drewery 2858a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 2868a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 2878a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 2888a7d859eSBaptiste Daroussin continue; 2898a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 2908a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 291f12db248SBryan Drewery continue; 292f12db248SBryan Drewery } 2938a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 2948a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 295f12db248SBryan Drewery continue; 296f12db248SBryan Drewery } 297f12db248SBryan Drewery } 298f12db248SBryan Drewery 299f12db248SBryan Drewery if (fp == NULL || function == NULL) 300f12db248SBryan Drewery return (NULL); 301f12db248SBryan Drewery 302f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 303f12db248SBryan Drewery fct = HASH_SHA256; 304f12db248SBryan Drewery 305f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 306d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 307f12db248SBryan Drewery return (NULL); 308f12db248SBryan Drewery } 309f12db248SBryan Drewery 310f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 311f12db248SBryan Drewery f->type = fct; 312f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 313f12db248SBryan Drewery 314f12db248SBryan Drewery return (f); 315f12db248SBryan Drewery } 316f12db248SBryan Drewery 317516aaf7cSBryan Drewery static void 318516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 319516aaf7cSBryan Drewery { 320d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 321516aaf7cSBryan Drewery 322d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 323516aaf7cSBryan Drewery free(fingerprint->name); 324516aaf7cSBryan Drewery free(fingerprint); 325516aaf7cSBryan Drewery } 326516aaf7cSBryan Drewery free(list); 327516aaf7cSBryan Drewery } 328516aaf7cSBryan Drewery 329f12db248SBryan Drewery static struct fingerprint * 330f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 331f12db248SBryan Drewery { 3328a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 3338a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 334f12db248SBryan Drewery struct fingerprint *f; 335f12db248SBryan Drewery char path[MAXPATHLEN]; 336f12db248SBryan Drewery 337f12db248SBryan Drewery f = NULL; 338f12db248SBryan Drewery 339f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 340f12db248SBryan Drewery 3418a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 3428a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 3438a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 3448a7d859eSBaptiste Daroussin ucl_parser_free(p); 345f12db248SBryan Drewery return (NULL); 3468a7d859eSBaptiste Daroussin } 347f12db248SBryan Drewery 3488a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 349f12db248SBryan Drewery 3508a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 3518a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 352f12db248SBryan Drewery 3538a7d859eSBaptiste Daroussin if (f != NULL) 354516aaf7cSBryan Drewery f->name = strdup(filename); 355f12db248SBryan Drewery 356b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 3578a7d859eSBaptiste Daroussin ucl_parser_free(p); 358f12db248SBryan Drewery 359f12db248SBryan Drewery return (f); 360f12db248SBryan Drewery } 361f12db248SBryan Drewery 362f12db248SBryan Drewery static struct fingerprint_list * 363f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 364f12db248SBryan Drewery { 365f12db248SBryan Drewery DIR *d; 366f12db248SBryan Drewery struct dirent *ent; 367f12db248SBryan Drewery struct fingerprint *finger; 368f12db248SBryan Drewery struct fingerprint_list *fingerprints; 369f12db248SBryan Drewery 370f12db248SBryan Drewery *count = 0; 371f12db248SBryan Drewery 372f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 373f12db248SBryan Drewery if (fingerprints == NULL) 374f12db248SBryan Drewery return (NULL); 375f12db248SBryan Drewery STAILQ_INIT(fingerprints); 376f12db248SBryan Drewery 37792947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 37892947daaSBaptiste Daroussin free(fingerprints); 37992947daaSBaptiste Daroussin 380f12db248SBryan Drewery return (NULL); 38192947daaSBaptiste Daroussin } 382f12db248SBryan Drewery 383f12db248SBryan Drewery while ((ent = readdir(d))) { 384f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 385f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 386f12db248SBryan Drewery continue; 387f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 388f12db248SBryan Drewery if (finger != NULL) { 389f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 390f12db248SBryan Drewery ++(*count); 391f12db248SBryan Drewery } 392f12db248SBryan Drewery } 393f12db248SBryan Drewery 394f12db248SBryan Drewery closedir(d); 395f12db248SBryan Drewery 396f12db248SBryan Drewery return (fingerprints); 397f12db248SBryan Drewery } 398f12db248SBryan Drewery 399f12db248SBryan Drewery static void 400f12db248SBryan Drewery sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 401f12db248SBryan Drewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 402f12db248SBryan Drewery { 403f12db248SBryan Drewery int i; 404f12db248SBryan Drewery 405f12db248SBryan Drewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 406f12db248SBryan Drewery sprintf(out + (i * 2), "%02x", hash[i]); 407f12db248SBryan Drewery 408f12db248SBryan Drewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 409f12db248SBryan Drewery } 410f12db248SBryan Drewery 411f12db248SBryan Drewery static void 412f12db248SBryan Drewery sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 413f12db248SBryan Drewery { 414f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 415f12db248SBryan Drewery SHA256_CTX sha256; 416f12db248SBryan Drewery 417f12db248SBryan Drewery out[0] = '\0'; 418f12db248SBryan Drewery 419f12db248SBryan Drewery SHA256_Init(&sha256); 420f12db248SBryan Drewery SHA256_Update(&sha256, buf, len); 421f12db248SBryan Drewery SHA256_Final(hash, &sha256); 422f12db248SBryan Drewery sha256_hash(hash, out); 423f12db248SBryan Drewery } 424f12db248SBryan Drewery 425f12db248SBryan Drewery static int 426f12db248SBryan Drewery sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 427f12db248SBryan Drewery { 428f12db248SBryan Drewery int my_fd; 429f12db248SBryan Drewery FILE *fp; 430f12db248SBryan Drewery char buffer[BUFSIZ]; 431f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 432f12db248SBryan Drewery size_t r; 433f12db248SBryan Drewery int ret; 434f12db248SBryan Drewery SHA256_CTX sha256; 435f12db248SBryan Drewery 436f12db248SBryan Drewery my_fd = -1; 437f12db248SBryan Drewery fp = NULL; 438f12db248SBryan Drewery r = 0; 439f12db248SBryan Drewery ret = 1; 440f12db248SBryan Drewery 441f12db248SBryan Drewery out[0] = '\0'; 442f12db248SBryan Drewery 443f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 444f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 445f12db248SBryan Drewery warnx("dup"); 446f12db248SBryan Drewery goto cleanup; 447f12db248SBryan Drewery } 448f12db248SBryan Drewery 449f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 450f12db248SBryan Drewery warnx("fdopen"); 451f12db248SBryan Drewery goto cleanup; 452f12db248SBryan Drewery } 453f12db248SBryan Drewery 454f12db248SBryan Drewery SHA256_Init(&sha256); 455f12db248SBryan Drewery 456f12db248SBryan Drewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 457f12db248SBryan Drewery SHA256_Update(&sha256, buffer, r); 458f12db248SBryan Drewery 459f12db248SBryan Drewery if (ferror(fp) != 0) { 460f12db248SBryan Drewery warnx("fread"); 461f12db248SBryan Drewery goto cleanup; 462f12db248SBryan Drewery } 463f12db248SBryan Drewery 464f12db248SBryan Drewery SHA256_Final(hash, &sha256); 465f12db248SBryan Drewery sha256_hash(hash, out); 466f12db248SBryan Drewery ret = 0; 467f12db248SBryan Drewery 468f12db248SBryan Drewery cleanup: 469f12db248SBryan Drewery if (fp != NULL) 470f12db248SBryan Drewery fclose(fp); 471f12db248SBryan Drewery else if (my_fd != -1) 472f12db248SBryan Drewery close(my_fd); 473f12db248SBryan Drewery (void)lseek(fd, 0, SEEK_SET); 474f12db248SBryan Drewery 475f12db248SBryan Drewery return (ret); 476f12db248SBryan Drewery } 477f12db248SBryan Drewery 478f12db248SBryan Drewery static EVP_PKEY * 47961acb458SBaptiste Daroussin load_public_key_file(const char *file) 48061acb458SBaptiste Daroussin { 48161acb458SBaptiste Daroussin EVP_PKEY *pkey; 48261acb458SBaptiste Daroussin BIO *bp; 48361acb458SBaptiste Daroussin char errbuf[1024]; 48461acb458SBaptiste Daroussin 48561acb458SBaptiste Daroussin bp = BIO_new_file(file, "r"); 48661acb458SBaptiste Daroussin if (!bp) 48761acb458SBaptiste Daroussin errx(EXIT_FAILURE, "Unable to read %s", file); 48861acb458SBaptiste Daroussin 48961acb458SBaptiste Daroussin if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 49061acb458SBaptiste Daroussin warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); 49161acb458SBaptiste Daroussin 49261acb458SBaptiste Daroussin BIO_free(bp); 49361acb458SBaptiste Daroussin 49461acb458SBaptiste Daroussin return (pkey); 49561acb458SBaptiste Daroussin } 49661acb458SBaptiste Daroussin 49761acb458SBaptiste Daroussin static EVP_PKEY * 498f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 499f12db248SBryan Drewery { 500f12db248SBryan Drewery EVP_PKEY *pkey; 501f12db248SBryan Drewery BIO *bp; 502f12db248SBryan Drewery char errbuf[1024]; 503f12db248SBryan Drewery 504c2788c07SBryan Drewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 505f12db248SBryan Drewery 506f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 507f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 508f12db248SBryan Drewery 509f12db248SBryan Drewery BIO_free(bp); 510f12db248SBryan Drewery 511f12db248SBryan Drewery return (pkey); 512f12db248SBryan Drewery } 513f12db248SBryan Drewery 514f12db248SBryan Drewery static bool 51561acb458SBaptiste Daroussin rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, 51661acb458SBaptiste Daroussin int keylen, unsigned char *sig, int siglen) 517f12db248SBryan Drewery { 518f12db248SBryan Drewery EVP_MD_CTX *mdctx; 519f12db248SBryan Drewery EVP_PKEY *pkey; 520f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 521f12db248SBryan Drewery char errbuf[1024]; 522f12db248SBryan Drewery bool ret; 523f12db248SBryan Drewery 524f12db248SBryan Drewery pkey = NULL; 525f12db248SBryan Drewery mdctx = NULL; 526f12db248SBryan Drewery ret = false; 527f12db248SBryan Drewery 52861acb458SBaptiste Daroussin SSL_load_error_strings(); 52961acb458SBaptiste Daroussin 530f12db248SBryan Drewery /* Compute SHA256 of the package. */ 531f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 532f12db248SBryan Drewery warn("lseek"); 533f12db248SBryan Drewery goto cleanup; 534f12db248SBryan Drewery } 535f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 536f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 537f12db248SBryan Drewery goto cleanup; 538f12db248SBryan Drewery } 539f12db248SBryan Drewery 54061acb458SBaptiste Daroussin if (sigfile != NULL) { 54161acb458SBaptiste Daroussin if ((pkey = load_public_key_file(sigfile)) == NULL) { 54261acb458SBaptiste Daroussin warnx("Error reading public key"); 54361acb458SBaptiste Daroussin goto cleanup; 54461acb458SBaptiste Daroussin } 54561acb458SBaptiste Daroussin } else { 546f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 547f12db248SBryan Drewery warnx("Error reading public key"); 548f12db248SBryan Drewery goto cleanup; 549f12db248SBryan Drewery } 55061acb458SBaptiste Daroussin } 551f12db248SBryan Drewery 552f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 553f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 554f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 555f12db248SBryan Drewery goto error; 556f12db248SBryan Drewery } 557f12db248SBryan Drewery 558f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 5594c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 560f12db248SBryan Drewery goto error; 561f12db248SBryan Drewery } 562f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 5634c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 564f12db248SBryan Drewery goto error; 565f12db248SBryan Drewery } 566f12db248SBryan Drewery 567f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 5684c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 569f12db248SBryan Drewery goto error; 570f12db248SBryan Drewery } 571f12db248SBryan Drewery 572f12db248SBryan Drewery ret = true; 573f12db248SBryan Drewery printf("done\n"); 574f12db248SBryan Drewery goto cleanup; 575f12db248SBryan Drewery 576f12db248SBryan Drewery error: 577f12db248SBryan Drewery printf("failed\n"); 578f12db248SBryan Drewery 579f12db248SBryan Drewery cleanup: 580f12db248SBryan Drewery if (pkey) 581f12db248SBryan Drewery EVP_PKEY_free(pkey); 582f12db248SBryan Drewery if (mdctx) 583f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 584f12db248SBryan Drewery ERR_free_strings(); 585f12db248SBryan Drewery 586f12db248SBryan Drewery return (ret); 587f12db248SBryan Drewery } 588f12db248SBryan Drewery 58961acb458SBaptiste Daroussin static struct pubkey * 59061acb458SBaptiste Daroussin read_pubkey(int fd) 59161acb458SBaptiste Daroussin { 59261acb458SBaptiste Daroussin struct pubkey *pk; 59361acb458SBaptiste Daroussin struct sbuf *sig; 59461acb458SBaptiste Daroussin char buf[4096]; 59561acb458SBaptiste Daroussin int r; 59661acb458SBaptiste Daroussin 59761acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 59861acb458SBaptiste Daroussin warn("lseek"); 59961acb458SBaptiste Daroussin return (NULL); 60061acb458SBaptiste Daroussin } 60161acb458SBaptiste Daroussin 60261acb458SBaptiste Daroussin sig = sbuf_new_auto(); 60361acb458SBaptiste Daroussin 60461acb458SBaptiste Daroussin while ((r = read(fd, buf, sizeof(buf))) >0) { 60561acb458SBaptiste Daroussin sbuf_bcat(sig, buf, r); 60661acb458SBaptiste Daroussin } 60761acb458SBaptiste Daroussin 60861acb458SBaptiste Daroussin sbuf_finish(sig); 60961acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 61061acb458SBaptiste Daroussin pk->siglen = sbuf_len(sig); 61161acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 61261acb458SBaptiste Daroussin memcpy(pk->sig, sbuf_data(sig), pk->siglen); 61361acb458SBaptiste Daroussin sbuf_delete(sig); 61461acb458SBaptiste Daroussin 61561acb458SBaptiste Daroussin return (pk); 61661acb458SBaptiste Daroussin } 61761acb458SBaptiste Daroussin 618f12db248SBryan Drewery static struct sig_cert * 619f12db248SBryan Drewery parse_cert(int fd) { 620f12db248SBryan Drewery int my_fd; 621f12db248SBryan Drewery struct sig_cert *sc; 622f12db248SBryan Drewery FILE *fp; 623f12db248SBryan Drewery struct sbuf *buf, *sig, *cert; 624f12db248SBryan Drewery char *line; 625f12db248SBryan Drewery size_t linecap; 626f12db248SBryan Drewery ssize_t linelen; 627f12db248SBryan Drewery 628c2788c07SBryan Drewery buf = NULL; 629f12db248SBryan Drewery my_fd = -1; 630f12db248SBryan Drewery sc = NULL; 631f12db248SBryan Drewery line = NULL; 632f12db248SBryan Drewery linecap = 0; 633f12db248SBryan Drewery 634f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 635f12db248SBryan Drewery warn("lseek"); 636f12db248SBryan Drewery return (NULL); 637f12db248SBryan Drewery } 638f12db248SBryan Drewery 639f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 640f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 641f12db248SBryan Drewery warnx("dup"); 642f12db248SBryan Drewery return (NULL); 643f12db248SBryan Drewery } 644f12db248SBryan Drewery 645f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 646f12db248SBryan Drewery warn("fdopen"); 647f12db248SBryan Drewery close(my_fd); 648f12db248SBryan Drewery return (NULL); 649f12db248SBryan Drewery } 650f12db248SBryan Drewery 651f12db248SBryan Drewery sig = sbuf_new_auto(); 652f12db248SBryan Drewery cert = sbuf_new_auto(); 653f12db248SBryan Drewery 654f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 655f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 656f12db248SBryan Drewery buf = sig; 657f12db248SBryan Drewery continue; 658f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 659f12db248SBryan Drewery buf = cert; 660f12db248SBryan Drewery continue; 661f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 662f12db248SBryan Drewery break; 663f12db248SBryan Drewery } 664f12db248SBryan Drewery if (buf != NULL) 665f12db248SBryan Drewery sbuf_bcat(buf, line, linelen); 666f12db248SBryan Drewery } 667f12db248SBryan Drewery 668f12db248SBryan Drewery fclose(fp); 669f12db248SBryan Drewery 670f12db248SBryan Drewery /* Trim out unrelated trailing newline */ 671f12db248SBryan Drewery sbuf_setpos(sig, sbuf_len(sig) - 1); 672f12db248SBryan Drewery 673f12db248SBryan Drewery sbuf_finish(sig); 674f12db248SBryan Drewery sbuf_finish(cert); 675f12db248SBryan Drewery 676f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 677f12db248SBryan Drewery sc->siglen = sbuf_len(sig); 678f12db248SBryan Drewery sc->sig = calloc(1, sc->siglen); 679f12db248SBryan Drewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 680f12db248SBryan Drewery 681f12db248SBryan Drewery sc->certlen = sbuf_len(cert); 682f12db248SBryan Drewery sc->cert = strdup(sbuf_data(cert)); 683f12db248SBryan Drewery 684f12db248SBryan Drewery sbuf_delete(sig); 685f12db248SBryan Drewery sbuf_delete(cert); 686f12db248SBryan Drewery 687f12db248SBryan Drewery return (sc); 688f12db248SBryan Drewery } 689f12db248SBryan Drewery 690f12db248SBryan Drewery static bool 69161acb458SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig) 69261acb458SBaptiste Daroussin { 69361acb458SBaptiste Daroussin struct pubkey *pk; 69461acb458SBaptiste Daroussin const char *pubkey; 69561acb458SBaptiste Daroussin bool ret; 69661acb458SBaptiste Daroussin 69761acb458SBaptiste Daroussin pk = NULL; 69861acb458SBaptiste Daroussin pubkey = NULL; 69961acb458SBaptiste Daroussin ret = false; 70061acb458SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 70161acb458SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined"); 70261acb458SBaptiste Daroussin goto cleanup; 70361acb458SBaptiste Daroussin } 70461acb458SBaptiste Daroussin 70561acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 70661acb458SBaptiste Daroussin warnx("Error reading signature"); 70761acb458SBaptiste Daroussin goto cleanup; 70861acb458SBaptiste Daroussin } 70961acb458SBaptiste Daroussin 71061acb458SBaptiste Daroussin /* Verify the signature. */ 71161acb458SBaptiste Daroussin printf("Verifying signature with public key %s... ", pubkey); 71261acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, 71361acb458SBaptiste Daroussin pk->siglen) == false) { 71461acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 71561acb458SBaptiste Daroussin goto cleanup; 71661acb458SBaptiste Daroussin } 71761acb458SBaptiste Daroussin 71861acb458SBaptiste Daroussin ret = true; 71961acb458SBaptiste Daroussin 72061acb458SBaptiste Daroussin cleanup: 72161acb458SBaptiste Daroussin if (pk) { 72261acb458SBaptiste Daroussin free(pk->sig); 72361acb458SBaptiste Daroussin free(pk); 72461acb458SBaptiste Daroussin } 72561acb458SBaptiste Daroussin 72661acb458SBaptiste Daroussin return (ret); 72761acb458SBaptiste Daroussin } 72861acb458SBaptiste Daroussin 72961acb458SBaptiste Daroussin static bool 730f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 731f12db248SBryan Drewery { 732f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 733f12db248SBryan Drewery struct fingerprint *fingerprint; 734f12db248SBryan Drewery struct sig_cert *sc; 735f12db248SBryan Drewery bool ret; 736f12db248SBryan Drewery int trusted_count, revoked_count; 737f12db248SBryan Drewery const char *fingerprints; 738f12db248SBryan Drewery char path[MAXPATHLEN]; 739f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 740f12db248SBryan Drewery 741516aaf7cSBryan Drewery sc = NULL; 742f12db248SBryan Drewery trusted = revoked = NULL; 743f12db248SBryan Drewery ret = false; 744f12db248SBryan Drewery 745f12db248SBryan Drewery /* Read and parse fingerprints. */ 746f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 747f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 748f12db248SBryan Drewery goto cleanup; 749f12db248SBryan Drewery } 750f12db248SBryan Drewery 751f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 752f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 753f12db248SBryan Drewery warnx("Error loading trusted certificates"); 754f12db248SBryan Drewery goto cleanup; 755f12db248SBryan Drewery } 756f12db248SBryan Drewery 757f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 758f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 759f12db248SBryan Drewery goto cleanup; 760f12db248SBryan Drewery } 761f12db248SBryan Drewery 762f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 763f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 764f12db248SBryan Drewery warnx("Error loading revoked certificates"); 765f12db248SBryan Drewery goto cleanup; 766f12db248SBryan Drewery } 767f12db248SBryan Drewery 768f12db248SBryan Drewery /* Read certificate and signature in. */ 769f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 770f12db248SBryan Drewery warnx("Error parsing certificate"); 771f12db248SBryan Drewery goto cleanup; 772f12db248SBryan Drewery } 773f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 774f12db248SBryan Drewery sc->trusted = false; 775f12db248SBryan Drewery 776f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 777f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 778f12db248SBryan Drewery 779f12db248SBryan Drewery /* Check if this hash is revoked */ 780f12db248SBryan Drewery if (revoked != NULL) { 781f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 782f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 783516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 784516aaf7cSBryan Drewery "revoked certificate %s\n", 785516aaf7cSBryan Drewery fingerprint->name); 786f12db248SBryan Drewery goto cleanup; 787f12db248SBryan Drewery } 788f12db248SBryan Drewery } 789f12db248SBryan Drewery } 790f12db248SBryan Drewery 791f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 792f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 793f12db248SBryan Drewery sc->trusted = true; 794516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 795f12db248SBryan Drewery break; 796f12db248SBryan Drewery } 797f12db248SBryan Drewery } 798f12db248SBryan Drewery 799f12db248SBryan Drewery if (sc->trusted == false) { 800516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 801f12db248SBryan Drewery "package's certificate\n"); 802f12db248SBryan Drewery goto cleanup; 803f12db248SBryan Drewery } 804f12db248SBryan Drewery 805f12db248SBryan Drewery /* Verify the signature. */ 806516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 80761acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, 808f12db248SBryan Drewery sc->siglen) == false) { 809f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 810f12db248SBryan Drewery goto cleanup; 811f12db248SBryan Drewery } 812f12db248SBryan Drewery 813f12db248SBryan Drewery ret = true; 814f12db248SBryan Drewery 815f12db248SBryan Drewery cleanup: 816516aaf7cSBryan Drewery if (trusted) 817516aaf7cSBryan Drewery free_fingerprint_list(trusted); 818516aaf7cSBryan Drewery if (revoked) 819516aaf7cSBryan Drewery free_fingerprint_list(revoked); 820f12db248SBryan Drewery if (sc) { 821f12db248SBryan Drewery free(sc->cert); 822f12db248SBryan Drewery free(sc->sig); 823516aaf7cSBryan Drewery free(sc->name); 824f12db248SBryan Drewery free(sc); 825f12db248SBryan Drewery } 826f12db248SBryan Drewery 827f12db248SBryan Drewery return (ret); 828f12db248SBryan Drewery } 829f12db248SBryan Drewery 830f12db248SBryan Drewery static int 8315212e8baSBryan Drewery bootstrap_pkg(bool force) 832f12db248SBryan Drewery { 833f12db248SBryan Drewery int fd_pkg, fd_sig; 834f12db248SBryan Drewery int ret; 835f12db248SBryan Drewery char url[MAXPATHLEN]; 836f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 837f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 838f12db248SBryan Drewery const char *packagesite; 839f12db248SBryan Drewery const char *signature_type; 840f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 841f12db248SBryan Drewery 842f12db248SBryan Drewery fd_sig = -1; 843f12db248SBryan Drewery ret = -1; 844f12db248SBryan Drewery 845f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 846f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 847f12db248SBryan Drewery return (-1); 848f12db248SBryan Drewery } 849f12db248SBryan Drewery 850f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 851f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 852f12db248SBryan Drewery return (-1); 853f12db248SBryan Drewery } 854f12db248SBryan Drewery 855f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 856f12db248SBryan Drewery 857f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 858f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 859f12db248SBryan Drewery no A record. */ 860f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 861f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 862f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 863f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 864f12db248SBryan Drewery 865f12db248SBryan Drewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 866f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 867f12db248SBryan Drewery 868f12db248SBryan Drewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 869f12db248SBryan Drewery goto fetchfail; 870f12db248SBryan Drewery 871f12db248SBryan Drewery if (signature_type != NULL && 87248f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 87361acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 87448f92706SXin LI 875f12db248SBryan Drewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 876f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 877f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 878f12db248SBryan Drewery packagesite); 879f12db248SBryan Drewery 880f12db248SBryan Drewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 88161acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 88261acb458SBaptiste Daroussin "available.\n"); 883f12db248SBryan Drewery goto fetchfail; 884f12db248SBryan Drewery } 885f12db248SBryan Drewery 886f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 887f12db248SBryan Drewery goto cleanup; 88861acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 88961acb458SBaptiste Daroussin 89061acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 89161acb458SBaptiste Daroussin "%s/pkg.txz.pubkeysig.XXXXXX", 89261acb458SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 89361acb458SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", 89461acb458SBaptiste Daroussin packagesite); 89561acb458SBaptiste Daroussin 89661acb458SBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 89761acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 89861acb458SBaptiste Daroussin "available.\n"); 89961acb458SBaptiste Daroussin goto fetchfail; 90061acb458SBaptiste Daroussin } 90161acb458SBaptiste Daroussin 90261acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 90361acb458SBaptiste Daroussin goto cleanup; 90461acb458SBaptiste Daroussin } else { 90561acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 90661acb458SBaptiste Daroussin "bootstrapping.", signature_type); 90761acb458SBaptiste Daroussin goto cleanup; 90861acb458SBaptiste Daroussin } 909f12db248SBryan Drewery } 910f12db248SBryan Drewery 911f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9125212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 9133aa4b42aSBaptiste Daroussin 914a6454741SBaptiste Daroussin goto cleanup; 915a6454741SBaptiste Daroussin 916a6454741SBaptiste Daroussin fetchfail: 917a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 918*a10f71c5STom Jones if (fetchLastErrCode == FETCH_RESOLV) { 919*a10f71c5STom Jones fprintf(stderr, "Address resolution failed for %s.\n", packagesite); 920*a10f71c5STom Jones fprintf(stderr, "Consider changing PACKAGESITE.\n"); 921*a10f71c5STom Jones } else { 9224ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 9234ff9a7efSBryan Drewery "your system.\n"); 9244ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 9254ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 926*a10f71c5STom Jones } 927a6454741SBaptiste Daroussin 9283aa4b42aSBaptiste Daroussin cleanup: 929f12db248SBryan Drewery if (fd_sig != -1) { 930f12db248SBryan Drewery close(fd_sig); 931f12db248SBryan Drewery unlink(tmpsig); 932f12db248SBryan Drewery } 93392947daaSBaptiste Daroussin 93492947daaSBaptiste Daroussin if (fd_pkg != -1) { 935f12db248SBryan Drewery close(fd_pkg); 9363aa4b42aSBaptiste Daroussin unlink(tmppkg); 93792947daaSBaptiste Daroussin } 9383aa4b42aSBaptiste Daroussin 939a6454741SBaptiste Daroussin return (ret); 9403aa4b42aSBaptiste Daroussin } 9413aa4b42aSBaptiste Daroussin 942e18ad51cSAlexander Kabaev static const char confirmation_message[] = 943e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 944e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 945e18ad51cSAlexander Kabaev 946e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 947575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 9481efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 949e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 950575c4095SBaptiste Daroussin 951e18ad51cSAlexander Kabaev static int 952e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 953e18ad51cSAlexander Kabaev { 954e18ad51cSAlexander Kabaev int ret, c; 955e18ad51cSAlexander Kabaev 95667c9f60eSPoul-Henning Kamp fflush(stdout); 957e18ad51cSAlexander Kabaev c = getchar(); 958e18ad51cSAlexander Kabaev 959e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 960e18ad51cSAlexander Kabaev ret = 1; 961e18ad51cSAlexander Kabaev else 962e18ad51cSAlexander Kabaev ret = 0; 963e18ad51cSAlexander Kabaev 964e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 965e18ad51cSAlexander Kabaev c = getchar(); 966e18ad51cSAlexander Kabaev 967e18ad51cSAlexander Kabaev return (ret); 968e18ad51cSAlexander Kabaev } 969e18ad51cSAlexander Kabaev 97052cb76feSBryan Drewery static int 9715212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 97252cb76feSBryan Drewery { 97352cb76feSBryan Drewery char path[MAXPATHLEN]; 97452cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 97552cb76feSBryan Drewery const char *signature_type; 97652cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 97752cb76feSBryan Drewery 97852cb76feSBryan Drewery fd_sig = -1; 97952cb76feSBryan Drewery ret = -1; 98052cb76feSBryan Drewery 98152cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 98252cb76feSBryan Drewery if (fd_pkg == -1) 98352cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 98452cb76feSBryan Drewery 98552cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 98652cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 98792947daaSBaptiste Daroussin goto cleanup; 98852cb76feSBryan Drewery } 98952cb76feSBryan Drewery if (signature_type != NULL && 99048f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 99161acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 99248f92706SXin LI 99352cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 99452cb76feSBryan Drewery 99552cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 99661acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 99761acb458SBaptiste Daroussin "available.\n"); 99852cb76feSBryan Drewery goto cleanup; 99952cb76feSBryan Drewery } 100052cb76feSBryan Drewery 100152cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 100252cb76feSBryan Drewery goto cleanup; 100361acb458SBaptiste Daroussin 100461acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 100561acb458SBaptiste Daroussin 100661acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 100761acb458SBaptiste Daroussin 100861acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 100961acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 101061acb458SBaptiste Daroussin "available.\n"); 101161acb458SBaptiste Daroussin goto cleanup; 101261acb458SBaptiste Daroussin } 101361acb458SBaptiste Daroussin 101461acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 101561acb458SBaptiste Daroussin goto cleanup; 101661acb458SBaptiste Daroussin 101761acb458SBaptiste Daroussin } else { 101861acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 101961acb458SBaptiste Daroussin "bootstrapping.", signature_type); 102061acb458SBaptiste Daroussin goto cleanup; 102161acb458SBaptiste Daroussin } 102252cb76feSBryan Drewery } 102352cb76feSBryan Drewery 102452cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 10255212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 102652cb76feSBryan Drewery 102752cb76feSBryan Drewery cleanup: 102852cb76feSBryan Drewery close(fd_pkg); 102952cb76feSBryan Drewery if (fd_sig != -1) 103052cb76feSBryan Drewery close(fd_sig); 103152cb76feSBryan Drewery 103252cb76feSBryan Drewery return (ret); 103352cb76feSBryan Drewery } 103452cb76feSBryan Drewery 10353aa4b42aSBaptiste Daroussin int 103646b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10373aa4b42aSBaptiste Daroussin { 10383aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 10395212e8baSBryan Drewery const char *pkgarg; 10408e877d85SBaptiste Daroussin int i; 10415212e8baSBryan Drewery bool bootstrap_only, force, yes; 10425212e8baSBryan Drewery 10435212e8baSBryan Drewery bootstrap_only = false; 10445212e8baSBryan Drewery force = false; 10455212e8baSBryan Drewery pkgarg = NULL; 10465212e8baSBryan Drewery yes = false; 10473aa4b42aSBaptiste Daroussin 10483aa4b42aSBaptiste Daroussin snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 10493aa4b42aSBaptiste Daroussin getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 10503aa4b42aSBaptiste Daroussin 10515212e8baSBryan Drewery if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 10525212e8baSBryan Drewery bootstrap_only = true; 10535212e8baSBryan Drewery if (argc == 3 && strcmp(argv[2], "-f") == 0) 10545212e8baSBryan Drewery force = true; 10555212e8baSBryan Drewery } 10565212e8baSBryan Drewery 10575212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1058e18ad51cSAlexander Kabaev /* 1059d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1060ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1061ecfed9f2SMatthew Seaman * when that argument is given as argv[1]. 1062ecfed9f2SMatthew Seaman */ 1063d8f9490cSMatthew Seaman if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 1064e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1065ecfed9f2SMatthew Seaman 106652cb76feSBryan Drewery config_init(); 106752cb76feSBryan Drewery 10685212e8baSBryan Drewery if (argc > 1 && strcmp(argv[1], "add") == 0) { 10695212e8baSBryan Drewery if (argc > 2 && strcmp(argv[2], "-f") == 0) { 10705212e8baSBryan Drewery force = true; 10715212e8baSBryan Drewery pkgarg = argv[3]; 10725212e8baSBryan Drewery } else 10735212e8baSBryan Drewery pkgarg = argv[2]; 10745212e8baSBryan Drewery if (pkgarg == NULL) { 10755212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 10765212e8baSBryan Drewery exit(EXIT_FAILURE); 10775212e8baSBryan Drewery } 10785212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 10795212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 10805212e8baSBryan Drewery exit(EXIT_FAILURE); 10815212e8baSBryan Drewery } 10825212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1083b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1084b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1085b70213b5SBaptiste Daroussin } 1086ecfed9f2SMatthew Seaman /* 1087e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1088e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1089e18ad51cSAlexander Kabaev * tucked in there already. 1090e18ad51cSAlexander Kabaev */ 10919950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 10929950eceeSBaptiste Daroussin if (!yes) { 10938e877d85SBaptiste Daroussin for (i = 1; i < argc; i++) { 10948e877d85SBaptiste Daroussin if (strcmp(argv[i], "-y") == 0 || 10958e877d85SBaptiste Daroussin strcmp(argv[i], "--yes") == 0) { 10968e877d85SBaptiste Daroussin yes = true; 10978e877d85SBaptiste Daroussin break; 10988e877d85SBaptiste Daroussin } 10998e877d85SBaptiste Daroussin } 11008e877d85SBaptiste Daroussin } 11018e877d85SBaptiste Daroussin if (!yes) { 1102575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1103e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 11043a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1105575c4095SBaptiste Daroussin } 1106204ea792SBaptiste Daroussin 1107575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1108204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1109e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1110e18ad51cSAlexander Kabaev } 11115212e8baSBryan Drewery if (bootstrap_pkg(force) != 0) 1112a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 11139950eceeSBaptiste Daroussin config_finish(); 1114c3e8a27aSBryan Drewery 11155212e8baSBryan Drewery if (bootstrap_only) 1116c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 11175212e8baSBryan Drewery } else if (bootstrap_only) { 11185212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1119c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1120c3e8a27aSBryan Drewery } 11213aa4b42aSBaptiste Daroussin 11223aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 11233aa4b42aSBaptiste Daroussin 1124a6454741SBaptiste Daroussin /* NOT REACHED */ 11253b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 11263aa4b42aSBaptiste Daroussin } 1127