LCOV - code coverage report
Current view: top level - libpkg - pkg_repo.c (source / functions) Hit Total Coverage
Test: rapport Lines: 310 683 45.4 %
Date: 2021-12-10 16:22:55 Functions: 13 20 65.0 %
Branches: 131 354 37.0 %

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

Generated by: LCOV version 1.15