LCOV - code coverage report
Current view: top level - libpkg - pkg_checksum.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 224 346 64.7 %
Date: 2015-08-15 Functions: 23 30 76.7 %

          Line data    Source code
       1             : /* Copyright (c) 2014, Vsevolod Stakhov <vsevolod@FreeBSD.org>
       2             :  * Copyright (c) 2014, Google Inc.
       3             :  * All rights reserved.
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions are met:
       7             :  *       * Redistributions of source code must retain the above copyright
       8             :  *         notice, this list of conditions and the following disclaimer.
       9             :  *       * Redistributions in binary form must reproduce the above copyright
      10             :  *         notice, this list of conditions and the following disclaimer in the
      11             :  *         documentation and/or other materials provided with the distribution.
      12             :  *
      13             :  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
      14             :  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      15             :  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      16             :  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
      17             :  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      18             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      19             :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      20             :  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      21             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      22             :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      23             :  */
      24             : 
      25             : #include <assert.h>
      26             : 
      27             : #include <sys/stat.h>
      28             : 
      29             : #include <fcntl.h>
      30             : #include "pkg.h"
      31             : #include "private/pkg.h"
      32             : #include "private/event.h"
      33             : #include "blake2.h"
      34             : 
      35             : struct pkg_checksum_entry {
      36             :         const char *field;
      37             :         char *value;
      38             :         struct pkg_checksum_entry *next, *prev;
      39             : };
      40             : 
      41             : /* Separate checksum parts */
      42             : #define PKG_CKSUM_SEPARATOR '$'
      43             : 
      44             : typedef void (*pkg_checksum_hash_func)(struct pkg_checksum_entry *entries,
      45             :                                 unsigned char **out, size_t *outlen);
      46             : typedef void (*pkg_checksum_hash_bulk_func)(const unsigned char *in, size_t inlen,
      47             :                                 unsigned char **out, size_t *outlen);
      48             : typedef void (*pkg_checksum_encode_func)(unsigned char *in, size_t inlen,
      49             :                                 char *out, size_t outlen);
      50             : 
      51             : typedef void (*pkg_checksum_hash_file_func)(int fd, unsigned char **out,
      52             :     size_t *outlen);
      53             : 
      54             : static void pkg_checksum_hash_sha256(struct pkg_checksum_entry *entries,
      55             :                                 unsigned char **out, size_t *outlen);
      56             : static void pkg_checksum_hash_sha256_bulk(const unsigned char *in, size_t inlen,
      57             :                                 unsigned char **out, size_t *outlen);
      58             : static void pkg_checksum_hash_sha256_file(int fd, unsigned char **out,
      59             :     size_t *outlen);
      60             : static void pkg_checksum_hash_blake2(struct pkg_checksum_entry *entries,
      61             :                                 unsigned char **out, size_t *outlen);
      62             : static void pkg_checksum_hash_blake2_bulk(const unsigned char *in, size_t inlen,
      63             :                                 unsigned char **out, size_t *outlen);
      64             : static void pkg_checksum_hash_blake2_file(int fd, unsigned char **out,
      65             :     size_t *outlen);
      66             : static void pkg_checksum_encode_base32(unsigned char *in, size_t inlen,
      67             :                                 char *out, size_t outlen);
      68             : static void pkg_checksum_encode_hex(unsigned char *in, size_t inlen,
      69             :                                 char *out, size_t outlen);
      70             : 
      71             : static const struct _pkg_cksum_type {
      72             :         const char *name;
      73             :         size_t hlen;
      74             :         pkg_checksum_hash_func hfunc;
      75             :         pkg_checksum_hash_bulk_func hbulkfunc;
      76             :         pkg_checksum_hash_file_func hfilefunc;
      77             :         pkg_checksum_encode_func encfunc;
      78             : } checksum_types[] = {
      79             :         [PKG_HASH_TYPE_SHA256_BASE32] = {
      80             :                 "sha256_base32",
      81             :                 PKG_CHECKSUM_SHA256_LEN,
      82             :                 pkg_checksum_hash_sha256,
      83             :                 pkg_checksum_hash_sha256_bulk,
      84             :                 pkg_checksum_hash_sha256_file,
      85             :                 pkg_checksum_encode_base32
      86             :         },
      87             :         [PKG_HASH_TYPE_SHA256_HEX] = {
      88             :                 "sha256_hex",
      89             :                 PKG_CHECKSUM_SHA256_LEN,
      90             :                 pkg_checksum_hash_sha256,
      91             :                 pkg_checksum_hash_sha256_bulk,
      92             :                 pkg_checksum_hash_sha256_file,
      93             :                 pkg_checksum_encode_hex
      94             :         },
      95             :         [PKG_HASH_TYPE_BLAKE2_BASE32] = {
      96             :                 "blake2_base32",
      97             :                 PKG_CHECKSUM_BLAKE2_LEN,
      98             :                 pkg_checksum_hash_blake2,
      99             :                 pkg_checksum_hash_blake2_bulk,
     100             :                 pkg_checksum_hash_blake2_file,
     101             :                 pkg_checksum_encode_base32
     102             :         },
     103             :         [PKG_HASH_TYPE_SHA256_RAW] = {
     104             :                 "sha256_raw",
     105             :                 SHA256_DIGEST_LENGTH,
     106             :                 pkg_checksum_hash_sha256,
     107             :                 pkg_checksum_hash_sha256_bulk,
     108             :                 pkg_checksum_hash_sha256_file,
     109             :                 NULL
     110             :         },
     111             :         [PKG_HASH_TYPE_BLAKE2_RAW] = {
     112             :                 "blake2_raw",
     113             :                 BLAKE2B_OUTBYTES,
     114             :                 pkg_checksum_hash_blake2,
     115             :                 pkg_checksum_hash_blake2_bulk,
     116             :                 pkg_checksum_hash_blake2_file,
     117             :                 NULL
     118             :         },
     119             :         [PKG_HASH_TYPE_UNKNOWN] = {
     120             :                 NULL,
     121             :                 -1,
     122             :                 NULL,
     123             :                 NULL,
     124             :                 NULL
     125             :         }
     126             : };
     127             : 
     128             : static void
     129         329 : pkg_checksum_free_entry(struct pkg_checksum_entry *e)
     130             : {
     131         329 :         if (e != NULL) {
     132         329 :                 if (e->value) {
     133         329 :                         free(e->value);
     134             :                 }
     135         329 :                 free(e);
     136             :         }
     137         329 : }
     138             : 
     139             : static void
     140         329 : pkg_checksum_add_entry(const char *key,
     141             :         const char *value,
     142             :         struct pkg_checksum_entry **entries)
     143             : {
     144             :         struct pkg_checksum_entry *e;
     145             : 
     146         329 :         e = malloc(sizeof(*e));
     147         329 :         if (e == NULL) {
     148           0 :                 pkg_emit_errno("malloc", "pkg_checksum_entry");
     149         329 :                 return;
     150             :         }
     151             : 
     152         329 :         e->field = key;
     153         329 :         e->value = strdup(value);
     154         329 :         DL_APPEND(*entries, e);
     155             : }
     156             : 
     157             : static int
     158         504 : pkg_checksum_entry_cmp(struct pkg_checksum_entry *e1,
     159             :         struct pkg_checksum_entry *e2)
     160             : {
     161             :         int r;
     162             : 
     163             :         /* Compare field names first. */
     164         504 :         r = strcmp(e1->field, e2->field);
     165         504 :         if (r != 0)
     166         484 :                 return r;
     167             : 
     168             :         /* If field names are the same, compare values. */
     169          20 :         return (strcmp(e1->value, e2->value));
     170             : }
     171             : 
     172             : /*
     173             :  * At the moment we use the following fields to calculate the unique checksum
     174             :  * of the following fields:
     175             :  * - name
     176             :  * - origin
     177             :  * - version
     178             :  * - arch
     179             :  * - options
     180             :  * - required_shlibs
     181             :  * - provided_shlibs
     182             :  * - users
     183             :  * - groups
     184             :  * - dependencies
     185             :  */
     186             : 
     187             : int
     188          63 : pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
     189             :         pkg_checksum_type_t type)
     190             : {
     191             :         unsigned char *bdigest;
     192             :         char *olduid, *buf;
     193             :         size_t blen;
     194          63 :         struct pkg_checksum_entry *entries = NULL;
     195          63 :         struct pkg_option *option = NULL;
     196          63 :         struct pkg_dep *dep = NULL;
     197             :         int i;
     198             : 
     199         126 :         if (pkg == NULL || type >= PKG_HASH_TYPE_UNKNOWN ||
     200          63 :                                         destlen < checksum_types[type].hlen)
     201           0 :                 return (EPKG_FATAL);
     202             : 
     203          63 :         pkg_checksum_add_entry("name", pkg->name, &entries);
     204          63 :         pkg_checksum_add_entry("origin", pkg->origin, &entries);
     205          63 :         pkg_checksum_add_entry("version", pkg->version, &entries);
     206          63 :         pkg_checksum_add_entry("arch", pkg->arch, &entries);
     207             : 
     208         136 :         while (pkg_options(pkg, &option) == EPKG_OK) {
     209          10 :                 pkg_checksum_add_entry(option->key, option->value, &entries);
     210             :         }
     211             : 
     212          63 :         buf = NULL;
     213         126 :         while (pkg_shlibs_required(pkg, &buf) == EPKG_OK) {
     214           0 :                 pkg_checksum_add_entry("required_shlib", buf, &entries);
     215             :         }
     216             : 
     217          63 :         buf = NULL;
     218         126 :         while (pkg_shlibs_provided(pkg, &buf) == EPKG_OK) {
     219           0 :                 pkg_checksum_add_entry("provided_shlib", buf, &entries);
     220             :         }
     221             : 
     222          63 :         buf = NULL;
     223         126 :         while (pkg_users(pkg, &buf) == EPKG_OK) {
     224           0 :                 pkg_checksum_add_entry("user", buf, &entries);
     225             :         }
     226             : 
     227          63 :         buf = NULL;
     228         126 :         while (pkg_groups(pkg, &buf) == EPKG_OK) {
     229           0 :                 pkg_checksum_add_entry("group", buf, &entries);
     230             :         }
     231             : 
     232         174 :         while (pkg_deps(pkg, &dep) == EPKG_OK) {
     233          48 :                 asprintf(&olduid, "%s~%s", dep->name, dep->origin);
     234          48 :                 pkg_checksum_add_entry("depend", olduid, &entries);
     235          48 :                 free(olduid);
     236             :         }
     237             : 
     238          63 :         buf = NULL;
     239         133 :         while (pkg_provides(pkg, &buf) == EPKG_OK) {
     240           7 :                 pkg_checksum_add_entry("provide", buf, &entries);
     241             :         }
     242             : 
     243          63 :         buf = NULL;
     244         138 :         while (pkg_requires(pkg, &buf) == EPKG_OK) {
     245          12 :                 pkg_checksum_add_entry("require", buf, &entries);
     246             :         }
     247             : 
     248             :         /* Sort before hashing */
     249          63 :         DL_SORT(entries, pkg_checksum_entry_cmp);
     250             : 
     251          63 :         checksum_types[type].hfunc(entries, &bdigest, &blen);
     252          63 :         if (blen == 0 || bdigest == NULL) {
     253           0 :                 LL_FREE(entries, pkg_checksum_free_entry);
     254           0 :                 return (EPKG_FATAL);
     255             :         }
     256             : 
     257          63 :         if (checksum_types[type].encfunc) {
     258          63 :                 i = snprintf(dest, destlen, "%d%c%d%c", PKG_CHECKSUM_CUR_VERSION,
     259             :                                 PKG_CKSUM_SEPARATOR, type, PKG_CKSUM_SEPARATOR);
     260          63 :                 assert(i < destlen);
     261          63 :                 checksum_types[type].encfunc(bdigest, blen, dest + i, destlen - i);
     262             :         }
     263             :         else {
     264             :                 /* For raw formats we just output digest */
     265           0 :                 assert(destlen >= blen);
     266           0 :                 memcpy(dest, bdigest, blen);
     267             :         }
     268             : 
     269          63 :         free(bdigest);
     270          63 :         LL_FREE(entries, pkg_checksum_free_entry);
     271             : 
     272          63 :         return (EPKG_OK);
     273             : }
     274             : 
     275             : bool
     276         176 : pkg_checksum_is_valid(const char *cksum, size_t clen)
     277             : {
     278             :         const char *sep;
     279             :         unsigned int value;
     280             : 
     281         176 :         if (clen < 4)
     282           0 :                 return (false);
     283             : 
     284         176 :         sep = strchr(cksum, PKG_CKSUM_SEPARATOR);
     285         176 :         if (sep == NULL || *sep == '\0')
     286           0 :                 return (false);
     287             : 
     288             :         /* Test version */
     289         176 :         value = strtoul(cksum, NULL, 10);
     290         176 :         if (value != PKG_CHECKSUM_CUR_VERSION)
     291           0 :                 return (false);
     292             : 
     293         176 :         cksum = sep + 1;
     294         176 :         sep = strchr(cksum, PKG_CKSUM_SEPARATOR);
     295         176 :         if (sep == NULL || *sep == '\0')
     296           0 :                 return (false);
     297             : 
     298             :         /* Test type */
     299         176 :         value = strtoul(cksum, NULL, 10);
     300         176 :         if (value >= PKG_HASH_TYPE_UNKNOWN)
     301           0 :                 return (false);
     302             : 
     303         176 :         return (true);
     304             : }
     305             : 
     306             : /* <hashtype>$<hash> */
     307             : pkg_checksum_type_t
     308           4 : pkg_checksum_file_get_type(const char *cksum, size_t clen)
     309             : {
     310             :         unsigned int value;
     311             : 
     312           4 :         if (strchr(cksum, PKG_CKSUM_SEPARATOR) == NULL)
     313           2 :                 return (PKG_HASH_TYPE_UNKNOWN);
     314             : 
     315           2 :         value = strtoul(cksum, NULL, 10);
     316           2 :         if (value < PKG_HASH_TYPE_UNKNOWN)
     317           2 :                 return (value);
     318             : 
     319           0 :         return (PKG_HASH_TYPE_UNKNOWN);
     320             : }
     321             : 
     322             : /* <version>$<hashtype>$<hash> */
     323             : pkg_checksum_type_t
     324           0 : pkg_checksum_get_type(const char *cksum, size_t clen)
     325             : {
     326             :         const char *sep;
     327             :         unsigned int value;
     328             : 
     329           0 :         sep = strchr(cksum, PKG_CKSUM_SEPARATOR);
     330           0 :         if (sep != NULL && *sep != '\0') {
     331           0 :                 value = strtoul(sep + 1, NULL, 10);
     332           0 :                 if (value < PKG_HASH_TYPE_UNKNOWN)
     333           0 :                         return (value);
     334             :         }
     335             : 
     336           0 :         return (PKG_HASH_TYPE_UNKNOWN);
     337             : }
     338             : 
     339             : static void
     340          63 : pkg_checksum_hash_sha256(struct pkg_checksum_entry *entries,
     341             :                 unsigned char **out, size_t *outlen)
     342             : {
     343             :         SHA256_CTX sign_ctx;
     344             : 
     345          63 :         SHA256_Init(&sign_ctx);
     346             : 
     347         455 :         while(entries) {
     348         329 :                 SHA256_Update(&sign_ctx, entries->field, strlen(entries->field));
     349         329 :                 SHA256_Update(&sign_ctx, entries->value, strlen(entries->value));
     350         329 :                 entries = entries->next;
     351             :         }
     352          63 :         *out = malloc(SHA256_DIGEST_LENGTH);
     353          63 :         if (*out != NULL) {
     354          63 :                 SHA256_Final(*out, &sign_ctx);
     355          63 :                 *outlen = SHA256_DIGEST_LENGTH;
     356             :         }
     357             :         else {
     358           0 :                 pkg_emit_errno("malloc", "pkg_checksum_hash_sha256");
     359           0 :                 *outlen = 0;
     360             :         }
     361          63 : }
     362             : 
     363             : static void
     364           4 : pkg_checksum_hash_sha256_bulk(const unsigned char *in, size_t inlen,
     365             :                                 unsigned char **out, size_t *outlen)
     366             : {
     367             :         SHA256_CTX sign_ctx;
     368             : 
     369           4 :         *out = malloc(SHA256_DIGEST_LENGTH);
     370           4 :         SHA256_Init(&sign_ctx);
     371           4 :         SHA256_Update(&sign_ctx, in, inlen);
     372           4 :         SHA256_Final(*out, &sign_ctx);
     373           4 :         *outlen = SHA256_DIGEST_LENGTH;
     374           4 : }
     375             : 
     376             : static void
     377          94 : pkg_checksum_hash_sha256_file(int fd, unsigned char **out, size_t *outlen)
     378             : {
     379             :         char buffer[8192];
     380             :         size_t r;
     381             : 
     382             :         SHA256_CTX sign_ctx;
     383          94 :         *out = malloc(SHA256_DIGEST_LENGTH);
     384          94 :         SHA256_Init(&sign_ctx);
     385         222 :         while ((r = read(fd, buffer, sizeof(buffer))) > 0)
     386          34 :                 SHA256_Update(&sign_ctx, buffer, r);
     387          94 :         SHA256_Final(*out, &sign_ctx);
     388          94 :         *outlen = SHA256_DIGEST_LENGTH;
     389          94 : }
     390             : 
     391             : static void
     392           0 : pkg_checksum_hash_blake2(struct pkg_checksum_entry *entries,
     393             :                 unsigned char **out, size_t *outlen)
     394             : {
     395             :         blake2b_state st;
     396             : 
     397           0 :         blake2b_init (&st, BLAKE2B_OUTBYTES);
     398             : 
     399           0 :         while(entries) {
     400           0 :                 blake2b_update (&st, entries->field, strlen(entries->field));
     401           0 :                 blake2b_update (&st, entries->value, strlen(entries->value));
     402           0 :                 entries = entries->next;
     403             :         }
     404           0 :         *out = malloc(BLAKE2B_OUTBYTES);
     405           0 :         if (*out != NULL) {
     406           0 :                 blake2b_final (&st, *out, BLAKE2B_OUTBYTES);
     407           0 :                 *outlen = BLAKE2B_OUTBYTES;
     408             :         }
     409             :         else {
     410           0 :                 pkg_emit_errno("malloc", "pkg_checksum_hash_blake2");
     411           0 :                 *outlen = 0;
     412             :         }
     413           0 : }
     414             : 
     415             : static void
     416           2 : pkg_checksum_hash_blake2_bulk(const unsigned char *in, size_t inlen,
     417             :                                 unsigned char **out, size_t *outlen)
     418             : {
     419           2 :         *out = malloc(BLAKE2B_OUTBYTES);
     420           2 :         blake2b(*out, in, NULL, BLAKE2B_OUTBYTES, inlen, 0);
     421           2 :         *outlen = BLAKE2B_OUTBYTES;
     422           2 : }
     423             : 
     424             : static void
     425           0 : pkg_checksum_hash_blake2_file(int fd, unsigned char **out, size_t *outlen)
     426             : {
     427             :         char buffer[8192];
     428             :         size_t r;
     429             : 
     430             :         blake2b_state st;
     431           0 :         blake2b_init(&st, BLAKE2B_OUTBYTES);
     432             : 
     433           0 :         while ((r = read(fd, buffer, sizeof(buffer))) > 0)
     434           0 :                 blake2b_update(&st, buffer, r);
     435             : 
     436           0 :         *out = malloc(BLAKE2B_OUTBYTES);
     437           0 :         blake2b_final(&st, *out, BLAKE2B_OUTBYTES);
     438           0 :         *outlen = BLAKE2B_OUTBYTES;
     439           0 : }
     440             : 
     441             : /*
     442             :  * We use here z-base32 encoding described here:
     443             :  * http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
     444             :  */
     445             : static const char b32[]="ybndrfg8ejkmcpqxot1uwisza345h769";
     446             : 
     447             : 
     448             : static void
     449          65 : pkg_checksum_encode_base32(unsigned char *in, size_t inlen,
     450             :                                 char *out, size_t outlen)
     451             : {
     452          65 :         int i, remain = -1, r, x;
     453             : 
     454          65 :         if (outlen < inlen * 8 / 5) {
     455           0 :                 pkg_emit_error("cannot encode base32 as outlen is not sufficient");
     456          65 :                 return;
     457             :         }
     458             : 
     459        2209 :         for (i = 0, r = 0; i < inlen; i++) {
     460        2144 :                 switch (i % 5) {
     461             :                 case 0:
     462             :                         /* 8 bits of input and 3 to remain */
     463         467 :                         x = in[i];
     464         467 :                         remain = in[i] >> 5;
     465         467 :                         out[r++] = b32[x & 0x1F];
     466         467 :                         break;
     467             :                 case 1:
     468             :                         /* 11 bits of input, 1 to remain */
     469         467 :                         x = remain | in[i] << 3;
     470         467 :                         out[r++] = b32[x & 0x1F];
     471         467 :                         out[r++] = b32[x >> 5 & 0x1F];
     472         467 :                         remain = x >> 10;
     473         467 :                         break;
     474             :                 case 2:
     475             :                         /* 9 bits of input, 4 to remain */
     476         404 :                         x = remain | in[i] << 1;
     477         404 :                         out[r++] = b32[x & 0x1F];
     478         404 :                         remain = x >> 5;
     479         404 :                         break;
     480             :                 case 3:
     481             :                         /* 12 bits of input, 2 to remain */
     482         404 :                         x = remain | in[i] << 4;
     483         404 :                         out[r++] = b32[x & 0x1F];
     484         404 :                         out[r++] = b32[x >> 5 & 0x1F];
     485         404 :                         remain = x >> 10 & 0x3;
     486         404 :                         break;
     487             :                 case 4:
     488             :                         /* 10 bits of output, nothing to remain */
     489         402 :                         x = remain | in[i] << 2;
     490         402 :                         out[r++] = b32[x & 0x1F];
     491         402 :                         out[r++] = b32[x >> 5 & 0x1F];
     492         402 :                         remain = -1;
     493         402 :                         break;
     494             :                 default:
     495             :                         /* Not to be happen */
     496           0 :                         break;
     497             :                 }
     498             : 
     499             :         }
     500          65 :         if (remain >= 0)
     501          65 :                 out[r++] = b32[remain];
     502             : 
     503          65 :         out[r] = 0;
     504             : }
     505             : 
     506             : static void
     507          98 : pkg_checksum_encode_hex(unsigned char *in, size_t inlen,
     508             :                                 char *out, size_t outlen)
     509             : {
     510             :         int i;
     511             : 
     512          98 :         if (outlen < inlen * 2) {
     513           0 :                 pkg_emit_error("cannot encode hex as outlen is not sufficient");
     514          98 :                 return;
     515             :         }
     516             : 
     517        3234 :         for (i = 0; i < inlen; i++)
     518        3136 :                 sprintf(out + (i * 2), "%02x", in[i]);
     519             : 
     520          98 :         out[inlen * 2] = '\0';
     521             : }
     522             : 
     523             : pkg_checksum_type_t
     524          34 : pkg_checksum_type_from_string(const char *name)
     525             : {
     526             :         int i;
     527          34 :         for (i = 0; i < PKG_HASH_TYPE_UNKNOWN; i ++) {
     528          34 :                 if (strcasecmp(name, checksum_types[i].name) == 0)
     529          34 :                         return (i);
     530             :         }
     531             : 
     532           0 :         return (PKG_HASH_TYPE_UNKNOWN);
     533             : }
     534             : 
     535             : const char*
     536          22 : pkg_checksum_type_to_string(pkg_checksum_type_t type)
     537             : {
     538          22 :         return (checksum_types[type].name);
     539             : }
     540             : 
     541             : size_t
     542         126 : pkg_checksum_type_size(pkg_checksum_type_t type)
     543             : {
     544         126 :         return (checksum_types[type].hlen);
     545             : }
     546             : 
     547             : int
     548          32 : pkg_checksum_calculate(struct pkg *pkg, struct pkgdb *db)
     549             : {
     550             :         char *new_digest;
     551             :         struct pkg_repo *repo;
     552          32 :         int rc = EPKG_OK;
     553          32 :         pkg_checksum_type_t type = 0;
     554             : 
     555          32 :         if (pkg->reponame != NULL) {
     556           0 :                 repo = pkg_repo_find(pkg->reponame);
     557             : 
     558           0 :                 if (repo != NULL)
     559           0 :                         type = repo->meta->digest_format;
     560             :         }
     561             : 
     562          32 :         new_digest = malloc(pkg_checksum_type_size(type));
     563          32 :         if (new_digest == NULL) {
     564           0 :                 pkg_emit_errno("malloc", "pkg_checksum_type_t");
     565           0 :                 return (EPKG_FATAL);
     566             :         }
     567             : 
     568          32 :         if (pkg_checksum_generate(pkg, new_digest, pkg_checksum_type_size(type), type)
     569             :                         != EPKG_OK) {
     570           0 :                 free(new_digest);
     571           0 :                 return (EPKG_FATAL);
     572             :         }
     573             : 
     574          32 :         free(pkg->digest);
     575          32 :         pkg->digest = new_digest;
     576             : 
     577          32 :         if (db != NULL)
     578           0 :                 pkgdb_set_pkg_digest(db, pkg);
     579             : 
     580          32 :         return (rc);
     581             : }
     582             : 
     583             : 
     584             : unsigned char *
     585           6 : pkg_checksum_data(const unsigned char *in, size_t inlen,
     586             :         pkg_checksum_type_t type)
     587             : {
     588             :         const struct _pkg_cksum_type *cksum;
     589           6 :         unsigned char *out, *res = NULL;
     590             :         size_t outlen;
     591             : 
     592           6 :         if (type >= PKG_HASH_TYPE_UNKNOWN || in == NULL)
     593           0 :                 return (NULL);
     594             : 
     595             :         /* Zero terminated string */
     596           6 :         if (inlen == 0) {
     597           0 :                 inlen = strlen(in);
     598             :         }
     599             : 
     600           6 :         cksum = &checksum_types[type];
     601             : 
     602           6 :         cksum->hbulkfunc(in, inlen, &out, &outlen);
     603           6 :         if (out != NULL) {
     604           6 :                 if (cksum->encfunc != NULL) {
     605           6 :                         res = malloc(cksum->hlen);
     606           6 :                         cksum->encfunc(out, outlen, res, cksum->hlen);
     607           6 :                         free(out);
     608             :                 }
     609             :                 else {
     610           0 :                         res = out;
     611             :                 }
     612             :         }
     613             : 
     614           6 :         return (res);
     615             : }
     616             : 
     617             : unsigned char *
     618           0 : pkg_checksum_fileat(int rootfd, const char *path, pkg_checksum_type_t type)
     619             : {
     620             :         int fd;
     621             :         unsigned char *ret;
     622             : 
     623           0 :         if ((fd = openat(rootfd, path, O_RDONLY)) == -1) {
     624           0 :                 pkg_emit_errno("open", path);
     625           0 :                 return (NULL);
     626             :         }
     627             : 
     628           0 :         ret = pkg_checksum_fd(fd, type);
     629             : 
     630           0 :         close(fd);
     631             : 
     632           0 :         return (ret);
     633             : }
     634             : 
     635             : unsigned char *
     636          94 : pkg_checksum_file(const char *path, pkg_checksum_type_t type)
     637             : {
     638             :         int fd;
     639             :         unsigned char *ret;
     640             : 
     641          94 :         if ((fd = open(path, O_RDONLY)) == -1) {
     642           0 :                 pkg_emit_errno("open", path);
     643           0 :                 return (NULL);
     644             :         }
     645             : 
     646          94 :         ret = pkg_checksum_fd(fd, type);
     647             : 
     648          94 :         close(fd);
     649             : 
     650          94 :         return (ret);
     651             : }
     652             : 
     653             : unsigned char *
     654          94 : pkg_checksum_fd(int fd, pkg_checksum_type_t type)
     655             : {
     656             :         const struct _pkg_cksum_type *cksum;
     657          94 :         unsigned char *out, *res = NULL;
     658             :         size_t outlen;
     659             : 
     660          94 :         if (type >= PKG_HASH_TYPE_UNKNOWN || fd < 0)
     661           0 :                 return (NULL);
     662             : 
     663          94 :         cksum = &checksum_types[type];
     664          94 :         cksum->hfilefunc(fd, &out, &outlen);
     665          94 :         if (out != NULL) {
     666          94 :                 if (cksum->encfunc != NULL) {
     667          94 :                         res = malloc(cksum->hlen);
     668          94 :                         cksum->encfunc(out, outlen, res, cksum->hlen);
     669          94 :                         free(out);
     670             :                 } else {
     671           0 :                         res = out;
     672             :                 }
     673             :         }
     674             : 
     675          94 :         return (res);
     676             : }
     677             : 
     678             : static unsigned char *
     679           6 : pkg_checksum_symlink_readlink(const char *linkbuf, int linklen, const char *root, pkg_checksum_type_t type)
     680             : {
     681             :         const char *lnk;
     682             : 
     683           6 :         lnk = linkbuf;
     684           6 :         if (root != NULL) {
     685             :                 /* Skip root from checksum, as it is meaningless */
     686           0 :                 if (strncmp(root, linkbuf, strlen(root)) == 0)
     687           0 :                         lnk += strlen(root);
     688             :         }
     689             : 
     690             :         /* Skip heading slashes */
     691          12 :         while(*lnk == '/')
     692           0 :                 lnk++;
     693             : 
     694           6 :         return (pkg_checksum_data(lnk, linklen, type));
     695             : }
     696             : 
     697             : unsigned char *
     698           6 : pkg_checksum_symlink(const char *path, const char *root, pkg_checksum_type_t type)
     699             : {
     700             :         char linkbuf[MAXPATHLEN];
     701             :         int linklen;
     702             : 
     703           6 :         if ((linklen = readlink(path, linkbuf, sizeof(linkbuf) - 1)) == -1) {
     704           0 :                 pkg_emit_errno("pkg_checksum_symlink", "readlink failed");
     705           0 :                 return (NULL);
     706             :         }
     707           6 :         linkbuf[linklen] = '\0';
     708             : 
     709           6 :         return (pkg_checksum_symlink_readlink(linkbuf, linklen, root, type));
     710             : }
     711             : 
     712             : unsigned char *
     713           0 : pkg_checksum_symlinkat(int fd, const char *path, const char *root, pkg_checksum_type_t type)
     714             : {
     715             :         char linkbuf[MAXPATHLEN];
     716             :         int linklen;
     717             : 
     718           0 :         if ((linklen = readlinkat(fd, path, linkbuf, sizeof(linkbuf) - 1)) == -1) {
     719           0 :                 pkg_emit_errno("pkg_checksum_symlinkat", "readlink failed");
     720           0 :                 return (NULL);
     721             :         }
     722           0 :         linkbuf[linklen] = '\0';
     723             : 
     724           0 :         return (pkg_checksum_symlink_readlink(linkbuf, linklen, root, type));
     725             : }
     726             : 
     727             : bool
     728           4 : pkg_checksum_validate_file(const char *path, const char *sum)
     729             : {
     730             :         struct stat st;
     731             :         char *newsum;
     732             :         pkg_checksum_type_t type;
     733             : 
     734           4 :         type = pkg_checksum_file_get_type(sum, strlen(sum));
     735           4 :         if (type == PKG_HASH_TYPE_UNKNOWN) {
     736           2 :                 type = PKG_HASH_TYPE_SHA256_HEX;
     737             :         } else {
     738           2 :                 sum = strchr(sum, PKG_CKSUM_SEPARATOR);
     739           2 :                 sum++;
     740             :         }
     741             : 
     742           4 :         if (lstat(path, &st) == -1) {
     743           0 :                 pkg_emit_errno("pkg_checksum_validate_file", "lstat");
     744           0 :                 return (false);
     745             :         }
     746             : 
     747           4 :         if (S_ISLNK(st.st_mode))
     748           3 :                 newsum = pkg_checksum_symlink(path, NULL, type);
     749             :         else
     750           1 :                 newsum = pkg_checksum_file(path, type);
     751             : 
     752           4 :         if (newsum == NULL)
     753           0 :                 return (false);
     754             : 
     755           4 :         if (strcmp(sum, newsum) != 0) {
     756           0 :                 free(newsum);
     757           0 :                 return (false);
     758             :         }
     759             : 
     760           4 :         free(newsum);
     761             : 
     762           4 :         return (true);
     763             : }
     764             : 
     765             : char *
     766          63 : pkg_checksum_generate_file(const char *path, pkg_checksum_type_t type)
     767             : {
     768             :         struct stat st;
     769             :         unsigned char *sum;
     770             :         char *cksum;
     771             : 
     772          63 :         if (lstat(path, &st) == -1) {
     773           0 :                 pkg_emit_errno("pkg_checksum_generate_file", "lstat");
     774           0 :                 return (NULL);
     775             :         }
     776             : 
     777          63 :         if (S_ISLNK(st.st_mode))
     778           2 :                 sum = pkg_checksum_symlink(path, NULL, type);
     779             :         else
     780          61 :                 sum = pkg_checksum_file(path, type);
     781             : 
     782          63 :         if (sum == NULL)
     783           0 :                 return (NULL);
     784             : 
     785          63 :         asprintf(&cksum, "%d%c%s", type, PKG_CKSUM_SEPARATOR, sum);
     786          63 :         free(sum);
     787             : 
     788          63 :         return (cksum);
     789             : }
     790             : 
     791             : bool
     792           0 : pkg_checksum_validate_fileat(int rootfd, const char *path, const char *sum)
     793             : {
     794             :         struct stat st;
     795             :         char *newsum;
     796             :         pkg_checksum_type_t type;
     797             : 
     798           0 :         type = pkg_checksum_file_get_type(sum, strlen(sum));
     799           0 :         if (type == PKG_HASH_TYPE_UNKNOWN) {
     800           0 :                 type = PKG_HASH_TYPE_SHA256_HEX;
     801             :         } else {
     802           0 :                 sum = strchr(sum, PKG_CKSUM_SEPARATOR);
     803           0 :                 sum++;
     804             :         }
     805             : 
     806           0 :         if (fstatat(rootfd, path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
     807           0 :                 pkg_emit_errno("pkg_checksum_validate_file", "lstat");
     808           0 :                 return (false);
     809             :         }
     810             : 
     811           0 :         if (S_ISLNK(st.st_mode))
     812           0 :                 newsum = pkg_checksum_symlinkat(rootfd, path, NULL, type);
     813             :         else
     814           0 :                 newsum = pkg_checksum_fileat(rootfd, path, type);
     815             : 
     816           0 :         if (newsum == NULL)
     817           0 :                 return (false);
     818             : 
     819           0 :         if (strcmp(sum, newsum) != 0) {
     820           0 :                 free(newsum);
     821           0 :                 return (false);
     822             :         }
     823             : 
     824           0 :         free(newsum);
     825             : 
     826           0 :         return (true);
     827             : }
     828             : 
     829             : char *
     830           0 : pkg_checksum_generate_fileat(int rootfd, const char *path,
     831             :     pkg_checksum_type_t type)
     832             : {
     833             :         struct stat st;
     834             :         unsigned char *sum;
     835             :         char *cksum;
     836             : 
     837           0 :         if (fstatat(rootfd, path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
     838           0 :                 pkg_emit_errno("pkg_checksum_generate_file", "lstat");
     839           0 :                 return (NULL);
     840             :         }
     841             : 
     842           0 :         if (S_ISLNK(st.st_mode))
     843           0 :                 sum = pkg_checksum_symlinkat(rootfd, path, NULL, type);
     844             :         else
     845           0 :                 sum = pkg_checksum_fileat(rootfd, path, type);
     846             : 
     847           0 :         if (sum == NULL)
     848           0 :                 return (NULL);
     849             : 
     850           0 :         asprintf(&cksum, "%d%c%s", type, PKG_CKSUM_SEPARATOR, sum);
     851           0 :         free(sum);
     852             : 
     853           0 :         return (cksum);
     854             : }

Generated by: LCOV version 1.10