pkg.c revision 278563
1234313Sbapt/*- 2263020Sbapt * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org> 3257353Sbdrewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 4234313Sbapt * All rights reserved. 5234313Sbapt * 6234313Sbapt * Redistribution and use in source and binary forms, with or without 7234313Sbapt * modification, are permitted provided that the following conditions 8234313Sbapt * are met: 9234313Sbapt * 1. Redistributions of source code must retain the above copyright 10234313Sbapt * notice, this list of conditions and the following disclaimer. 11234313Sbapt * 2. Redistributions in binary form must reproduce the above copyright 12234313Sbapt * notice, this list of conditions and the following disclaimer in the 13234313Sbapt * documentation and/or other materials provided with the distribution. 14234313Sbapt * 15234313Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16234313Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17234313Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18234313Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19234313Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20234313Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21234313Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22234313Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23234313Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24234313Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25234313Sbapt * SUCH DAMAGE. 26234313Sbapt */ 27234313Sbapt 28234313Sbapt#include <sys/cdefs.h> 29234313Sbapt__FBSDID("$FreeBSD: stable/10/usr.sbin/pkg/pkg.c 278563 2015-02-11 08:07:32Z bapt $"); 30234313Sbapt 31234313Sbapt#include <sys/param.h> 32257353Sbdrewery#include <sys/queue.h> 33257353Sbdrewery#include <sys/types.h> 34257353Sbdrewery#include <sys/sbuf.h> 35234322Sbapt#include <sys/wait.h> 36234313Sbapt 37257353Sbdrewery#define _WITH_GETLINE 38234313Sbapt#include <archive.h> 39234313Sbapt#include <archive_entry.h> 40257353Sbdrewery#include <dirent.h> 41234313Sbapt#include <err.h> 42234313Sbapt#include <errno.h> 43257309Sbapt#include <fcntl.h> 44234322Sbapt#include <fetch.h> 45234351Sbapt#include <paths.h> 46247841Sbapt#include <stdbool.h> 47234313Sbapt#include <stdlib.h> 48234313Sbapt#include <stdio.h> 49234313Sbapt#include <string.h> 50234313Sbapt#include <time.h> 51234313Sbapt#include <unistd.h> 52263020Sbapt#include <ucl.h> 53234313Sbapt 54257353Sbdrewery#include <openssl/err.h> 55257353Sbdrewery#include <openssl/ssl.h> 56257353Sbdrewery 57243883Sbapt#include "dns_utils.h" 58247841Sbapt#include "config.h" 59234313Sbapt 60257353Sbdrewerystruct sig_cert { 61257353Sbdrewery char *name; 62257353Sbdrewery unsigned char *sig; 63257353Sbdrewery int siglen; 64257353Sbdrewery unsigned char *cert; 65257353Sbdrewery int certlen; 66257353Sbdrewery bool trusted; 67257353Sbdrewery}; 68257353Sbdrewery 69257353Sbdrewerytypedef enum { 70257353Sbdrewery HASH_UNKNOWN, 71257353Sbdrewery HASH_SHA256, 72257353Sbdrewery} hash_t; 73257353Sbdrewery 74257353Sbdrewerystruct fingerprint { 75257353Sbdrewery hash_t type; 76257353Sbdrewery char *name; 77257353Sbdrewery char hash[BUFSIZ]; 78257353Sbdrewery STAILQ_ENTRY(fingerprint) next; 79257353Sbdrewery}; 80257353Sbdrewery 81257353SbdrewerySTAILQ_HEAD(fingerprint_list, fingerprint); 82257353Sbdrewery 83234313Sbaptstatic int 84234313Sbaptextract_pkg_static(int fd, char *p, int sz) 85234313Sbapt{ 86234313Sbapt struct archive *a; 87234313Sbapt struct archive_entry *ae; 88234313Sbapt char *end; 89234313Sbapt int ret, r; 90234313Sbapt 91234351Sbapt ret = -1; 92234313Sbapt a = archive_read_new(); 93234351Sbapt if (a == NULL) { 94234351Sbapt warn("archive_read_new"); 95234351Sbapt return (ret); 96234351Sbapt } 97247060Sbapt archive_read_support_filter_all(a); 98234313Sbapt archive_read_support_format_tar(a); 99234313Sbapt 100234351Sbapt if (lseek(fd, 0, 0) == -1) { 101234351Sbapt warn("lseek"); 102234351Sbapt goto cleanup; 103234351Sbapt } 104234313Sbapt 105234313Sbapt if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 106234351Sbapt warnx("archive_read_open_fd: %s", archive_error_string(a)); 107234313Sbapt goto cleanup; 108234313Sbapt } 109234313Sbapt 110234313Sbapt ae = NULL; 111234313Sbapt while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 112234313Sbapt end = strrchr(archive_entry_pathname(ae), '/'); 113234313Sbapt if (end == NULL) 114234313Sbapt continue; 115234313Sbapt 116234313Sbapt if (strcmp(end, "/pkg-static") == 0) { 117234313Sbapt r = archive_read_extract(a, ae, 118234322Sbapt ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 119234322Sbapt ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 120234322Sbapt ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 121234351Sbapt strlcpy(p, archive_entry_pathname(ae), sz); 122234313Sbapt break; 123234313Sbapt } 124234313Sbapt } 125234313Sbapt 126234351Sbapt if (r == ARCHIVE_OK) 127234351Sbapt ret = 0; 128234351Sbapt else 129269937Sgavin warnx("failed to extract pkg-static: %s", 130269937Sgavin archive_error_string(a)); 131234313Sbapt 132234313Sbaptcleanup: 133247060Sbapt archive_read_free(a); 134234322Sbapt return (ret); 135234313Sbapt 136234313Sbapt} 137234313Sbapt 138234313Sbaptstatic int 139257632Sbdreweryinstall_pkg_static(const char *path, const char *pkgpath, bool force) 140234313Sbapt{ 141234313Sbapt int pstat; 142234313Sbapt pid_t pid; 143234313Sbapt 144234313Sbapt switch ((pid = fork())) { 145234351Sbapt case -1: 146234351Sbapt return (-1); 147234351Sbapt case 0: 148257632Sbdrewery if (force) 149257632Sbdrewery execl(path, "pkg-static", "add", "-f", pkgpath, 150257632Sbdrewery (char *)NULL); 151257632Sbdrewery else 152257632Sbdrewery execl(path, "pkg-static", "add", pkgpath, 153257632Sbdrewery (char *)NULL); 154234351Sbapt _exit(1); 155234351Sbapt default: 156234351Sbapt break; 157234313Sbapt } 158234313Sbapt 159234351Sbapt while (waitpid(pid, &pstat, 0) == -1) 160234313Sbapt if (errno != EINTR) 161234313Sbapt return (-1); 162234313Sbapt 163234351Sbapt if (WEXITSTATUS(pstat)) 164234351Sbapt return (WEXITSTATUS(pstat)); 165234351Sbapt else if (WIFSIGNALED(pstat)) 166234351Sbapt return (128 & (WTERMSIG(pstat))); 167234351Sbapt return (pstat); 168234313Sbapt} 169234313Sbapt 170234313Sbaptstatic int 171257353Sbdreweryfetch_to_fd(const char *url, char *path) 172234313Sbapt{ 173243883Sbapt struct url *u; 174257353Sbdrewery struct dns_srvinfo *mirrors, *current; 175257353Sbdrewery struct url_stat st; 176234313Sbapt FILE *remote; 177243883Sbapt /* To store _https._tcp. + hostname + \0 */ 178257353Sbdrewery int fd; 179257353Sbdrewery int retry, max_retry; 180257353Sbdrewery off_t done, r; 181257353Sbdrewery time_t now, last; 182257353Sbdrewery char buf[10240]; 183243883Sbapt char zone[MAXHOSTNAMELEN + 13]; 184257353Sbdrewery static const char *mirror_type = NULL; 185234313Sbapt 186234313Sbapt done = 0; 187234351Sbapt last = 0; 188243883Sbapt max_retry = 3; 189257353Sbdrewery current = mirrors = NULL; 190234313Sbapt remote = NULL; 191234313Sbapt 192257353Sbdrewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 193257353Sbdrewery != 0) { 194247841Sbapt warnx("No MIRROR_TYPE defined"); 195247841Sbapt return (-1); 196247841Sbapt } 197257328Sbdrewery 198257353Sbdrewery if ((fd = mkstemp(path)) == -1) { 199234313Sbapt warn("mkstemp()"); 200234322Sbapt return (-1); 201234313Sbapt } 202234313Sbapt 203243883Sbapt retry = max_retry; 204234313Sbapt 205243883Sbapt u = fetchParseURL(url); 206243883Sbapt while (remote == NULL) { 207243883Sbapt if (retry == max_retry) { 208247841Sbapt if (strcmp(u->scheme, "file") != 0 && 209247841Sbapt strcasecmp(mirror_type, "srv") == 0) { 210243883Sbapt snprintf(zone, sizeof(zone), 211243883Sbapt "_%s._tcp.%s", u->scheme, u->host); 212243883Sbapt mirrors = dns_getsrvinfo(zone); 213243883Sbapt current = mirrors; 214243883Sbapt } 215243883Sbapt } 216243883Sbapt 217257309Sbapt if (mirrors != NULL) { 218243883Sbapt strlcpy(u->host, current->host, sizeof(u->host)); 219257309Sbapt u->port = current->port; 220257309Sbapt } 221243883Sbapt 222243883Sbapt remote = fetchXGet(u, &st, ""); 223243883Sbapt if (remote == NULL) { 224243883Sbapt --retry; 225243883Sbapt if (retry <= 0) 226243883Sbapt goto fetchfail; 227243883Sbapt if (mirrors == NULL) { 228243883Sbapt sleep(1); 229243883Sbapt } else { 230243883Sbapt current = current->next; 231243883Sbapt if (current == NULL) 232243883Sbapt current = mirrors; 233243883Sbapt } 234243883Sbapt } 235243883Sbapt } 236243883Sbapt 237234351Sbapt if (remote == NULL) 238234351Sbapt goto fetchfail; 239234351Sbapt 240234313Sbapt while (done < st.size) { 241234313Sbapt if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) 242234313Sbapt break; 243234313Sbapt 244234313Sbapt if (write(fd, buf, r) != r) { 245234313Sbapt warn("write()"); 246257353Sbdrewery goto fetchfail; 247234313Sbapt } 248234313Sbapt 249234313Sbapt done += r; 250234313Sbapt now = time(NULL); 251234351Sbapt if (now > last || done == st.size) 252234313Sbapt last = now; 253234313Sbapt } 254234313Sbapt 255234351Sbapt if (ferror(remote)) 256234351Sbapt goto fetchfail; 257234313Sbapt 258257353Sbdrewery goto cleanup; 259257353Sbdrewery 260257353Sbdreweryfetchfail: 261257353Sbdrewery if (fd != -1) { 262257353Sbdrewery close(fd); 263257353Sbdrewery fd = -1; 264257353Sbdrewery unlink(path); 265257353Sbdrewery } 266257353Sbdrewery 267257353Sbdrewerycleanup: 268257353Sbdrewery if (remote != NULL) 269257353Sbdrewery fclose(remote); 270257353Sbdrewery 271257353Sbdrewery return fd; 272257353Sbdrewery} 273257353Sbdrewery 274257353Sbdrewerystatic struct fingerprint * 275263020Sbaptparse_fingerprint(ucl_object_t *obj) 276257353Sbdrewery{ 277268896Sbapt const ucl_object_t *cur; 278263020Sbapt ucl_object_iter_t it = NULL; 279263020Sbapt const char *function, *fp, *key; 280257353Sbdrewery struct fingerprint *f; 281257353Sbdrewery hash_t fct = HASH_UNKNOWN; 282257353Sbdrewery 283257353Sbdrewery function = fp = NULL; 284257353Sbdrewery 285263020Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 286263020Sbapt key = ucl_object_key(cur); 287263020Sbapt if (cur->type != UCL_STRING) 288257353Sbdrewery continue; 289263020Sbapt if (strcasecmp(key, "function") == 0) { 290263020Sbapt function = ucl_object_tostring(cur); 291263020Sbapt continue; 292257353Sbdrewery } 293263020Sbapt if (strcasecmp(key, "fingerprint") == 0) { 294263020Sbapt fp = ucl_object_tostring(cur); 295257353Sbdrewery continue; 296257353Sbdrewery } 297257353Sbdrewery } 298257353Sbdrewery 299257353Sbdrewery if (fp == NULL || function == NULL) 300257353Sbdrewery return (NULL); 301257353Sbdrewery 302257353Sbdrewery if (strcasecmp(function, "sha256") == 0) 303257353Sbdrewery fct = HASH_SHA256; 304257353Sbdrewery 305257353Sbdrewery if (fct == HASH_UNKNOWN) { 306263020Sbapt warnx("Unsupported hashing function: %s", function); 307257353Sbdrewery return (NULL); 308257353Sbdrewery } 309257353Sbdrewery 310257353Sbdrewery f = calloc(1, sizeof(struct fingerprint)); 311257353Sbdrewery f->type = fct; 312257353Sbdrewery strlcpy(f->hash, fp, sizeof(f->hash)); 313257353Sbdrewery 314257353Sbdrewery return (f); 315257353Sbdrewery} 316257353Sbdrewery 317257353Sbdrewerystatic void 318257353Sbdreweryfree_fingerprint_list(struct fingerprint_list* list) 319257353Sbdrewery{ 320258126Sglebius struct fingerprint *fingerprint, *tmp; 321257353Sbdrewery 322258126Sglebius STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 323257353Sbdrewery if (fingerprint->name) 324257353Sbdrewery free(fingerprint->name); 325257353Sbdrewery free(fingerprint); 326257353Sbdrewery } 327257353Sbdrewery free(list); 328257353Sbdrewery} 329257353Sbdrewery 330257353Sbdrewerystatic struct fingerprint * 331257353Sbdreweryload_fingerprint(const char *dir, const char *filename) 332257353Sbdrewery{ 333263020Sbapt ucl_object_t *obj = NULL; 334263020Sbapt struct ucl_parser *p = NULL; 335257353Sbdrewery struct fingerprint *f; 336257353Sbdrewery char path[MAXPATHLEN]; 337257353Sbdrewery 338257353Sbdrewery f = NULL; 339257353Sbdrewery 340257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 341257353Sbdrewery 342263020Sbapt p = ucl_parser_new(0); 343263020Sbapt if (!ucl_parser_add_file(p, path)) { 344263020Sbapt warnx("%s: %s", path, ucl_parser_get_error(p)); 345263020Sbapt ucl_parser_free(p); 346257353Sbdrewery return (NULL); 347263020Sbapt } 348257353Sbdrewery 349263020Sbapt obj = ucl_parser_get_object(p); 350257353Sbdrewery 351263020Sbapt if (obj->type == UCL_OBJECT) 352263020Sbapt f = parse_fingerprint(obj); 353257353Sbdrewery 354263020Sbapt if (f != NULL) 355263020Sbapt f->name = strdup(filename); 356257353Sbdrewery 357268896Sbapt ucl_object_unref(obj); 358263020Sbapt ucl_parser_free(p); 359257353Sbdrewery 360257353Sbdrewery return (f); 361257353Sbdrewery} 362257353Sbdrewery 363257353Sbdrewerystatic struct fingerprint_list * 364257353Sbdreweryload_fingerprints(const char *path, int *count) 365257353Sbdrewery{ 366257353Sbdrewery DIR *d; 367257353Sbdrewery struct dirent *ent; 368257353Sbdrewery struct fingerprint *finger; 369257353Sbdrewery struct fingerprint_list *fingerprints; 370257353Sbdrewery 371257353Sbdrewery *count = 0; 372257353Sbdrewery 373257353Sbdrewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 374257353Sbdrewery if (fingerprints == NULL) 375257353Sbdrewery return (NULL); 376257353Sbdrewery STAILQ_INIT(fingerprints); 377257353Sbdrewery 378278563Sbapt if ((d = opendir(path)) == NULL) { 379278563Sbapt free(fingerprints); 380278563Sbapt 381257353Sbdrewery return (NULL); 382278563Sbapt } 383257353Sbdrewery 384257353Sbdrewery while ((ent = readdir(d))) { 385257353Sbdrewery if (strcmp(ent->d_name, ".") == 0 || 386257353Sbdrewery strcmp(ent->d_name, "..") == 0) 387257353Sbdrewery continue; 388257353Sbdrewery finger = load_fingerprint(path, ent->d_name); 389257353Sbdrewery if (finger != NULL) { 390257353Sbdrewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 391257353Sbdrewery ++(*count); 392257353Sbdrewery } 393257353Sbdrewery } 394257353Sbdrewery 395257353Sbdrewery closedir(d); 396257353Sbdrewery 397257353Sbdrewery return (fingerprints); 398257353Sbdrewery} 399257353Sbdrewery 400257353Sbdrewerystatic void 401257353Sbdrewerysha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 402257353Sbdrewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 403257353Sbdrewery{ 404257353Sbdrewery int i; 405257353Sbdrewery 406257353Sbdrewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 407257353Sbdrewery sprintf(out + (i * 2), "%02x", hash[i]); 408257353Sbdrewery 409257353Sbdrewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 410257353Sbdrewery} 411257353Sbdrewery 412257353Sbdrewerystatic void 413257353Sbdrewerysha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 414257353Sbdrewery{ 415257353Sbdrewery unsigned char hash[SHA256_DIGEST_LENGTH]; 416257353Sbdrewery SHA256_CTX sha256; 417257353Sbdrewery 418257353Sbdrewery out[0] = '\0'; 419257353Sbdrewery 420257353Sbdrewery SHA256_Init(&sha256); 421257353Sbdrewery SHA256_Update(&sha256, buf, len); 422257353Sbdrewery SHA256_Final(hash, &sha256); 423257353Sbdrewery sha256_hash(hash, out); 424257353Sbdrewery} 425257353Sbdrewery 426257353Sbdrewerystatic int 427257353Sbdrewerysha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 428257353Sbdrewery{ 429257353Sbdrewery int my_fd; 430257353Sbdrewery FILE *fp; 431257353Sbdrewery char buffer[BUFSIZ]; 432257353Sbdrewery unsigned char hash[SHA256_DIGEST_LENGTH]; 433257353Sbdrewery size_t r; 434257353Sbdrewery int ret; 435257353Sbdrewery SHA256_CTX sha256; 436257353Sbdrewery 437257353Sbdrewery my_fd = -1; 438257353Sbdrewery fp = NULL; 439257353Sbdrewery r = 0; 440257353Sbdrewery ret = 1; 441257353Sbdrewery 442257353Sbdrewery out[0] = '\0'; 443257353Sbdrewery 444257353Sbdrewery /* Duplicate the fd so that fclose(3) does not close it. */ 445257353Sbdrewery if ((my_fd = dup(fd)) == -1) { 446257353Sbdrewery warnx("dup"); 447257353Sbdrewery goto cleanup; 448257353Sbdrewery } 449257353Sbdrewery 450257353Sbdrewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 451257353Sbdrewery warnx("fdopen"); 452257353Sbdrewery goto cleanup; 453257353Sbdrewery } 454257353Sbdrewery 455257353Sbdrewery SHA256_Init(&sha256); 456257353Sbdrewery 457257353Sbdrewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 458257353Sbdrewery SHA256_Update(&sha256, buffer, r); 459257353Sbdrewery 460257353Sbdrewery if (ferror(fp) != 0) { 461257353Sbdrewery warnx("fread"); 462257353Sbdrewery goto cleanup; 463257353Sbdrewery } 464257353Sbdrewery 465257353Sbdrewery SHA256_Final(hash, &sha256); 466257353Sbdrewery sha256_hash(hash, out); 467257353Sbdrewery ret = 0; 468257353Sbdrewery 469257353Sbdrewerycleanup: 470257353Sbdrewery if (fp != NULL) 471257353Sbdrewery fclose(fp); 472257353Sbdrewery else if (my_fd != -1) 473257353Sbdrewery close(my_fd); 474257353Sbdrewery (void)lseek(fd, 0, SEEK_SET); 475257353Sbdrewery 476257353Sbdrewery return (ret); 477257353Sbdrewery} 478257353Sbdrewery 479257353Sbdrewerystatic EVP_PKEY * 480257353Sbdreweryload_public_key_buf(const unsigned char *cert, int certlen) 481257353Sbdrewery{ 482257353Sbdrewery EVP_PKEY *pkey; 483257353Sbdrewery BIO *bp; 484257353Sbdrewery char errbuf[1024]; 485257353Sbdrewery 486257353Sbdrewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 487257353Sbdrewery 488257353Sbdrewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 489257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 490257353Sbdrewery 491257353Sbdrewery BIO_free(bp); 492257353Sbdrewery 493257353Sbdrewery return (pkey); 494257353Sbdrewery} 495257353Sbdrewery 496257353Sbdrewerystatic bool 497257353Sbdreweryrsa_verify_cert(int fd, const unsigned char *key, int keylen, 498257353Sbdrewery unsigned char *sig, int siglen) 499257353Sbdrewery{ 500257353Sbdrewery EVP_MD_CTX *mdctx; 501257353Sbdrewery EVP_PKEY *pkey; 502257353Sbdrewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 503257353Sbdrewery char errbuf[1024]; 504257353Sbdrewery bool ret; 505257353Sbdrewery 506257353Sbdrewery pkey = NULL; 507257353Sbdrewery mdctx = NULL; 508257353Sbdrewery ret = false; 509257353Sbdrewery 510257353Sbdrewery /* Compute SHA256 of the package. */ 511257353Sbdrewery if (lseek(fd, 0, 0) == -1) { 512257353Sbdrewery warn("lseek"); 513257353Sbdrewery goto cleanup; 514257353Sbdrewery } 515257353Sbdrewery if ((sha256_fd(fd, sha256)) == -1) { 516257353Sbdrewery warnx("Error creating SHA256 hash for package"); 517257353Sbdrewery goto cleanup; 518257353Sbdrewery } 519257353Sbdrewery 520257353Sbdrewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 521257353Sbdrewery warnx("Error reading public key"); 522257353Sbdrewery goto cleanup; 523257353Sbdrewery } 524257353Sbdrewery 525257353Sbdrewery /* Verify signature of the SHA256(pkg) is valid. */ 526257353Sbdrewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 527257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 528257353Sbdrewery goto error; 529257353Sbdrewery } 530257353Sbdrewery 531257353Sbdrewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 532257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 533257353Sbdrewery goto error; 534257353Sbdrewery } 535257353Sbdrewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 536257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 537257353Sbdrewery goto error; 538257353Sbdrewery } 539257353Sbdrewery 540257353Sbdrewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 541257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 542257353Sbdrewery goto error; 543257353Sbdrewery } 544257353Sbdrewery 545257353Sbdrewery ret = true; 546257353Sbdrewery printf("done\n"); 547257353Sbdrewery goto cleanup; 548257353Sbdrewery 549257353Sbdreweryerror: 550257353Sbdrewery printf("failed\n"); 551257353Sbdrewery 552257353Sbdrewerycleanup: 553257353Sbdrewery if (pkey) 554257353Sbdrewery EVP_PKEY_free(pkey); 555257353Sbdrewery if (mdctx) 556257353Sbdrewery EVP_MD_CTX_destroy(mdctx); 557257353Sbdrewery ERR_free_strings(); 558257353Sbdrewery 559257353Sbdrewery return (ret); 560257353Sbdrewery} 561257353Sbdrewery 562257353Sbdrewerystatic struct sig_cert * 563257353Sbdreweryparse_cert(int fd) { 564257353Sbdrewery int my_fd; 565257353Sbdrewery struct sig_cert *sc; 566257353Sbdrewery FILE *fp; 567257353Sbdrewery struct sbuf *buf, *sig, *cert; 568257353Sbdrewery char *line; 569257353Sbdrewery size_t linecap; 570257353Sbdrewery ssize_t linelen; 571257353Sbdrewery 572257353Sbdrewery buf = NULL; 573257353Sbdrewery my_fd = -1; 574257353Sbdrewery sc = NULL; 575257353Sbdrewery line = NULL; 576257353Sbdrewery linecap = 0; 577257353Sbdrewery 578257353Sbdrewery if (lseek(fd, 0, 0) == -1) { 579257353Sbdrewery warn("lseek"); 580257353Sbdrewery return (NULL); 581257353Sbdrewery } 582257353Sbdrewery 583257353Sbdrewery /* Duplicate the fd so that fclose(3) does not close it. */ 584257353Sbdrewery if ((my_fd = dup(fd)) == -1) { 585257353Sbdrewery warnx("dup"); 586257353Sbdrewery return (NULL); 587257353Sbdrewery } 588257353Sbdrewery 589257353Sbdrewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 590257353Sbdrewery warn("fdopen"); 591257353Sbdrewery close(my_fd); 592257353Sbdrewery return (NULL); 593257353Sbdrewery } 594257353Sbdrewery 595257353Sbdrewery sig = sbuf_new_auto(); 596257353Sbdrewery cert = sbuf_new_auto(); 597257353Sbdrewery 598257353Sbdrewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 599257353Sbdrewery if (strcmp(line, "SIGNATURE\n") == 0) { 600257353Sbdrewery buf = sig; 601257353Sbdrewery continue; 602257353Sbdrewery } else if (strcmp(line, "CERT\n") == 0) { 603257353Sbdrewery buf = cert; 604257353Sbdrewery continue; 605257353Sbdrewery } else if (strcmp(line, "END\n") == 0) { 606257353Sbdrewery break; 607257353Sbdrewery } 608257353Sbdrewery if (buf != NULL) 609257353Sbdrewery sbuf_bcat(buf, line, linelen); 610257353Sbdrewery } 611257353Sbdrewery 612257353Sbdrewery fclose(fp); 613257353Sbdrewery 614257353Sbdrewery /* Trim out unrelated trailing newline */ 615257353Sbdrewery sbuf_setpos(sig, sbuf_len(sig) - 1); 616257353Sbdrewery 617257353Sbdrewery sbuf_finish(sig); 618257353Sbdrewery sbuf_finish(cert); 619257353Sbdrewery 620257353Sbdrewery sc = calloc(1, sizeof(struct sig_cert)); 621257353Sbdrewery sc->siglen = sbuf_len(sig); 622257353Sbdrewery sc->sig = calloc(1, sc->siglen); 623257353Sbdrewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 624257353Sbdrewery 625257353Sbdrewery sc->certlen = sbuf_len(cert); 626257353Sbdrewery sc->cert = strdup(sbuf_data(cert)); 627257353Sbdrewery 628257353Sbdrewery sbuf_delete(sig); 629257353Sbdrewery sbuf_delete(cert); 630257353Sbdrewery 631257353Sbdrewery return (sc); 632257353Sbdrewery} 633257353Sbdrewery 634257353Sbdrewerystatic bool 635257353Sbdreweryverify_signature(int fd_pkg, int fd_sig) 636257353Sbdrewery{ 637257353Sbdrewery struct fingerprint_list *trusted, *revoked; 638257353Sbdrewery struct fingerprint *fingerprint; 639257353Sbdrewery struct sig_cert *sc; 640257353Sbdrewery bool ret; 641257353Sbdrewery int trusted_count, revoked_count; 642257353Sbdrewery const char *fingerprints; 643257353Sbdrewery char path[MAXPATHLEN]; 644257353Sbdrewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 645257353Sbdrewery 646257353Sbdrewery sc = NULL; 647257353Sbdrewery trusted = revoked = NULL; 648257353Sbdrewery ret = false; 649257353Sbdrewery 650257353Sbdrewery /* Read and parse fingerprints. */ 651257353Sbdrewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 652257353Sbdrewery warnx("No CONFIG_FINGERPRINTS defined"); 653257353Sbdrewery goto cleanup; 654257353Sbdrewery } 655257353Sbdrewery 656257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 657257353Sbdrewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 658257353Sbdrewery warnx("Error loading trusted certificates"); 659257353Sbdrewery goto cleanup; 660257353Sbdrewery } 661257353Sbdrewery 662257353Sbdrewery if (trusted_count == 0 || trusted == NULL) { 663257353Sbdrewery fprintf(stderr, "No trusted certificates found.\n"); 664257353Sbdrewery goto cleanup; 665257353Sbdrewery } 666257353Sbdrewery 667257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 668257353Sbdrewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 669257353Sbdrewery warnx("Error loading revoked certificates"); 670257353Sbdrewery goto cleanup; 671257353Sbdrewery } 672257353Sbdrewery 673257353Sbdrewery /* Read certificate and signature in. */ 674257353Sbdrewery if ((sc = parse_cert(fd_sig)) == NULL) { 675257353Sbdrewery warnx("Error parsing certificate"); 676257353Sbdrewery goto cleanup; 677257353Sbdrewery } 678257353Sbdrewery /* Explicitly mark as non-trusted until proven otherwise. */ 679257353Sbdrewery sc->trusted = false; 680257353Sbdrewery 681257353Sbdrewery /* Parse signature and pubkey out of the certificate */ 682257353Sbdrewery sha256_buf(sc->cert, sc->certlen, hash); 683257353Sbdrewery 684257353Sbdrewery /* Check if this hash is revoked */ 685257353Sbdrewery if (revoked != NULL) { 686257353Sbdrewery STAILQ_FOREACH(fingerprint, revoked, next) { 687257353Sbdrewery if (strcasecmp(fingerprint->hash, hash) == 0) { 688257353Sbdrewery fprintf(stderr, "The package was signed with " 689257353Sbdrewery "revoked certificate %s\n", 690257353Sbdrewery fingerprint->name); 691257353Sbdrewery goto cleanup; 692257353Sbdrewery } 693257353Sbdrewery } 694257353Sbdrewery } 695257353Sbdrewery 696257353Sbdrewery STAILQ_FOREACH(fingerprint, trusted, next) { 697257353Sbdrewery if (strcasecmp(fingerprint->hash, hash) == 0) { 698257353Sbdrewery sc->trusted = true; 699257353Sbdrewery sc->name = strdup(fingerprint->name); 700257353Sbdrewery break; 701257353Sbdrewery } 702257353Sbdrewery } 703257353Sbdrewery 704257353Sbdrewery if (sc->trusted == false) { 705257353Sbdrewery fprintf(stderr, "No trusted fingerprint found matching " 706257353Sbdrewery "package's certificate\n"); 707257353Sbdrewery goto cleanup; 708257353Sbdrewery } 709257353Sbdrewery 710257353Sbdrewery /* Verify the signature. */ 711257353Sbdrewery printf("Verifying signature with trusted certificate %s... ", sc->name); 712257353Sbdrewery if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig, 713257353Sbdrewery sc->siglen) == false) { 714257353Sbdrewery fprintf(stderr, "Signature is not valid\n"); 715257353Sbdrewery goto cleanup; 716257353Sbdrewery } 717257353Sbdrewery 718257353Sbdrewery ret = true; 719257353Sbdrewery 720257353Sbdrewerycleanup: 721257353Sbdrewery if (trusted) 722257353Sbdrewery free_fingerprint_list(trusted); 723257353Sbdrewery if (revoked) 724257353Sbdrewery free_fingerprint_list(revoked); 725257353Sbdrewery if (sc) { 726257353Sbdrewery if (sc->cert) 727257353Sbdrewery free(sc->cert); 728257353Sbdrewery if (sc->sig) 729257353Sbdrewery free(sc->sig); 730257353Sbdrewery if (sc->name) 731257353Sbdrewery free(sc->name); 732257353Sbdrewery free(sc); 733257353Sbdrewery } 734257353Sbdrewery 735257353Sbdrewery return (ret); 736257353Sbdrewery} 737257353Sbdrewery 738257353Sbdrewerystatic int 739257632Sbdrewerybootstrap_pkg(bool force) 740257353Sbdrewery{ 741257353Sbdrewery int fd_pkg, fd_sig; 742257353Sbdrewery int ret; 743257353Sbdrewery char url[MAXPATHLEN]; 744257353Sbdrewery char tmppkg[MAXPATHLEN]; 745257353Sbdrewery char tmpsig[MAXPATHLEN]; 746257353Sbdrewery const char *packagesite; 747257353Sbdrewery const char *signature_type; 748257353Sbdrewery char pkgstatic[MAXPATHLEN]; 749257353Sbdrewery 750257353Sbdrewery fd_sig = -1; 751257353Sbdrewery ret = -1; 752257353Sbdrewery 753257353Sbdrewery if (config_string(PACKAGESITE, &packagesite) != 0) { 754257353Sbdrewery warnx("No PACKAGESITE defined"); 755257353Sbdrewery return (-1); 756257353Sbdrewery } 757257353Sbdrewery 758257353Sbdrewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 759257353Sbdrewery warnx("Error looking up SIGNATURE_TYPE"); 760257353Sbdrewery return (-1); 761257353Sbdrewery } 762257353Sbdrewery 763257353Sbdrewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 764257353Sbdrewery 765257353Sbdrewery /* Support pkg+http:// for PACKAGESITE which is the new format 766257353Sbdrewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 767257353Sbdrewery no A record. */ 768257353Sbdrewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 769257353Sbdrewery strlen(URL_SCHEME_PREFIX)) == 0) 770257353Sbdrewery packagesite += strlen(URL_SCHEME_PREFIX); 771257353Sbdrewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 772257353Sbdrewery 773257353Sbdrewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 774257353Sbdrewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 775257353Sbdrewery 776257353Sbdrewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 777257353Sbdrewery goto fetchfail; 778257353Sbdrewery 779257353Sbdrewery if (signature_type != NULL && 780257353Sbdrewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 781257353Sbdrewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 782257353Sbdrewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 783257353Sbdrewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 784257353Sbdrewery packagesite); 785257353Sbdrewery 786257353Sbdrewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 787257353Sbdrewery fprintf(stderr, "Signature for pkg not available.\n"); 788257353Sbdrewery goto fetchfail; 789257353Sbdrewery } 790257353Sbdrewery 791257353Sbdrewery if (verify_signature(fd_pkg, fd_sig) == false) 792257353Sbdrewery goto cleanup; 793257353Sbdrewery } 794257353Sbdrewery 795257353Sbdrewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 796257632Sbdrewery ret = install_pkg_static(pkgstatic, tmppkg, force); 797234313Sbapt 798234351Sbapt goto cleanup; 799234351Sbapt 800234351Sbaptfetchfail: 801234351Sbapt warnx("Error fetching %s: %s", url, fetchLastErrString); 802257353Sbdrewery fprintf(stderr, "A pre-built version of pkg could not be found for " 803257353Sbdrewery "your system.\n"); 804257353Sbdrewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 805257353Sbdrewery "ports: 'ports-mgmt/pkg'.\n"); 806234351Sbapt 807234313Sbaptcleanup: 808257353Sbdrewery if (fd_sig != -1) { 809257353Sbdrewery close(fd_sig); 810257353Sbdrewery unlink(tmpsig); 811257353Sbdrewery } 812234313Sbapt 813278563Sbapt if (fd_pkg != -1) { 814278563Sbapt close(fd_pkg); 815278563Sbapt unlink(tmppkg); 816278563Sbapt } 817278563Sbapt 818234351Sbapt return (ret); 819234313Sbapt} 820234313Sbapt 821238461Skanstatic const char confirmation_message[] = 822238461Skan"The package management tool is not yet installed on your system.\n" 823238461Skan"Do you want to fetch and install it now? [y/N]: "; 824238461Skan 825238461Skanstatic int 826238461Skanpkg_query_yes_no(void) 827238461Skan{ 828238461Skan int ret, c; 829238461Skan 830238461Skan c = getchar(); 831238461Skan 832238461Skan if (c == 'y' || c == 'Y') 833238461Skan ret = 1; 834238461Skan else 835238461Skan ret = 0; 836238461Skan 837238461Skan while (c != '\n' && c != EOF) 838238461Skan c = getchar(); 839238461Skan 840238461Skan return (ret); 841238461Skan} 842238461Skan 843257353Sbdrewerystatic int 844257632Sbdrewerybootstrap_pkg_local(const char *pkgpath, bool force) 845257353Sbdrewery{ 846257353Sbdrewery char path[MAXPATHLEN]; 847257353Sbdrewery char pkgstatic[MAXPATHLEN]; 848257353Sbdrewery const char *signature_type; 849257353Sbdrewery int fd_pkg, fd_sig, ret; 850257353Sbdrewery 851257353Sbdrewery fd_sig = -1; 852257353Sbdrewery ret = -1; 853257353Sbdrewery 854257353Sbdrewery fd_pkg = open(pkgpath, O_RDONLY); 855257353Sbdrewery if (fd_pkg == -1) 856257353Sbdrewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 857257353Sbdrewery 858257353Sbdrewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 859257353Sbdrewery warnx("Error looking up SIGNATURE_TYPE"); 860278563Sbapt goto cleanup; 861257353Sbdrewery } 862257353Sbdrewery if (signature_type != NULL && 863257353Sbdrewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 864257353Sbdrewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 865257353Sbdrewery 866257353Sbdrewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 867257353Sbdrewery fprintf(stderr, "Signature for pkg not available.\n"); 868257353Sbdrewery goto cleanup; 869257353Sbdrewery } 870257353Sbdrewery 871257353Sbdrewery if (verify_signature(fd_pkg, fd_sig) == false) 872257353Sbdrewery goto cleanup; 873257353Sbdrewery } 874257353Sbdrewery 875257353Sbdrewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 876257632Sbdrewery ret = install_pkg_static(pkgstatic, pkgpath, force); 877257353Sbdrewery 878257353Sbdrewerycleanup: 879257353Sbdrewery close(fd_pkg); 880257353Sbdrewery if (fd_sig != -1) 881257353Sbdrewery close(fd_sig); 882257353Sbdrewery 883257353Sbdrewery return (ret); 884257353Sbdrewery} 885257353Sbdrewery 886234313Sbaptint 887234322Sbaptmain(__unused int argc, char *argv[]) 888234313Sbapt{ 889234313Sbapt char pkgpath[MAXPATHLEN]; 890257632Sbdrewery const char *pkgarg; 891257632Sbdrewery bool bootstrap_only, force, yes; 892234313Sbapt 893257632Sbdrewery bootstrap_only = false; 894257632Sbdrewery force = false; 895257632Sbdrewery pkgarg = NULL; 896257632Sbdrewery yes = false; 897257632Sbdrewery 898234313Sbapt snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 899234322Sbapt getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 900234313Sbapt 901257632Sbdrewery if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 902257632Sbdrewery bootstrap_only = true; 903257632Sbdrewery if (argc == 3 && strcmp(argv[2], "-f") == 0) 904257632Sbdrewery force = true; 905257632Sbdrewery } 906257632Sbdrewery 907257632Sbdrewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 908244553Smatthew /* 909244594Smatthew * To allow 'pkg -N' to be used as a reliable test for whether 910244553Smatthew * a system is configured to use pkg, don't bootstrap pkg 911244553Smatthew * when that argument is given as argv[1]. 912244553Smatthew */ 913244639Smatthew if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 914244639Smatthew errx(EXIT_FAILURE, "pkg is not installed"); 915244553Smatthew 916257353Sbdrewery config_init(); 917257353Sbdrewery 918257632Sbdrewery if (argc > 1 && strcmp(argv[1], "add") == 0) { 919257632Sbdrewery if (argc > 2 && strcmp(argv[2], "-f") == 0) { 920257632Sbdrewery force = true; 921257632Sbdrewery pkgarg = argv[3]; 922257632Sbdrewery } else 923257632Sbdrewery pkgarg = argv[2]; 924257632Sbdrewery if (pkgarg == NULL) { 925257632Sbdrewery fprintf(stderr, "Path to pkg.txz required\n"); 926257309Sbapt exit(EXIT_FAILURE); 927257632Sbdrewery } 928257632Sbdrewery if (access(pkgarg, R_OK) == -1) { 929257632Sbdrewery fprintf(stderr, "No such file: %s\n", pkgarg); 930257632Sbdrewery exit(EXIT_FAILURE); 931257632Sbdrewery } 932257632Sbdrewery if (bootstrap_pkg_local(pkgarg, force) != 0) 933257632Sbdrewery exit(EXIT_FAILURE); 934257309Sbapt exit(EXIT_SUCCESS); 935257309Sbapt } 936238461Skan /* 937238461Skan * Do not ask for confirmation if either of stdin or stdout is 938238461Skan * not tty. Check the environment to see if user has answer 939238461Skan * tucked in there already. 940238461Skan */ 941247841Sbapt config_bool(ASSUME_ALWAYS_YES, &yes); 942247841Sbapt if (!yes) { 943238461Skan printf("%s", confirmation_message); 944239664Sbapt if (!isatty(fileno(stdin))) 945238461Skan exit(EXIT_FAILURE); 946239664Sbapt 947239664Sbapt if (pkg_query_yes_no() == 0) 948239663Sbapt exit(EXIT_FAILURE); 949238461Skan } 950257632Sbdrewery if (bootstrap_pkg(force) != 0) 951234351Sbapt exit(EXIT_FAILURE); 952247841Sbapt config_finish(); 953257571Sbdrewery 954257632Sbdrewery if (bootstrap_only) 955257571Sbdrewery exit(EXIT_SUCCESS); 956257632Sbdrewery } else if (bootstrap_only) { 957257632Sbdrewery printf("pkg already bootstrapped at %s\n", pkgpath); 958257632Sbdrewery exit(EXIT_SUCCESS); 959238461Skan } 960234313Sbapt 961234313Sbapt execv(pkgpath, argv); 962234313Sbapt 963234351Sbapt /* NOT REACHED */ 964234322Sbapt return (EXIT_FAILURE); 965234313Sbapt} 966