13aa4b42aSBaptiste Daroussin /*- 20ad5dbacSBaptiste Daroussin * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org> 3f12db248SBryan Drewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 43aa4b42aSBaptiste Daroussin * All rights reserved. 53aa4b42aSBaptiste Daroussin * 63aa4b42aSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 73aa4b42aSBaptiste Daroussin * modification, are permitted provided that the following conditions 83aa4b42aSBaptiste Daroussin * are met: 93aa4b42aSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 103aa4b42aSBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 113aa4b42aSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 123aa4b42aSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 133aa4b42aSBaptiste Daroussin * documentation and/or other materials provided with the distribution. 143aa4b42aSBaptiste Daroussin * 153aa4b42aSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163aa4b42aSBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173aa4b42aSBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183aa4b42aSBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193aa4b42aSBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203aa4b42aSBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213aa4b42aSBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223aa4b42aSBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233aa4b42aSBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243aa4b42aSBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253aa4b42aSBaptiste Daroussin * SUCH DAMAGE. 263aa4b42aSBaptiste Daroussin */ 273aa4b42aSBaptiste Daroussin 283aa4b42aSBaptiste Daroussin #include <sys/cdefs.h> 293aa4b42aSBaptiste Daroussin __FBSDID("$FreeBSD$"); 303aa4b42aSBaptiste Daroussin 313aa4b42aSBaptiste Daroussin #include <sys/param.h> 32f12db248SBryan Drewery #include <sys/queue.h> 33f12db248SBryan Drewery #include <sys/types.h> 34f12db248SBryan Drewery #include <sys/sbuf.h> 353b05c2a8SBaptiste Daroussin #include <sys/wait.h> 363aa4b42aSBaptiste Daroussin 373aa4b42aSBaptiste Daroussin #include <archive.h> 383aa4b42aSBaptiste Daroussin #include <archive_entry.h> 39f12db248SBryan Drewery #include <dirent.h> 403aa4b42aSBaptiste Daroussin #include <err.h> 413aa4b42aSBaptiste Daroussin #include <errno.h> 42b70213b5SBaptiste Daroussin #include <fcntl.h> 433b05c2a8SBaptiste Daroussin #include <fetch.h> 44a6454741SBaptiste Daroussin #include <paths.h> 459950eceeSBaptiste Daroussin #include <stdbool.h> 463aa4b42aSBaptiste Daroussin #include <stdlib.h> 473aa4b42aSBaptiste Daroussin #include <stdio.h> 483aa4b42aSBaptiste Daroussin #include <string.h> 493aa4b42aSBaptiste Daroussin #include <unistd.h> 508a7d859eSBaptiste Daroussin #include <ucl.h> 51f12db248SBryan Drewery 52f12db248SBryan Drewery #include <openssl/err.h> 53f12db248SBryan Drewery #include <openssl/ssl.h> 543aa4b42aSBaptiste Daroussin 5529aaa961SBaptiste Daroussin #include "dns_utils.h" 569950eceeSBaptiste Daroussin #include "config.h" 573aa4b42aSBaptiste Daroussin 58f12db248SBryan Drewery struct sig_cert { 59516aaf7cSBryan Drewery char *name; 60f12db248SBryan Drewery unsigned char *sig; 61f12db248SBryan Drewery int siglen; 62f12db248SBryan Drewery unsigned char *cert; 63f12db248SBryan Drewery int certlen; 64f12db248SBryan Drewery bool trusted; 65f12db248SBryan Drewery }; 66f12db248SBryan Drewery 6761acb458SBaptiste Daroussin struct pubkey { 6861acb458SBaptiste Daroussin unsigned char *sig; 6961acb458SBaptiste Daroussin int siglen; 7061acb458SBaptiste Daroussin }; 7161acb458SBaptiste Daroussin 72f12db248SBryan Drewery typedef enum { 73f12db248SBryan Drewery HASH_UNKNOWN, 74f12db248SBryan Drewery HASH_SHA256, 75f12db248SBryan Drewery } hash_t; 76f12db248SBryan Drewery 77f12db248SBryan Drewery struct fingerprint { 78f12db248SBryan Drewery hash_t type; 79516aaf7cSBryan Drewery char *name; 80f12db248SBryan Drewery char hash[BUFSIZ]; 81f12db248SBryan Drewery STAILQ_ENTRY(fingerprint) next; 82f12db248SBryan Drewery }; 83f12db248SBryan Drewery 84f12db248SBryan Drewery STAILQ_HEAD(fingerprint_list, fingerprint); 85f12db248SBryan Drewery 863aa4b42aSBaptiste Daroussin static int 873aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz) 883aa4b42aSBaptiste Daroussin { 893aa4b42aSBaptiste Daroussin struct archive *a; 903aa4b42aSBaptiste Daroussin struct archive_entry *ae; 913aa4b42aSBaptiste Daroussin char *end; 923aa4b42aSBaptiste Daroussin int ret, r; 933aa4b42aSBaptiste Daroussin 94a6454741SBaptiste Daroussin ret = -1; 953aa4b42aSBaptiste Daroussin a = archive_read_new(); 96a6454741SBaptiste Daroussin if (a == NULL) { 97a6454741SBaptiste Daroussin warn("archive_read_new"); 98a6454741SBaptiste Daroussin return (ret); 99a6454741SBaptiste Daroussin } 100ff75c36aSBaptiste Daroussin archive_read_support_filter_all(a); 1013aa4b42aSBaptiste Daroussin archive_read_support_format_tar(a); 1023aa4b42aSBaptiste Daroussin 103a6454741SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 104a6454741SBaptiste Daroussin warn("lseek"); 105a6454741SBaptiste Daroussin goto cleanup; 106a6454741SBaptiste Daroussin } 1073aa4b42aSBaptiste Daroussin 1083aa4b42aSBaptiste Daroussin if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 109a6454741SBaptiste Daroussin warnx("archive_read_open_fd: %s", archive_error_string(a)); 1103aa4b42aSBaptiste Daroussin goto cleanup; 1113aa4b42aSBaptiste Daroussin } 1123aa4b42aSBaptiste Daroussin 1133aa4b42aSBaptiste Daroussin ae = NULL; 1143aa4b42aSBaptiste Daroussin while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 1153aa4b42aSBaptiste Daroussin end = strrchr(archive_entry_pathname(ae), '/'); 1163aa4b42aSBaptiste Daroussin if (end == NULL) 1173aa4b42aSBaptiste Daroussin continue; 1183aa4b42aSBaptiste Daroussin 1193aa4b42aSBaptiste Daroussin if (strcmp(end, "/pkg-static") == 0) { 1203aa4b42aSBaptiste Daroussin r = archive_read_extract(a, ae, 1213aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 1223aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 1233aa4b42aSBaptiste Daroussin ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 124a6454741SBaptiste Daroussin strlcpy(p, archive_entry_pathname(ae), sz); 1253aa4b42aSBaptiste Daroussin break; 1263aa4b42aSBaptiste Daroussin } 1273aa4b42aSBaptiste Daroussin } 1283aa4b42aSBaptiste Daroussin 129a6454741SBaptiste Daroussin if (r == ARCHIVE_OK) 130a6454741SBaptiste Daroussin ret = 0; 131a6454741SBaptiste Daroussin else 1324622bc4eSGavin Atkinson warnx("failed to extract pkg-static: %s", 1334622bc4eSGavin Atkinson archive_error_string(a)); 1343aa4b42aSBaptiste Daroussin 1353aa4b42aSBaptiste Daroussin cleanup: 136ff75c36aSBaptiste Daroussin archive_read_free(a); 1373b05c2a8SBaptiste Daroussin return (ret); 1383aa4b42aSBaptiste Daroussin 1393aa4b42aSBaptiste Daroussin } 1403aa4b42aSBaptiste Daroussin 1413aa4b42aSBaptiste Daroussin static int 1425212e8baSBryan Drewery install_pkg_static(const char *path, const char *pkgpath, bool force) 1433aa4b42aSBaptiste Daroussin { 1443aa4b42aSBaptiste Daroussin int pstat; 1453aa4b42aSBaptiste Daroussin pid_t pid; 1463aa4b42aSBaptiste Daroussin 1473aa4b42aSBaptiste Daroussin switch ((pid = fork())) { 1483aa4b42aSBaptiste Daroussin case -1: 1493aa4b42aSBaptiste Daroussin return (-1); 1503aa4b42aSBaptiste Daroussin case 0: 1515212e8baSBryan Drewery if (force) 1525212e8baSBryan Drewery execl(path, "pkg-static", "add", "-f", pkgpath, 1535212e8baSBryan Drewery (char *)NULL); 1545212e8baSBryan Drewery else 1555212e8baSBryan Drewery execl(path, "pkg-static", "add", pkgpath, 1565212e8baSBryan Drewery (char *)NULL); 1573b05c2a8SBaptiste Daroussin _exit(1); 1583aa4b42aSBaptiste Daroussin default: 1593aa4b42aSBaptiste Daroussin break; 1603aa4b42aSBaptiste Daroussin } 1613aa4b42aSBaptiste Daroussin 162a6454741SBaptiste Daroussin while (waitpid(pid, &pstat, 0) == -1) 1633aa4b42aSBaptiste Daroussin if (errno != EINTR) 1643aa4b42aSBaptiste Daroussin return (-1); 1653aa4b42aSBaptiste Daroussin 166a6454741SBaptiste Daroussin if (WEXITSTATUS(pstat)) 1673aa4b42aSBaptiste Daroussin return (WEXITSTATUS(pstat)); 168a6454741SBaptiste Daroussin else if (WIFSIGNALED(pstat)) 169a6454741SBaptiste Daroussin return (128 & (WTERMSIG(pstat))); 170a6454741SBaptiste Daroussin return (pstat); 1713aa4b42aSBaptiste Daroussin } 1723aa4b42aSBaptiste Daroussin 1733aa4b42aSBaptiste Daroussin static int 174f12db248SBryan Drewery fetch_to_fd(const char *url, char *path) 1753aa4b42aSBaptiste Daroussin { 17629aaa961SBaptiste Daroussin struct url *u; 17729aaa961SBaptiste Daroussin struct dns_srvinfo *mirrors, *current; 178a6454741SBaptiste Daroussin struct url_stat st; 179f12db248SBryan Drewery FILE *remote; 180f12db248SBryan Drewery /* To store _https._tcp. + hostname + \0 */ 181f12db248SBryan Drewery int fd; 182f12db248SBryan Drewery int retry, max_retry; 183cc36fe49SBaptiste Daroussin ssize_t r; 184f12db248SBryan Drewery char buf[10240]; 185f12db248SBryan Drewery char zone[MAXHOSTNAMELEN + 13]; 186f12db248SBryan Drewery static const char *mirror_type = NULL; 1873aa4b42aSBaptiste Daroussin 18829aaa961SBaptiste Daroussin max_retry = 3; 18929aaa961SBaptiste Daroussin current = mirrors = NULL; 190f12db248SBryan Drewery remote = NULL; 1913aa4b42aSBaptiste Daroussin 192f12db248SBryan Drewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 193f12db248SBryan Drewery != 0) { 1949950eceeSBaptiste Daroussin warnx("No MIRROR_TYPE defined"); 1959950eceeSBaptiste Daroussin return (-1); 1969950eceeSBaptiste Daroussin } 19762940ea9SBryan Drewery 198f12db248SBryan Drewery if ((fd = mkstemp(path)) == -1) { 1993aa4b42aSBaptiste Daroussin warn("mkstemp()"); 2003b05c2a8SBaptiste Daroussin return (-1); 2013aa4b42aSBaptiste Daroussin } 2023aa4b42aSBaptiste Daroussin 20329aaa961SBaptiste Daroussin retry = max_retry; 20429aaa961SBaptiste Daroussin 20579fe80efSBaptiste Daroussin if ((u = fetchParseURL(url)) == NULL) { 20679fe80efSBaptiste Daroussin warn("fetchParseURL('%s')", url); 20779fe80efSBaptiste Daroussin return (-1); 20879fe80efSBaptiste Daroussin } 20979fe80efSBaptiste Daroussin 21029aaa961SBaptiste Daroussin while (remote == NULL) { 21129aaa961SBaptiste Daroussin if (retry == max_retry) { 2129950eceeSBaptiste Daroussin if (strcmp(u->scheme, "file") != 0 && 2139950eceeSBaptiste Daroussin strcasecmp(mirror_type, "srv") == 0) { 21429aaa961SBaptiste Daroussin snprintf(zone, sizeof(zone), 21529aaa961SBaptiste Daroussin "_%s._tcp.%s", u->scheme, u->host); 21629aaa961SBaptiste Daroussin mirrors = dns_getsrvinfo(zone); 21729aaa961SBaptiste Daroussin current = mirrors; 21829aaa961SBaptiste Daroussin } 21929aaa961SBaptiste Daroussin } 22029aaa961SBaptiste Daroussin 22135e07a7aSBaptiste Daroussin if (mirrors != NULL) { 22229aaa961SBaptiste Daroussin strlcpy(u->host, current->host, sizeof(u->host)); 22335e07a7aSBaptiste Daroussin u->port = current->port; 22435e07a7aSBaptiste Daroussin } 22529aaa961SBaptiste Daroussin 22629aaa961SBaptiste Daroussin remote = fetchXGet(u, &st, ""); 22729aaa961SBaptiste Daroussin if (remote == NULL) { 22829aaa961SBaptiste Daroussin --retry; 22929aaa961SBaptiste Daroussin if (retry <= 0) 23029aaa961SBaptiste Daroussin goto fetchfail; 23129aaa961SBaptiste Daroussin if (mirrors == NULL) { 2323aa4b42aSBaptiste Daroussin sleep(1); 23329aaa961SBaptiste Daroussin } else { 23429aaa961SBaptiste Daroussin current = current->next; 23529aaa961SBaptiste Daroussin if (current == NULL) 23629aaa961SBaptiste Daroussin current = mirrors; 23729aaa961SBaptiste Daroussin } 23829aaa961SBaptiste Daroussin } 23929aaa961SBaptiste Daroussin } 240a6454741SBaptiste Daroussin 241cc36fe49SBaptiste Daroussin while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 2423aa4b42aSBaptiste Daroussin if (write(fd, buf, r) != r) { 2433aa4b42aSBaptiste Daroussin warn("write()"); 244f12db248SBryan Drewery goto fetchfail; 2453aa4b42aSBaptiste Daroussin } 246cc36fe49SBaptiste Daroussin } 2473aa4b42aSBaptiste Daroussin 248cc36fe49SBaptiste Daroussin if (r != 0) { 249cc36fe49SBaptiste Daroussin warn("An error occurred while fetching pkg(8)"); 250cc36fe49SBaptiste Daroussin goto fetchfail; 2513aa4b42aSBaptiste Daroussin } 2523aa4b42aSBaptiste Daroussin 253a6454741SBaptiste Daroussin if (ferror(remote)) 254a6454741SBaptiste Daroussin goto fetchfail; 2553aa4b42aSBaptiste Daroussin 256f12db248SBryan Drewery goto cleanup; 257f12db248SBryan Drewery 258f12db248SBryan Drewery fetchfail: 259f12db248SBryan Drewery if (fd != -1) { 260f12db248SBryan Drewery close(fd); 261f12db248SBryan Drewery fd = -1; 262f12db248SBryan Drewery unlink(path); 263f12db248SBryan Drewery } 264f12db248SBryan Drewery 265f12db248SBryan Drewery cleanup: 266f12db248SBryan Drewery if (remote != NULL) 267f12db248SBryan Drewery fclose(remote); 268f12db248SBryan Drewery 269f12db248SBryan Drewery return fd; 270f12db248SBryan Drewery } 271f12db248SBryan Drewery 272f12db248SBryan Drewery static struct fingerprint * 2738a7d859eSBaptiste Daroussin parse_fingerprint(ucl_object_t *obj) 274f12db248SBryan Drewery { 275b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 2768a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 2778a7d859eSBaptiste Daroussin const char *function, *fp, *key; 278f12db248SBryan Drewery struct fingerprint *f; 279f12db248SBryan Drewery hash_t fct = HASH_UNKNOWN; 280f12db248SBryan Drewery 281f12db248SBryan Drewery function = fp = NULL; 282f12db248SBryan Drewery 2838a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 2848a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 2858a7d859eSBaptiste Daroussin if (cur->type != UCL_STRING) 2868a7d859eSBaptiste Daroussin continue; 2878a7d859eSBaptiste Daroussin if (strcasecmp(key, "function") == 0) { 2888a7d859eSBaptiste Daroussin function = ucl_object_tostring(cur); 289f12db248SBryan Drewery continue; 290f12db248SBryan Drewery } 2918a7d859eSBaptiste Daroussin if (strcasecmp(key, "fingerprint") == 0) { 2928a7d859eSBaptiste Daroussin fp = ucl_object_tostring(cur); 293f12db248SBryan Drewery continue; 294f12db248SBryan Drewery } 295f12db248SBryan Drewery } 296f12db248SBryan Drewery 297f12db248SBryan Drewery if (fp == NULL || function == NULL) 298f12db248SBryan Drewery return (NULL); 299f12db248SBryan Drewery 300f12db248SBryan Drewery if (strcasecmp(function, "sha256") == 0) 301f12db248SBryan Drewery fct = HASH_SHA256; 302f12db248SBryan Drewery 303f12db248SBryan Drewery if (fct == HASH_UNKNOWN) { 304d8cfb943SBaptiste Daroussin warnx("Unsupported hashing function: %s", function); 305f12db248SBryan Drewery return (NULL); 306f12db248SBryan Drewery } 307f12db248SBryan Drewery 308f12db248SBryan Drewery f = calloc(1, sizeof(struct fingerprint)); 309f12db248SBryan Drewery f->type = fct; 310f12db248SBryan Drewery strlcpy(f->hash, fp, sizeof(f->hash)); 311f12db248SBryan Drewery 312f12db248SBryan Drewery return (f); 313f12db248SBryan Drewery } 314f12db248SBryan Drewery 315516aaf7cSBryan Drewery static void 316516aaf7cSBryan Drewery free_fingerprint_list(struct fingerprint_list* list) 317516aaf7cSBryan Drewery { 318d2201d13SGleb Smirnoff struct fingerprint *fingerprint, *tmp; 319516aaf7cSBryan Drewery 320d2201d13SGleb Smirnoff STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 321516aaf7cSBryan Drewery free(fingerprint->name); 322516aaf7cSBryan Drewery free(fingerprint); 323516aaf7cSBryan Drewery } 324516aaf7cSBryan Drewery free(list); 325516aaf7cSBryan Drewery } 326516aaf7cSBryan Drewery 327f12db248SBryan Drewery static struct fingerprint * 328f12db248SBryan Drewery load_fingerprint(const char *dir, const char *filename) 329f12db248SBryan Drewery { 3308a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 3318a7d859eSBaptiste Daroussin struct ucl_parser *p = NULL; 332f12db248SBryan Drewery struct fingerprint *f; 333f12db248SBryan Drewery char path[MAXPATHLEN]; 334f12db248SBryan Drewery 335f12db248SBryan Drewery f = NULL; 336f12db248SBryan Drewery 337f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 338f12db248SBryan Drewery 3398a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 3408a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, path)) { 3418a7d859eSBaptiste Daroussin warnx("%s: %s", path, ucl_parser_get_error(p)); 3428a7d859eSBaptiste Daroussin ucl_parser_free(p); 343f12db248SBryan Drewery return (NULL); 3448a7d859eSBaptiste Daroussin } 345f12db248SBryan Drewery 3468a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 347f12db248SBryan Drewery 3488a7d859eSBaptiste Daroussin if (obj->type == UCL_OBJECT) 3498a7d859eSBaptiste Daroussin f = parse_fingerprint(obj); 350f12db248SBryan Drewery 3518a7d859eSBaptiste Daroussin if (f != NULL) 352516aaf7cSBryan Drewery f->name = strdup(filename); 353f12db248SBryan Drewery 354b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 3558a7d859eSBaptiste Daroussin ucl_parser_free(p); 356f12db248SBryan Drewery 357f12db248SBryan Drewery return (f); 358f12db248SBryan Drewery } 359f12db248SBryan Drewery 360f12db248SBryan Drewery static struct fingerprint_list * 361f12db248SBryan Drewery load_fingerprints(const char *path, int *count) 362f12db248SBryan Drewery { 363f12db248SBryan Drewery DIR *d; 364f12db248SBryan Drewery struct dirent *ent; 365f12db248SBryan Drewery struct fingerprint *finger; 366f12db248SBryan Drewery struct fingerprint_list *fingerprints; 367f12db248SBryan Drewery 368f12db248SBryan Drewery *count = 0; 369f12db248SBryan Drewery 370f12db248SBryan Drewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 371f12db248SBryan Drewery if (fingerprints == NULL) 372f12db248SBryan Drewery return (NULL); 373f12db248SBryan Drewery STAILQ_INIT(fingerprints); 374f12db248SBryan Drewery 37592947daaSBaptiste Daroussin if ((d = opendir(path)) == NULL) { 37692947daaSBaptiste Daroussin free(fingerprints); 37792947daaSBaptiste Daroussin 378f12db248SBryan Drewery return (NULL); 37992947daaSBaptiste Daroussin } 380f12db248SBryan Drewery 381f12db248SBryan Drewery while ((ent = readdir(d))) { 382f12db248SBryan Drewery if (strcmp(ent->d_name, ".") == 0 || 383f12db248SBryan Drewery strcmp(ent->d_name, "..") == 0) 384f12db248SBryan Drewery continue; 385f12db248SBryan Drewery finger = load_fingerprint(path, ent->d_name); 386f12db248SBryan Drewery if (finger != NULL) { 387f12db248SBryan Drewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 388f12db248SBryan Drewery ++(*count); 389f12db248SBryan Drewery } 390f12db248SBryan Drewery } 391f12db248SBryan Drewery 392f12db248SBryan Drewery closedir(d); 393f12db248SBryan Drewery 394f12db248SBryan Drewery return (fingerprints); 395f12db248SBryan Drewery } 396f12db248SBryan Drewery 397f12db248SBryan Drewery static void 398f12db248SBryan Drewery sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 399f12db248SBryan Drewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 400f12db248SBryan Drewery { 401f12db248SBryan Drewery int i; 402f12db248SBryan Drewery 403f12db248SBryan Drewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 404f12db248SBryan Drewery sprintf(out + (i * 2), "%02x", hash[i]); 405f12db248SBryan Drewery 406f12db248SBryan Drewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 407f12db248SBryan Drewery } 408f12db248SBryan Drewery 409f12db248SBryan Drewery static void 410f12db248SBryan Drewery sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 411f12db248SBryan Drewery { 412f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 413f12db248SBryan Drewery SHA256_CTX sha256; 414f12db248SBryan Drewery 415f12db248SBryan Drewery out[0] = '\0'; 416f12db248SBryan Drewery 417f12db248SBryan Drewery SHA256_Init(&sha256); 418f12db248SBryan Drewery SHA256_Update(&sha256, buf, len); 419f12db248SBryan Drewery SHA256_Final(hash, &sha256); 420f12db248SBryan Drewery sha256_hash(hash, out); 421f12db248SBryan Drewery } 422f12db248SBryan Drewery 423f12db248SBryan Drewery static int 424f12db248SBryan Drewery sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 425f12db248SBryan Drewery { 426f12db248SBryan Drewery int my_fd; 427f12db248SBryan Drewery FILE *fp; 428f12db248SBryan Drewery char buffer[BUFSIZ]; 429f12db248SBryan Drewery unsigned char hash[SHA256_DIGEST_LENGTH]; 430f12db248SBryan Drewery size_t r; 431f12db248SBryan Drewery int ret; 432f12db248SBryan Drewery SHA256_CTX sha256; 433f12db248SBryan Drewery 434f12db248SBryan Drewery my_fd = -1; 435f12db248SBryan Drewery fp = NULL; 436f12db248SBryan Drewery r = 0; 437f12db248SBryan Drewery ret = 1; 438f12db248SBryan Drewery 439f12db248SBryan Drewery out[0] = '\0'; 440f12db248SBryan Drewery 441f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 442f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 443f12db248SBryan Drewery warnx("dup"); 444f12db248SBryan Drewery goto cleanup; 445f12db248SBryan Drewery } 446f12db248SBryan Drewery 447f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 448f12db248SBryan Drewery warnx("fdopen"); 449f12db248SBryan Drewery goto cleanup; 450f12db248SBryan Drewery } 451f12db248SBryan Drewery 452f12db248SBryan Drewery SHA256_Init(&sha256); 453f12db248SBryan Drewery 454f12db248SBryan Drewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 455f12db248SBryan Drewery SHA256_Update(&sha256, buffer, r); 456f12db248SBryan Drewery 457f12db248SBryan Drewery if (ferror(fp) != 0) { 458f12db248SBryan Drewery warnx("fread"); 459f12db248SBryan Drewery goto cleanup; 460f12db248SBryan Drewery } 461f12db248SBryan Drewery 462f12db248SBryan Drewery SHA256_Final(hash, &sha256); 463f12db248SBryan Drewery sha256_hash(hash, out); 464f12db248SBryan Drewery ret = 0; 465f12db248SBryan Drewery 466f12db248SBryan Drewery cleanup: 467f12db248SBryan Drewery if (fp != NULL) 468f12db248SBryan Drewery fclose(fp); 469f12db248SBryan Drewery else if (my_fd != -1) 470f12db248SBryan Drewery close(my_fd); 471f12db248SBryan Drewery (void)lseek(fd, 0, SEEK_SET); 472f12db248SBryan Drewery 473f12db248SBryan Drewery return (ret); 474f12db248SBryan Drewery } 475f12db248SBryan Drewery 476f12db248SBryan Drewery static EVP_PKEY * 47761acb458SBaptiste Daroussin load_public_key_file(const char *file) 47861acb458SBaptiste Daroussin { 47961acb458SBaptiste Daroussin EVP_PKEY *pkey; 48061acb458SBaptiste Daroussin BIO *bp; 48161acb458SBaptiste Daroussin char errbuf[1024]; 48261acb458SBaptiste Daroussin 48361acb458SBaptiste Daroussin bp = BIO_new_file(file, "r"); 48461acb458SBaptiste Daroussin if (!bp) 48561acb458SBaptiste Daroussin errx(EXIT_FAILURE, "Unable to read %s", file); 48661acb458SBaptiste Daroussin 48761acb458SBaptiste Daroussin if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 48861acb458SBaptiste Daroussin warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); 48961acb458SBaptiste Daroussin 49061acb458SBaptiste Daroussin BIO_free(bp); 49161acb458SBaptiste Daroussin 49261acb458SBaptiste Daroussin return (pkey); 49361acb458SBaptiste Daroussin } 49461acb458SBaptiste Daroussin 49561acb458SBaptiste Daroussin static EVP_PKEY * 496f12db248SBryan Drewery load_public_key_buf(const unsigned char *cert, int certlen) 497f12db248SBryan Drewery { 498f12db248SBryan Drewery EVP_PKEY *pkey; 499f12db248SBryan Drewery BIO *bp; 500f12db248SBryan Drewery char errbuf[1024]; 501f12db248SBryan Drewery 502c2788c07SBryan Drewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 503f12db248SBryan Drewery 504f12db248SBryan Drewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 505f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 506f12db248SBryan Drewery 507f12db248SBryan Drewery BIO_free(bp); 508f12db248SBryan Drewery 509f12db248SBryan Drewery return (pkey); 510f12db248SBryan Drewery } 511f12db248SBryan Drewery 512f12db248SBryan Drewery static bool 51361acb458SBaptiste Daroussin rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, 51461acb458SBaptiste Daroussin int keylen, unsigned char *sig, int siglen) 515f12db248SBryan Drewery { 516f12db248SBryan Drewery EVP_MD_CTX *mdctx; 517f12db248SBryan Drewery EVP_PKEY *pkey; 518f12db248SBryan Drewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 519f12db248SBryan Drewery char errbuf[1024]; 520f12db248SBryan Drewery bool ret; 521f12db248SBryan Drewery 522f12db248SBryan Drewery pkey = NULL; 523f12db248SBryan Drewery mdctx = NULL; 524f12db248SBryan Drewery ret = false; 525f12db248SBryan Drewery 52661acb458SBaptiste Daroussin SSL_load_error_strings(); 52761acb458SBaptiste Daroussin 528f12db248SBryan Drewery /* Compute SHA256 of the package. */ 529f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 530f12db248SBryan Drewery warn("lseek"); 531f12db248SBryan Drewery goto cleanup; 532f12db248SBryan Drewery } 533f12db248SBryan Drewery if ((sha256_fd(fd, sha256)) == -1) { 534f12db248SBryan Drewery warnx("Error creating SHA256 hash for package"); 535f12db248SBryan Drewery goto cleanup; 536f12db248SBryan Drewery } 537f12db248SBryan Drewery 53861acb458SBaptiste Daroussin if (sigfile != NULL) { 53961acb458SBaptiste Daroussin if ((pkey = load_public_key_file(sigfile)) == NULL) { 54061acb458SBaptiste Daroussin warnx("Error reading public key"); 54161acb458SBaptiste Daroussin goto cleanup; 54261acb458SBaptiste Daroussin } 54361acb458SBaptiste Daroussin } else { 544f12db248SBryan Drewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 545f12db248SBryan Drewery warnx("Error reading public key"); 546f12db248SBryan Drewery goto cleanup; 547f12db248SBryan Drewery } 54861acb458SBaptiste Daroussin } 549f12db248SBryan Drewery 550f12db248SBryan Drewery /* Verify signature of the SHA256(pkg) is valid. */ 551f12db248SBryan Drewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 552f12db248SBryan Drewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 553f12db248SBryan Drewery goto error; 554f12db248SBryan Drewery } 555f12db248SBryan Drewery 556f12db248SBryan Drewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 5574c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 558f12db248SBryan Drewery goto error; 559f12db248SBryan Drewery } 560f12db248SBryan Drewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 5614c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 562f12db248SBryan Drewery goto error; 563f12db248SBryan Drewery } 564f12db248SBryan Drewery 565f12db248SBryan Drewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 5664c79e0d6SBaptiste Daroussin warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 567f12db248SBryan Drewery goto error; 568f12db248SBryan Drewery } 569f12db248SBryan Drewery 570f12db248SBryan Drewery ret = true; 571f12db248SBryan Drewery printf("done\n"); 572f12db248SBryan Drewery goto cleanup; 573f12db248SBryan Drewery 574f12db248SBryan Drewery error: 575f12db248SBryan Drewery printf("failed\n"); 576f12db248SBryan Drewery 577f12db248SBryan Drewery cleanup: 578f12db248SBryan Drewery if (pkey) 579f12db248SBryan Drewery EVP_PKEY_free(pkey); 580f12db248SBryan Drewery if (mdctx) 581f12db248SBryan Drewery EVP_MD_CTX_destroy(mdctx); 582f12db248SBryan Drewery ERR_free_strings(); 583f12db248SBryan Drewery 584f12db248SBryan Drewery return (ret); 585f12db248SBryan Drewery } 586f12db248SBryan Drewery 58761acb458SBaptiste Daroussin static struct pubkey * 58861acb458SBaptiste Daroussin read_pubkey(int fd) 58961acb458SBaptiste Daroussin { 59061acb458SBaptiste Daroussin struct pubkey *pk; 59161acb458SBaptiste Daroussin struct sbuf *sig; 59261acb458SBaptiste Daroussin char buf[4096]; 59361acb458SBaptiste Daroussin int r; 59461acb458SBaptiste Daroussin 59561acb458SBaptiste Daroussin if (lseek(fd, 0, 0) == -1) { 59661acb458SBaptiste Daroussin warn("lseek"); 59761acb458SBaptiste Daroussin return (NULL); 59861acb458SBaptiste Daroussin } 59961acb458SBaptiste Daroussin 60061acb458SBaptiste Daroussin sig = sbuf_new_auto(); 60161acb458SBaptiste Daroussin 60261acb458SBaptiste Daroussin while ((r = read(fd, buf, sizeof(buf))) >0) { 60361acb458SBaptiste Daroussin sbuf_bcat(sig, buf, r); 60461acb458SBaptiste Daroussin } 60561acb458SBaptiste Daroussin 60661acb458SBaptiste Daroussin sbuf_finish(sig); 60761acb458SBaptiste Daroussin pk = calloc(1, sizeof(struct pubkey)); 60861acb458SBaptiste Daroussin pk->siglen = sbuf_len(sig); 60961acb458SBaptiste Daroussin pk->sig = calloc(1, pk->siglen); 61061acb458SBaptiste Daroussin memcpy(pk->sig, sbuf_data(sig), pk->siglen); 61161acb458SBaptiste Daroussin sbuf_delete(sig); 61261acb458SBaptiste Daroussin 61361acb458SBaptiste Daroussin return (pk); 61461acb458SBaptiste Daroussin } 61561acb458SBaptiste Daroussin 616f12db248SBryan Drewery static struct sig_cert * 617f12db248SBryan Drewery parse_cert(int fd) { 618f12db248SBryan Drewery int my_fd; 619f12db248SBryan Drewery struct sig_cert *sc; 620f12db248SBryan Drewery FILE *fp; 621f12db248SBryan Drewery struct sbuf *buf, *sig, *cert; 622f12db248SBryan Drewery char *line; 623f12db248SBryan Drewery size_t linecap; 624f12db248SBryan Drewery ssize_t linelen; 625f12db248SBryan Drewery 626c2788c07SBryan Drewery buf = NULL; 627f12db248SBryan Drewery my_fd = -1; 628f12db248SBryan Drewery sc = NULL; 629f12db248SBryan Drewery line = NULL; 630f12db248SBryan Drewery linecap = 0; 631f12db248SBryan Drewery 632f12db248SBryan Drewery if (lseek(fd, 0, 0) == -1) { 633f12db248SBryan Drewery warn("lseek"); 634f12db248SBryan Drewery return (NULL); 635f12db248SBryan Drewery } 636f12db248SBryan Drewery 637f12db248SBryan Drewery /* Duplicate the fd so that fclose(3) does not close it. */ 638f12db248SBryan Drewery if ((my_fd = dup(fd)) == -1) { 639f12db248SBryan Drewery warnx("dup"); 640f12db248SBryan Drewery return (NULL); 641f12db248SBryan Drewery } 642f12db248SBryan Drewery 643f12db248SBryan Drewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 644f12db248SBryan Drewery warn("fdopen"); 645f12db248SBryan Drewery close(my_fd); 646f12db248SBryan Drewery return (NULL); 647f12db248SBryan Drewery } 648f12db248SBryan Drewery 649f12db248SBryan Drewery sig = sbuf_new_auto(); 650f12db248SBryan Drewery cert = sbuf_new_auto(); 651f12db248SBryan Drewery 652f12db248SBryan Drewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 653f12db248SBryan Drewery if (strcmp(line, "SIGNATURE\n") == 0) { 654f12db248SBryan Drewery buf = sig; 655f12db248SBryan Drewery continue; 656f12db248SBryan Drewery } else if (strcmp(line, "CERT\n") == 0) { 657f12db248SBryan Drewery buf = cert; 658f12db248SBryan Drewery continue; 659f12db248SBryan Drewery } else if (strcmp(line, "END\n") == 0) { 660f12db248SBryan Drewery break; 661f12db248SBryan Drewery } 662f12db248SBryan Drewery if (buf != NULL) 663f12db248SBryan Drewery sbuf_bcat(buf, line, linelen); 664f12db248SBryan Drewery } 665f12db248SBryan Drewery 666f12db248SBryan Drewery fclose(fp); 667f12db248SBryan Drewery 668f12db248SBryan Drewery /* Trim out unrelated trailing newline */ 669f12db248SBryan Drewery sbuf_setpos(sig, sbuf_len(sig) - 1); 670f12db248SBryan Drewery 671f12db248SBryan Drewery sbuf_finish(sig); 672f12db248SBryan Drewery sbuf_finish(cert); 673f12db248SBryan Drewery 674f12db248SBryan Drewery sc = calloc(1, sizeof(struct sig_cert)); 675f12db248SBryan Drewery sc->siglen = sbuf_len(sig); 676f12db248SBryan Drewery sc->sig = calloc(1, sc->siglen); 677f12db248SBryan Drewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 678f12db248SBryan Drewery 679f12db248SBryan Drewery sc->certlen = sbuf_len(cert); 680f12db248SBryan Drewery sc->cert = strdup(sbuf_data(cert)); 681f12db248SBryan Drewery 682f12db248SBryan Drewery sbuf_delete(sig); 683f12db248SBryan Drewery sbuf_delete(cert); 684f12db248SBryan Drewery 685f12db248SBryan Drewery return (sc); 686f12db248SBryan Drewery } 687f12db248SBryan Drewery 688f12db248SBryan Drewery static bool 68961acb458SBaptiste Daroussin verify_pubsignature(int fd_pkg, int fd_sig) 69061acb458SBaptiste Daroussin { 69161acb458SBaptiste Daroussin struct pubkey *pk; 69261acb458SBaptiste Daroussin const char *pubkey; 69361acb458SBaptiste Daroussin bool ret; 69461acb458SBaptiste Daroussin 69561acb458SBaptiste Daroussin pk = NULL; 69661acb458SBaptiste Daroussin pubkey = NULL; 69761acb458SBaptiste Daroussin ret = false; 69861acb458SBaptiste Daroussin if (config_string(PUBKEY, &pubkey) != 0) { 69961acb458SBaptiste Daroussin warnx("No CONFIG_PUBKEY defined"); 70061acb458SBaptiste Daroussin goto cleanup; 70161acb458SBaptiste Daroussin } 70261acb458SBaptiste Daroussin 70361acb458SBaptiste Daroussin if ((pk = read_pubkey(fd_sig)) == NULL) { 70461acb458SBaptiste Daroussin warnx("Error reading signature"); 70561acb458SBaptiste Daroussin goto cleanup; 70661acb458SBaptiste Daroussin } 70761acb458SBaptiste Daroussin 70861acb458SBaptiste Daroussin /* Verify the signature. */ 70961acb458SBaptiste Daroussin printf("Verifying signature with public key %s... ", pubkey); 71061acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, 71161acb458SBaptiste Daroussin pk->siglen) == false) { 71261acb458SBaptiste Daroussin fprintf(stderr, "Signature is not valid\n"); 71361acb458SBaptiste Daroussin goto cleanup; 71461acb458SBaptiste Daroussin } 71561acb458SBaptiste Daroussin 71661acb458SBaptiste Daroussin ret = true; 71761acb458SBaptiste Daroussin 71861acb458SBaptiste Daroussin cleanup: 71961acb458SBaptiste Daroussin if (pk) { 72061acb458SBaptiste Daroussin free(pk->sig); 72161acb458SBaptiste Daroussin free(pk); 72261acb458SBaptiste Daroussin } 72361acb458SBaptiste Daroussin 72461acb458SBaptiste Daroussin return (ret); 72561acb458SBaptiste Daroussin } 72661acb458SBaptiste Daroussin 72761acb458SBaptiste Daroussin static bool 728f12db248SBryan Drewery verify_signature(int fd_pkg, int fd_sig) 729f12db248SBryan Drewery { 730f12db248SBryan Drewery struct fingerprint_list *trusted, *revoked; 731f12db248SBryan Drewery struct fingerprint *fingerprint; 732f12db248SBryan Drewery struct sig_cert *sc; 733f12db248SBryan Drewery bool ret; 734f12db248SBryan Drewery int trusted_count, revoked_count; 735f12db248SBryan Drewery const char *fingerprints; 736f12db248SBryan Drewery char path[MAXPATHLEN]; 737f12db248SBryan Drewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 738f12db248SBryan Drewery 739516aaf7cSBryan Drewery sc = NULL; 740f12db248SBryan Drewery trusted = revoked = NULL; 741f12db248SBryan Drewery ret = false; 742f12db248SBryan Drewery 743f12db248SBryan Drewery /* Read and parse fingerprints. */ 744f12db248SBryan Drewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 745f12db248SBryan Drewery warnx("No CONFIG_FINGERPRINTS defined"); 746f12db248SBryan Drewery goto cleanup; 747f12db248SBryan Drewery } 748f12db248SBryan Drewery 749f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 750f12db248SBryan Drewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 751f12db248SBryan Drewery warnx("Error loading trusted certificates"); 752f12db248SBryan Drewery goto cleanup; 753f12db248SBryan Drewery } 754f12db248SBryan Drewery 755f12db248SBryan Drewery if (trusted_count == 0 || trusted == NULL) { 756f12db248SBryan Drewery fprintf(stderr, "No trusted certificates found.\n"); 757f12db248SBryan Drewery goto cleanup; 758f12db248SBryan Drewery } 759f12db248SBryan Drewery 760f12db248SBryan Drewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 761f12db248SBryan Drewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 762f12db248SBryan Drewery warnx("Error loading revoked certificates"); 763f12db248SBryan Drewery goto cleanup; 764f12db248SBryan Drewery } 765f12db248SBryan Drewery 766f12db248SBryan Drewery /* Read certificate and signature in. */ 767f12db248SBryan Drewery if ((sc = parse_cert(fd_sig)) == NULL) { 768f12db248SBryan Drewery warnx("Error parsing certificate"); 769f12db248SBryan Drewery goto cleanup; 770f12db248SBryan Drewery } 771f12db248SBryan Drewery /* Explicitly mark as non-trusted until proven otherwise. */ 772f12db248SBryan Drewery sc->trusted = false; 773f12db248SBryan Drewery 774f12db248SBryan Drewery /* Parse signature and pubkey out of the certificate */ 775f12db248SBryan Drewery sha256_buf(sc->cert, sc->certlen, hash); 776f12db248SBryan Drewery 777f12db248SBryan Drewery /* Check if this hash is revoked */ 778f12db248SBryan Drewery if (revoked != NULL) { 779f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, revoked, next) { 780f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 781516aaf7cSBryan Drewery fprintf(stderr, "The package was signed with " 782516aaf7cSBryan Drewery "revoked certificate %s\n", 783516aaf7cSBryan Drewery fingerprint->name); 784f12db248SBryan Drewery goto cleanup; 785f12db248SBryan Drewery } 786f12db248SBryan Drewery } 787f12db248SBryan Drewery } 788f12db248SBryan Drewery 789f12db248SBryan Drewery STAILQ_FOREACH(fingerprint, trusted, next) { 790f12db248SBryan Drewery if (strcasecmp(fingerprint->hash, hash) == 0) { 791f12db248SBryan Drewery sc->trusted = true; 792516aaf7cSBryan Drewery sc->name = strdup(fingerprint->name); 793f12db248SBryan Drewery break; 794f12db248SBryan Drewery } 795f12db248SBryan Drewery } 796f12db248SBryan Drewery 797f12db248SBryan Drewery if (sc->trusted == false) { 798516aaf7cSBryan Drewery fprintf(stderr, "No trusted fingerprint found matching " 799f12db248SBryan Drewery "package's certificate\n"); 800f12db248SBryan Drewery goto cleanup; 801f12db248SBryan Drewery } 802f12db248SBryan Drewery 803f12db248SBryan Drewery /* Verify the signature. */ 804516aaf7cSBryan Drewery printf("Verifying signature with trusted certificate %s... ", sc->name); 80561acb458SBaptiste Daroussin if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, 806f12db248SBryan Drewery sc->siglen) == false) { 807f12db248SBryan Drewery fprintf(stderr, "Signature is not valid\n"); 808f12db248SBryan Drewery goto cleanup; 809f12db248SBryan Drewery } 810f12db248SBryan Drewery 811f12db248SBryan Drewery ret = true; 812f12db248SBryan Drewery 813f12db248SBryan Drewery cleanup: 814516aaf7cSBryan Drewery if (trusted) 815516aaf7cSBryan Drewery free_fingerprint_list(trusted); 816516aaf7cSBryan Drewery if (revoked) 817516aaf7cSBryan Drewery free_fingerprint_list(revoked); 818f12db248SBryan Drewery if (sc) { 819f12db248SBryan Drewery free(sc->cert); 820f12db248SBryan Drewery free(sc->sig); 821516aaf7cSBryan Drewery free(sc->name); 822f12db248SBryan Drewery free(sc); 823f12db248SBryan Drewery } 824f12db248SBryan Drewery 825f12db248SBryan Drewery return (ret); 826f12db248SBryan Drewery } 827f12db248SBryan Drewery 828f12db248SBryan Drewery static int 8295212e8baSBryan Drewery bootstrap_pkg(bool force) 830f12db248SBryan Drewery { 831f12db248SBryan Drewery int fd_pkg, fd_sig; 832f12db248SBryan Drewery int ret; 833f12db248SBryan Drewery char url[MAXPATHLEN]; 834f12db248SBryan Drewery char tmppkg[MAXPATHLEN]; 835f12db248SBryan Drewery char tmpsig[MAXPATHLEN]; 836f12db248SBryan Drewery const char *packagesite; 837f12db248SBryan Drewery const char *signature_type; 838f12db248SBryan Drewery char pkgstatic[MAXPATHLEN]; 839f12db248SBryan Drewery 840f12db248SBryan Drewery fd_sig = -1; 841f12db248SBryan Drewery ret = -1; 842f12db248SBryan Drewery 843f12db248SBryan Drewery if (config_string(PACKAGESITE, &packagesite) != 0) { 844f12db248SBryan Drewery warnx("No PACKAGESITE defined"); 845f12db248SBryan Drewery return (-1); 846f12db248SBryan Drewery } 847f12db248SBryan Drewery 848f12db248SBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 849f12db248SBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 850f12db248SBryan Drewery return (-1); 851f12db248SBryan Drewery } 852f12db248SBryan Drewery 853f12db248SBryan Drewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 854f12db248SBryan Drewery 855f12db248SBryan Drewery /* Support pkg+http:// for PACKAGESITE which is the new format 856f12db248SBryan Drewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 857f12db248SBryan Drewery no A record. */ 858f12db248SBryan Drewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 859f12db248SBryan Drewery strlen(URL_SCHEME_PREFIX)) == 0) 860f12db248SBryan Drewery packagesite += strlen(URL_SCHEME_PREFIX); 861f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 862f12db248SBryan Drewery 863f12db248SBryan Drewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 864f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 865f12db248SBryan Drewery 866f12db248SBryan Drewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 867f12db248SBryan Drewery goto fetchfail; 868f12db248SBryan Drewery 869f12db248SBryan Drewery if (signature_type != NULL && 87048f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 87161acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 87248f92706SXin LI 873f12db248SBryan Drewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 874f12db248SBryan Drewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 875f12db248SBryan Drewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 876f12db248SBryan Drewery packagesite); 877f12db248SBryan Drewery 878f12db248SBryan Drewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 87961acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 88061acb458SBaptiste Daroussin "available.\n"); 881f12db248SBryan Drewery goto fetchfail; 882f12db248SBryan Drewery } 883f12db248SBryan Drewery 884f12db248SBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 885f12db248SBryan Drewery goto cleanup; 88661acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 88761acb458SBaptiste Daroussin 88861acb458SBaptiste Daroussin snprintf(tmpsig, MAXPATHLEN, 88961acb458SBaptiste Daroussin "%s/pkg.txz.pubkeysig.XXXXXX", 89061acb458SBaptiste Daroussin getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 89161acb458SBaptiste Daroussin snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", 89261acb458SBaptiste Daroussin packagesite); 89361acb458SBaptiste Daroussin 89461acb458SBaptiste Daroussin if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 89561acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 89661acb458SBaptiste Daroussin "available.\n"); 89761acb458SBaptiste Daroussin goto fetchfail; 89861acb458SBaptiste Daroussin } 89961acb458SBaptiste Daroussin 90061acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 90161acb458SBaptiste Daroussin goto cleanup; 90261acb458SBaptiste Daroussin } else { 90361acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 90461acb458SBaptiste Daroussin "bootstrapping.", signature_type); 90561acb458SBaptiste Daroussin goto cleanup; 90661acb458SBaptiste Daroussin } 907f12db248SBryan Drewery } 908f12db248SBryan Drewery 909f12db248SBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 9105212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, tmppkg, force); 9113aa4b42aSBaptiste Daroussin 912a6454741SBaptiste Daroussin goto cleanup; 913a6454741SBaptiste Daroussin 914a6454741SBaptiste Daroussin fetchfail: 915a6454741SBaptiste Daroussin warnx("Error fetching %s: %s", url, fetchLastErrString); 9164ff9a7efSBryan Drewery fprintf(stderr, "A pre-built version of pkg could not be found for " 9174ff9a7efSBryan Drewery "your system.\n"); 9184ff9a7efSBryan Drewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 9194ff9a7efSBryan Drewery "ports: 'ports-mgmt/pkg'.\n"); 920a6454741SBaptiste Daroussin 9213aa4b42aSBaptiste Daroussin cleanup: 922f12db248SBryan Drewery if (fd_sig != -1) { 923f12db248SBryan Drewery close(fd_sig); 924f12db248SBryan Drewery unlink(tmpsig); 925f12db248SBryan Drewery } 92692947daaSBaptiste Daroussin 92792947daaSBaptiste Daroussin if (fd_pkg != -1) { 928f12db248SBryan Drewery close(fd_pkg); 9293aa4b42aSBaptiste Daroussin unlink(tmppkg); 93092947daaSBaptiste Daroussin } 9313aa4b42aSBaptiste Daroussin 932a6454741SBaptiste Daroussin return (ret); 9333aa4b42aSBaptiste Daroussin } 9343aa4b42aSBaptiste Daroussin 935e18ad51cSAlexander Kabaev static const char confirmation_message[] = 936e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n" 937e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: "; 938e18ad51cSAlexander Kabaev 939e9d9ee52SBaptiste Daroussin static const char non_interactive_message[] = 940575c4095SBaptiste Daroussin "The package management tool is not yet installed on your system.\n" 9411efc8970SBaptiste Daroussin "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 942e9d9ee52SBaptiste Daroussin "in non-interactive (stdin not being a tty)\n"; 943575c4095SBaptiste Daroussin 944e18ad51cSAlexander Kabaev static int 945e18ad51cSAlexander Kabaev pkg_query_yes_no(void) 946e18ad51cSAlexander Kabaev { 947e18ad51cSAlexander Kabaev int ret, c; 948e18ad51cSAlexander Kabaev 949*67c9f60eSPoul-Henning Kamp fflush(stdout); 950e18ad51cSAlexander Kabaev c = getchar(); 951e18ad51cSAlexander Kabaev 952e18ad51cSAlexander Kabaev if (c == 'y' || c == 'Y') 953e18ad51cSAlexander Kabaev ret = 1; 954e18ad51cSAlexander Kabaev else 955e18ad51cSAlexander Kabaev ret = 0; 956e18ad51cSAlexander Kabaev 957e18ad51cSAlexander Kabaev while (c != '\n' && c != EOF) 958e18ad51cSAlexander Kabaev c = getchar(); 959e18ad51cSAlexander Kabaev 960e18ad51cSAlexander Kabaev return (ret); 961e18ad51cSAlexander Kabaev } 962e18ad51cSAlexander Kabaev 96352cb76feSBryan Drewery static int 9645212e8baSBryan Drewery bootstrap_pkg_local(const char *pkgpath, bool force) 96552cb76feSBryan Drewery { 96652cb76feSBryan Drewery char path[MAXPATHLEN]; 96752cb76feSBryan Drewery char pkgstatic[MAXPATHLEN]; 96852cb76feSBryan Drewery const char *signature_type; 96952cb76feSBryan Drewery int fd_pkg, fd_sig, ret; 97052cb76feSBryan Drewery 97152cb76feSBryan Drewery fd_sig = -1; 97252cb76feSBryan Drewery ret = -1; 97352cb76feSBryan Drewery 97452cb76feSBryan Drewery fd_pkg = open(pkgpath, O_RDONLY); 97552cb76feSBryan Drewery if (fd_pkg == -1) 97652cb76feSBryan Drewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 97752cb76feSBryan Drewery 97852cb76feSBryan Drewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 97952cb76feSBryan Drewery warnx("Error looking up SIGNATURE_TYPE"); 98092947daaSBaptiste Daroussin goto cleanup; 98152cb76feSBryan Drewery } 98252cb76feSBryan Drewery if (signature_type != NULL && 98348f92706SXin LI strcasecmp(signature_type, "NONE") != 0) { 98461acb458SBaptiste Daroussin if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 98548f92706SXin LI 98652cb76feSBryan Drewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 98752cb76feSBryan Drewery 98852cb76feSBryan Drewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 98961acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 99061acb458SBaptiste Daroussin "available.\n"); 99152cb76feSBryan Drewery goto cleanup; 99252cb76feSBryan Drewery } 99352cb76feSBryan Drewery 99452cb76feSBryan Drewery if (verify_signature(fd_pkg, fd_sig) == false) 99552cb76feSBryan Drewery goto cleanup; 99661acb458SBaptiste Daroussin 99761acb458SBaptiste Daroussin } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 99861acb458SBaptiste Daroussin 99961acb458SBaptiste Daroussin snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 100061acb458SBaptiste Daroussin 100161acb458SBaptiste Daroussin if ((fd_sig = open(path, O_RDONLY)) == -1) { 100261acb458SBaptiste Daroussin fprintf(stderr, "Signature for pkg not " 100361acb458SBaptiste Daroussin "available.\n"); 100461acb458SBaptiste Daroussin goto cleanup; 100561acb458SBaptiste Daroussin } 100661acb458SBaptiste Daroussin 100761acb458SBaptiste Daroussin if (verify_pubsignature(fd_pkg, fd_sig) == false) 100861acb458SBaptiste Daroussin goto cleanup; 100961acb458SBaptiste Daroussin 101061acb458SBaptiste Daroussin } else { 101161acb458SBaptiste Daroussin warnx("Signature type %s is not supported for " 101261acb458SBaptiste Daroussin "bootstrapping.", signature_type); 101361acb458SBaptiste Daroussin goto cleanup; 101461acb458SBaptiste Daroussin } 101552cb76feSBryan Drewery } 101652cb76feSBryan Drewery 101752cb76feSBryan Drewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 10185212e8baSBryan Drewery ret = install_pkg_static(pkgstatic, pkgpath, force); 101952cb76feSBryan Drewery 102052cb76feSBryan Drewery cleanup: 102152cb76feSBryan Drewery close(fd_pkg); 102252cb76feSBryan Drewery if (fd_sig != -1) 102352cb76feSBryan Drewery close(fd_sig); 102452cb76feSBryan Drewery 102552cb76feSBryan Drewery return (ret); 102652cb76feSBryan Drewery } 102752cb76feSBryan Drewery 10283aa4b42aSBaptiste Daroussin int 102946b67edeSBaptiste Daroussin main(int argc, char *argv[]) 10303aa4b42aSBaptiste Daroussin { 10313aa4b42aSBaptiste Daroussin char pkgpath[MAXPATHLEN]; 10325212e8baSBryan Drewery const char *pkgarg; 10335212e8baSBryan Drewery bool bootstrap_only, force, yes; 10345212e8baSBryan Drewery 10355212e8baSBryan Drewery bootstrap_only = false; 10365212e8baSBryan Drewery force = false; 10375212e8baSBryan Drewery pkgarg = NULL; 10385212e8baSBryan Drewery yes = false; 10393aa4b42aSBaptiste Daroussin 10403aa4b42aSBaptiste Daroussin snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 10413aa4b42aSBaptiste Daroussin getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 10423aa4b42aSBaptiste Daroussin 10435212e8baSBryan Drewery if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 10445212e8baSBryan Drewery bootstrap_only = true; 10455212e8baSBryan Drewery if (argc == 3 && strcmp(argv[2], "-f") == 0) 10465212e8baSBryan Drewery force = true; 10475212e8baSBryan Drewery } 10485212e8baSBryan Drewery 10495212e8baSBryan Drewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1050e18ad51cSAlexander Kabaev /* 1051d482e1f4SMatthew Seaman * To allow 'pkg -N' to be used as a reliable test for whether 1052ecfed9f2SMatthew Seaman * a system is configured to use pkg, don't bootstrap pkg 1053ecfed9f2SMatthew Seaman * when that argument is given as argv[1]. 1054ecfed9f2SMatthew Seaman */ 1055d8f9490cSMatthew Seaman if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 1056e41b8acbSMatthew Seaman errx(EXIT_FAILURE, "pkg is not installed"); 1057ecfed9f2SMatthew Seaman 105852cb76feSBryan Drewery config_init(); 105952cb76feSBryan Drewery 10605212e8baSBryan Drewery if (argc > 1 && strcmp(argv[1], "add") == 0) { 10615212e8baSBryan Drewery if (argc > 2 && strcmp(argv[2], "-f") == 0) { 10625212e8baSBryan Drewery force = true; 10635212e8baSBryan Drewery pkgarg = argv[3]; 10645212e8baSBryan Drewery } else 10655212e8baSBryan Drewery pkgarg = argv[2]; 10665212e8baSBryan Drewery if (pkgarg == NULL) { 10675212e8baSBryan Drewery fprintf(stderr, "Path to pkg.txz required\n"); 10685212e8baSBryan Drewery exit(EXIT_FAILURE); 10695212e8baSBryan Drewery } 10705212e8baSBryan Drewery if (access(pkgarg, R_OK) == -1) { 10715212e8baSBryan Drewery fprintf(stderr, "No such file: %s\n", pkgarg); 10725212e8baSBryan Drewery exit(EXIT_FAILURE); 10735212e8baSBryan Drewery } 10745212e8baSBryan Drewery if (bootstrap_pkg_local(pkgarg, force) != 0) 1075b70213b5SBaptiste Daroussin exit(EXIT_FAILURE); 1076b70213b5SBaptiste Daroussin exit(EXIT_SUCCESS); 1077b70213b5SBaptiste Daroussin } 1078ecfed9f2SMatthew Seaman /* 1079e18ad51cSAlexander Kabaev * Do not ask for confirmation if either of stdin or stdout is 1080e18ad51cSAlexander Kabaev * not tty. Check the environment to see if user has answer 1081e18ad51cSAlexander Kabaev * tucked in there already. 1082e18ad51cSAlexander Kabaev */ 10839950eceeSBaptiste Daroussin config_bool(ASSUME_ALWAYS_YES, &yes); 10849950eceeSBaptiste Daroussin if (!yes) { 1085575c4095SBaptiste Daroussin if (!isatty(fileno(stdin))) { 1086e9d9ee52SBaptiste Daroussin fprintf(stderr, non_interactive_message); 10873a480126SBaptiste Daroussin exit(EXIT_FAILURE); 1088575c4095SBaptiste Daroussin } 1089204ea792SBaptiste Daroussin 1090575c4095SBaptiste Daroussin printf("%s", confirmation_message); 1091204ea792SBaptiste Daroussin if (pkg_query_yes_no() == 0) 1092e18ad51cSAlexander Kabaev exit(EXIT_FAILURE); 1093e18ad51cSAlexander Kabaev } 10945212e8baSBryan Drewery if (bootstrap_pkg(force) != 0) 1095a6454741SBaptiste Daroussin exit(EXIT_FAILURE); 10969950eceeSBaptiste Daroussin config_finish(); 1097c3e8a27aSBryan Drewery 10985212e8baSBryan Drewery if (bootstrap_only) 1099c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 11005212e8baSBryan Drewery } else if (bootstrap_only) { 11015212e8baSBryan Drewery printf("pkg already bootstrapped at %s\n", pkgpath); 1102c3e8a27aSBryan Drewery exit(EXIT_SUCCESS); 1103c3e8a27aSBryan Drewery } 11043aa4b42aSBaptiste Daroussin 11053aa4b42aSBaptiste Daroussin execv(pkgpath, argv); 11063aa4b42aSBaptiste Daroussin 1107a6454741SBaptiste Daroussin /* NOT REACHED */ 11083b05c2a8SBaptiste Daroussin return (EXIT_FAILURE); 11093aa4b42aSBaptiste Daroussin } 1110