1234313Sbapt/*- 2263038Sbapt * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org> 3263038Sbapt * 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$"); 30234313Sbapt 31234313Sbapt#include <sys/param.h> 32263038Sbapt#include <sys/queue.h> 33263038Sbapt#include <sys/types.h> 34263038Sbapt#include <sys/sbuf.h> 35235112Sbapt#include <sys/wait.h> 36234313Sbapt 37263038Sbapt#define _WITH_GETLINE 38234313Sbapt#include <archive.h> 39234313Sbapt#include <archive_entry.h> 40263038Sbapt#include <dirent.h> 41234313Sbapt#include <err.h> 42234313Sbapt#include <errno.h> 43234313Sbapt#include <fcntl.h> 44235112Sbapt#include <fetch.h> 45235112Sbapt#include <paths.h> 46263038Sbapt#include <stdbool.h> 47234313Sbapt#include <stdlib.h> 48234313Sbapt#include <stdio.h> 49234313Sbapt#include <string.h> 50234313Sbapt#include <unistd.h> 51263038Sbapt#include <ucl.h> 52234313Sbapt 53263038Sbapt#include <openssl/err.h> 54263038Sbapt#include <openssl/ssl.h> 55263038Sbapt 56245394Sbapt#include "dns_utils.h" 57263038Sbapt#include "config.h" 58234313Sbapt 59263038Sbaptstruct sig_cert { 60263038Sbapt char *name; 61263038Sbapt unsigned char *sig; 62263038Sbapt int siglen; 63263038Sbapt unsigned char *cert; 64263038Sbapt int certlen; 65263038Sbapt bool trusted; 66263038Sbapt}; 67234313Sbapt 68287873Sdelphijstruct pubkey { 69287873Sdelphij unsigned char *sig; 70287873Sdelphij int siglen; 71287873Sdelphij}; 72287873Sdelphij 73263038Sbapttypedef enum { 74263038Sbapt HASH_UNKNOWN, 75263038Sbapt HASH_SHA256, 76263038Sbapt} hash_t; 77234313Sbapt 78263038Sbaptstruct fingerprint { 79263038Sbapt hash_t type; 80263038Sbapt char *name; 81263038Sbapt char hash[BUFSIZ]; 82263038Sbapt STAILQ_ENTRY(fingerprint) next; 83263038Sbapt}; 84234313Sbapt 85263038SbaptSTAILQ_HEAD(fingerprint_list, fingerprint); 86234313Sbapt 87234313Sbaptstatic int 88234313Sbaptextract_pkg_static(int fd, char *p, int sz) 89234313Sbapt{ 90234313Sbapt struct archive *a; 91234313Sbapt struct archive_entry *ae; 92234313Sbapt char *end; 93234313Sbapt int ret, r; 94234313Sbapt 95235112Sbapt ret = -1; 96234313Sbapt a = archive_read_new(); 97235112Sbapt if (a == NULL) { 98235112Sbapt warn("archive_read_new"); 99235112Sbapt return (ret); 100235112Sbapt } 101234313Sbapt archive_read_support_compression_all(a); 102234313Sbapt archive_read_support_format_tar(a); 103234313Sbapt 104235112Sbapt if (lseek(fd, 0, 0) == -1) { 105235112Sbapt warn("lseek"); 106235112Sbapt goto cleanup; 107235112Sbapt } 108234313Sbapt 109234313Sbapt if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { 110235112Sbapt warnx("archive_read_open_fd: %s", archive_error_string(a)); 111234313Sbapt goto cleanup; 112234313Sbapt } 113234313Sbapt 114234313Sbapt ae = NULL; 115234313Sbapt while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { 116234313Sbapt end = strrchr(archive_entry_pathname(ae), '/'); 117234313Sbapt if (end == NULL) 118234313Sbapt continue; 119234313Sbapt 120234313Sbapt if (strcmp(end, "/pkg-static") == 0) { 121234313Sbapt r = archive_read_extract(a, ae, 122235112Sbapt ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 123235112Sbapt ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | 124235112Sbapt ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); 125235112Sbapt strlcpy(p, archive_entry_pathname(ae), sz); 126234313Sbapt break; 127234313Sbapt } 128234313Sbapt } 129234313Sbapt 130235112Sbapt if (r == ARCHIVE_OK) 131235112Sbapt ret = 0; 132235112Sbapt else 133234313Sbapt warnx("fail to extract pkg-static"); 134234313Sbapt 135234313Sbaptcleanup: 136263038Sbapt archive_read_free(a); 137235112Sbapt return (ret); 138234313Sbapt 139234313Sbapt} 140234313Sbapt 141234313Sbaptstatic int 142263038Sbaptinstall_pkg_static(const char *path, const char *pkgpath, bool force) 143234313Sbapt{ 144234313Sbapt int pstat; 145234313Sbapt pid_t pid; 146234313Sbapt 147234313Sbapt switch ((pid = fork())) { 148235112Sbapt case -1: 149235112Sbapt return (-1); 150235112Sbapt case 0: 151263038Sbapt if (force) 152263038Sbapt execl(path, "pkg-static", "add", "-f", pkgpath, 153263038Sbapt (char *)NULL); 154263038Sbapt else 155263038Sbapt execl(path, "pkg-static", "add", pkgpath, 156263038Sbapt (char *)NULL); 157235112Sbapt _exit(1); 158235112Sbapt default: 159235112Sbapt break; 160234313Sbapt } 161234313Sbapt 162235112Sbapt while (waitpid(pid, &pstat, 0) == -1) 163234313Sbapt if (errno != EINTR) 164234313Sbapt return (-1); 165234313Sbapt 166235112Sbapt if (WEXITSTATUS(pstat)) 167235112Sbapt return (WEXITSTATUS(pstat)); 168235112Sbapt else if (WIFSIGNALED(pstat)) 169235112Sbapt return (128 & (WTERMSIG(pstat))); 170235112Sbapt return (pstat); 171234313Sbapt} 172234313Sbapt 173234313Sbaptstatic int 174263038Sbaptfetch_to_fd(const char *url, char *path) 175234313Sbapt{ 176245394Sbapt struct url *u; 177263038Sbapt struct dns_srvinfo *mirrors, *current; 178263038Sbapt struct url_stat st; 179234313Sbapt FILE *remote; 180245394Sbapt /* To store _https._tcp. + hostname + \0 */ 181263038Sbapt int fd; 182263038Sbapt int retry, max_retry; 183287873Sdelphij ssize_t r; 184263038Sbapt char buf[10240]; 185245394Sbapt char zone[MAXHOSTNAMELEN + 13]; 186263038Sbapt static const char *mirror_type = NULL; 187234313Sbapt 188245394Sbapt max_retry = 3; 189263038Sbapt current = mirrors = NULL; 190234313Sbapt remote = NULL; 191234313Sbapt 192263038Sbapt if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) 193263038Sbapt != 0) { 194263038Sbapt warnx("No MIRROR_TYPE defined"); 195235112Sbapt return (-1); 196234313Sbapt } 197234313Sbapt 198263038Sbapt if ((fd = mkstemp(path)) == -1) { 199234313Sbapt warn("mkstemp()"); 200235112Sbapt return (-1); 201234313Sbapt } 202234313Sbapt 203245394Sbapt retry = max_retry; 204234313Sbapt 205245394Sbapt u = fetchParseURL(url); 206245394Sbapt while (remote == NULL) { 207245394Sbapt if (retry == max_retry) { 208263038Sbapt if (strcmp(u->scheme, "file") != 0 && 209263038Sbapt strcasecmp(mirror_type, "srv") == 0) { 210245394Sbapt snprintf(zone, sizeof(zone), 211245394Sbapt "_%s._tcp.%s", u->scheme, u->host); 212245394Sbapt mirrors = dns_getsrvinfo(zone); 213245394Sbapt current = mirrors; 214245394Sbapt } 215245394Sbapt } 216245394Sbapt 217263038Sbapt if (mirrors != NULL) { 218245394Sbapt strlcpy(u->host, current->host, sizeof(u->host)); 219263038Sbapt u->port = current->port; 220263038Sbapt } 221245394Sbapt 222245394Sbapt remote = fetchXGet(u, &st, ""); 223245394Sbapt if (remote == NULL) { 224245394Sbapt --retry; 225245394Sbapt if (retry <= 0) 226245394Sbapt goto fetchfail; 227245394Sbapt if (mirrors == NULL) { 228245394Sbapt sleep(1); 229245394Sbapt } else { 230245394Sbapt current = current->next; 231245394Sbapt if (current == NULL) 232245394Sbapt current = mirrors; 233245394Sbapt } 234245394Sbapt } 235245394Sbapt } 236245394Sbapt 237287873Sdelphij while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { 238234313Sbapt if (write(fd, buf, r) != r) { 239234313Sbapt warn("write()"); 240263038Sbapt goto fetchfail; 241234313Sbapt } 242287873Sdelphij } 243234313Sbapt 244287873Sdelphij if (r != 0) { 245287873Sdelphij warn("An error occurred while fetching pkg(8)"); 246287873Sdelphij goto fetchfail; 247234313Sbapt } 248234313Sbapt 249235112Sbapt if (ferror(remote)) 250235112Sbapt goto fetchfail; 251234313Sbapt 252263038Sbapt goto cleanup; 253234313Sbapt 254263038Sbaptfetchfail: 255263038Sbapt if (fd != -1) { 256263038Sbapt close(fd); 257263038Sbapt fd = -1; 258263038Sbapt unlink(path); 259263038Sbapt } 260235112Sbapt 261263038Sbaptcleanup: 262263038Sbapt if (remote != NULL) 263263038Sbapt fclose(remote); 264235112Sbapt 265263038Sbapt return fd; 266263038Sbapt} 267263038Sbapt 268263038Sbaptstatic struct fingerprint * 269263038Sbaptparse_fingerprint(ucl_object_t *obj) 270263038Sbapt{ 271263038Sbapt ucl_object_t *cur; 272263038Sbapt ucl_object_iter_t it = NULL; 273263038Sbapt const char *function, *fp, *key; 274263038Sbapt struct fingerprint *f; 275263038Sbapt hash_t fct = HASH_UNKNOWN; 276263038Sbapt 277263038Sbapt function = fp = NULL; 278263038Sbapt 279263038Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 280263038Sbapt key = ucl_object_key(cur); 281263038Sbapt if (cur->type != UCL_STRING) 282263038Sbapt continue; 283263038Sbapt if (strcasecmp(key, "function") == 0) { 284263038Sbapt function = ucl_object_tostring(cur); 285263038Sbapt continue; 286263038Sbapt } 287263038Sbapt if (strcasecmp(key, "fingerprint") == 0) { 288263038Sbapt fp = ucl_object_tostring(cur); 289263038Sbapt continue; 290263038Sbapt } 291263038Sbapt } 292263038Sbapt 293263038Sbapt if (fp == NULL || function == NULL) 294263038Sbapt return (NULL); 295263038Sbapt 296263038Sbapt if (strcasecmp(function, "sha256") == 0) 297263038Sbapt fct = HASH_SHA256; 298263038Sbapt 299263038Sbapt if (fct == HASH_UNKNOWN) { 300263038Sbapt warnx("Unsupported hashing function: %s", function); 301263038Sbapt return (NULL); 302263038Sbapt } 303263038Sbapt 304263038Sbapt f = calloc(1, sizeof(struct fingerprint)); 305263038Sbapt f->type = fct; 306263038Sbapt strlcpy(f->hash, fp, sizeof(f->hash)); 307263038Sbapt 308263038Sbapt return (f); 309263038Sbapt} 310263038Sbapt 311263038Sbaptstatic void 312263038Sbaptfree_fingerprint_list(struct fingerprint_list* list) 313263038Sbapt{ 314263038Sbapt struct fingerprint *fingerprint, *tmp; 315263038Sbapt 316263038Sbapt STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 317263038Sbapt free(fingerprint->name); 318263038Sbapt free(fingerprint); 319263038Sbapt } 320263038Sbapt free(list); 321263038Sbapt} 322263038Sbapt 323263038Sbaptstatic struct fingerprint * 324263038Sbaptload_fingerprint(const char *dir, const char *filename) 325263038Sbapt{ 326263038Sbapt ucl_object_t *obj = NULL; 327263038Sbapt struct ucl_parser *p = NULL; 328263038Sbapt struct fingerprint *f; 329263038Sbapt char path[MAXPATHLEN]; 330263038Sbapt 331263038Sbapt f = NULL; 332263038Sbapt 333263038Sbapt snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 334263038Sbapt 335263038Sbapt p = ucl_parser_new(0); 336263038Sbapt if (!ucl_parser_add_file(p, path)) { 337263038Sbapt warnx("%s: %s", path, ucl_parser_get_error(p)); 338263038Sbapt ucl_parser_free(p); 339263038Sbapt return (NULL); 340263038Sbapt } 341263038Sbapt 342263038Sbapt obj = ucl_parser_get_object(p); 343263038Sbapt 344263038Sbapt if (obj->type == UCL_OBJECT) 345263038Sbapt f = parse_fingerprint(obj); 346263038Sbapt 347263038Sbapt if (f != NULL) 348263038Sbapt f->name = strdup(filename); 349263038Sbapt 350263038Sbapt ucl_object_free(obj); 351263038Sbapt ucl_parser_free(p); 352263038Sbapt 353263038Sbapt return (f); 354263038Sbapt} 355263038Sbapt 356263038Sbaptstatic struct fingerprint_list * 357263038Sbaptload_fingerprints(const char *path, int *count) 358263038Sbapt{ 359263038Sbapt DIR *d; 360263038Sbapt struct dirent *ent; 361263038Sbapt struct fingerprint *finger; 362263038Sbapt struct fingerprint_list *fingerprints; 363263038Sbapt 364263038Sbapt *count = 0; 365263038Sbapt 366263038Sbapt fingerprints = calloc(1, sizeof(struct fingerprint_list)); 367263038Sbapt if (fingerprints == NULL) 368263038Sbapt return (NULL); 369263038Sbapt STAILQ_INIT(fingerprints); 370263038Sbapt 371263038Sbapt if ((d = opendir(path)) == NULL) 372263038Sbapt return (NULL); 373263038Sbapt 374263038Sbapt while ((ent = readdir(d))) { 375263038Sbapt if (strcmp(ent->d_name, ".") == 0 || 376263038Sbapt strcmp(ent->d_name, "..") == 0) 377263038Sbapt continue; 378263038Sbapt finger = load_fingerprint(path, ent->d_name); 379263038Sbapt if (finger != NULL) { 380263038Sbapt STAILQ_INSERT_TAIL(fingerprints, finger, next); 381263038Sbapt ++(*count); 382263038Sbapt } 383263038Sbapt } 384263038Sbapt 385263038Sbapt closedir(d); 386263038Sbapt 387263038Sbapt return (fingerprints); 388263038Sbapt} 389263038Sbapt 390263038Sbaptstatic void 391263038Sbaptsha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 392263038Sbapt char out[SHA256_DIGEST_LENGTH * 2 + 1]) 393263038Sbapt{ 394263038Sbapt int i; 395263038Sbapt 396263038Sbapt for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 397263038Sbapt sprintf(out + (i * 2), "%02x", hash[i]); 398263038Sbapt 399263038Sbapt out[SHA256_DIGEST_LENGTH * 2] = '\0'; 400263038Sbapt} 401263038Sbapt 402263038Sbaptstatic void 403263038Sbaptsha256_buf_bin(char *buf, size_t len, char hash[SHA256_DIGEST_LENGTH]) 404263038Sbapt{ 405263038Sbapt SHA256_CTX sha256; 406263038Sbapt 407263038Sbapt SHA256_Init(&sha256); 408263038Sbapt SHA256_Update(&sha256, buf, len); 409263038Sbapt SHA256_Final(hash, &sha256); 410263038Sbapt} 411263038Sbapt 412263038Sbapt 413263038Sbaptstatic void 414263038Sbaptsha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 415263038Sbapt{ 416263038Sbapt unsigned char hash[SHA256_DIGEST_LENGTH]; 417263038Sbapt SHA256_CTX sha256; 418263038Sbapt 419263038Sbapt out[0] = '\0'; 420263038Sbapt 421263038Sbapt SHA256_Init(&sha256); 422263038Sbapt SHA256_Update(&sha256, buf, len); 423263038Sbapt SHA256_Final(hash, &sha256); 424263038Sbapt sha256_hash(hash, out); 425263038Sbapt} 426263038Sbapt 427263038Sbaptstatic int 428263038Sbaptsha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 429263038Sbapt{ 430263038Sbapt int my_fd; 431263038Sbapt FILE *fp; 432263038Sbapt char buffer[BUFSIZ]; 433263038Sbapt unsigned char hash[SHA256_DIGEST_LENGTH]; 434263038Sbapt size_t r; 435263038Sbapt int ret; 436263038Sbapt SHA256_CTX sha256; 437263038Sbapt 438263038Sbapt my_fd = -1; 439263038Sbapt fp = NULL; 440263038Sbapt r = 0; 441263038Sbapt ret = 1; 442263038Sbapt 443263038Sbapt out[0] = '\0'; 444263038Sbapt 445263038Sbapt /* Duplicate the fd so that fclose(3) does not close it. */ 446263038Sbapt if ((my_fd = dup(fd)) == -1) { 447263038Sbapt warnx("dup"); 448263038Sbapt goto cleanup; 449263038Sbapt } 450263038Sbapt 451263038Sbapt if ((fp = fdopen(my_fd, "rb")) == NULL) { 452263038Sbapt warnx("fdopen"); 453263038Sbapt goto cleanup; 454263038Sbapt } 455263038Sbapt 456263038Sbapt SHA256_Init(&sha256); 457263038Sbapt 458263038Sbapt while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 459263038Sbapt SHA256_Update(&sha256, buffer, r); 460263038Sbapt 461263038Sbapt if (ferror(fp) != 0) { 462263038Sbapt warnx("fread"); 463263038Sbapt goto cleanup; 464263038Sbapt } 465263038Sbapt 466263038Sbapt SHA256_Final(hash, &sha256); 467263038Sbapt sha256_hash(hash, out); 468263038Sbapt ret = 0; 469263038Sbapt 470263038Sbaptcleanup: 471263038Sbapt if (fp != NULL) 472263038Sbapt fclose(fp); 473263038Sbapt else if (my_fd != -1) 474263038Sbapt close(my_fd); 475263038Sbapt (void)lseek(fd, 0, SEEK_SET); 476263038Sbapt 477263038Sbapt return (ret); 478263038Sbapt} 479263038Sbapt 480263038Sbaptstatic RSA * 481287873Sdelphijload_rsa_public_key_file(const char *file) 482287873Sdelphij{ 483287873Sdelphij RSA *rsa = NULL; 484287873Sdelphij BIO *bp; 485287873Sdelphij char errbuf[1024]; 486287873Sdelphij 487287873Sdelphij bp = BIO_new_file(file, "r"); 488287873Sdelphij if (!bp) 489287873Sdelphij errx(EXIT_FAILURE, "Unable to read %s", file); 490287873Sdelphij 491287873Sdelphij if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) { 492287873Sdelphij warn("error reading public key: %s", 493287873Sdelphij ERR_error_string(ERR_get_error(), errbuf)); 494287873Sdelphij BIO_free(bp); 495287873Sdelphij return (NULL); 496287873Sdelphij } 497287873Sdelphij 498287873Sdelphij BIO_free(bp); 499287873Sdelphij 500287873Sdelphij return (rsa); 501287873Sdelphij} 502287873Sdelphij 503287873Sdelphijstatic RSA * 504263038Sbaptload_rsa_public_key_buf(unsigned char *cert, int certlen) 505263038Sbapt{ 506263038Sbapt RSA *rsa = NULL; 507263038Sbapt BIO *bp; 508263038Sbapt char errbuf[1024]; 509263038Sbapt 510263038Sbapt bp = BIO_new_mem_buf((void *)cert, certlen); 511263038Sbapt if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) { 512263038Sbapt warn("error reading public key: %s", 513263038Sbapt ERR_error_string(ERR_get_error(), errbuf)); 514263038Sbapt BIO_free(bp); 515263038Sbapt return (NULL); 516263038Sbapt } 517263038Sbapt BIO_free(bp); 518263038Sbapt return (rsa); 519263038Sbapt} 520263038Sbapt 521263038Sbapt 522263038Sbaptstatic bool 523287873Sdelphijrsa_verify_cert(int fd, const char *sigfile, unsigned char *key, 524287873Sdelphij int keylen, unsigned char *sig, int siglen) 525263038Sbapt{ 526263038Sbapt char sha256[SHA256_DIGEST_LENGTH *2 +1]; 527263038Sbapt char hash[SHA256_DIGEST_LENGTH]; 528263038Sbapt char errbuf[1024]; 529263038Sbapt RSA *rsa = NULL; 530263038Sbapt int ret; 531263038Sbapt 532263038Sbapt lseek(fd, 0, SEEK_SET); 533263038Sbapt sha256_fd(fd, sha256); 534263038Sbapt 535263038Sbapt SSL_load_error_strings(); 536263038Sbapt OpenSSL_add_all_algorithms(); 537263038Sbapt OpenSSL_add_all_ciphers(); 538263038Sbapt 539263038Sbapt sha256_buf_bin(sha256, strlen(sha256), hash); 540263038Sbapt 541287873Sdelphij if (sigfile != NULL) { 542287873Sdelphij rsa = load_rsa_public_key_file(sigfile); 543287873Sdelphij } else { 544287873Sdelphij rsa = load_rsa_public_key_buf(key, keylen); 545287873Sdelphij } 546263038Sbapt if (rsa == NULL) 547263038Sbapt return (false); 548263038Sbapt ret = RSA_verify(NID_sha256, hash, sizeof(hash), sig, siglen, rsa); 549263038Sbapt if (ret == 0) { 550263038Sbapt warnx("%s: %s", key, ERR_error_string(ERR_get_error(), errbuf)); 551263038Sbapt return (false); 552263038Sbapt } 553263038Sbapt 554263038Sbapt RSA_free(rsa); 555263038Sbapt ERR_free_strings(); 556263038Sbapt 557263038Sbapt return (true); 558263038Sbapt} 559263038Sbapt 560287873Sdelphijstatic struct pubkey * 561287873Sdelphijread_pubkey(int fd) 562287873Sdelphij{ 563287873Sdelphij struct pubkey *pk; 564287873Sdelphij struct sbuf *sig; 565287873Sdelphij char buf[4096]; 566287873Sdelphij int r; 567287873Sdelphij 568287873Sdelphij if (lseek(fd, 0, 0) == -1) { 569287873Sdelphij warn("lseek"); 570287873Sdelphij return (NULL); 571287873Sdelphij } 572287873Sdelphij 573287873Sdelphij sig = sbuf_new_auto(); 574287873Sdelphij 575287873Sdelphij while ((r = read(fd, buf, sizeof(buf))) >0) { 576287873Sdelphij sbuf_bcat(sig, buf, r); 577287873Sdelphij } 578287873Sdelphij 579287873Sdelphij sbuf_finish(sig); 580287873Sdelphij pk = calloc(1, sizeof(struct pubkey)); 581287873Sdelphij pk->siglen = sbuf_len(sig); 582287873Sdelphij pk->sig = calloc(1, pk->siglen); 583287873Sdelphij memcpy(pk->sig, sbuf_data(sig), pk->siglen); 584287873Sdelphij sbuf_delete(sig); 585287873Sdelphij 586287873Sdelphij return (pk); 587287873Sdelphij} 588287873Sdelphij 589263038Sbaptstatic struct sig_cert * 590263038Sbaptparse_cert(int fd) { 591263038Sbapt int my_fd; 592263038Sbapt struct sig_cert *sc; 593263038Sbapt FILE *fp; 594263038Sbapt struct sbuf *buf, *sig, *cert; 595263038Sbapt char *line; 596263038Sbapt size_t linecap; 597263038Sbapt ssize_t linelen; 598263038Sbapt 599263038Sbapt buf = NULL; 600263038Sbapt my_fd = -1; 601263038Sbapt sc = NULL; 602263038Sbapt line = NULL; 603263038Sbapt linecap = 0; 604263038Sbapt 605263038Sbapt if (lseek(fd, 0, 0) == -1) { 606263038Sbapt warn("lseek"); 607263038Sbapt return (NULL); 608263038Sbapt } 609263038Sbapt 610263038Sbapt /* Duplicate the fd so that fclose(3) does not close it. */ 611263038Sbapt if ((my_fd = dup(fd)) == -1) { 612263038Sbapt warnx("dup"); 613263038Sbapt return (NULL); 614263038Sbapt } 615263038Sbapt 616263038Sbapt if ((fp = fdopen(my_fd, "rb")) == NULL) { 617263038Sbapt warn("fdopen"); 618263038Sbapt close(my_fd); 619263038Sbapt return (NULL); 620263038Sbapt } 621263038Sbapt 622263038Sbapt sig = sbuf_new_auto(); 623263038Sbapt cert = sbuf_new_auto(); 624263038Sbapt 625263038Sbapt while ((linelen = getline(&line, &linecap, fp)) > 0) { 626263038Sbapt if (strcmp(line, "SIGNATURE\n") == 0) { 627263038Sbapt buf = sig; 628263038Sbapt continue; 629263038Sbapt } else if (strcmp(line, "CERT\n") == 0) { 630263038Sbapt buf = cert; 631263038Sbapt continue; 632263038Sbapt } else if (strcmp(line, "END\n") == 0) { 633263038Sbapt break; 634263038Sbapt } 635263038Sbapt if (buf != NULL) 636263038Sbapt sbuf_bcat(buf, line, linelen); 637263038Sbapt } 638263038Sbapt 639263038Sbapt fclose(fp); 640263038Sbapt 641263038Sbapt /* Trim out unrelated trailing newline */ 642263038Sbapt sbuf_setpos(sig, sbuf_len(sig) - 1); 643263038Sbapt 644263038Sbapt sbuf_finish(sig); 645263038Sbapt sbuf_finish(cert); 646263038Sbapt 647263038Sbapt sc = calloc(1, sizeof(struct sig_cert)); 648263038Sbapt sc->siglen = sbuf_len(sig); 649263038Sbapt sc->sig = calloc(1, sc->siglen); 650263038Sbapt memcpy(sc->sig, sbuf_data(sig), sc->siglen); 651263038Sbapt 652263038Sbapt sc->certlen = sbuf_len(cert); 653263038Sbapt sc->cert = strdup(sbuf_data(cert)); 654263038Sbapt 655263038Sbapt sbuf_delete(sig); 656263038Sbapt sbuf_delete(cert); 657263038Sbapt 658263038Sbapt return (sc); 659263038Sbapt} 660263038Sbapt 661263038Sbaptstatic bool 662287873Sdelphijverify_pubsignature(int fd_pkg, int fd_sig) 663287873Sdelphij{ 664287873Sdelphij struct pubkey *pk; 665287873Sdelphij const char *pubkey; 666287873Sdelphij bool ret; 667287873Sdelphij 668287873Sdelphij pk = NULL; 669287873Sdelphij pubkey = NULL; 670287873Sdelphij ret = false; 671287873Sdelphij if (config_string(PUBKEY, &pubkey) != 0) { 672287873Sdelphij warnx("No CONFIG_PUBKEY defined"); 673287873Sdelphij goto cleanup; 674287873Sdelphij } 675287873Sdelphij 676287873Sdelphij if ((pk = read_pubkey(fd_sig)) == NULL) { 677287873Sdelphij warnx("Error reading signature"); 678287873Sdelphij goto cleanup; 679287873Sdelphij } 680287873Sdelphij 681287873Sdelphij /* Verify the signature. */ 682287873Sdelphij printf("Verifying signature with public key %s... ", pubkey); 683287873Sdelphij if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, 684287873Sdelphij pk->siglen) == false) { 685287873Sdelphij fprintf(stderr, "Signature is not valid\n"); 686287873Sdelphij goto cleanup; 687287873Sdelphij } 688287873Sdelphij 689287873Sdelphij ret = true; 690287873Sdelphij 691287873Sdelphijcleanup: 692287873Sdelphij if (pk) { 693287873Sdelphij free(pk->sig); 694287873Sdelphij free(pk); 695287873Sdelphij } 696287873Sdelphij 697287873Sdelphij return (ret); 698287873Sdelphij} 699287873Sdelphij 700287873Sdelphijstatic bool 701263038Sbaptverify_signature(int fd_pkg, int fd_sig) 702263038Sbapt{ 703263038Sbapt struct fingerprint_list *trusted, *revoked; 704263038Sbapt struct fingerprint *fingerprint; 705263038Sbapt struct sig_cert *sc; 706263038Sbapt bool ret; 707263038Sbapt int trusted_count, revoked_count; 708263038Sbapt const char *fingerprints; 709263038Sbapt char path[MAXPATHLEN]; 710263038Sbapt char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 711263038Sbapt 712263038Sbapt sc = NULL; 713263038Sbapt trusted = revoked = NULL; 714263038Sbapt ret = false; 715263038Sbapt 716263038Sbapt /* Read and parse fingerprints. */ 717263038Sbapt if (config_string(FINGERPRINTS, &fingerprints) != 0) { 718263038Sbapt warnx("No CONFIG_FINGERPRINTS defined"); 719263038Sbapt goto cleanup; 720263038Sbapt } 721263038Sbapt 722263038Sbapt snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 723263038Sbapt if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 724263038Sbapt warnx("Error loading trusted certificates"); 725263038Sbapt goto cleanup; 726263038Sbapt } 727263038Sbapt 728263038Sbapt if (trusted_count == 0 || trusted == NULL) { 729263038Sbapt fprintf(stderr, "No trusted certificates found.\n"); 730263038Sbapt goto cleanup; 731263038Sbapt } 732263038Sbapt 733263038Sbapt snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 734263038Sbapt if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 735263038Sbapt warnx("Error loading revoked certificates"); 736263038Sbapt goto cleanup; 737263038Sbapt } 738263038Sbapt 739263038Sbapt /* Read certificate and signature in. */ 740263038Sbapt if ((sc = parse_cert(fd_sig)) == NULL) { 741263038Sbapt warnx("Error parsing certificate"); 742263038Sbapt goto cleanup; 743263038Sbapt } 744263038Sbapt /* Explicitly mark as non-trusted until proven otherwise. */ 745263038Sbapt sc->trusted = false; 746263038Sbapt 747263038Sbapt /* Parse signature and pubkey out of the certificate */ 748263038Sbapt sha256_buf(sc->cert, sc->certlen, hash); 749263038Sbapt 750263038Sbapt /* Check if this hash is revoked */ 751263038Sbapt if (revoked != NULL) { 752263038Sbapt STAILQ_FOREACH(fingerprint, revoked, next) { 753263038Sbapt if (strcasecmp(fingerprint->hash, hash) == 0) { 754263038Sbapt fprintf(stderr, "The package was signed with " 755263038Sbapt "revoked certificate %s\n", 756263038Sbapt fingerprint->name); 757263038Sbapt goto cleanup; 758263038Sbapt } 759263038Sbapt } 760263038Sbapt } 761263038Sbapt 762263038Sbapt STAILQ_FOREACH(fingerprint, trusted, next) { 763263038Sbapt if (strcasecmp(fingerprint->hash, hash) == 0) { 764263038Sbapt sc->trusted = true; 765263038Sbapt sc->name = strdup(fingerprint->name); 766263038Sbapt break; 767263038Sbapt } 768263038Sbapt } 769263038Sbapt 770263038Sbapt if (sc->trusted == false) { 771263038Sbapt fprintf(stderr, "No trusted fingerprint found matching " 772263038Sbapt "package's certificate\n"); 773263038Sbapt goto cleanup; 774263038Sbapt } 775263038Sbapt 776263038Sbapt /* Verify the signature. */ 777263038Sbapt printf("Verifying signature with trusted certificate %s... ", sc->name); 778287873Sdelphij if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, 779263038Sbapt sc->siglen) == false) { 780263038Sbapt printf("failed\n"); 781263038Sbapt fprintf(stderr, "Signature is not valid\n"); 782263038Sbapt goto cleanup; 783263038Sbapt } 784263038Sbapt printf("done\n"); 785263038Sbapt 786263038Sbapt ret = true; 787263038Sbapt 788263038Sbaptcleanup: 789263038Sbapt if (trusted) 790263038Sbapt free_fingerprint_list(trusted); 791263038Sbapt if (revoked) 792263038Sbapt free_fingerprint_list(revoked); 793263038Sbapt if (sc) { 794263038Sbapt free(sc->cert); 795263038Sbapt free(sc->sig); 796263038Sbapt free(sc->name); 797263038Sbapt free(sc); 798263038Sbapt } 799263038Sbapt 800263038Sbapt return (ret); 801263038Sbapt} 802263038Sbapt 803263038Sbaptstatic int 804263038Sbaptbootstrap_pkg(bool force) 805263038Sbapt{ 806263038Sbapt int fd_pkg, fd_sig; 807263038Sbapt int ret; 808263038Sbapt char url[MAXPATHLEN]; 809263038Sbapt char tmppkg[MAXPATHLEN]; 810263038Sbapt char tmpsig[MAXPATHLEN]; 811263038Sbapt const char *packagesite; 812263038Sbapt const char *signature_type; 813263038Sbapt char pkgstatic[MAXPATHLEN]; 814263038Sbapt 815263038Sbapt fd_sig = -1; 816263038Sbapt ret = -1; 817263038Sbapt 818263038Sbapt if (config_string(PACKAGESITE, &packagesite) != 0) { 819263038Sbapt warnx("No PACKAGESITE defined"); 820263038Sbapt return (-1); 821263038Sbapt } 822263038Sbapt 823263038Sbapt if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 824263038Sbapt warnx("Error looking up SIGNATURE_TYPE"); 825263038Sbapt return (-1); 826263038Sbapt } 827263038Sbapt 828263038Sbapt printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 829263038Sbapt 830263038Sbapt /* Support pkg+http:// for PACKAGESITE which is the new format 831263038Sbapt in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 832263038Sbapt no A record. */ 833263038Sbapt if (strncmp(URL_SCHEME_PREFIX, packagesite, 834263038Sbapt strlen(URL_SCHEME_PREFIX)) == 0) 835263038Sbapt packagesite += strlen(URL_SCHEME_PREFIX); 836263038Sbapt snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 837263038Sbapt 838263038Sbapt snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 839263038Sbapt getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 840263038Sbapt 841263038Sbapt if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 842263038Sbapt goto fetchfail; 843263038Sbapt 844263038Sbapt if (signature_type != NULL && 845287147Sdelphij strcasecmp(signature_type, "NONE") != 0) { 846287873Sdelphij if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 847287873Sdelphij 848287873Sdelphij snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 849287873Sdelphij getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 850287873Sdelphij snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 851287873Sdelphij packagesite); 852287873Sdelphij 853287873Sdelphij if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 854287873Sdelphij fprintf(stderr, "Signature for pkg not " 855287873Sdelphij "available.\n"); 856287873Sdelphij goto fetchfail; 857287873Sdelphij } 858287873Sdelphij 859287873Sdelphij if (verify_signature(fd_pkg, fd_sig) == false) 860287873Sdelphij goto cleanup; 861287873Sdelphij } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 862287873Sdelphij 863287873Sdelphij snprintf(tmpsig, MAXPATHLEN, 864287873Sdelphij "%s/pkg.txz.pubkeysig.XXXXXX", 865287873Sdelphij getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 866287873Sdelphij snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", 867287873Sdelphij packagesite); 868287873Sdelphij 869287873Sdelphij if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 870287873Sdelphij fprintf(stderr, "Signature for pkg not " 871287873Sdelphij "available.\n"); 872287873Sdelphij goto fetchfail; 873287873Sdelphij } 874287873Sdelphij 875287873Sdelphij if (verify_pubsignature(fd_pkg, fd_sig) == false) 876287873Sdelphij goto cleanup; 877287873Sdelphij } else { 878287147Sdelphij warnx("Signature type %s is not supported for " 879287147Sdelphij "bootstrapping.", signature_type); 880287147Sdelphij goto cleanup; 881287147Sdelphij } 882235112Sbapt } 883235112Sbapt 884263038Sbapt if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 885263038Sbapt ret = install_pkg_static(pkgstatic, tmppkg, force); 886263038Sbapt 887235112Sbapt goto cleanup; 888235112Sbapt 889235112Sbaptfetchfail: 890235112Sbapt warnx("Error fetching %s: %s", url, fetchLastErrString); 891263038Sbapt fprintf(stderr, "A pre-built version of pkg could not be found for " 892263038Sbapt "your system.\n"); 893263038Sbapt fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 894263038Sbapt "ports: 'ports-mgmt/pkg'.\n"); 895235112Sbapt 896234313Sbaptcleanup: 897263038Sbapt if (fd_sig != -1) { 898263038Sbapt close(fd_sig); 899263038Sbapt unlink(tmpsig); 900263038Sbapt } 901263038Sbapt close(fd_pkg); 902234313Sbapt unlink(tmppkg); 903234313Sbapt 904235112Sbapt return (ret); 905234313Sbapt} 906234313Sbapt 907238829Sbaptstatic const char confirmation_message[] = 908238829Sbapt"The package management tool is not yet installed on your system.\n" 909238829Sbapt"Do you want to fetch and install it now? [y/N]: "; 910238829Sbapt 911263038Sbaptstatic const char non_interactive_message[] = 912263038Sbapt"The package management tool is not yet installed on your system.\n" 913263038Sbapt"Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " 914263038Sbapt"in non-interactive (stdin not being a tty)\n"; 915263038Sbapt 916238829Sbaptstatic int 917238829Sbaptpkg_query_yes_no(void) 918238829Sbapt{ 919238829Sbapt int ret, c; 920238829Sbapt 921238829Sbapt c = getchar(); 922238829Sbapt 923238829Sbapt if (c == 'y' || c == 'Y') 924238829Sbapt ret = 1; 925238829Sbapt else 926238829Sbapt ret = 0; 927238829Sbapt 928238829Sbapt while (c != '\n' && c != EOF) 929238829Sbapt c = getchar(); 930238829Sbapt 931238829Sbapt return (ret); 932238829Sbapt} 933238829Sbapt 934263038Sbaptstatic int 935263038Sbaptbootstrap_pkg_local(const char *pkgpath, bool force) 936263038Sbapt{ 937263038Sbapt char path[MAXPATHLEN]; 938263038Sbapt char pkgstatic[MAXPATHLEN]; 939263038Sbapt const char *signature_type; 940263038Sbapt int fd_pkg, fd_sig, ret; 941263038Sbapt 942263038Sbapt fd_sig = -1; 943263038Sbapt ret = -1; 944263038Sbapt 945263038Sbapt fd_pkg = open(pkgpath, O_RDONLY); 946263038Sbapt if (fd_pkg == -1) 947263038Sbapt err(EXIT_FAILURE, "Unable to open %s", pkgpath); 948263038Sbapt 949263038Sbapt if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 950263038Sbapt warnx("Error looking up SIGNATURE_TYPE"); 951263038Sbapt return (-1); 952263038Sbapt } 953263038Sbapt if (signature_type != NULL && 954287147Sdelphij strcasecmp(signature_type, "NONE") != 0) { 955287873Sdelphij if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { 956287873Sdelphij 957287873Sdelphij snprintf(path, sizeof(path), "%s.sig", pkgpath); 958287873Sdelphij 959287873Sdelphij if ((fd_sig = open(path, O_RDONLY)) == -1) { 960287873Sdelphij fprintf(stderr, "Signature for pkg not " 961287873Sdelphij "available.\n"); 962287873Sdelphij goto cleanup; 963287873Sdelphij } 964287873Sdelphij 965287873Sdelphij if (verify_signature(fd_pkg, fd_sig) == false) 966287873Sdelphij goto cleanup; 967287873Sdelphij 968287873Sdelphij } else if (strcasecmp(signature_type, "PUBKEY") == 0) { 969287873Sdelphij 970287873Sdelphij snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); 971287873Sdelphij 972287873Sdelphij if ((fd_sig = open(path, O_RDONLY)) == -1) { 973287873Sdelphij fprintf(stderr, "Signature for pkg not " 974287873Sdelphij "available.\n"); 975287873Sdelphij goto cleanup; 976287873Sdelphij } 977287873Sdelphij 978287873Sdelphij if (verify_pubsignature(fd_pkg, fd_sig) == false) 979287873Sdelphij goto cleanup; 980287873Sdelphij 981287873Sdelphij } else { 982287147Sdelphij warnx("Signature type %s is not supported for " 983287147Sdelphij "bootstrapping.", signature_type); 984287147Sdelphij goto cleanup; 985287147Sdelphij } 986263038Sbapt } 987263038Sbapt 988263038Sbapt if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 989263038Sbapt ret = install_pkg_static(pkgstatic, pkgpath, force); 990263038Sbapt 991263038Sbaptcleanup: 992263038Sbapt close(fd_pkg); 993263038Sbapt if (fd_sig != -1) 994263038Sbapt close(fd_sig); 995263038Sbapt 996263038Sbapt return (ret); 997263038Sbapt} 998263038Sbapt 999234313Sbaptint 1000263038Sbaptmain(int argc, char *argv[]) 1001234313Sbapt{ 1002234313Sbapt char pkgpath[MAXPATHLEN]; 1003263038Sbapt const char *pkgarg; 1004263038Sbapt bool bootstrap_only, force, yes; 1005234313Sbapt 1006263038Sbapt bootstrap_only = false; 1007263038Sbapt force = false; 1008263038Sbapt pkgarg = NULL; 1009263038Sbapt yes = false; 1010263038Sbapt 1011234313Sbapt snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 1012235112Sbapt getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 1013234313Sbapt 1014263038Sbapt if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 1015263038Sbapt bootstrap_only = true; 1016263038Sbapt if (argc == 3 && strcmp(argv[2], "-f") == 0) 1017263038Sbapt force = true; 1018263038Sbapt } 1019263038Sbapt 1020263038Sbapt if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 1021245451Sbapt /* 1022245451Sbapt * To allow 'pkg -N' to be used as a reliable test for whether 1023245451Sbapt * a system is configured to use pkg, don't bootstrap pkg 1024245451Sbapt * when that argument is given as argv[1]. 1025245451Sbapt */ 1026245451Sbapt if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 1027245451Sbapt errx(EXIT_FAILURE, "pkg is not installed"); 1028245451Sbapt 1029263038Sbapt config_init(); 1030263038Sbapt 1031263038Sbapt if (argc > 1 && strcmp(argv[1], "add") == 0) { 1032263038Sbapt if (argc > 2 && strcmp(argv[2], "-f") == 0) { 1033263038Sbapt force = true; 1034263038Sbapt pkgarg = argv[3]; 1035263038Sbapt } else 1036263038Sbapt pkgarg = argv[2]; 1037263038Sbapt if (pkgarg == NULL) { 1038263038Sbapt fprintf(stderr, "Path to pkg.txz required\n"); 1039263038Sbapt exit(EXIT_FAILURE); 1040263038Sbapt } 1041263038Sbapt if (access(pkgarg, R_OK) == -1) { 1042263038Sbapt fprintf(stderr, "No such file: %s\n", pkgarg); 1043263038Sbapt exit(EXIT_FAILURE); 1044263038Sbapt } 1045263038Sbapt if (bootstrap_pkg_local(pkgarg, force) != 0) 1046263038Sbapt exit(EXIT_FAILURE); 1047263038Sbapt exit(EXIT_SUCCESS); 1048263038Sbapt } 1049238829Sbapt /* 1050238829Sbapt * Do not ask for confirmation if either of stdin or stdout is 1051238829Sbapt * not tty. Check the environment to see if user has answer 1052238829Sbapt * tucked in there already. 1053238829Sbapt */ 1054263038Sbapt config_bool(ASSUME_ALWAYS_YES, &yes); 1055263038Sbapt if (!yes) { 1056263038Sbapt if (!isatty(fileno(stdin))) { 1057263038Sbapt fprintf(stderr, non_interactive_message); 1058240290Sbapt exit(EXIT_FAILURE); 1059263038Sbapt } 1060240290Sbapt 1061263038Sbapt printf("%s", confirmation_message); 1062238829Sbapt if (pkg_query_yes_no() == 0) 1063238829Sbapt exit(EXIT_FAILURE); 1064238829Sbapt } 1065263038Sbapt if (bootstrap_pkg(force) != 0) 1066235112Sbapt exit(EXIT_FAILURE); 1067263038Sbapt config_finish(); 1068263038Sbapt 1069263038Sbapt if (bootstrap_only) 1070263038Sbapt exit(EXIT_SUCCESS); 1071263038Sbapt } else if (bootstrap_only) { 1072263038Sbapt printf("pkg already bootstrapped at %s\n", pkgpath); 1073263038Sbapt exit(EXIT_SUCCESS); 1074238829Sbapt } 1075234313Sbapt 1076234313Sbapt execv(pkgpath, argv); 1077234313Sbapt 1078235112Sbapt /* NOT REACHED */ 1079235112Sbapt return (EXIT_FAILURE); 1080234313Sbapt} 1081