LCOV - code coverage report
Current view: top level - libpkg - pkg_repo.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 112 625 17.9 %
Date: 2015-08-15 Functions: 7 21 33.3 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
       5             :  * Copyright (c) 2012-2015 Matthew Seaman <matthew@FreeBSD.org>
       6             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       7             :  *
       8             :  * All rights reserved.
       9             :  * 
      10             :  * Redistribution and use in source and binary forms, with or without
      11             :  * modification, are permitted provided that the following conditions
      12             :  * are met:
      13             :  * 1. Redistributions of source code must retain the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer
      15             :  *    in this position and unchanged.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  * 
      20             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      21             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      22             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      23             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      24             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      25             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      29             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             :  */
      31             : 
      32             : #include <sys/types.h>
      33             : #include <sys/stat.h>
      34             : #include <sys/sysctl.h>
      35             : #include <sys/uio.h>
      36             : 
      37             : #include <archive_entry.h>
      38             : #include <assert.h>
      39             : #include <fts.h>
      40             : #include <libgen.h>
      41             : #include <sqlite3.h>
      42             : #include <string.h>
      43             : #include <dirent.h>
      44             : #define _WITH_GETLINE
      45             : #include <stdio.h>
      46             : #include <stdbool.h>
      47             : #include <sysexits.h>
      48             : #include <unistd.h>
      49             : #include <errno.h>
      50             : #include <sys/mman.h>
      51             : #include <fcntl.h>
      52             : 
      53             : #include "pkg.h"
      54             : #include "private/event.h"
      55             : #include "private/utils.h"
      56             : #include "private/pkg.h"
      57             : #include "private/pkgdb.h"
      58             : 
      59             : struct sig_cert {
      60             :         char name[MAXPATHLEN];
      61             :         char *sig;
      62             :         int64_t siglen;
      63             :         char *cert;
      64             :         int64_t certlen;
      65             :         bool cert_allocated;
      66             :         UT_hash_handle hh;
      67             :         bool trusted;
      68             : };
      69             : 
      70             : static int
      71          16 : pkg_repo_fetch_remote_tmp(struct pkg_repo *repo,
      72             :                 const char *filename, const char *extension, time_t *t, int *rc)
      73             : {
      74             :         char url[MAXPATHLEN];
      75             :         char tmp[MAXPATHLEN];
      76             :         int fd;
      77             :         const char *tmpdir, *dot;
      78             : 
      79             :         /*
      80             :          * XXX: here we support old naming scheme, such as filename.yaml
      81             :          */
      82          16 :         dot = strrchr(filename, '.');
      83          16 :         if (dot != NULL) {
      84           8 :                 snprintf(tmp, MIN(sizeof(tmp), dot - filename + 1), "%s", filename);
      85           8 :                 snprintf(url, sizeof(url), "%s/%s.%s", pkg_repo_url(repo), tmp,
      86             :                                 extension);
      87             :         }
      88             :         else {
      89           8 :                 snprintf(url, sizeof(url), "%s/%s.%s", pkg_repo_url(repo), filename,
      90             :                                 extension);
      91             :         }
      92             : 
      93          16 :         tmpdir = getenv("TMPDIR");
      94          16 :         if (tmpdir == NULL)
      95           0 :                 tmpdir = "/tmp";
      96          16 :         mkdirs(tmpdir);
      97          16 :         snprintf(tmp, sizeof(tmp), "%s/%s.%s.XXXXXX", tmpdir, filename, extension);
      98             : 
      99          16 :         fd = mkstemp(tmp);
     100          16 :         if (fd == -1) {
     101           0 :                 pkg_emit_error("Could not create temporary file %s, "
     102             :                     "aborting update.\n", tmp);
     103           0 :                 *rc = EPKG_FATAL;
     104           0 :                 return (-1);
     105             :         }
     106          16 :         (void)unlink(tmp);
     107             : 
     108          16 :         if ((*rc = pkg_fetch_file_to_fd(repo, url, fd, t, -1, 0)) != EPKG_OK) {
     109           2 :                 close(fd);
     110           2 :                 fd = -1;
     111             :         }
     112             : 
     113          16 :         return (fd);
     114             : }
     115             : 
     116             : static bool
     117           0 : pkg_repo_file_has_ext(const char *path, const char *ext)
     118             : {
     119             :         size_t n, l;
     120           0 :         const char *p = NULL;
     121             : 
     122           0 :         n = strlen(path);
     123           0 :         l = strlen(ext);
     124           0 :         p = &path[n - l];
     125             : 
     126           0 :         if (strcmp(p, ext) == 0)
     127           0 :                 return (true);
     128             : 
     129           0 :         return (false);
     130             : }
     131             : 
     132             : static bool
     133           0 : pkg_repo_check_fingerprint(struct pkg_repo *repo, struct sig_cert *sc, bool fatal)
     134             : {
     135           0 :         struct fingerprint *f = NULL;
     136             :         char *hash;
     137           0 :         int nbgood = 0;
     138           0 :         struct sig_cert *s = NULL, *stmp = NULL;
     139           0 :         struct pkg_repo_meta_key *mk = NULL;
     140             : 
     141           0 :         if (HASH_COUNT(sc) == 0) {
     142           0 :                 if (fatal)
     143           0 :                         pkg_emit_error("No signature found");
     144           0 :                 return (false);
     145             :         }
     146             : 
     147             :         /* load fingerprints */
     148           0 :         if (repo->trusted_fp == NULL) {
     149           0 :                 if (pkg_repo_load_fingerprints(repo) != EPKG_OK)
     150           0 :                         return (false);
     151             :         }
     152             : 
     153           0 :         HASH_ITER(hh, sc, s, stmp) {
     154           0 :                 if (s->sig != NULL && s->cert == NULL) {
     155             :                         /*
     156             :                          * We may want to check meta
     157             :                          */
     158           0 :                         if (repo->meta != NULL && repo->meta->keys != NULL)
     159           0 :                                 HASH_FIND_STR(repo->meta->keys, s->name, mk);
     160             : 
     161           0 :                         if (mk != NULL && mk->pubkey != NULL) {
     162           0 :                                 s->cert = mk->pubkey;
     163           0 :                                 s->certlen = strlen(mk->pubkey);
     164             :                         }
     165             :                         else {
     166           0 :                                 if (fatal)
     167           0 :                                         pkg_emit_error("No key with name %s has been found", s->name);
     168           0 :                                 return (false);
     169             :                         }
     170             :                 }
     171           0 :                 else if (s->sig == NULL) {
     172           0 :                         if (fatal)
     173           0 :                                 pkg_emit_error("No signature with name %s has been found", s->name);
     174           0 :                         return (false);
     175             :                 }
     176             : 
     177           0 :                 s->trusted = false;
     178           0 :                 hash = pkg_checksum_data(s->cert, s->certlen,
     179             :                     PKG_HASH_TYPE_SHA256_HEX);
     180           0 :                 HASH_FIND_STR(repo->revoked_fp, hash, f);
     181           0 :                 if (f != NULL) {
     182           0 :                         if (fatal)
     183           0 :                                 pkg_emit_error("At least one of the "
     184             :                                         " certificates has been revoked");
     185             : 
     186           0 :                         free(hash);
     187           0 :                         return (false);
     188             :                 }
     189             : 
     190           0 :                 HASH_FIND_STR(repo->trusted_fp, hash, f);
     191           0 :                 free(hash);
     192           0 :                 if (f != NULL) {
     193           0 :                         nbgood++;
     194           0 :                         s->trusted = true;
     195             :                 }
     196             :         }
     197             : 
     198           0 :         if (nbgood == 0) {
     199           0 :                 if (fatal)
     200           0 :                         pkg_emit_error("No trusted public keys found");
     201             : 
     202           0 :                 return (false);
     203             :         }
     204             : 
     205           0 :         return (true);
     206             : }
     207             : 
     208             : static void
     209           0 : pkg_repo_signatures_free(struct sig_cert *sc)
     210             : {
     211             :         struct sig_cert *s, *stmp;
     212             : 
     213           0 :         HASH_ITER(hh, sc, s, stmp) {
     214           0 :                 HASH_DELETE(hh, sc, s);
     215           0 :                 free(s->sig);
     216           0 :                 if (s->cert_allocated)
     217           0 :                         free(s->cert);
     218           0 :                 free(s);
     219             :         }
     220           0 : }
     221             : 
     222             : 
     223             : struct pkg_extract_cbdata {
     224             :         int afd;
     225             :         int tfd;
     226             :         const char *fname;
     227             :         bool need_sig;
     228             : };
     229             : 
     230             : static int
     231           0 : pkg_repo_meta_extract_signature_pubkey(int fd, void *ud)
     232             : {
     233           0 :         struct archive *a = NULL;
     234           0 :         struct archive_entry *ae = NULL;
     235           0 :         struct pkg_extract_cbdata *cb = ud;
     236             :         int siglen;
     237             :         void *sig;
     238           0 :         int rc = EPKG_FATAL;
     239             : 
     240           0 :         pkg_debug(1, "PkgRepo: extracting signature of repo in a sandbox");
     241             : 
     242           0 :         a = archive_read_new();
     243           0 :         archive_read_support_filter_all(a);
     244           0 :         archive_read_support_format_tar(a);
     245             : 
     246           0 :         archive_read_open_fd(a, cb->afd, 4096);
     247             : 
     248           0 :         while (archive_read_next_header(a, &ae) == ARCHIVE_OK) {
     249           0 :                 if (cb->need_sig && strcmp(archive_entry_pathname(ae), "signature") == 0) {
     250           0 :                         siglen = archive_entry_size(ae);
     251           0 :                         sig = malloc(siglen);
     252           0 :                         if (sig == NULL) {
     253           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     254             :                                                 "malloc failed");
     255           0 :                                 return (EPKG_FATAL);
     256             :                         }
     257           0 :                         if (archive_read_data(a, sig, siglen) == -1) {
     258           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     259             :                                                 "archive_read_data failed");
     260           0 :                                 free(sig);
     261           0 :                                 return (EPKG_FATAL);
     262             :                         }
     263           0 :                         if (write(fd, sig, siglen) == -1) {
     264           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     265             :                                                 "write failed");
     266           0 :                                 free(sig);
     267           0 :                                 return (EPKG_FATAL);
     268             :                         }
     269           0 :                         free(sig);
     270           0 :                         rc = EPKG_OK;
     271             :                 }
     272           0 :                 else if (strcmp(archive_entry_pathname(ae), cb->fname) == 0) {
     273           0 :                         if (archive_read_data_into_fd(a, cb->tfd) != 0) {
     274           0 :                                 pkg_emit_errno("archive_read_extract", "extract error");
     275           0 :                                 rc = EPKG_FATAL;
     276           0 :                                 break;
     277             :                         }
     278           0 :                         else if (!cb->need_sig) {
     279           0 :                                 rc = EPKG_OK;
     280             :                         }
     281             :                 }
     282             :         }
     283             : 
     284           0 :         close(cb->tfd);
     285             :         /*
     286             :          * XXX: do not free resources here since the sandbox is terminated anyway
     287             :          */
     288           0 :         return (rc);
     289             : }
     290             : /*
     291             :  * We use here the following format:
     292             :  * <type(0|1)><namelen(int)><name><datalen(int)><data>
     293             :  */
     294             : static int
     295           0 : pkg_repo_meta_extract_signature_fingerprints(int fd, void *ud)
     296             : {
     297           0 :         struct archive *a = NULL;
     298           0 :         struct archive_entry *ae = NULL;
     299           0 :         struct pkg_extract_cbdata *cb = ud;
     300             :         int siglen, keylen;
     301             :         void *sig;
     302           0 :         int rc = EPKG_FATAL;
     303             :         char key[MAXPATHLEN], t;
     304             :         struct iovec iov[5];
     305             : 
     306           0 :         pkg_debug(1, "PkgRepo: extracting signature of repo in a sandbox");
     307             : 
     308           0 :         a = archive_read_new();
     309           0 :         archive_read_support_filter_all(a);
     310           0 :         archive_read_support_format_tar(a);
     311             : 
     312           0 :         archive_read_open_fd(a, cb->afd, 4096);
     313             : 
     314           0 :         while (archive_read_next_header(a, &ae) == ARCHIVE_OK) {
     315           0 :                 if (pkg_repo_file_has_ext(archive_entry_pathname(ae), ".sig")) {
     316           0 :                         snprintf(key, sizeof(key), "%.*s",
     317           0 :                                         (int) strlen(archive_entry_pathname(ae)) - 4,
     318             :                                         archive_entry_pathname(ae));
     319           0 :                         siglen = archive_entry_size(ae);
     320           0 :                         sig = malloc(siglen);
     321           0 :                         if (sig == NULL) {
     322           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     323             :                                                 "malloc failed");
     324           0 :                                 return (EPKG_FATAL);
     325             :                         }
     326           0 :                         if (archive_read_data(a, sig, siglen) == -1) {
     327           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     328             :                                                 "archive_read_data failed");
     329           0 :                                 free(sig);
     330           0 :                                 return (EPKG_FATAL);
     331             :                         }
     332             :                         /* Signature type */
     333           0 :                         t = 0;
     334           0 :                         keylen = strlen(key);
     335           0 :                         iov[0].iov_base = &t;
     336           0 :                         iov[0].iov_len = sizeof(t);
     337           0 :                         iov[1].iov_base = &keylen;
     338           0 :                         iov[1].iov_len = sizeof(keylen);
     339           0 :                         iov[2].iov_base = key;
     340           0 :                         iov[2].iov_len = keylen;
     341           0 :                         iov[3].iov_base = &siglen;
     342           0 :                         iov[3].iov_len = sizeof(siglen);
     343           0 :                         iov[4].iov_base = sig;
     344           0 :                         iov[4].iov_len = siglen;
     345           0 :                         if (writev(fd, iov, NELEM(iov)) == -1) {
     346           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     347             :                                                 "writev failed");
     348           0 :                                 free(sig);
     349           0 :                                 return (EPKG_FATAL);
     350             :                         }
     351           0 :                         free(sig);
     352           0 :                         rc = EPKG_OK;
     353             :                 }
     354           0 :                 else if (pkg_repo_file_has_ext(archive_entry_pathname(ae), ".pub")) {
     355           0 :                         snprintf(key, sizeof(key), "%.*s",
     356           0 :                                         (int) strlen(archive_entry_pathname(ae)) - 4,
     357             :                                         archive_entry_pathname(ae));
     358           0 :                         siglen = archive_entry_size(ae);
     359           0 :                         sig = malloc(siglen);
     360           0 :                         if (sig == NULL) {
     361           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     362             :                                                 "malloc failed");
     363           0 :                                 return (EPKG_FATAL);
     364             :                         }
     365           0 :                         if (archive_read_data(a, sig, siglen) == -1) {
     366           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     367             :                                                 "archive_read_data failed");
     368           0 :                                 free(sig);
     369           0 :                                 return (EPKG_FATAL);
     370             :                         }
     371             :                         /* Pubkey type */
     372           0 :                         t = 1;
     373           0 :                         keylen = strlen(key);
     374           0 :                         iov[0].iov_base = &t;
     375           0 :                         iov[0].iov_len = sizeof(t);
     376           0 :                         iov[1].iov_base = &keylen;
     377           0 :                         iov[1].iov_len = sizeof(keylen);
     378           0 :                         iov[2].iov_base = key;
     379           0 :                         iov[2].iov_len = keylen;
     380           0 :                         iov[3].iov_base = &siglen;
     381           0 :                         iov[3].iov_len = sizeof(siglen);
     382           0 :                         iov[4].iov_base = sig;
     383           0 :                         iov[4].iov_len = siglen;
     384           0 :                         if (writev(fd, iov, NELEM(iov)) == -1) {
     385           0 :                                 pkg_emit_errno("pkg_repo_meta_extract_signature",
     386             :                                                 "writev failed");
     387           0 :                                 free(sig);
     388           0 :                                 return (EPKG_FATAL);
     389             :                         }
     390           0 :                         free(sig);
     391           0 :                         rc = EPKG_OK;
     392             :                 }
     393             :                 else {
     394           0 :                         if (strcmp(archive_entry_pathname(ae), cb->fname) == 0) {
     395           0 :                                 if (archive_read_data_into_fd(a, cb->tfd) != 0) {
     396           0 :                                         pkg_emit_errno("archive_read_extract", "extract error");
     397           0 :                                         rc = EPKG_FATAL;
     398           0 :                                         break;
     399             :                                 }
     400             :                         }
     401             :                 }
     402             :         }
     403           0 :         close(cb->tfd);
     404             :         /*
     405             :          * XXX: do not free resources here since the sandbox is terminated anyway
     406             :          */
     407           0 :         return (rc);
     408             : }
     409             : 
     410             : static int
     411           0 : pkg_repo_parse_sigkeys(const char *in, int inlen, struct sig_cert **sc)
     412             : {
     413           0 :         const char *p = in, *end = in + inlen;
     414           0 :         int rc = EPKG_OK;
     415             :         enum {
     416             :                 fp_parse_type,
     417             :                 fp_parse_flen,
     418             :                 fp_parse_file,
     419             :                 fp_parse_siglen,
     420             :                 fp_parse_sig
     421           0 :         } state = fp_parse_type;
     422           0 :         char type = 0;
     423             :         unsigned char *sig;
     424           0 :         int len = 0, tlen;
     425           0 :         struct sig_cert *s = NULL;
     426           0 :         bool new = false;
     427             : 
     428           0 :         while (p < end) {
     429           0 :                 switch (state) {
     430             :                 case fp_parse_type:
     431           0 :                         type = *p;
     432           0 :                         if (type != 0 && type != 1) {
     433             :                                 /* Invalid type */
     434           0 :                                 pkg_emit_error("%d is not a valid type for signature_fingerprints"
     435             :                                                 "output", type);
     436           0 :                                 return (EPKG_FATAL);
     437             :                         }
     438           0 :                         state = fp_parse_flen;
     439           0 :                         s = NULL;
     440           0 :                         p ++;
     441           0 :                         break;
     442             :                 case fp_parse_flen:
     443           0 :                         if (end - p < sizeof (int)) {
     444           0 :                                 pkg_emit_error("truncated reply for signature_fingerprints"
     445             :                                                 "output", type);
     446           0 :                                 return (EPKG_FATAL);
     447             :                         }
     448           0 :                         memcpy(&len, p, sizeof(int));
     449           0 :                         state = fp_parse_file;
     450           0 :                         p += sizeof(int);
     451           0 :                         s = NULL;
     452           0 :                         break;
     453             :                 case fp_parse_file:
     454           0 :                         if (end - p < len || len <= 0) {
     455           0 :                                 pkg_emit_error("truncated reply for signature_fingerprints"
     456             :                                                 "output, wanted %d bytes", type, len);
     457           0 :                                 return (EPKG_FATAL);
     458             :                         }
     459           0 :                         else if (len >= MAXPATHLEN) {
     460           0 :                                 pkg_emit_error("filename is incorrect for signature_fingerprints"
     461             :                                                 "output: %d, wanted 5..%d bytes", type, len, MAXPATHLEN);
     462           0 :                                 free(s);
     463           0 :                                 return (EPKG_FATAL);
     464             :                         }
     465           0 :                         HASH_FIND(hh, *sc, p, len, s);
     466           0 :                         if (s == NULL) {
     467           0 :                                 s = calloc(1, sizeof(struct sig_cert));
     468           0 :                                 if (s == NULL) {
     469           0 :                                         pkg_emit_errno("pkg_repo_parse_sigkeys", "calloc failed");
     470           0 :                                         return (EPKG_FATAL);
     471             :                                 }
     472           0 :                                 tlen = MIN(len, sizeof(s->name) - 1);
     473           0 :                                 memcpy(s->name, p, tlen);
     474           0 :                                 s->name[tlen] = '\0';
     475           0 :                                 new = true;
     476             :                         }
     477             :                         else {
     478           0 :                                 new = false;
     479             :                         }
     480           0 :                         state = fp_parse_siglen;
     481           0 :                         p += len;
     482           0 :                         break;
     483             :                 case fp_parse_siglen:
     484           0 :                         if (s == NULL) {
     485           0 :                                 pkg_emit_error("fatal state machine failure at pkg_repo_parse_sigkeys");
     486           0 :                                 return (EPKG_FATAL);
     487             :                         }
     488           0 :                         if (end - p < sizeof (int)) {
     489           0 :                                 pkg_emit_error("truncated reply for signature_fingerprints"
     490             :                                                 "output", type);
     491           0 :                                 free(s);
     492           0 :                                 return (EPKG_FATAL);
     493             :                         }
     494           0 :                         memcpy(&len, p, sizeof(int));
     495           0 :                         state = fp_parse_sig;
     496           0 :                         p += sizeof(int);
     497           0 :                         break;
     498             :                 case fp_parse_sig:
     499           0 :                         if (s == NULL) {
     500           0 :                                 pkg_emit_error("fatal state machine failure at pkg_repo_parse_sigkeys");
     501           0 :                                 return (EPKG_FATAL);
     502             :                         }
     503           0 :                         if (end - p < len || len <= 0) {
     504           0 :                                 pkg_emit_error("truncated reply for signature_fingerprints"
     505             :                                                 "output, wanted %d bytes", type, len);
     506           0 :                                 free(s);
     507           0 :                                 return (EPKG_FATAL);
     508             :                         }
     509           0 :                         sig = malloc(len);
     510           0 :                         if (sig == NULL) {
     511           0 :                                 pkg_emit_errno("pkg_repo_parse_sigkeys", "malloc failed");
     512           0 :                                 free(s);
     513           0 :                                 return (EPKG_FATAL);
     514             :                         }
     515           0 :                         memcpy(sig, p, len);
     516           0 :                         if (type == 0) {
     517           0 :                                 s->sig = sig;
     518           0 :                                 s->siglen = len;
     519             :                         }
     520             :                         else {
     521           0 :                                 s->cert = sig;
     522           0 :                                 s->certlen = len;
     523           0 :                                 s->cert_allocated = true;
     524             :                         }
     525           0 :                         state = fp_parse_type;
     526           0 :                         p += len;
     527             : 
     528           0 :                         if (new)
     529           0 :                                 HASH_ADD_STR(*sc, name, s);
     530             : 
     531           0 :                         break;
     532             :                 }
     533             :         }
     534             : 
     535           0 :         return (rc);
     536             : }
     537             : 
     538             : static int
     539          14 : pkg_repo_archive_extract_archive(int fd, const char *file,
     540             :     const char *dest, struct pkg_repo *repo, int dest_fd,
     541             :     struct sig_cert **signatures)
     542             : {
     543          14 :         struct sig_cert *sc = NULL, *s;
     544             :         struct pkg_extract_cbdata cbdata;
     545             : 
     546          14 :         char *sig = NULL;
     547          14 :         int rc = EPKG_OK;
     548          14 :         int64_t siglen = 0;
     549             : 
     550             : 
     551          14 :         pkg_debug(1, "PkgRepo: extracting %s of repo %s", file, pkg_repo_name(repo));
     552             : 
     553             :         /* Seek to the begin of file */
     554          14 :         (void)lseek(fd, 0, SEEK_SET);
     555             : 
     556          14 :         cbdata.afd = fd;
     557          14 :         cbdata.fname = file;
     558          14 :         if (dest_fd != -1) {
     559           7 :                 cbdata.tfd = dest_fd;
     560             :         }
     561           7 :         else if (dest != NULL) {
     562           7 :                 cbdata.tfd = open (dest, O_WRONLY | O_CREAT | O_TRUNC,
     563             :                                 0644);
     564           7 :                 if (cbdata.tfd == -1) {
     565           0 :                         pkg_emit_errno("archive_read_extract", "open error");
     566           0 :                         rc = EPKG_FATAL;
     567           0 :                         goto cleanup;
     568             :                 }
     569           7 :                 fchown (fd, 0, 0);
     570             :         }
     571             :         else {
     572           0 :                 pkg_emit_error("internal error: both fd and name are invalid");
     573           0 :                 return (EPKG_FATAL);
     574             :         }
     575             : 
     576          14 :         if (pkg_repo_signature_type(repo) == SIG_PUBKEY) {
     577           0 :                 cbdata.need_sig = true;
     578           0 :                 if (pkg_emit_sandbox_get_string(pkg_repo_meta_extract_signature_pubkey,
     579           0 :                                 &cbdata, (char **)&sig, &siglen) == EPKG_OK && sig != NULL) {
     580           0 :                         s = calloc(1, sizeof(struct sig_cert));
     581           0 :                         if (s == NULL) {
     582           0 :                                 pkg_emit_errno("pkg_repo_archive_extract_archive",
     583             :                                                 "malloc failed");
     584           0 :                                 rc = EPKG_FATAL;
     585           0 :                                 goto cleanup;
     586             :                         }
     587           0 :                         s->sig = sig;
     588           0 :                         s->siglen = siglen;
     589           0 :                         strlcpy(s->name, "signature", sizeof(s->name));
     590           0 :                         HASH_ADD_STR(sc, name, s);
     591             :                 }
     592             :         }
     593          14 :         else if (pkg_repo_signature_type(repo) == SIG_FINGERPRINT) {
     594           0 :                 if (pkg_emit_sandbox_get_string(pkg_repo_meta_extract_signature_fingerprints,
     595           0 :                                 &cbdata, (char **)&sig, &siglen) == EPKG_OK && sig != NULL &&
     596           0 :                                 siglen > 0) {
     597           0 :                         if (pkg_repo_parse_sigkeys(sig, siglen, &sc) == EPKG_FATAL) {
     598           0 :                                 return (EPKG_FATAL);
     599             :                         }
     600           0 :                         free(sig);
     601           0 :                         if (!pkg_repo_check_fingerprint(repo, sc, true)) {
     602           0 :                                 return (EPKG_FATAL);
     603             :                         }
     604             :                 }
     605             :                 else {
     606           0 :                         pkg_emit_error("No signature found");
     607           0 :                         return (EPKG_FATAL);
     608             :                 }
     609             :         }
     610             :         else {
     611          14 :                 cbdata.need_sig = false;
     612          14 :                 if (pkg_emit_sandbox_get_string(pkg_repo_meta_extract_signature_pubkey,
     613             :                         &cbdata, (char **)&sig, &siglen) == EPKG_OK) {
     614          14 :                         free(sig);
     615             :                 }
     616             :                 else {
     617           0 :                         pkg_emit_error("Repo extraction failed");
     618           0 :                         return (EPKG_FATAL);
     619             :                 }
     620             :         }
     621          14 :         (void)lseek(fd, 0, SEEK_SET);
     622          14 :         if (dest_fd != -1)
     623           7 :                 (void)lseek(dest_fd, 0, SEEK_SET);
     624             : 
     625             : cleanup:
     626          14 :         if (rc == EPKG_OK) {
     627          14 :                 if (signatures != NULL)
     628          14 :                         *signatures = sc;
     629             :                 else
     630           0 :                         pkg_repo_signatures_free(sc);
     631             :         }
     632             :         else {
     633           0 :                 pkg_repo_signatures_free(sc);
     634             :         }
     635             : 
     636          14 :         if (rc != EPKG_OK)
     637           0 :                 unlink(dest);
     638             : 
     639          14 :         return rc;
     640             : }
     641             : 
     642             : static int
     643           7 : pkg_repo_archive_extract_check_archive(int fd, const char *file,
     644             :     const char *dest, struct pkg_repo *repo, int dest_fd)
     645             : {
     646           7 :         struct sig_cert *sc = NULL, *s, *stmp;
     647             :         int ret, rc;
     648             : 
     649           7 :         ret = rc = EPKG_OK;
     650             : 
     651           7 :         if (pkg_repo_archive_extract_archive(fd, file, dest, repo, dest_fd, &sc)
     652             :                         != EPKG_OK)
     653           0 :                 return (EPKG_FATAL);
     654             : 
     655           7 :         if (pkg_repo_signature_type(repo) == SIG_PUBKEY) {
     656           0 :                 if (pkg_repo_key(repo) == NULL) {
     657           0 :                         pkg_emit_error("No PUBKEY defined. Removing "
     658             :                             "repository.");
     659           0 :                         rc = EPKG_FATAL;
     660           0 :                         goto cleanup;
     661             :                 }
     662           0 :                 if (sc == NULL) {
     663           0 :                         pkg_emit_error("No signature found in the repository.  "
     664             :                                         "Can not validate against %s key.", pkg_repo_key(repo));
     665           0 :                         rc = EPKG_FATAL;
     666           0 :                         goto cleanup;
     667             :                 }
     668             :                 /*
     669             :                  * Here are dragons:
     670             :                  * 1) rsa_verify is NOT rsa_verify_cert
     671             :                  * 2) siglen must be reduced by one to support this legacy method
     672             :                  *
     673             :                  * by @bdrewery
     674             :                  */
     675           0 :                 ret = rsa_verify(dest, pkg_repo_key(repo), sc->sig, sc->siglen - 1,
     676             :                                 dest_fd);
     677           0 :                 if (ret != EPKG_OK) {
     678           0 :                         pkg_emit_error("Invalid signature, "
     679             :                                         "removing repository.");
     680           0 :                         rc = EPKG_FATAL;
     681           0 :                         goto cleanup;
     682             :                 }
     683             :         }
     684           7 :         else if (pkg_repo_signature_type(repo) == SIG_FINGERPRINT) {
     685           0 :                 HASH_ITER(hh, sc, s, stmp) {
     686           0 :                         ret = rsa_verify_cert(dest, s->cert, s->certlen, s->sig, s->siglen,
     687             :                                 dest_fd);
     688           0 :                         if (ret == EPKG_OK && s->trusted) {
     689           0 :                                 break;
     690             :                         }
     691           0 :                         ret = EPKG_FATAL;
     692             :                 }
     693           0 :                 if (ret != EPKG_OK) {
     694           0 :                         pkg_emit_error("No trusted certificate has been used "
     695             :                             "to sign the repository");
     696           0 :                         rc = EPKG_FATAL;
     697           0 :                         goto cleanup;
     698             :                 }
     699             :         }
     700             : 
     701             : cleanup:
     702           7 :         if (rc != EPKG_OK && dest != NULL)
     703           0 :                 unlink(dest);
     704             : 
     705           7 :         return rc;
     706             : }
     707             : 
     708             : static int
     709           8 : pkg_repo_fetch_remote_extract_fd(struct pkg_repo *repo, const char *filename,
     710             :     time_t *t, int *rc)
     711             : {
     712             :         int fd, dest_fd;
     713             :         const char *tmpdir;
     714             :         char tmp[MAXPATHLEN];
     715             : 
     716           8 :         fd = pkg_repo_fetch_remote_tmp(repo, filename,
     717           8 :                         packing_format_to_string(repo->meta->packing_format), t, rc);
     718           8 :         if (fd == -1)
     719           1 :                 return (-1);
     720             : 
     721           7 :         tmpdir = getenv("TMPDIR");
     722           7 :         if (tmpdir == NULL)
     723           0 :                 tmpdir = "/tmp";
     724           7 :         snprintf(tmp, sizeof(tmp), "%s/%s.XXXXXX", tmpdir, filename);
     725             : 
     726           7 :         dest_fd = mkstemp(tmp);
     727           7 :         if (dest_fd == -1) {
     728           0 :                 pkg_emit_error("Could not create temporary file %s, "
     729             :                                 "aborting update.\n", tmp);
     730           0 :                 close(fd);
     731           0 :                 *rc = EPKG_FATAL;
     732           0 :                 return (-1);
     733             :         }
     734             : 
     735           7 :         (void)unlink(tmp);
     736           7 :         if (pkg_repo_archive_extract_check_archive(fd, filename, NULL, repo, dest_fd)
     737             :                         != EPKG_OK) {
     738           0 :                 *rc = EPKG_FATAL;
     739           0 :                 close(dest_fd);
     740           0 :                 close(fd);
     741           0 :                 return (-1);
     742             :         }
     743             : 
     744             :         /* Thus removing archived file as well */
     745           7 :         close(fd);
     746             : 
     747           7 :         return (dest_fd);
     748             : }
     749             : 
     750             : unsigned char *
     751           8 : pkg_repo_fetch_remote_extract_mmap(struct pkg_repo *repo, const char *filename,
     752             :     time_t *t, int *rc, size_t *sz)
     753             : {
     754             :         int fd;
     755             :         struct stat st;
     756             :         unsigned char *map;
     757             : 
     758           8 :         fd = pkg_repo_fetch_remote_extract_fd(repo, filename, t, rc);
     759           8 :         if (fd == -1) {
     760           1 :                 return (NULL);
     761             :         }
     762             : 
     763           7 :         if (fstat(fd, &st) == -1) {
     764           0 :                 close(fd);
     765           0 :                 return (MAP_FAILED);
     766             :         }
     767             : 
     768           7 :         *sz = st.st_size;
     769             :         if (st.st_size > SSIZE_MAX) {
     770             :                 pkg_emit_error("%s too large", filename);
     771             :                 close(fd);
     772             :                 return (MAP_FAILED);
     773             :         }
     774             : 
     775           7 :         map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
     776           7 :         close(fd);
     777           7 :         if (map == MAP_FAILED) {
     778           0 :                 pkg_emit_errno("pkg_repo_fetch_remote_mmap", "cannot mmap fetched");
     779           0 :                 *rc = EPKG_FATAL;
     780           0 :                 return (MAP_FAILED);
     781             :         }
     782             : 
     783           7 :         return (map);
     784             : }
     785             : 
     786             : FILE *
     787           0 : pkg_repo_fetch_remote_extract_tmp(struct pkg_repo *repo, const char *filename,
     788             :                 time_t *t, int *rc)
     789             : {
     790             :         int dest_fd;
     791             :         FILE *res;
     792             : 
     793           0 :         dest_fd = pkg_repo_fetch_remote_extract_fd(repo, filename, t, rc);
     794           0 :         if (dest_fd == -1) {
     795           0 :                 *rc = EPKG_FATAL;
     796           0 :                 return (NULL);
     797             :         }
     798             : 
     799           0 :         res = fdopen(dest_fd, "r");
     800           0 :         if (res == NULL) {
     801           0 :                 pkg_emit_errno("fdopen", "digest open failed");
     802           0 :                 *rc = EPKG_FATAL;
     803           0 :                 close(dest_fd);
     804           0 :                 return (NULL);
     805             :         }
     806             : 
     807           0 :         *rc = EPKG_OK;
     808           0 :         return (res);
     809             : }
     810             : 
     811             : struct pkg_repo_check_cbdata {
     812             :         unsigned char *map;
     813             :         size_t len;
     814             :         const char *name;
     815             : };
     816             : 
     817             : static int
     818           0 : pkg_repo_meta_extract_pubkey(int fd, void *ud)
     819             : {
     820           0 :         struct pkg_repo_check_cbdata *cbdata = ud;
     821             :         struct ucl_parser *parser;
     822             :         ucl_object_t *top;
     823             :         const ucl_object_t *obj, *cur, *elt;
     824           0 :         ucl_object_iter_t iter = NULL;
     825             :         struct iovec iov[2];
     826           0 :         int rc = EPKG_OK;
     827           0 :         int64_t res_len = 0;
     828           0 :         bool found = false;
     829             : 
     830           0 :         parser = ucl_parser_new(0);
     831           0 :         if (!ucl_parser_add_chunk(parser, cbdata->map, cbdata->len)) {
     832           0 :                 pkg_emit_error("cannot parse repository meta from %s",
     833             :                                 ucl_parser_get_error(parser));
     834           0 :                 ucl_parser_free(parser);
     835           0 :                 return (EPKG_FATAL);
     836             :         }
     837             : 
     838           0 :         top = ucl_parser_get_object(parser);
     839           0 :         ucl_parser_free(parser);
     840             : 
     841             :         /* Now search for the required key */
     842           0 :         obj = ucl_object_find_key(top, "cert");
     843           0 :         if (obj == NULL) {
     844           0 :                 pkg_emit_error("cannot find key for signature %s in meta",
     845             :                                 cbdata->name);
     846           0 :                 rc = EPKG_FATAL;
     847             :         }
     848             :         else {
     849           0 :                 while(!found && (cur = ucl_iterate_object(obj, &iter, false)) != NULL) {
     850           0 :                         elt = ucl_object_find_key(cur, "name");
     851           0 :                         if (elt != NULL && elt->type == UCL_STRING) {
     852           0 :                                 if (strcmp(ucl_object_tostring(elt), cbdata->name) == 0) {
     853           0 :                                         elt = ucl_object_find_key(cur, "data");
     854           0 :                                         if (elt == NULL || elt->type != UCL_STRING)
     855           0 :                                                 continue;
     856             : 
     857             :                                         /* +1 to include \0 at the end */
     858           0 :                                         res_len = elt->len + 1;
     859           0 :                                         iov[0].iov_base = (void *)ucl_object_tostring(elt);
     860           0 :                                         iov[0].iov_len = res_len;
     861           0 :                                         if (writev(fd, iov, 1) == -1) {
     862           0 :                                                 pkg_emit_errno("pkg_repo_meta_extract_pubkey",
     863             :                                                                 "writev error");
     864           0 :                                                 rc = EPKG_FATAL;
     865           0 :                                                 break;
     866             :                                         }
     867           0 :                                         found = true;
     868             :                                 }
     869             :                         }
     870             :                 }
     871             :         }
     872             : 
     873           0 :         ucl_object_unref(top);
     874             : 
     875           0 :         return (rc);
     876             : }
     877             : 
     878             : int
     879           8 : pkg_repo_fetch_meta(struct pkg_repo *repo, time_t *t)
     880             : {
     881             :         char filepath[MAXPATHLEN];
     882             :         struct pkg_repo_meta *nmeta;
     883             :         struct stat st;
     884           8 :         const char *dbdir = NULL;
     885           8 :         unsigned char *map = NULL;
     886             :         int fd;
     887           8 :         int rc = EPKG_OK, ret;
     888           8 :         struct sig_cert *sc = NULL, *s, *stmp;
     889             :         struct pkg_repo_check_cbdata cbdata;
     890             : 
     891           8 :         dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
     892             : 
     893           8 :         fd = pkg_repo_fetch_remote_tmp(repo, "meta", "txz", t, &rc);
     894           8 :         if (fd == -1)
     895           1 :                 return (rc);
     896             : 
     897           7 :         snprintf(filepath, sizeof(filepath), "%s/%s.meta", dbdir, pkg_repo_name(repo));
     898             : 
     899             :         /* Remove old metafile */
     900           7 :         if (unlink (filepath) == -1 && errno != ENOENT) {
     901           0 :                 close(fd);
     902           0 :                 return (EPKG_FATAL);
     903             :         }
     904             : 
     905           7 :         if (pkg_repo_signature_type(repo) == SIG_PUBKEY) {
     906           0 :                 if ((rc = pkg_repo_archive_extract_check_archive(fd, "meta", filepath, repo, -1)) != EPKG_OK) {
     907           0 :                         close (fd);
     908           0 :                         return (rc);
     909             :                 }
     910           0 :                 goto load_meta;
     911             :         }
     912             : 
     913             :         /*
     914             :          * For fingerprints we cannot just load pubkeys as they could be in metafile itself
     915             :          * To do it, we parse meta in sandbox and for each unloaded pubkey we try to return
     916             :          * a corresponding key from meta file.
     917             :          */
     918             : 
     919           7 :         if ((rc = pkg_repo_archive_extract_archive(fd, "meta", filepath, repo, -1, &sc)) != EPKG_OK) {
     920           0 :                 close (fd);
     921           0 :                 return (rc);
     922             :         }
     923             : 
     924           7 :         close(fd);
     925             : 
     926           7 :         if (repo->signature_type == SIG_FINGERPRINT && repo->trusted_fp == NULL) {
     927           0 :                 if (pkg_repo_load_fingerprints(repo) != EPKG_OK)
     928           0 :                         return (EPKG_FATAL);
     929             :         }
     930             : 
     931             :         /* Map meta file for extracting pubkeys from it */
     932           7 :         if (stat(filepath, &st) == -1) {
     933           0 :                 pkg_emit_errno("pkg_repo_fetch_meta", "cannot stat meta fetched");
     934           0 :                 rc = EPKG_FATAL;
     935           0 :                 goto cleanup;
     936             :         }
     937           7 :         if ((fd = open(filepath, O_RDONLY)) == -1) {
     938           0 :                 pkg_emit_errno("pkg_repo_fetch_meta", "cannot open meta fetched");
     939           0 :                 rc = EPKG_FATAL;
     940           0 :                 goto cleanup;
     941             :         }
     942             : 
     943           7 :         map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
     944           7 :         close(fd);
     945           7 :         if (map == MAP_FAILED) {
     946           0 :                 pkg_emit_errno("pkg_repo_fetch_meta", "cannot mmap meta fetched");
     947           0 :                 rc = EPKG_FATAL;
     948           0 :                 goto cleanup;
     949             :         }
     950             : 
     951           7 :         if (repo->signature_type == SIG_FINGERPRINT) {
     952           0 :                 cbdata.len = st.st_size;
     953           0 :                 cbdata.map = map;
     954           0 :                 HASH_ITER(hh, sc, s, stmp) {
     955           0 :                         if (s->siglen != 0 && s->certlen == 0) {
     956             :                                 /*
     957             :                                  * We need to load this pubkey from meta
     958             :                                  */
     959           0 :                                 cbdata.name = s->name;
     960           0 :                                 if (pkg_emit_sandbox_get_string(pkg_repo_meta_extract_pubkey, &cbdata,
     961             :                                                 (char **)&s->cert, &s->certlen) != EPKG_OK) {
     962           0 :                                         rc = EPKG_FATAL;
     963           0 :                                         goto cleanup;
     964             :                                 }
     965           0 :                                 s->cert_allocated = true;
     966             :                         }
     967             :                 }
     968             : 
     969           0 :                 if (!pkg_repo_check_fingerprint(repo, sc, true)) {
     970           0 :                         rc = EPKG_FATAL;
     971           0 :                         goto cleanup;
     972             :                 }
     973             : 
     974           0 :                 HASH_ITER(hh, sc, s, stmp) {
     975           0 :                         ret = rsa_verify_cert(filepath, s->cert, s->certlen, s->sig, s->siglen,
     976             :                                 -1);
     977           0 :                         if (ret == EPKG_OK && s->trusted)
     978           0 :                                 break;
     979             : 
     980           0 :                         ret = EPKG_FATAL;
     981             :                 }
     982           0 :                 if (ret != EPKG_OK) {
     983           0 :                         pkg_emit_error("No trusted certificate has been used "
     984             :                                 "to sign the repository");
     985           0 :                         rc = EPKG_FATAL;
     986           0 :                         goto cleanup;
     987             :                 }
     988             :         }
     989             : 
     990             : load_meta:
     991           7 :         if ((rc = pkg_repo_meta_load(filepath, &nmeta)) != EPKG_OK) {
     992           0 :                 if (map != NULL)
     993           0 :                         munmap(map, st.st_size);
     994             : 
     995           0 :                 return (rc);
     996             :         }
     997             : 
     998           7 :         if (repo->meta != NULL)
     999           7 :                 pkg_repo_meta_free(repo->meta);
    1000             : 
    1001           7 :         repo->meta = nmeta;
    1002             : 
    1003             : cleanup:
    1004           7 :         if (map != NULL)
    1005           7 :                 munmap(map, st.st_size);
    1006             : 
    1007           7 :         if (sc != NULL)
    1008           0 :                 pkg_repo_signatures_free(sc);
    1009             : 
    1010           7 :         if (rc != EPKG_OK)
    1011           0 :                 unlink(filepath);
    1012             : 
    1013           7 :         return (rc);
    1014             : }
    1015             : 
    1016             : static struct fingerprint *
    1017           0 : pkg_repo_parse_fingerprint(ucl_object_t *obj)
    1018             : {
    1019             :         const ucl_object_t *cur;
    1020           0 :         ucl_object_iter_t it = NULL;
    1021           0 :         const char *function = NULL, *fp = NULL;
    1022           0 :         hash_t fct = HASH_UNKNOWN;
    1023           0 :         struct fingerprint *f = NULL;
    1024             :         const char *key;
    1025             : 
    1026           0 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
    1027           0 :                 key = ucl_object_key(cur);
    1028           0 :                 if (cur->type != UCL_STRING)
    1029           0 :                         continue;
    1030             : 
    1031           0 :                 if (strcasecmp(key, "function") == 0) {
    1032           0 :                         function = ucl_object_tostring(cur);
    1033           0 :                         continue;
    1034             :                 }
    1035             : 
    1036           0 :                 if (strcasecmp(key, "fingerprint") == 0) {
    1037           0 :                         fp = ucl_object_tostring(cur);
    1038           0 :                         continue;
    1039             :                 }
    1040             :         }
    1041             : 
    1042           0 :         if (fp == NULL || function == NULL)
    1043           0 :                 return (NULL);
    1044             : 
    1045           0 :         if (strcasecmp(function, "sha256") == 0)
    1046           0 :                 fct = HASH_SHA256;
    1047             : 
    1048           0 :         if (fct == HASH_UNKNOWN) {
    1049           0 :                 pkg_emit_error("Unsupported hashing function: %s", function);
    1050           0 :                 return (NULL);
    1051             :         }
    1052             : 
    1053           0 :         f = calloc(1, sizeof(struct fingerprint));
    1054           0 :         f->type = fct;
    1055           0 :         strlcpy(f->hash, fp, sizeof(f->hash));
    1056             : 
    1057           0 :         return (f);
    1058             : }
    1059             : 
    1060             : static struct fingerprint *
    1061           0 : pkg_repo_load_fingerprint(const char *dir, const char *filename)
    1062             : {
    1063           0 :         ucl_object_t *obj = NULL;
    1064           0 :         struct ucl_parser *p = NULL;
    1065             :         char path[MAXPATHLEN];
    1066           0 :         struct fingerprint *f = NULL;
    1067             : 
    1068           0 :         snprintf(path, sizeof(path), "%s/%s", dir, filename);
    1069             : 
    1070           0 :         p = ucl_parser_new(0);
    1071             : 
    1072           0 :         if (!ucl_parser_add_file(p, path)) {
    1073           0 :                 pkg_emit_error("%s", ucl_parser_get_error(p));
    1074           0 :                 ucl_parser_free(p);
    1075           0 :                 return (NULL);
    1076             :         }
    1077             : 
    1078           0 :         obj = ucl_parser_get_object(p);
    1079             : 
    1080           0 :         if (obj->type == UCL_OBJECT)
    1081           0 :                 f = pkg_repo_parse_fingerprint(obj);
    1082             : 
    1083           0 :         ucl_object_unref(obj);
    1084           0 :         ucl_parser_free(p);
    1085             : 
    1086           0 :         return (f);
    1087             : }
    1088             : 
    1089             : static int
    1090           0 : pkg_repo_load_fingerprints_from_path(const char *path, struct fingerprint **f)
    1091             : {
    1092             :         DIR *d;
    1093             :         struct dirent *ent;
    1094           0 :         struct fingerprint *finger = NULL;
    1095             : 
    1096           0 :         *f = NULL;
    1097             : 
    1098           0 :         if ((d = opendir(path)) == NULL)
    1099           0 :                 return (EPKG_FATAL);
    1100             : 
    1101           0 :         while ((ent = readdir(d))) {
    1102           0 :                 if (strcmp(ent->d_name, ".") == 0 ||
    1103           0 :                     strcmp(ent->d_name, "..") == 0)
    1104           0 :                         continue;
    1105           0 :                 finger = pkg_repo_load_fingerprint(path, ent->d_name);
    1106           0 :                 if (finger != NULL)
    1107           0 :                         HASH_ADD_STR(*f, hash, finger);
    1108             :         }
    1109             : 
    1110           0 :         closedir(d);
    1111             : 
    1112           0 :         return (EPKG_OK);
    1113             : }
    1114             : 
    1115             : int
    1116           0 : pkg_repo_load_fingerprints(struct pkg_repo *repo)
    1117             : {
    1118             :         char path[MAXPATHLEN];
    1119             :         struct stat st;
    1120             : 
    1121           0 :         snprintf(path, sizeof(path), "%s/trusted", pkg_repo_fingerprints(repo));
    1122           0 :         if ((pkg_repo_load_fingerprints_from_path(path, &repo->trusted_fp)) != EPKG_OK) {
    1123           0 :                 pkg_emit_error("Error loading trusted certificates");
    1124           0 :                 return (EPKG_FATAL);
    1125             :         }
    1126             : 
    1127           0 :         if (HASH_COUNT(repo->trusted_fp) == 0) {
    1128           0 :                 pkg_emit_error("No trusted certificates");
    1129           0 :                 return (EPKG_FATAL);
    1130             :         }
    1131             : 
    1132           0 :         snprintf(path, sizeof(path), "%s/revoked", pkg_repo_fingerprints(repo));
    1133             :         /* Absence of revoked certificates is not a fatal error */
    1134           0 :         if (stat(path, &st) != -1) {
    1135           0 :                 if ((pkg_repo_load_fingerprints_from_path(path, &repo->revoked_fp)) != EPKG_OK) {
    1136           0 :                         pkg_emit_error("Error loading revoked certificates");
    1137           0 :                         return (EPKG_FATAL);
    1138             :                 }
    1139             :         }
    1140             : 
    1141           0 :         return (EPKG_OK);
    1142             : }
    1143             : 
    1144             : 
    1145             : 
    1146             : int
    1147           0 : pkg_repo_fetch_package(struct pkg *pkg)
    1148             : {
    1149             :         struct pkg_repo *repo;
    1150             : 
    1151           0 :         if (pkg->repo == NULL) {
    1152           0 :                 pkg_emit_error("Trying to fetch package without repository");
    1153           0 :                 return (EPKG_FATAL);
    1154             :         }
    1155             : 
    1156           0 :         repo = pkg->repo;
    1157           0 :         if (repo->ops->fetch_pkg == NULL) {
    1158           0 :                 pkg_emit_error("Repository %s does not support fetching", repo->name);
    1159           0 :                 return (EPKG_FATAL);
    1160             :         }
    1161             : 
    1162           0 :         return (repo->ops->fetch_pkg(repo, pkg));
    1163             : }
    1164             : 
    1165             : int
    1166           0 : pkg_repo_mirror_package(struct pkg *pkg, const char *destdir)
    1167             : {
    1168             :         struct pkg_repo *repo;
    1169             : 
    1170           0 :         if (pkg->repo == NULL) {
    1171           0 :                 pkg_emit_error("Trying to mirror package without repository");
    1172           0 :                 return (EPKG_FATAL);
    1173             :         }
    1174             : 
    1175           0 :         repo = pkg->repo;
    1176           0 :         if (repo->ops->mirror_pkg == NULL) {
    1177           0 :                 pkg_emit_error("Repository %s does not support mirroring", repo->name);
    1178           0 :                 return (EPKG_FATAL);
    1179             :         }
    1180             : 
    1181           0 :         return (repo->ops->mirror_pkg(repo, pkg, destdir));
    1182             : }
    1183             : 
    1184             : int
    1185          64 : pkg_repo_cached_name(struct pkg *pkg, char *dest, size_t destlen)
    1186             : {
    1187             :         struct pkg_repo *repo;
    1188             : 
    1189          64 :         if (pkg->repo == NULL)
    1190           0 :                 return (EPKG_FATAL);
    1191             : 
    1192          64 :         repo = pkg->repo;
    1193          64 :         if (repo->ops->get_cached_name == NULL)
    1194           0 :                 return (EPKG_FATAL);
    1195             : 
    1196          64 :         return (repo->ops->get_cached_name(repo, pkg, dest, destlen));
    1197             : }

Generated by: LCOV version 1.10