pkg.c revision 263020
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 263020 2014-03-11 13:16:03Z 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 129234313Sbapt warnx("fail to extract pkg-static"); 130234313Sbapt 131234313Sbaptcleanup: 132247060Sbapt archive_read_free(a); 133234322Sbapt return (ret); 134234313Sbapt 135234313Sbapt} 136234313Sbapt 137234313Sbaptstatic int 138257632Sbdreweryinstall_pkg_static(const char *path, const char *pkgpath, bool force) 139234313Sbapt{ 140234313Sbapt int pstat; 141234313Sbapt pid_t pid; 142234313Sbapt 143234313Sbapt switch ((pid = fork())) { 144234351Sbapt case -1: 145234351Sbapt return (-1); 146234351Sbapt case 0: 147257632Sbdrewery if (force) 148257632Sbdrewery execl(path, "pkg-static", "add", "-f", pkgpath, 149257632Sbdrewery (char *)NULL); 150257632Sbdrewery else 151257632Sbdrewery execl(path, "pkg-static", "add", pkgpath, 152257632Sbdrewery (char *)NULL); 153234351Sbapt _exit(1); 154234351Sbapt default: 155234351Sbapt break; 156234313Sbapt } 157234313Sbapt 158234351Sbapt while (waitpid(pid, &pstat, 0) == -1) 159234313Sbapt if (errno != EINTR) 160234313Sbapt return (-1); 161234313Sbapt 162234351Sbapt if (WEXITSTATUS(pstat)) 163234351Sbapt return (WEXITSTATUS(pstat)); 164234351Sbapt else if (WIFSIGNALED(pstat)) 165234351Sbapt return (128 & (WTERMSIG(pstat))); 166234351Sbapt return (pstat); 167234313Sbapt} 168234313Sbapt 169234313Sbaptstatic int 170257353Sbdreweryfetch_to_fd(const char *url, char *path) 171234313Sbapt{ 172243883Sbapt struct url *u; 173257353Sbdrewery struct dns_srvinfo *mirrors, *current; 174257353Sbdrewery struct url_stat st; 175234313Sbapt FILE *remote; 176243883Sbapt /* To store _https._tcp. + hostname + \0 */ 177257353Sbdrewery int fd; 178257353Sbdrewery int retry, max_retry; 179257353Sbdrewery off_t done, r; 180257353Sbdrewery time_t now, last; 181257353Sbdrewery char buf[10240]; 182243883Sbapt char zone[MAXHOSTNAMELEN + 13]; 183257353Sbdrewery static const char *mirror_type = NULL; 184234313Sbapt 185234313Sbapt done = 0; 186234351Sbapt last = 0; 187243883Sbapt max_retry = 3; 188257353Sbdrewery current = mirrors = NULL; 189234313Sbapt remote = NULL; 190234313Sbapt 191257353Sbdrewery if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 192257353Sbdrewery != 0) { 193247841Sbapt warnx("No MIRROR_TYPE defined"); 194247841Sbapt return (-1); 195247841Sbapt } 196257328Sbdrewery 197257353Sbdrewery if ((fd = mkstemp(path)) == -1) { 198234313Sbapt warn("mkstemp()"); 199234322Sbapt return (-1); 200234313Sbapt } 201234313Sbapt 202243883Sbapt retry = max_retry; 203234313Sbapt 204243883Sbapt u = fetchParseURL(url); 205243883Sbapt while (remote == NULL) { 206243883Sbapt if (retry == max_retry) { 207247841Sbapt if (strcmp(u->scheme, "file") != 0 && 208247841Sbapt strcasecmp(mirror_type, "srv") == 0) { 209243883Sbapt snprintf(zone, sizeof(zone), 210243883Sbapt "_%s._tcp.%s", u->scheme, u->host); 211243883Sbapt mirrors = dns_getsrvinfo(zone); 212243883Sbapt current = mirrors; 213243883Sbapt } 214243883Sbapt } 215243883Sbapt 216257309Sbapt if (mirrors != NULL) { 217243883Sbapt strlcpy(u->host, current->host, sizeof(u->host)); 218257309Sbapt u->port = current->port; 219257309Sbapt } 220243883Sbapt 221243883Sbapt remote = fetchXGet(u, &st, ""); 222243883Sbapt if (remote == NULL) { 223243883Sbapt --retry; 224243883Sbapt if (retry <= 0) 225243883Sbapt goto fetchfail; 226243883Sbapt if (mirrors == NULL) { 227243883Sbapt sleep(1); 228243883Sbapt } else { 229243883Sbapt current = current->next; 230243883Sbapt if (current == NULL) 231243883Sbapt current = mirrors; 232243883Sbapt } 233243883Sbapt } 234243883Sbapt } 235243883Sbapt 236234351Sbapt if (remote == NULL) 237234351Sbapt goto fetchfail; 238234351Sbapt 239234313Sbapt while (done < st.size) { 240234313Sbapt if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) 241234313Sbapt break; 242234313Sbapt 243234313Sbapt if (write(fd, buf, r) != r) { 244234313Sbapt warn("write()"); 245257353Sbdrewery goto fetchfail; 246234313Sbapt } 247234313Sbapt 248234313Sbapt done += r; 249234313Sbapt now = time(NULL); 250234351Sbapt if (now > last || done == st.size) 251234313Sbapt last = now; 252234313Sbapt } 253234313Sbapt 254234351Sbapt if (ferror(remote)) 255234351Sbapt goto fetchfail; 256234313Sbapt 257257353Sbdrewery goto cleanup; 258257353Sbdrewery 259257353Sbdreweryfetchfail: 260257353Sbdrewery if (fd != -1) { 261257353Sbdrewery close(fd); 262257353Sbdrewery fd = -1; 263257353Sbdrewery unlink(path); 264257353Sbdrewery } 265257353Sbdrewery 266257353Sbdrewerycleanup: 267257353Sbdrewery if (remote != NULL) 268257353Sbdrewery fclose(remote); 269257353Sbdrewery 270257353Sbdrewery return fd; 271257353Sbdrewery} 272257353Sbdrewery 273257353Sbdrewerystatic struct fingerprint * 274263020Sbaptparse_fingerprint(ucl_object_t *obj) 275257353Sbdrewery{ 276263020Sbapt ucl_object_t *cur; 277263020Sbapt ucl_object_iter_t it = NULL; 278263020Sbapt const char *function, *fp, *key; 279257353Sbdrewery struct fingerprint *f; 280257353Sbdrewery hash_t fct = HASH_UNKNOWN; 281257353Sbdrewery 282257353Sbdrewery function = fp = NULL; 283257353Sbdrewery 284263020Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 285263020Sbapt key = ucl_object_key(cur); 286263020Sbapt if (cur->type != UCL_STRING) 287257353Sbdrewery continue; 288263020Sbapt if (strcasecmp(key, "function") == 0) { 289263020Sbapt function = ucl_object_tostring(cur); 290263020Sbapt continue; 291257353Sbdrewery } 292263020Sbapt if (strcasecmp(key, "fingerprint") == 0) { 293263020Sbapt fp = ucl_object_tostring(cur); 294257353Sbdrewery continue; 295257353Sbdrewery } 296257353Sbdrewery } 297257353Sbdrewery 298257353Sbdrewery if (fp == NULL || function == NULL) 299257353Sbdrewery return (NULL); 300257353Sbdrewery 301257353Sbdrewery if (strcasecmp(function, "sha256") == 0) 302257353Sbdrewery fct = HASH_SHA256; 303257353Sbdrewery 304257353Sbdrewery if (fct == HASH_UNKNOWN) { 305263020Sbapt warnx("Unsupported hashing function: %s", function); 306257353Sbdrewery return (NULL); 307257353Sbdrewery } 308257353Sbdrewery 309257353Sbdrewery f = calloc(1, sizeof(struct fingerprint)); 310257353Sbdrewery f->type = fct; 311257353Sbdrewery strlcpy(f->hash, fp, sizeof(f->hash)); 312257353Sbdrewery 313257353Sbdrewery return (f); 314257353Sbdrewery} 315257353Sbdrewery 316257353Sbdrewerystatic void 317257353Sbdreweryfree_fingerprint_list(struct fingerprint_list* list) 318257353Sbdrewery{ 319258126Sglebius struct fingerprint *fingerprint, *tmp; 320257353Sbdrewery 321258126Sglebius STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 322257353Sbdrewery if (fingerprint->name) 323257353Sbdrewery free(fingerprint->name); 324257353Sbdrewery free(fingerprint); 325257353Sbdrewery } 326257353Sbdrewery free(list); 327257353Sbdrewery} 328257353Sbdrewery 329257353Sbdrewerystatic struct fingerprint * 330257353Sbdreweryload_fingerprint(const char *dir, const char *filename) 331257353Sbdrewery{ 332263020Sbapt ucl_object_t *obj = NULL; 333263020Sbapt struct ucl_parser *p = NULL; 334257353Sbdrewery struct fingerprint *f; 335257353Sbdrewery char path[MAXPATHLEN]; 336257353Sbdrewery 337257353Sbdrewery f = NULL; 338257353Sbdrewery 339257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 340257353Sbdrewery 341263020Sbapt p = ucl_parser_new(0); 342263020Sbapt if (!ucl_parser_add_file(p, path)) { 343263020Sbapt warnx("%s: %s", path, ucl_parser_get_error(p)); 344263020Sbapt ucl_parser_free(p); 345257353Sbdrewery return (NULL); 346263020Sbapt } 347257353Sbdrewery 348263020Sbapt obj = ucl_parser_get_object(p); 349257353Sbdrewery 350263020Sbapt if (obj->type == UCL_OBJECT) 351263020Sbapt f = parse_fingerprint(obj); 352257353Sbdrewery 353263020Sbapt if (f != NULL) 354263020Sbapt f->name = strdup(filename); 355257353Sbdrewery 356263020Sbapt ucl_object_free(obj); 357263020Sbapt ucl_parser_free(p); 358257353Sbdrewery 359257353Sbdrewery return (f); 360257353Sbdrewery} 361257353Sbdrewery 362257353Sbdrewerystatic struct fingerprint_list * 363257353Sbdreweryload_fingerprints(const char *path, int *count) 364257353Sbdrewery{ 365257353Sbdrewery DIR *d; 366257353Sbdrewery struct dirent *ent; 367257353Sbdrewery struct fingerprint *finger; 368257353Sbdrewery struct fingerprint_list *fingerprints; 369257353Sbdrewery 370257353Sbdrewery *count = 0; 371257353Sbdrewery 372257353Sbdrewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 373257353Sbdrewery if (fingerprints == NULL) 374257353Sbdrewery return (NULL); 375257353Sbdrewery STAILQ_INIT(fingerprints); 376257353Sbdrewery 377257353Sbdrewery if ((d = opendir(path)) == NULL) 378257353Sbdrewery return (NULL); 379257353Sbdrewery 380257353Sbdrewery while ((ent = readdir(d))) { 381257353Sbdrewery if (strcmp(ent->d_name, ".") == 0 || 382257353Sbdrewery strcmp(ent->d_name, "..") == 0) 383257353Sbdrewery continue; 384257353Sbdrewery finger = load_fingerprint(path, ent->d_name); 385257353Sbdrewery if (finger != NULL) { 386257353Sbdrewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 387257353Sbdrewery ++(*count); 388257353Sbdrewery } 389257353Sbdrewery } 390257353Sbdrewery 391257353Sbdrewery closedir(d); 392257353Sbdrewery 393257353Sbdrewery return (fingerprints); 394257353Sbdrewery} 395257353Sbdrewery 396257353Sbdrewerystatic void 397257353Sbdrewerysha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 398257353Sbdrewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 399257353Sbdrewery{ 400257353Sbdrewery int i; 401257353Sbdrewery 402257353Sbdrewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 403257353Sbdrewery sprintf(out + (i * 2), "%02x", hash[i]); 404257353Sbdrewery 405257353Sbdrewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 406257353Sbdrewery} 407257353Sbdrewery 408257353Sbdrewerystatic void 409257353Sbdrewerysha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 410257353Sbdrewery{ 411257353Sbdrewery unsigned char hash[SHA256_DIGEST_LENGTH]; 412257353Sbdrewery SHA256_CTX sha256; 413257353Sbdrewery 414257353Sbdrewery out[0] = '\0'; 415257353Sbdrewery 416257353Sbdrewery SHA256_Init(&sha256); 417257353Sbdrewery SHA256_Update(&sha256, buf, len); 418257353Sbdrewery SHA256_Final(hash, &sha256); 419257353Sbdrewery sha256_hash(hash, out); 420257353Sbdrewery} 421257353Sbdrewery 422257353Sbdrewerystatic int 423257353Sbdrewerysha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 424257353Sbdrewery{ 425257353Sbdrewery int my_fd; 426257353Sbdrewery FILE *fp; 427257353Sbdrewery char buffer[BUFSIZ]; 428257353Sbdrewery unsigned char hash[SHA256_DIGEST_LENGTH]; 429257353Sbdrewery size_t r; 430257353Sbdrewery int ret; 431257353Sbdrewery SHA256_CTX sha256; 432257353Sbdrewery 433257353Sbdrewery my_fd = -1; 434257353Sbdrewery fp = NULL; 435257353Sbdrewery r = 0; 436257353Sbdrewery ret = 1; 437257353Sbdrewery 438257353Sbdrewery out[0] = '\0'; 439257353Sbdrewery 440257353Sbdrewery /* Duplicate the fd so that fclose(3) does not close it. */ 441257353Sbdrewery if ((my_fd = dup(fd)) == -1) { 442257353Sbdrewery warnx("dup"); 443257353Sbdrewery goto cleanup; 444257353Sbdrewery } 445257353Sbdrewery 446257353Sbdrewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 447257353Sbdrewery warnx("fdopen"); 448257353Sbdrewery goto cleanup; 449257353Sbdrewery } 450257353Sbdrewery 451257353Sbdrewery SHA256_Init(&sha256); 452257353Sbdrewery 453257353Sbdrewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 454257353Sbdrewery SHA256_Update(&sha256, buffer, r); 455257353Sbdrewery 456257353Sbdrewery if (ferror(fp) != 0) { 457257353Sbdrewery warnx("fread"); 458257353Sbdrewery goto cleanup; 459257353Sbdrewery } 460257353Sbdrewery 461257353Sbdrewery SHA256_Final(hash, &sha256); 462257353Sbdrewery sha256_hash(hash, out); 463257353Sbdrewery ret = 0; 464257353Sbdrewery 465257353Sbdrewerycleanup: 466257353Sbdrewery if (fp != NULL) 467257353Sbdrewery fclose(fp); 468257353Sbdrewery else if (my_fd != -1) 469257353Sbdrewery close(my_fd); 470257353Sbdrewery (void)lseek(fd, 0, SEEK_SET); 471257353Sbdrewery 472257353Sbdrewery return (ret); 473257353Sbdrewery} 474257353Sbdrewery 475257353Sbdrewerystatic EVP_PKEY * 476257353Sbdreweryload_public_key_buf(const unsigned char *cert, int certlen) 477257353Sbdrewery{ 478257353Sbdrewery EVP_PKEY *pkey; 479257353Sbdrewery BIO *bp; 480257353Sbdrewery char errbuf[1024]; 481257353Sbdrewery 482257353Sbdrewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 483257353Sbdrewery 484257353Sbdrewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 485257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 486257353Sbdrewery 487257353Sbdrewery BIO_free(bp); 488257353Sbdrewery 489257353Sbdrewery return (pkey); 490257353Sbdrewery} 491257353Sbdrewery 492257353Sbdrewerystatic bool 493257353Sbdreweryrsa_verify_cert(int fd, const unsigned char *key, int keylen, 494257353Sbdrewery unsigned char *sig, int siglen) 495257353Sbdrewery{ 496257353Sbdrewery EVP_MD_CTX *mdctx; 497257353Sbdrewery EVP_PKEY *pkey; 498257353Sbdrewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 499257353Sbdrewery char errbuf[1024]; 500257353Sbdrewery bool ret; 501257353Sbdrewery 502257353Sbdrewery pkey = NULL; 503257353Sbdrewery mdctx = NULL; 504257353Sbdrewery ret = false; 505257353Sbdrewery 506257353Sbdrewery /* Compute SHA256 of the package. */ 507257353Sbdrewery if (lseek(fd, 0, 0) == -1) { 508257353Sbdrewery warn("lseek"); 509257353Sbdrewery goto cleanup; 510257353Sbdrewery } 511257353Sbdrewery if ((sha256_fd(fd, sha256)) == -1) { 512257353Sbdrewery warnx("Error creating SHA256 hash for package"); 513257353Sbdrewery goto cleanup; 514257353Sbdrewery } 515257353Sbdrewery 516257353Sbdrewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 517257353Sbdrewery warnx("Error reading public key"); 518257353Sbdrewery goto cleanup; 519257353Sbdrewery } 520257353Sbdrewery 521257353Sbdrewery /* Verify signature of the SHA256(pkg) is valid. */ 522257353Sbdrewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 523257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 524257353Sbdrewery goto error; 525257353Sbdrewery } 526257353Sbdrewery 527257353Sbdrewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 528257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 529257353Sbdrewery goto error; 530257353Sbdrewery } 531257353Sbdrewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 532257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 533257353Sbdrewery goto error; 534257353Sbdrewery } 535257353Sbdrewery 536257353Sbdrewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 537257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 538257353Sbdrewery goto error; 539257353Sbdrewery } 540257353Sbdrewery 541257353Sbdrewery ret = true; 542257353Sbdrewery printf("done\n"); 543257353Sbdrewery goto cleanup; 544257353Sbdrewery 545257353Sbdreweryerror: 546257353Sbdrewery printf("failed\n"); 547257353Sbdrewery 548257353Sbdrewerycleanup: 549257353Sbdrewery if (pkey) 550257353Sbdrewery EVP_PKEY_free(pkey); 551257353Sbdrewery if (mdctx) 552257353Sbdrewery EVP_MD_CTX_destroy(mdctx); 553257353Sbdrewery ERR_free_strings(); 554257353Sbdrewery 555257353Sbdrewery return (ret); 556257353Sbdrewery} 557257353Sbdrewery 558257353Sbdrewerystatic struct sig_cert * 559257353Sbdreweryparse_cert(int fd) { 560257353Sbdrewery int my_fd; 561257353Sbdrewery struct sig_cert *sc; 562257353Sbdrewery FILE *fp; 563257353Sbdrewery struct sbuf *buf, *sig, *cert; 564257353Sbdrewery char *line; 565257353Sbdrewery size_t linecap; 566257353Sbdrewery ssize_t linelen; 567257353Sbdrewery 568257353Sbdrewery buf = NULL; 569257353Sbdrewery my_fd = -1; 570257353Sbdrewery sc = NULL; 571257353Sbdrewery line = NULL; 572257353Sbdrewery linecap = 0; 573257353Sbdrewery 574257353Sbdrewery if (lseek(fd, 0, 0) == -1) { 575257353Sbdrewery warn("lseek"); 576257353Sbdrewery return (NULL); 577257353Sbdrewery } 578257353Sbdrewery 579257353Sbdrewery /* Duplicate the fd so that fclose(3) does not close it. */ 580257353Sbdrewery if ((my_fd = dup(fd)) == -1) { 581257353Sbdrewery warnx("dup"); 582257353Sbdrewery return (NULL); 583257353Sbdrewery } 584257353Sbdrewery 585257353Sbdrewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 586257353Sbdrewery warn("fdopen"); 587257353Sbdrewery close(my_fd); 588257353Sbdrewery return (NULL); 589257353Sbdrewery } 590257353Sbdrewery 591257353Sbdrewery sig = sbuf_new_auto(); 592257353Sbdrewery cert = sbuf_new_auto(); 593257353Sbdrewery 594257353Sbdrewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 595257353Sbdrewery if (strcmp(line, "SIGNATURE\n") == 0) { 596257353Sbdrewery buf = sig; 597257353Sbdrewery continue; 598257353Sbdrewery } else if (strcmp(line, "CERT\n") == 0) { 599257353Sbdrewery buf = cert; 600257353Sbdrewery continue; 601257353Sbdrewery } else if (strcmp(line, "END\n") == 0) { 602257353Sbdrewery break; 603257353Sbdrewery } 604257353Sbdrewery if (buf != NULL) 605257353Sbdrewery sbuf_bcat(buf, line, linelen); 606257353Sbdrewery } 607257353Sbdrewery 608257353Sbdrewery fclose(fp); 609257353Sbdrewery 610257353Sbdrewery /* Trim out unrelated trailing newline */ 611257353Sbdrewery sbuf_setpos(sig, sbuf_len(sig) - 1); 612257353Sbdrewery 613257353Sbdrewery sbuf_finish(sig); 614257353Sbdrewery sbuf_finish(cert); 615257353Sbdrewery 616257353Sbdrewery sc = calloc(1, sizeof(struct sig_cert)); 617257353Sbdrewery sc->siglen = sbuf_len(sig); 618257353Sbdrewery sc->sig = calloc(1, sc->siglen); 619257353Sbdrewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 620257353Sbdrewery 621257353Sbdrewery sc->certlen = sbuf_len(cert); 622257353Sbdrewery sc->cert = strdup(sbuf_data(cert)); 623257353Sbdrewery 624257353Sbdrewery sbuf_delete(sig); 625257353Sbdrewery sbuf_delete(cert); 626257353Sbdrewery 627257353Sbdrewery return (sc); 628257353Sbdrewery} 629257353Sbdrewery 630257353Sbdrewerystatic bool 631257353Sbdreweryverify_signature(int fd_pkg, int fd_sig) 632257353Sbdrewery{ 633257353Sbdrewery struct fingerprint_list *trusted, *revoked; 634257353Sbdrewery struct fingerprint *fingerprint; 635257353Sbdrewery struct sig_cert *sc; 636257353Sbdrewery bool ret; 637257353Sbdrewery int trusted_count, revoked_count; 638257353Sbdrewery const char *fingerprints; 639257353Sbdrewery char path[MAXPATHLEN]; 640257353Sbdrewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 641257353Sbdrewery 642257353Sbdrewery sc = NULL; 643257353Sbdrewery trusted = revoked = NULL; 644257353Sbdrewery ret = false; 645257353Sbdrewery 646257353Sbdrewery /* Read and parse fingerprints. */ 647257353Sbdrewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 648257353Sbdrewery warnx("No CONFIG_FINGERPRINTS defined"); 649257353Sbdrewery goto cleanup; 650257353Sbdrewery } 651257353Sbdrewery 652257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 653257353Sbdrewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 654257353Sbdrewery warnx("Error loading trusted certificates"); 655257353Sbdrewery goto cleanup; 656257353Sbdrewery } 657257353Sbdrewery 658257353Sbdrewery if (trusted_count == 0 || trusted == NULL) { 659257353Sbdrewery fprintf(stderr, "No trusted certificates found.\n"); 660257353Sbdrewery goto cleanup; 661257353Sbdrewery } 662257353Sbdrewery 663257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 664257353Sbdrewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 665257353Sbdrewery warnx("Error loading revoked certificates"); 666257353Sbdrewery goto cleanup; 667257353Sbdrewery } 668257353Sbdrewery 669257353Sbdrewery /* Read certificate and signature in. */ 670257353Sbdrewery if ((sc = parse_cert(fd_sig)) == NULL) { 671257353Sbdrewery warnx("Error parsing certificate"); 672257353Sbdrewery goto cleanup; 673257353Sbdrewery } 674257353Sbdrewery /* Explicitly mark as non-trusted until proven otherwise. */ 675257353Sbdrewery sc->trusted = false; 676257353Sbdrewery 677257353Sbdrewery /* Parse signature and pubkey out of the certificate */ 678257353Sbdrewery sha256_buf(sc->cert, sc->certlen, hash); 679257353Sbdrewery 680257353Sbdrewery /* Check if this hash is revoked */ 681257353Sbdrewery if (revoked != NULL) { 682257353Sbdrewery STAILQ_FOREACH(fingerprint, revoked, next) { 683257353Sbdrewery if (strcasecmp(fingerprint->hash, hash) == 0) { 684257353Sbdrewery fprintf(stderr, "The package was signed with " 685257353Sbdrewery "revoked certificate %s\n", 686257353Sbdrewery fingerprint->name); 687257353Sbdrewery goto cleanup; 688257353Sbdrewery } 689257353Sbdrewery } 690257353Sbdrewery } 691257353Sbdrewery 692257353Sbdrewery STAILQ_FOREACH(fingerprint, trusted, next) { 693257353Sbdrewery if (strcasecmp(fingerprint->hash, hash) == 0) { 694257353Sbdrewery sc->trusted = true; 695257353Sbdrewery sc->name = strdup(fingerprint->name); 696257353Sbdrewery break; 697257353Sbdrewery } 698257353Sbdrewery } 699257353Sbdrewery 700257353Sbdrewery if (sc->trusted == false) { 701257353Sbdrewery fprintf(stderr, "No trusted fingerprint found matching " 702257353Sbdrewery "package's certificate\n"); 703257353Sbdrewery goto cleanup; 704257353Sbdrewery } 705257353Sbdrewery 706257353Sbdrewery /* Verify the signature. */ 707257353Sbdrewery printf("Verifying signature with trusted certificate %s... ", sc->name); 708257353Sbdrewery if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig, 709257353Sbdrewery sc->siglen) == false) { 710257353Sbdrewery fprintf(stderr, "Signature is not valid\n"); 711257353Sbdrewery goto cleanup; 712257353Sbdrewery } 713257353Sbdrewery 714257353Sbdrewery ret = true; 715257353Sbdrewery 716257353Sbdrewerycleanup: 717257353Sbdrewery if (trusted) 718257353Sbdrewery free_fingerprint_list(trusted); 719257353Sbdrewery if (revoked) 720257353Sbdrewery free_fingerprint_list(revoked); 721257353Sbdrewery if (sc) { 722257353Sbdrewery if (sc->cert) 723257353Sbdrewery free(sc->cert); 724257353Sbdrewery if (sc->sig) 725257353Sbdrewery free(sc->sig); 726257353Sbdrewery if (sc->name) 727257353Sbdrewery free(sc->name); 728257353Sbdrewery free(sc); 729257353Sbdrewery } 730257353Sbdrewery 731257353Sbdrewery return (ret); 732257353Sbdrewery} 733257353Sbdrewery 734257353Sbdrewerystatic int 735257632Sbdrewerybootstrap_pkg(bool force) 736257353Sbdrewery{ 737257353Sbdrewery int fd_pkg, fd_sig; 738257353Sbdrewery int ret; 739257353Sbdrewery char url[MAXPATHLEN]; 740257353Sbdrewery char tmppkg[MAXPATHLEN]; 741257353Sbdrewery char tmpsig[MAXPATHLEN]; 742257353Sbdrewery const char *packagesite; 743257353Sbdrewery const char *signature_type; 744257353Sbdrewery char pkgstatic[MAXPATHLEN]; 745257353Sbdrewery 746257353Sbdrewery fd_sig = -1; 747257353Sbdrewery ret = -1; 748257353Sbdrewery 749257353Sbdrewery if (config_string(PACKAGESITE, &packagesite) != 0) { 750257353Sbdrewery warnx("No PACKAGESITE defined"); 751257353Sbdrewery return (-1); 752257353Sbdrewery } 753257353Sbdrewery 754257353Sbdrewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 755257353Sbdrewery warnx("Error looking up SIGNATURE_TYPE"); 756257353Sbdrewery return (-1); 757257353Sbdrewery } 758257353Sbdrewery 759257353Sbdrewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 760257353Sbdrewery 761257353Sbdrewery /* Support pkg+http:// for PACKAGESITE which is the new format 762257353Sbdrewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 763257353Sbdrewery no A record. */ 764257353Sbdrewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 765257353Sbdrewery strlen(URL_SCHEME_PREFIX)) == 0) 766257353Sbdrewery packagesite += strlen(URL_SCHEME_PREFIX); 767257353Sbdrewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 768257353Sbdrewery 769257353Sbdrewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 770257353Sbdrewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 771257353Sbdrewery 772257353Sbdrewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 773257353Sbdrewery goto fetchfail; 774257353Sbdrewery 775257353Sbdrewery if (signature_type != NULL && 776257353Sbdrewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 777257353Sbdrewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 778257353Sbdrewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 779257353Sbdrewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 780257353Sbdrewery packagesite); 781257353Sbdrewery 782257353Sbdrewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 783257353Sbdrewery fprintf(stderr, "Signature for pkg not available.\n"); 784257353Sbdrewery goto fetchfail; 785257353Sbdrewery } 786257353Sbdrewery 787257353Sbdrewery if (verify_signature(fd_pkg, fd_sig) == false) 788257353Sbdrewery goto cleanup; 789257353Sbdrewery } 790257353Sbdrewery 791257353Sbdrewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 792257632Sbdrewery ret = install_pkg_static(pkgstatic, tmppkg, force); 793234313Sbapt 794234351Sbapt goto cleanup; 795234351Sbapt 796234351Sbaptfetchfail: 797234351Sbapt warnx("Error fetching %s: %s", url, fetchLastErrString); 798257353Sbdrewery fprintf(stderr, "A pre-built version of pkg could not be found for " 799257353Sbdrewery "your system.\n"); 800257353Sbdrewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 801257353Sbdrewery "ports: 'ports-mgmt/pkg'.\n"); 802234351Sbapt 803234313Sbaptcleanup: 804257353Sbdrewery if (fd_sig != -1) { 805257353Sbdrewery close(fd_sig); 806257353Sbdrewery unlink(tmpsig); 807257353Sbdrewery } 808257353Sbdrewery close(fd_pkg); 809234313Sbapt unlink(tmppkg); 810234313Sbapt 811234351Sbapt return (ret); 812234313Sbapt} 813234313Sbapt 814238461Skanstatic const char confirmation_message[] = 815238461Skan"The package management tool is not yet installed on your system.\n" 816238461Skan"Do you want to fetch and install it now? [y/N]: "; 817238461Skan 818238461Skanstatic int 819238461Skanpkg_query_yes_no(void) 820238461Skan{ 821238461Skan int ret, c; 822238461Skan 823238461Skan c = getchar(); 824238461Skan 825238461Skan if (c == 'y' || c == 'Y') 826238461Skan ret = 1; 827238461Skan else 828238461Skan ret = 0; 829238461Skan 830238461Skan while (c != '\n' && c != EOF) 831238461Skan c = getchar(); 832238461Skan 833238461Skan return (ret); 834238461Skan} 835238461Skan 836257353Sbdrewerystatic int 837257632Sbdrewerybootstrap_pkg_local(const char *pkgpath, bool force) 838257353Sbdrewery{ 839257353Sbdrewery char path[MAXPATHLEN]; 840257353Sbdrewery char pkgstatic[MAXPATHLEN]; 841257353Sbdrewery const char *signature_type; 842257353Sbdrewery int fd_pkg, fd_sig, ret; 843257353Sbdrewery 844257353Sbdrewery fd_sig = -1; 845257353Sbdrewery ret = -1; 846257353Sbdrewery 847257353Sbdrewery fd_pkg = open(pkgpath, O_RDONLY); 848257353Sbdrewery if (fd_pkg == -1) 849257353Sbdrewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 850257353Sbdrewery 851257353Sbdrewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 852257353Sbdrewery warnx("Error looking up SIGNATURE_TYPE"); 853257353Sbdrewery return (-1); 854257353Sbdrewery } 855257353Sbdrewery if (signature_type != NULL && 856257353Sbdrewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 857257353Sbdrewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 858257353Sbdrewery 859257353Sbdrewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 860257353Sbdrewery fprintf(stderr, "Signature for pkg not available.\n"); 861257353Sbdrewery goto cleanup; 862257353Sbdrewery } 863257353Sbdrewery 864257353Sbdrewery if (verify_signature(fd_pkg, fd_sig) == false) 865257353Sbdrewery goto cleanup; 866257353Sbdrewery } 867257353Sbdrewery 868257353Sbdrewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 869257632Sbdrewery ret = install_pkg_static(pkgstatic, pkgpath, force); 870257353Sbdrewery 871257353Sbdrewerycleanup: 872257353Sbdrewery close(fd_pkg); 873257353Sbdrewery if (fd_sig != -1) 874257353Sbdrewery close(fd_sig); 875257353Sbdrewery 876257353Sbdrewery return (ret); 877257353Sbdrewery} 878257353Sbdrewery 879234313Sbaptint 880234322Sbaptmain(__unused int argc, char *argv[]) 881234313Sbapt{ 882234313Sbapt char pkgpath[MAXPATHLEN]; 883257632Sbdrewery const char *pkgarg; 884257632Sbdrewery bool bootstrap_only, force, yes; 885234313Sbapt 886257632Sbdrewery bootstrap_only = false; 887257632Sbdrewery force = false; 888257632Sbdrewery pkgarg = NULL; 889257632Sbdrewery yes = false; 890257632Sbdrewery 891234313Sbapt snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 892234322Sbapt getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 893234313Sbapt 894257632Sbdrewery if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 895257632Sbdrewery bootstrap_only = true; 896257632Sbdrewery if (argc == 3 && strcmp(argv[2], "-f") == 0) 897257632Sbdrewery force = true; 898257632Sbdrewery } 899257632Sbdrewery 900257632Sbdrewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 901244553Smatthew /* 902244594Smatthew * To allow 'pkg -N' to be used as a reliable test for whether 903244553Smatthew * a system is configured to use pkg, don't bootstrap pkg 904244553Smatthew * when that argument is given as argv[1]. 905244553Smatthew */ 906244639Smatthew if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 907244639Smatthew errx(EXIT_FAILURE, "pkg is not installed"); 908244553Smatthew 909257353Sbdrewery config_init(); 910257353Sbdrewery 911257632Sbdrewery if (argc > 1 && strcmp(argv[1], "add") == 0) { 912257632Sbdrewery if (argc > 2 && strcmp(argv[2], "-f") == 0) { 913257632Sbdrewery force = true; 914257632Sbdrewery pkgarg = argv[3]; 915257632Sbdrewery } else 916257632Sbdrewery pkgarg = argv[2]; 917257632Sbdrewery if (pkgarg == NULL) { 918257632Sbdrewery fprintf(stderr, "Path to pkg.txz required\n"); 919257309Sbapt exit(EXIT_FAILURE); 920257632Sbdrewery } 921257632Sbdrewery if (access(pkgarg, R_OK) == -1) { 922257632Sbdrewery fprintf(stderr, "No such file: %s\n", pkgarg); 923257632Sbdrewery exit(EXIT_FAILURE); 924257632Sbdrewery } 925257632Sbdrewery if (bootstrap_pkg_local(pkgarg, force) != 0) 926257632Sbdrewery exit(EXIT_FAILURE); 927257309Sbapt exit(EXIT_SUCCESS); 928257309Sbapt } 929238461Skan /* 930238461Skan * Do not ask for confirmation if either of stdin or stdout is 931238461Skan * not tty. Check the environment to see if user has answer 932238461Skan * tucked in there already. 933238461Skan */ 934247841Sbapt config_bool(ASSUME_ALWAYS_YES, &yes); 935247841Sbapt if (!yes) { 936238461Skan printf("%s", confirmation_message); 937239664Sbapt if (!isatty(fileno(stdin))) 938238461Skan exit(EXIT_FAILURE); 939239664Sbapt 940239664Sbapt if (pkg_query_yes_no() == 0) 941239663Sbapt exit(EXIT_FAILURE); 942238461Skan } 943257632Sbdrewery if (bootstrap_pkg(force) != 0) 944234351Sbapt exit(EXIT_FAILURE); 945247841Sbapt config_finish(); 946257571Sbdrewery 947257632Sbdrewery if (bootstrap_only) 948257571Sbdrewery exit(EXIT_SUCCESS); 949257632Sbdrewery } else if (bootstrap_only) { 950257632Sbdrewery printf("pkg already bootstrapped at %s\n", pkgpath); 951257632Sbdrewery exit(EXIT_SUCCESS); 952238461Skan } 953234313Sbapt 954234313Sbapt execv(pkgpath, argv); 955234313Sbapt 956234351Sbapt /* NOT REACHED */ 957234322Sbapt return (EXIT_FAILURE); 958234313Sbapt} 959