pkg.c revision 258126
1234313Sbapt/*- 2247841Sbapt * Copyright (c) 2012-2013 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 258126 2013-11-14 09:26:52Z glebius $"); 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> 52257353Sbdrewery#include <yaml.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 * 274257353Sbdreweryparse_fingerprint(yaml_document_t *doc, yaml_node_t *node) 275257353Sbdrewery{ 276257353Sbdrewery yaml_node_pair_t *pair; 277257353Sbdrewery yaml_char_t *function, *fp; 278257353Sbdrewery struct fingerprint *f; 279257353Sbdrewery hash_t fct = HASH_UNKNOWN; 280257353Sbdrewery 281257353Sbdrewery function = fp = NULL; 282257353Sbdrewery 283257353Sbdrewery pair = node->data.mapping.pairs.start; 284257353Sbdrewery while (pair < node->data.mapping.pairs.top) { 285257353Sbdrewery yaml_node_t *key = yaml_document_get_node(doc, pair->key); 286257353Sbdrewery yaml_node_t *val = yaml_document_get_node(doc, pair->value); 287257353Sbdrewery 288257353Sbdrewery if (key->data.scalar.length <= 0) { 289257353Sbdrewery ++pair; 290257353Sbdrewery continue; 291257353Sbdrewery } 292257353Sbdrewery 293257353Sbdrewery if (val->type != YAML_SCALAR_NODE) { 294257353Sbdrewery ++pair; 295257353Sbdrewery continue; 296257353Sbdrewery } 297257353Sbdrewery 298257353Sbdrewery if (strcasecmp(key->data.scalar.value, "function") == 0) 299257353Sbdrewery function = val->data.scalar.value; 300257353Sbdrewery else if (strcasecmp(key->data.scalar.value, "fingerprint") 301257353Sbdrewery == 0) 302257353Sbdrewery fp = val->data.scalar.value; 303257353Sbdrewery 304257353Sbdrewery ++pair; 305257353Sbdrewery continue; 306257353Sbdrewery } 307257353Sbdrewery 308257353Sbdrewery if (fp == NULL || function == NULL) 309257353Sbdrewery return (NULL); 310257353Sbdrewery 311257353Sbdrewery if (strcasecmp(function, "sha256") == 0) 312257353Sbdrewery fct = HASH_SHA256; 313257353Sbdrewery 314257353Sbdrewery if (fct == HASH_UNKNOWN) { 315257353Sbdrewery fprintf(stderr, "Unsupported hashing function: %s\n", function); 316257353Sbdrewery return (NULL); 317257353Sbdrewery } 318257353Sbdrewery 319257353Sbdrewery f = calloc(1, sizeof(struct fingerprint)); 320257353Sbdrewery f->type = fct; 321257353Sbdrewery strlcpy(f->hash, fp, sizeof(f->hash)); 322257353Sbdrewery 323257353Sbdrewery return (f); 324257353Sbdrewery} 325257353Sbdrewery 326257353Sbdrewerystatic void 327257353Sbdreweryfree_fingerprint_list(struct fingerprint_list* list) 328257353Sbdrewery{ 329258126Sglebius struct fingerprint *fingerprint, *tmp; 330257353Sbdrewery 331258126Sglebius STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { 332257353Sbdrewery if (fingerprint->name) 333257353Sbdrewery free(fingerprint->name); 334257353Sbdrewery free(fingerprint); 335257353Sbdrewery } 336257353Sbdrewery free(list); 337257353Sbdrewery} 338257353Sbdrewery 339257353Sbdrewerystatic struct fingerprint * 340257353Sbdreweryload_fingerprint(const char *dir, const char *filename) 341257353Sbdrewery{ 342257353Sbdrewery yaml_parser_t parser; 343257353Sbdrewery yaml_document_t doc; 344257353Sbdrewery yaml_node_t *node; 345257353Sbdrewery FILE *fp; 346257353Sbdrewery struct fingerprint *f; 347257353Sbdrewery char path[MAXPATHLEN]; 348257353Sbdrewery 349257353Sbdrewery f = NULL; 350257353Sbdrewery 351257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); 352257353Sbdrewery 353257353Sbdrewery if ((fp = fopen(path, "r")) == NULL) 354257353Sbdrewery return (NULL); 355257353Sbdrewery 356257353Sbdrewery yaml_parser_initialize(&parser); 357257353Sbdrewery yaml_parser_set_input_file(&parser, fp); 358257353Sbdrewery yaml_parser_load(&parser, &doc); 359257353Sbdrewery 360257353Sbdrewery node = yaml_document_get_root_node(&doc); 361257353Sbdrewery if (node == NULL || node->type != YAML_MAPPING_NODE) 362257353Sbdrewery goto out; 363257353Sbdrewery 364257353Sbdrewery f = parse_fingerprint(&doc, node); 365257353Sbdrewery f->name = strdup(filename); 366257353Sbdrewery 367257353Sbdreweryout: 368257353Sbdrewery yaml_document_delete(&doc); 369257353Sbdrewery yaml_parser_delete(&parser); 370257353Sbdrewery fclose(fp); 371257353Sbdrewery 372257353Sbdrewery return (f); 373257353Sbdrewery} 374257353Sbdrewery 375257353Sbdrewerystatic struct fingerprint_list * 376257353Sbdreweryload_fingerprints(const char *path, int *count) 377257353Sbdrewery{ 378257353Sbdrewery DIR *d; 379257353Sbdrewery struct dirent *ent; 380257353Sbdrewery struct fingerprint *finger; 381257353Sbdrewery struct fingerprint_list *fingerprints; 382257353Sbdrewery 383257353Sbdrewery *count = 0; 384257353Sbdrewery 385257353Sbdrewery fingerprints = calloc(1, sizeof(struct fingerprint_list)); 386257353Sbdrewery if (fingerprints == NULL) 387257353Sbdrewery return (NULL); 388257353Sbdrewery STAILQ_INIT(fingerprints); 389257353Sbdrewery 390257353Sbdrewery if ((d = opendir(path)) == NULL) 391257353Sbdrewery return (NULL); 392257353Sbdrewery 393257353Sbdrewery while ((ent = readdir(d))) { 394257353Sbdrewery if (strcmp(ent->d_name, ".") == 0 || 395257353Sbdrewery strcmp(ent->d_name, "..") == 0) 396257353Sbdrewery continue; 397257353Sbdrewery finger = load_fingerprint(path, ent->d_name); 398257353Sbdrewery if (finger != NULL) { 399257353Sbdrewery STAILQ_INSERT_TAIL(fingerprints, finger, next); 400257353Sbdrewery ++(*count); 401257353Sbdrewery } 402257353Sbdrewery } 403257353Sbdrewery 404257353Sbdrewery closedir(d); 405257353Sbdrewery 406257353Sbdrewery return (fingerprints); 407257353Sbdrewery} 408257353Sbdrewery 409257353Sbdrewerystatic void 410257353Sbdrewerysha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], 411257353Sbdrewery char out[SHA256_DIGEST_LENGTH * 2 + 1]) 412257353Sbdrewery{ 413257353Sbdrewery int i; 414257353Sbdrewery 415257353Sbdrewery for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 416257353Sbdrewery sprintf(out + (i * 2), "%02x", hash[i]); 417257353Sbdrewery 418257353Sbdrewery out[SHA256_DIGEST_LENGTH * 2] = '\0'; 419257353Sbdrewery} 420257353Sbdrewery 421257353Sbdrewerystatic void 422257353Sbdrewerysha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 423257353Sbdrewery{ 424257353Sbdrewery unsigned char hash[SHA256_DIGEST_LENGTH]; 425257353Sbdrewery SHA256_CTX sha256; 426257353Sbdrewery 427257353Sbdrewery out[0] = '\0'; 428257353Sbdrewery 429257353Sbdrewery SHA256_Init(&sha256); 430257353Sbdrewery SHA256_Update(&sha256, buf, len); 431257353Sbdrewery SHA256_Final(hash, &sha256); 432257353Sbdrewery sha256_hash(hash, out); 433257353Sbdrewery} 434257353Sbdrewery 435257353Sbdrewerystatic int 436257353Sbdrewerysha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) 437257353Sbdrewery{ 438257353Sbdrewery int my_fd; 439257353Sbdrewery FILE *fp; 440257353Sbdrewery char buffer[BUFSIZ]; 441257353Sbdrewery unsigned char hash[SHA256_DIGEST_LENGTH]; 442257353Sbdrewery size_t r; 443257353Sbdrewery int ret; 444257353Sbdrewery SHA256_CTX sha256; 445257353Sbdrewery 446257353Sbdrewery my_fd = -1; 447257353Sbdrewery fp = NULL; 448257353Sbdrewery r = 0; 449257353Sbdrewery ret = 1; 450257353Sbdrewery 451257353Sbdrewery out[0] = '\0'; 452257353Sbdrewery 453257353Sbdrewery /* Duplicate the fd so that fclose(3) does not close it. */ 454257353Sbdrewery if ((my_fd = dup(fd)) == -1) { 455257353Sbdrewery warnx("dup"); 456257353Sbdrewery goto cleanup; 457257353Sbdrewery } 458257353Sbdrewery 459257353Sbdrewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 460257353Sbdrewery warnx("fdopen"); 461257353Sbdrewery goto cleanup; 462257353Sbdrewery } 463257353Sbdrewery 464257353Sbdrewery SHA256_Init(&sha256); 465257353Sbdrewery 466257353Sbdrewery while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) 467257353Sbdrewery SHA256_Update(&sha256, buffer, r); 468257353Sbdrewery 469257353Sbdrewery if (ferror(fp) != 0) { 470257353Sbdrewery warnx("fread"); 471257353Sbdrewery goto cleanup; 472257353Sbdrewery } 473257353Sbdrewery 474257353Sbdrewery SHA256_Final(hash, &sha256); 475257353Sbdrewery sha256_hash(hash, out); 476257353Sbdrewery ret = 0; 477257353Sbdrewery 478257353Sbdrewerycleanup: 479257353Sbdrewery if (fp != NULL) 480257353Sbdrewery fclose(fp); 481257353Sbdrewery else if (my_fd != -1) 482257353Sbdrewery close(my_fd); 483257353Sbdrewery (void)lseek(fd, 0, SEEK_SET); 484257353Sbdrewery 485257353Sbdrewery return (ret); 486257353Sbdrewery} 487257353Sbdrewery 488257353Sbdrewerystatic EVP_PKEY * 489257353Sbdreweryload_public_key_buf(const unsigned char *cert, int certlen) 490257353Sbdrewery{ 491257353Sbdrewery EVP_PKEY *pkey; 492257353Sbdrewery BIO *bp; 493257353Sbdrewery char errbuf[1024]; 494257353Sbdrewery 495257353Sbdrewery bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); 496257353Sbdrewery 497257353Sbdrewery if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) 498257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 499257353Sbdrewery 500257353Sbdrewery BIO_free(bp); 501257353Sbdrewery 502257353Sbdrewery return (pkey); 503257353Sbdrewery} 504257353Sbdrewery 505257353Sbdrewerystatic bool 506257353Sbdreweryrsa_verify_cert(int fd, const unsigned char *key, int keylen, 507257353Sbdrewery unsigned char *sig, int siglen) 508257353Sbdrewery{ 509257353Sbdrewery EVP_MD_CTX *mdctx; 510257353Sbdrewery EVP_PKEY *pkey; 511257353Sbdrewery char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; 512257353Sbdrewery char errbuf[1024]; 513257353Sbdrewery bool ret; 514257353Sbdrewery 515257353Sbdrewery pkey = NULL; 516257353Sbdrewery mdctx = NULL; 517257353Sbdrewery ret = false; 518257353Sbdrewery 519257353Sbdrewery /* Compute SHA256 of the package. */ 520257353Sbdrewery if (lseek(fd, 0, 0) == -1) { 521257353Sbdrewery warn("lseek"); 522257353Sbdrewery goto cleanup; 523257353Sbdrewery } 524257353Sbdrewery if ((sha256_fd(fd, sha256)) == -1) { 525257353Sbdrewery warnx("Error creating SHA256 hash for package"); 526257353Sbdrewery goto cleanup; 527257353Sbdrewery } 528257353Sbdrewery 529257353Sbdrewery if ((pkey = load_public_key_buf(key, keylen)) == NULL) { 530257353Sbdrewery warnx("Error reading public key"); 531257353Sbdrewery goto cleanup; 532257353Sbdrewery } 533257353Sbdrewery 534257353Sbdrewery /* Verify signature of the SHA256(pkg) is valid. */ 535257353Sbdrewery if ((mdctx = EVP_MD_CTX_create()) == NULL) { 536257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 537257353Sbdrewery goto error; 538257353Sbdrewery } 539257353Sbdrewery 540257353Sbdrewery if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { 541257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 542257353Sbdrewery goto error; 543257353Sbdrewery } 544257353Sbdrewery if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { 545257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 546257353Sbdrewery goto error; 547257353Sbdrewery } 548257353Sbdrewery 549257353Sbdrewery if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { 550257353Sbdrewery warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); 551257353Sbdrewery goto error; 552257353Sbdrewery } 553257353Sbdrewery 554257353Sbdrewery ret = true; 555257353Sbdrewery printf("done\n"); 556257353Sbdrewery goto cleanup; 557257353Sbdrewery 558257353Sbdreweryerror: 559257353Sbdrewery printf("failed\n"); 560257353Sbdrewery 561257353Sbdrewerycleanup: 562257353Sbdrewery if (pkey) 563257353Sbdrewery EVP_PKEY_free(pkey); 564257353Sbdrewery if (mdctx) 565257353Sbdrewery EVP_MD_CTX_destroy(mdctx); 566257353Sbdrewery ERR_free_strings(); 567257353Sbdrewery 568257353Sbdrewery return (ret); 569257353Sbdrewery} 570257353Sbdrewery 571257353Sbdrewerystatic struct sig_cert * 572257353Sbdreweryparse_cert(int fd) { 573257353Sbdrewery int my_fd; 574257353Sbdrewery struct sig_cert *sc; 575257353Sbdrewery FILE *fp; 576257353Sbdrewery struct sbuf *buf, *sig, *cert; 577257353Sbdrewery char *line; 578257353Sbdrewery size_t linecap; 579257353Sbdrewery ssize_t linelen; 580257353Sbdrewery 581257353Sbdrewery buf = NULL; 582257353Sbdrewery my_fd = -1; 583257353Sbdrewery sc = NULL; 584257353Sbdrewery line = NULL; 585257353Sbdrewery linecap = 0; 586257353Sbdrewery 587257353Sbdrewery if (lseek(fd, 0, 0) == -1) { 588257353Sbdrewery warn("lseek"); 589257353Sbdrewery return (NULL); 590257353Sbdrewery } 591257353Sbdrewery 592257353Sbdrewery /* Duplicate the fd so that fclose(3) does not close it. */ 593257353Sbdrewery if ((my_fd = dup(fd)) == -1) { 594257353Sbdrewery warnx("dup"); 595257353Sbdrewery return (NULL); 596257353Sbdrewery } 597257353Sbdrewery 598257353Sbdrewery if ((fp = fdopen(my_fd, "rb")) == NULL) { 599257353Sbdrewery warn("fdopen"); 600257353Sbdrewery close(my_fd); 601257353Sbdrewery return (NULL); 602257353Sbdrewery } 603257353Sbdrewery 604257353Sbdrewery sig = sbuf_new_auto(); 605257353Sbdrewery cert = sbuf_new_auto(); 606257353Sbdrewery 607257353Sbdrewery while ((linelen = getline(&line, &linecap, fp)) > 0) { 608257353Sbdrewery if (strcmp(line, "SIGNATURE\n") == 0) { 609257353Sbdrewery buf = sig; 610257353Sbdrewery continue; 611257353Sbdrewery } else if (strcmp(line, "CERT\n") == 0) { 612257353Sbdrewery buf = cert; 613257353Sbdrewery continue; 614257353Sbdrewery } else if (strcmp(line, "END\n") == 0) { 615257353Sbdrewery break; 616257353Sbdrewery } 617257353Sbdrewery if (buf != NULL) 618257353Sbdrewery sbuf_bcat(buf, line, linelen); 619257353Sbdrewery } 620257353Sbdrewery 621257353Sbdrewery fclose(fp); 622257353Sbdrewery 623257353Sbdrewery /* Trim out unrelated trailing newline */ 624257353Sbdrewery sbuf_setpos(sig, sbuf_len(sig) - 1); 625257353Sbdrewery 626257353Sbdrewery sbuf_finish(sig); 627257353Sbdrewery sbuf_finish(cert); 628257353Sbdrewery 629257353Sbdrewery sc = calloc(1, sizeof(struct sig_cert)); 630257353Sbdrewery sc->siglen = sbuf_len(sig); 631257353Sbdrewery sc->sig = calloc(1, sc->siglen); 632257353Sbdrewery memcpy(sc->sig, sbuf_data(sig), sc->siglen); 633257353Sbdrewery 634257353Sbdrewery sc->certlen = sbuf_len(cert); 635257353Sbdrewery sc->cert = strdup(sbuf_data(cert)); 636257353Sbdrewery 637257353Sbdrewery sbuf_delete(sig); 638257353Sbdrewery sbuf_delete(cert); 639257353Sbdrewery 640257353Sbdrewery return (sc); 641257353Sbdrewery} 642257353Sbdrewery 643257353Sbdrewerystatic bool 644257353Sbdreweryverify_signature(int fd_pkg, int fd_sig) 645257353Sbdrewery{ 646257353Sbdrewery struct fingerprint_list *trusted, *revoked; 647257353Sbdrewery struct fingerprint *fingerprint; 648257353Sbdrewery struct sig_cert *sc; 649257353Sbdrewery bool ret; 650257353Sbdrewery int trusted_count, revoked_count; 651257353Sbdrewery const char *fingerprints; 652257353Sbdrewery char path[MAXPATHLEN]; 653257353Sbdrewery char hash[SHA256_DIGEST_LENGTH * 2 + 1]; 654257353Sbdrewery 655257353Sbdrewery sc = NULL; 656257353Sbdrewery trusted = revoked = NULL; 657257353Sbdrewery ret = false; 658257353Sbdrewery 659257353Sbdrewery /* Read and parse fingerprints. */ 660257353Sbdrewery if (config_string(FINGERPRINTS, &fingerprints) != 0) { 661257353Sbdrewery warnx("No CONFIG_FINGERPRINTS defined"); 662257353Sbdrewery goto cleanup; 663257353Sbdrewery } 664257353Sbdrewery 665257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); 666257353Sbdrewery if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { 667257353Sbdrewery warnx("Error loading trusted certificates"); 668257353Sbdrewery goto cleanup; 669257353Sbdrewery } 670257353Sbdrewery 671257353Sbdrewery if (trusted_count == 0 || trusted == NULL) { 672257353Sbdrewery fprintf(stderr, "No trusted certificates found.\n"); 673257353Sbdrewery goto cleanup; 674257353Sbdrewery } 675257353Sbdrewery 676257353Sbdrewery snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); 677257353Sbdrewery if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { 678257353Sbdrewery warnx("Error loading revoked certificates"); 679257353Sbdrewery goto cleanup; 680257353Sbdrewery } 681257353Sbdrewery 682257353Sbdrewery /* Read certificate and signature in. */ 683257353Sbdrewery if ((sc = parse_cert(fd_sig)) == NULL) { 684257353Sbdrewery warnx("Error parsing certificate"); 685257353Sbdrewery goto cleanup; 686257353Sbdrewery } 687257353Sbdrewery /* Explicitly mark as non-trusted until proven otherwise. */ 688257353Sbdrewery sc->trusted = false; 689257353Sbdrewery 690257353Sbdrewery /* Parse signature and pubkey out of the certificate */ 691257353Sbdrewery sha256_buf(sc->cert, sc->certlen, hash); 692257353Sbdrewery 693257353Sbdrewery /* Check if this hash is revoked */ 694257353Sbdrewery if (revoked != NULL) { 695257353Sbdrewery STAILQ_FOREACH(fingerprint, revoked, next) { 696257353Sbdrewery if (strcasecmp(fingerprint->hash, hash) == 0) { 697257353Sbdrewery fprintf(stderr, "The package was signed with " 698257353Sbdrewery "revoked certificate %s\n", 699257353Sbdrewery fingerprint->name); 700257353Sbdrewery goto cleanup; 701257353Sbdrewery } 702257353Sbdrewery } 703257353Sbdrewery } 704257353Sbdrewery 705257353Sbdrewery STAILQ_FOREACH(fingerprint, trusted, next) { 706257353Sbdrewery if (strcasecmp(fingerprint->hash, hash) == 0) { 707257353Sbdrewery sc->trusted = true; 708257353Sbdrewery sc->name = strdup(fingerprint->name); 709257353Sbdrewery break; 710257353Sbdrewery } 711257353Sbdrewery } 712257353Sbdrewery 713257353Sbdrewery if (sc->trusted == false) { 714257353Sbdrewery fprintf(stderr, "No trusted fingerprint found matching " 715257353Sbdrewery "package's certificate\n"); 716257353Sbdrewery goto cleanup; 717257353Sbdrewery } 718257353Sbdrewery 719257353Sbdrewery /* Verify the signature. */ 720257353Sbdrewery printf("Verifying signature with trusted certificate %s... ", sc->name); 721257353Sbdrewery if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig, 722257353Sbdrewery sc->siglen) == false) { 723257353Sbdrewery fprintf(stderr, "Signature is not valid\n"); 724257353Sbdrewery goto cleanup; 725257353Sbdrewery } 726257353Sbdrewery 727257353Sbdrewery ret = true; 728257353Sbdrewery 729257353Sbdrewerycleanup: 730257353Sbdrewery if (trusted) 731257353Sbdrewery free_fingerprint_list(trusted); 732257353Sbdrewery if (revoked) 733257353Sbdrewery free_fingerprint_list(revoked); 734257353Sbdrewery if (sc) { 735257353Sbdrewery if (sc->cert) 736257353Sbdrewery free(sc->cert); 737257353Sbdrewery if (sc->sig) 738257353Sbdrewery free(sc->sig); 739257353Sbdrewery if (sc->name) 740257353Sbdrewery free(sc->name); 741257353Sbdrewery free(sc); 742257353Sbdrewery } 743257353Sbdrewery 744257353Sbdrewery return (ret); 745257353Sbdrewery} 746257353Sbdrewery 747257353Sbdrewerystatic int 748257632Sbdrewerybootstrap_pkg(bool force) 749257353Sbdrewery{ 750257353Sbdrewery FILE *config; 751257353Sbdrewery int fd_pkg, fd_sig; 752257353Sbdrewery int ret; 753257353Sbdrewery char *site; 754257353Sbdrewery char url[MAXPATHLEN]; 755257353Sbdrewery char conf[MAXPATHLEN]; 756257353Sbdrewery char tmppkg[MAXPATHLEN]; 757257353Sbdrewery char tmpsig[MAXPATHLEN]; 758257353Sbdrewery const char *packagesite; 759257353Sbdrewery const char *signature_type; 760257353Sbdrewery char pkgstatic[MAXPATHLEN]; 761257353Sbdrewery 762257353Sbdrewery fd_sig = -1; 763257353Sbdrewery ret = -1; 764257353Sbdrewery config = NULL; 765257353Sbdrewery 766257353Sbdrewery if (config_string(PACKAGESITE, &packagesite) != 0) { 767257353Sbdrewery warnx("No PACKAGESITE defined"); 768257353Sbdrewery return (-1); 769257353Sbdrewery } 770257353Sbdrewery 771257353Sbdrewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 772257353Sbdrewery warnx("Error looking up SIGNATURE_TYPE"); 773257353Sbdrewery return (-1); 774257353Sbdrewery } 775257353Sbdrewery 776257353Sbdrewery printf("Bootstrapping pkg from %s, please wait...\n", packagesite); 777257353Sbdrewery 778257353Sbdrewery /* Support pkg+http:// for PACKAGESITE which is the new format 779257353Sbdrewery in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has 780257353Sbdrewery no A record. */ 781257353Sbdrewery if (strncmp(URL_SCHEME_PREFIX, packagesite, 782257353Sbdrewery strlen(URL_SCHEME_PREFIX)) == 0) 783257353Sbdrewery packagesite += strlen(URL_SCHEME_PREFIX); 784257353Sbdrewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); 785257353Sbdrewery 786257353Sbdrewery snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", 787257353Sbdrewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 788257353Sbdrewery 789257353Sbdrewery if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) 790257353Sbdrewery goto fetchfail; 791257353Sbdrewery 792257353Sbdrewery if (signature_type != NULL && 793257353Sbdrewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 794257353Sbdrewery snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", 795257353Sbdrewery getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); 796257353Sbdrewery snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", 797257353Sbdrewery packagesite); 798257353Sbdrewery 799257353Sbdrewery if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { 800257353Sbdrewery fprintf(stderr, "Signature for pkg not available.\n"); 801257353Sbdrewery goto fetchfail; 802257353Sbdrewery } 803257353Sbdrewery 804257353Sbdrewery if (verify_signature(fd_pkg, fd_sig) == false) 805257353Sbdrewery goto cleanup; 806257353Sbdrewery } 807257353Sbdrewery 808257353Sbdrewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 809257632Sbdrewery ret = install_pkg_static(pkgstatic, tmppkg, force); 810234313Sbapt 811234870Sbapt snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf", 812234870Sbapt getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 813234870Sbapt 814234870Sbapt if (access(conf, R_OK) == -1) { 815234870Sbapt site = strrchr(url, '/'); 816234870Sbapt if (site == NULL) 817234870Sbapt goto cleanup; 818234870Sbapt site[0] = '\0'; 819234870Sbapt site = strrchr(url, '/'); 820234870Sbapt if (site == NULL) 821234870Sbapt goto cleanup; 822234870Sbapt site[0] = '\0'; 823234870Sbapt 824234870Sbapt config = fopen(conf, "w+"); 825234870Sbapt if (config == NULL) 826234870Sbapt goto cleanup; 827235726Sbapt fprintf(config, "packagesite: %s\n", url); 828234870Sbapt fclose(config); 829234870Sbapt } 830234870Sbapt 831234351Sbapt goto cleanup; 832234351Sbapt 833234351Sbaptfetchfail: 834234351Sbapt warnx("Error fetching %s: %s", url, fetchLastErrString); 835257353Sbdrewery fprintf(stderr, "A pre-built version of pkg could not be found for " 836257353Sbdrewery "your system.\n"); 837257353Sbdrewery fprintf(stderr, "Consider changing PACKAGESITE or installing it from " 838257353Sbdrewery "ports: 'ports-mgmt/pkg'.\n"); 839234351Sbapt 840234313Sbaptcleanup: 841257353Sbdrewery if (fd_sig != -1) { 842257353Sbdrewery close(fd_sig); 843257353Sbdrewery unlink(tmpsig); 844257353Sbdrewery } 845257353Sbdrewery close(fd_pkg); 846234313Sbapt unlink(tmppkg); 847234313Sbapt 848234351Sbapt return (ret); 849234313Sbapt} 850234313Sbapt 851238461Skanstatic const char confirmation_message[] = 852238461Skan"The package management tool is not yet installed on your system.\n" 853238461Skan"Do you want to fetch and install it now? [y/N]: "; 854238461Skan 855238461Skanstatic int 856238461Skanpkg_query_yes_no(void) 857238461Skan{ 858238461Skan int ret, c; 859238461Skan 860238461Skan c = getchar(); 861238461Skan 862238461Skan if (c == 'y' || c == 'Y') 863238461Skan ret = 1; 864238461Skan else 865238461Skan ret = 0; 866238461Skan 867238461Skan while (c != '\n' && c != EOF) 868238461Skan c = getchar(); 869238461Skan 870238461Skan return (ret); 871238461Skan} 872238461Skan 873257353Sbdrewerystatic int 874257632Sbdrewerybootstrap_pkg_local(const char *pkgpath, bool force) 875257353Sbdrewery{ 876257353Sbdrewery char path[MAXPATHLEN]; 877257353Sbdrewery char pkgstatic[MAXPATHLEN]; 878257353Sbdrewery const char *signature_type; 879257353Sbdrewery int fd_pkg, fd_sig, ret; 880257353Sbdrewery 881257353Sbdrewery fd_sig = -1; 882257353Sbdrewery ret = -1; 883257353Sbdrewery 884257353Sbdrewery fd_pkg = open(pkgpath, O_RDONLY); 885257353Sbdrewery if (fd_pkg == -1) 886257353Sbdrewery err(EXIT_FAILURE, "Unable to open %s", pkgpath); 887257353Sbdrewery 888257353Sbdrewery if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { 889257353Sbdrewery warnx("Error looking up SIGNATURE_TYPE"); 890257353Sbdrewery return (-1); 891257353Sbdrewery } 892257353Sbdrewery if (signature_type != NULL && 893257353Sbdrewery strcasecmp(signature_type, "FINGERPRINTS") == 0) { 894257353Sbdrewery snprintf(path, sizeof(path), "%s.sig", pkgpath); 895257353Sbdrewery 896257353Sbdrewery if ((fd_sig = open(path, O_RDONLY)) == -1) { 897257353Sbdrewery fprintf(stderr, "Signature for pkg not available.\n"); 898257353Sbdrewery goto cleanup; 899257353Sbdrewery } 900257353Sbdrewery 901257353Sbdrewery if (verify_signature(fd_pkg, fd_sig) == false) 902257353Sbdrewery goto cleanup; 903257353Sbdrewery } 904257353Sbdrewery 905257353Sbdrewery if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) 906257632Sbdrewery ret = install_pkg_static(pkgstatic, pkgpath, force); 907257353Sbdrewery 908257353Sbdrewerycleanup: 909257353Sbdrewery close(fd_pkg); 910257353Sbdrewery if (fd_sig != -1) 911257353Sbdrewery close(fd_sig); 912257353Sbdrewery 913257353Sbdrewery return (ret); 914257353Sbdrewery} 915257353Sbdrewery 916234313Sbaptint 917234322Sbaptmain(__unused int argc, char *argv[]) 918234313Sbapt{ 919234313Sbapt char pkgpath[MAXPATHLEN]; 920257632Sbdrewery const char *pkgarg; 921257632Sbdrewery bool bootstrap_only, force, yes; 922234313Sbapt 923257632Sbdrewery bootstrap_only = false; 924257632Sbdrewery force = false; 925257632Sbdrewery pkgarg = NULL; 926257632Sbdrewery yes = false; 927257632Sbdrewery 928234313Sbapt snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", 929234322Sbapt getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); 930234313Sbapt 931257632Sbdrewery if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { 932257632Sbdrewery bootstrap_only = true; 933257632Sbdrewery if (argc == 3 && strcmp(argv[2], "-f") == 0) 934257632Sbdrewery force = true; 935257632Sbdrewery } 936257632Sbdrewery 937257632Sbdrewery if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { 938244553Smatthew /* 939244594Smatthew * To allow 'pkg -N' to be used as a reliable test for whether 940244553Smatthew * a system is configured to use pkg, don't bootstrap pkg 941244553Smatthew * when that argument is given as argv[1]. 942244553Smatthew */ 943244639Smatthew if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) 944244639Smatthew errx(EXIT_FAILURE, "pkg is not installed"); 945244553Smatthew 946257353Sbdrewery config_init(); 947257353Sbdrewery 948257632Sbdrewery if (argc > 1 && strcmp(argv[1], "add") == 0) { 949257632Sbdrewery if (argc > 2 && strcmp(argv[2], "-f") == 0) { 950257632Sbdrewery force = true; 951257632Sbdrewery pkgarg = argv[3]; 952257632Sbdrewery } else 953257632Sbdrewery pkgarg = argv[2]; 954257632Sbdrewery if (pkgarg == NULL) { 955257632Sbdrewery fprintf(stderr, "Path to pkg.txz required\n"); 956257309Sbapt exit(EXIT_FAILURE); 957257632Sbdrewery } 958257632Sbdrewery if (access(pkgarg, R_OK) == -1) { 959257632Sbdrewery fprintf(stderr, "No such file: %s\n", pkgarg); 960257632Sbdrewery exit(EXIT_FAILURE); 961257632Sbdrewery } 962257632Sbdrewery if (bootstrap_pkg_local(pkgarg, force) != 0) 963257632Sbdrewery exit(EXIT_FAILURE); 964257309Sbapt exit(EXIT_SUCCESS); 965257309Sbapt } 966238461Skan /* 967238461Skan * Do not ask for confirmation if either of stdin or stdout is 968238461Skan * not tty. Check the environment to see if user has answer 969238461Skan * tucked in there already. 970238461Skan */ 971247841Sbapt config_bool(ASSUME_ALWAYS_YES, &yes); 972247841Sbapt if (!yes) { 973238461Skan printf("%s", confirmation_message); 974239664Sbapt if (!isatty(fileno(stdin))) 975238461Skan exit(EXIT_FAILURE); 976239664Sbapt 977239664Sbapt if (pkg_query_yes_no() == 0) 978239663Sbapt exit(EXIT_FAILURE); 979238461Skan } 980257632Sbdrewery if (bootstrap_pkg(force) != 0) 981234351Sbapt exit(EXIT_FAILURE); 982247841Sbapt config_finish(); 983257571Sbdrewery 984257632Sbdrewery if (bootstrap_only) 985257571Sbdrewery exit(EXIT_SUCCESS); 986257632Sbdrewery } else if (bootstrap_only) { 987257632Sbdrewery printf("pkg already bootstrapped at %s\n", pkgpath); 988257632Sbdrewery exit(EXIT_SUCCESS); 989238461Skan } 990234313Sbapt 991234313Sbapt execv(pkgpath, argv); 992234313Sbapt 993234351Sbapt /* NOT REACHED */ 994234322Sbapt return (EXIT_FAILURE); 995234313Sbapt} 996