Branch data 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 <errno.h>
31 : : #include "pkg.h"
32 : : #include "private/pkg.h"
33 : : #include "private/event.h"
34 : : #include "sha256.h"
35 : : #include "blake2.h"
36 : :
37 : : struct pkg_checksum_entry {
38 : : const char *field;
39 : : char *value;
40 : : struct pkg_checksum_entry *next, *prev;
41 : : };
42 : :
43 : : /* Separate checksum parts */
44 : : #define PKG_CKSUM_SEPARATOR '$'
45 : :
46 : : /* Hash is in format <version>:<typeid>:<hexhash> */
47 : : #define PKG_CHECKSUM_SHA256_LEN (SHA256_BLOCK_SIZE * 2 + 1)
48 : : #define PKG_CHECKSUM_BLAKE2_LEN (BLAKE2B_OUTBYTES * 8 / 5 + sizeof("100") * 2 + 2)
49 : : #define PKG_CHECKSUM_BLAKE2S_LEN (BLAKE2S_OUTBYTES * 8 / 5 + sizeof("100") * 2 + 2)
50 : : #define PKG_CHECKSUM_CUR_VERSION 2
51 : :
52 : : typedef void (*pkg_checksum_hash_func)(struct pkg_checksum_entry *entries,
53 : : unsigned char **out, size_t *outlen);
54 : : typedef void (*pkg_checksum_hash_bulk_func)(const unsigned char *in, size_t inlen,
55 : : unsigned char **out, size_t *outlen);
56 : : typedef void (*pkg_checksum_encode_func)(unsigned char *in, size_t inlen,
57 : : char *out, size_t outlen);
58 : :
59 : : typedef void (*pkg_checksum_hash_file_func)(int fd, unsigned char **out,
60 : : size_t *outlen);
61 : :
62 : : static void pkg_checksum_hash_sha256(struct pkg_checksum_entry *entries,
63 : : unsigned char **out, size_t *outlen);
64 : : static void pkg_checksum_hash_sha256_bulk(const unsigned char *in, size_t inlen,
65 : : unsigned char **out, size_t *outlen);
66 : : static void pkg_checksum_hash_sha256_file(int fd, unsigned char **out,
67 : : size_t *outlen);
68 : : static void pkg_checksum_hash_blake2(struct pkg_checksum_entry *entries,
69 : : unsigned char **out, size_t *outlen);
70 : : static void pkg_checksum_hash_blake2_bulk(const unsigned char *in, size_t inlen,
71 : : unsigned char **out, size_t *outlen);
72 : : static void pkg_checksum_hash_blake2_file(int fd, unsigned char **out,
73 : : size_t *outlen);
74 : : static void pkg_checksum_hash_blake2s(struct pkg_checksum_entry *entries,
75 : : unsigned char **out, size_t *outlen);
76 : : static void pkg_checksum_hash_blake2s_bulk(const unsigned char *in, size_t inlen,
77 : : unsigned char **out, size_t *outlen);
78 : : static void pkg_checksum_hash_blake2s_file(int fd, unsigned char **out,
79 : : size_t *outlen);
80 : : static void pkg_checksum_encode_base32(unsigned char *in, size_t inlen,
81 : : char *out, size_t outlen);
82 : : static void pkg_checksum_encode_hex(unsigned char *in, size_t inlen,
83 : : char *out, size_t outlen);
84 : :
85 : : static const struct _pkg_cksum_type {
86 : : const char *name;
87 : : size_t hlen;
88 : : pkg_checksum_hash_func hfunc;
89 : : pkg_checksum_hash_bulk_func hbulkfunc;
90 : : pkg_checksum_hash_file_func hfilefunc;
91 : : pkg_checksum_encode_func encfunc;
92 : : } checksum_types[] = {
93 : : [PKG_HASH_TYPE_SHA256_BASE32] = {
94 : : "sha256_base32",
95 : : PKG_CHECKSUM_SHA256_LEN,
96 : : pkg_checksum_hash_sha256,
97 : : pkg_checksum_hash_sha256_bulk,
98 : : pkg_checksum_hash_sha256_file,
99 : : pkg_checksum_encode_base32
100 : : },
101 : : [PKG_HASH_TYPE_SHA256_HEX] = {
102 : : "sha256_hex",
103 : : PKG_CHECKSUM_SHA256_LEN,
104 : : pkg_checksum_hash_sha256,
105 : : pkg_checksum_hash_sha256_bulk,
106 : : pkg_checksum_hash_sha256_file,
107 : : pkg_checksum_encode_hex
108 : : },
109 : : [PKG_HASH_TYPE_BLAKE2_BASE32] = {
110 : : "blake2_base32",
111 : : PKG_CHECKSUM_BLAKE2_LEN,
112 : : pkg_checksum_hash_blake2,
113 : : pkg_checksum_hash_blake2_bulk,
114 : : pkg_checksum_hash_blake2_file,
115 : : pkg_checksum_encode_base32
116 : : },
117 : : [PKG_HASH_TYPE_SHA256_RAW] = {
118 : : "sha256_raw",
119 : : SHA256_BLOCK_SIZE,
120 : : pkg_checksum_hash_sha256,
121 : : pkg_checksum_hash_sha256_bulk,
122 : : pkg_checksum_hash_sha256_file,
123 : : NULL
124 : : },
125 : : [PKG_HASH_TYPE_BLAKE2_RAW] = {
126 : : "blake2_raw",
127 : : BLAKE2B_OUTBYTES,
128 : : pkg_checksum_hash_blake2,
129 : : pkg_checksum_hash_blake2_bulk,
130 : : pkg_checksum_hash_blake2_file,
131 : : NULL
132 : : },
133 : : [PKG_HASH_TYPE_BLAKE2S_BASE32] = {
134 : : "blake2s_base32",
135 : : PKG_CHECKSUM_BLAKE2S_LEN,
136 : : pkg_checksum_hash_blake2s,
137 : : pkg_checksum_hash_blake2s_bulk,
138 : : pkg_checksum_hash_blake2s_file,
139 : : pkg_checksum_encode_base32
140 : : },
141 : : [PKG_HASH_TYPE_BLAKE2S_RAW] = {
142 : : "blake2_raw",
143 : : BLAKE2S_OUTBYTES,
144 : : pkg_checksum_hash_blake2s,
145 : : pkg_checksum_hash_blake2s_bulk,
146 : : pkg_checksum_hash_blake2s_file,
147 : : NULL
148 : : },
149 : : [PKG_HASH_TYPE_UNKNOWN] = {
150 : : NULL,
151 : : -1,
152 : : NULL,
153 : : NULL,
154 : : NULL
155 : : }
156 : : };
157 : :
158 : : static void
159 : 4336 : pkg_checksum_free_entry(struct pkg_checksum_entry *e)
160 : : {
161 [ - + ]: 4336 : if (e != NULL) {
162 [ + - ]: 4336 : if (e->value) {
163 : 4336 : free(e->value);
164 : 4336 : }
165 : 4336 : free(e);
166 : 4336 : }
167 : 4336 : }
168 : :
169 : : static void
170 : 4336 : pkg_checksum_add_entry(const char *key,
171 : : const char *value,
172 : : struct pkg_checksum_entry **entries)
173 : : {
174 : : struct pkg_checksum_entry *e;
175 : :
176 : 4336 : e = xmalloc(sizeof(*e));
177 : 4336 : e->field = key;
178 : 4336 : e->value = xstrdup(value);
179 [ + + ]: 4336 : DL_APPEND(*entries, e);
180 : 4336 : }
181 : :
182 : : static int
183 : 6015 : pkg_checksum_entry_cmp(struct pkg_checksum_entry *e1,
184 : : struct pkg_checksum_entry *e2)
185 : : {
186 : : int r;
187 : :
188 : : /* Compare field names first. */
189 : 6015 : r = strcmp(e1->field, e2->field);
190 [ + + ]: 6015 : if (r != 0)
191 : 5963 : return r;
192 : :
193 : : /* If field names are the same, compare values. */
194 : 52 : return (strcmp(e1->value, e2->value));
195 : 6015 : }
196 : :
197 : : /*
198 : : * At the moment we use the following fields to calculate the unique checksum
199 : : * of the following fields:
200 : : * - name
201 : : * - origin
202 : : * - version
203 : : * - arch
204 : : * - options
205 : : * - required_shlibs
206 : : * - provided_shlibs
207 : : * - users
208 : : * - groups
209 : : * - dependencies
210 : : */
211 : :
212 : : int
213 : 935 : pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
214 : : pkg_checksum_type_t type, bool inc_scripts, bool inc_version, bool inc_files)
215 : : {
216 : : unsigned char *bdigest;
217 : : char *olduid, *buf;
218 : : size_t blen;
219 : 935 : struct pkg_checksum_entry *entries = NULL;
220 : 935 : struct pkg_option *option = NULL;
221 : 935 : struct pkg_dep *dep = NULL;
222 : 935 : struct pkg_file *f = NULL;
223 : : pkghash_it it;
224 : : int i;
225 : :
226 [ + - + - : 935 : if (pkg == NULL || type >= PKG_HASH_TYPE_UNKNOWN ||
- + ]
227 : 935 : destlen < checksum_types[type].hlen)
228 : 0 : return (EPKG_FATAL);
229 : :
230 : 935 : pkg_checksum_add_entry("name", pkg->name, &entries);
231 : 935 : pkg_checksum_add_entry("origin", pkg->origin, &entries);
232 [ + + ]: 935 : if (inc_version)
233 : 927 : pkg_checksum_add_entry("version", pkg->version, &entries);
234 : 935 : pkg_checksum_add_entry("arch", pkg->arch, &entries);
235 : :
236 [ + + ]: 1071 : while (pkg_options(pkg, &option) == EPKG_OK) {
237 : 136 : pkg_checksum_add_entry(option->key, option->value, &entries);
238 : : }
239 : :
240 : 935 : buf = NULL;
241 : 935 : it = pkghash_iterator(pkg->shlibs_required);
242 [ + + ]: 943 : while (pkghash_next(&it)) {
243 : 8 : pkg_checksum_add_entry("required_shlib", it.key, &entries);
244 : : }
245 : :
246 : 935 : buf = NULL;
247 : 935 : it = pkghash_iterator(pkg->shlibs_provided);
248 [ + + ]: 955 : while (pkghash_next(&it)) {
249 : 20 : pkg_checksum_add_entry("provided_shlib", it.key, &entries);
250 : : }
251 : :
252 : 935 : buf = NULL;
253 : 935 : it = pkghash_iterator(pkg->users);
254 [ - + ]: 935 : while (pkghash_next(&it)) {
255 : 0 : pkg_checksum_add_entry("user", it.key, &entries);
256 : : }
257 : :
258 : 935 : buf = NULL;
259 : 935 : it = pkghash_iterator(pkg->groups);
260 [ - + ]: 935 : while (pkghash_next(&it)) {
261 : 0 : pkg_checksum_add_entry("group", it.key, &entries);
262 : : }
263 : :
264 [ + + ]: 1147 : while (pkg_deps(pkg, &dep) == EPKG_OK) {
265 : 212 : xasprintf(&olduid, "%s~%s", dep->name, dep->origin);
266 : 212 : pkg_checksum_add_entry("depend", olduid, &entries);
267 : 212 : free(olduid);
268 : : }
269 : :
270 : 935 : buf = NULL;
271 : 935 : it = pkghash_iterator(pkg->provides);
272 [ + + ]: 951 : while (pkghash_next(&it)) {
273 : 16 : pkg_checksum_add_entry("provide", it.key, &entries);
274 : : }
275 : :
276 : 935 : buf = NULL;
277 : 935 : it = pkghash_iterator(pkg->requires);
278 [ + + ]: 959 : while (pkghash_next(&it)) {
279 : 24 : pkg_checksum_add_entry("require", it.key, &entries);
280 : : }
281 : :
282 [ + + ]: 935 : if (inc_scripts) {
283 [ + + ]: 80 : for (int i = 0; i < PKG_NUM_SCRIPTS; i++) {
284 [ - + ]: 72 : if (pkg->scripts[i] != NULL) {
285 : 0 : fflush(pkg->scripts[i]->fp);
286 : 0 : pkg_checksum_add_entry("script",
287 : 0 : pkg->scripts[i]->buf,
288 : : &entries);
289 : 0 : }
290 : 72 : }
291 [ + + ]: 48 : for (int i = 0; i < PKG_NUM_LUA_SCRIPTS; i++) {
292 [ - + ]: 40 : if (pkg->lua_scripts[i] != NULL)
293 : 0 : pkg_checksum_add_entry("lua_script",
294 : 0 : pkg->lua_scripts[i]->script,
295 : : &entries);
296 : 40 : }
297 : 8 : }
298 : :
299 [ + + ]: 1123 : while (pkg_files(pkg, &f) == EPKG_OK) {
300 : 188 : pkg_checksum_add_entry(f->path, f->sum, &entries);
301 : : }
302 : :
303 : : /* Sort before hashing */
304 [ + - + + : 23706 : DL_SORT(entries, pkg_checksum_entry_cmp);
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + ]
305 : :
306 : 935 : checksum_types[type].hfunc(entries, &bdigest, &blen);
307 [ + - - + ]: 935 : if (blen == 0 || bdigest == NULL) {
308 [ # # # # : 0 : LL_FREE(entries, pkg_checksum_free_entry);
# # # # #
# # # ]
309 : 0 : return (EPKG_FATAL);
310 : : }
311 : :
312 [ + - ]: 935 : if (checksum_types[type].encfunc) {
313 : 1870 : i = snprintf(dest, destlen, "%d%c%d%c", PKG_CHECKSUM_CUR_VERSION,
314 : 935 : PKG_CKSUM_SEPARATOR, type, PKG_CKSUM_SEPARATOR);
315 [ + - ]: 935 : assert(i < destlen);
316 : 935 : checksum_types[type].encfunc(bdigest, blen, dest + i, destlen - i);
317 : 935 : }
318 : : else {
319 : : /* For raw formats we just output digest */
320 [ # # ]: 0 : assert(destlen >= blen);
321 : 0 : memcpy(dest, bdigest, blen);
322 : : }
323 : :
324 : 935 : free(bdigest);
325 [ + + + + : 5271 : LL_FREE(entries, pkg_checksum_free_entry);
- + # # #
# # # ]
326 : :
327 : 935 : return (EPKG_OK);
328 : 935 : }
329 : :
330 : : bool
331 : 4983 : pkg_checksum_is_valid(const char *cksum, size_t clen)
332 : : {
333 : : const char *sep;
334 : : unsigned int value;
335 : :
336 [ - + ]: 4983 : if (clen < 4)
337 : 0 : return (false);
338 : :
339 : 4983 : sep = strchr(cksum, PKG_CKSUM_SEPARATOR);
340 [ + - - + ]: 4983 : if (sep == NULL || *sep == '\0')
341 : 0 : return (false);
342 : :
343 : : /* Test version */
344 : 4983 : value = strtoul(cksum, NULL, 10);
345 [ - + ]: 4983 : if (value != PKG_CHECKSUM_CUR_VERSION)
346 : 0 : return (false);
347 : :
348 : 4983 : cksum = sep + 1;
349 : 4983 : sep = strchr(cksum, PKG_CKSUM_SEPARATOR);
350 [ + - - + ]: 4983 : if (sep == NULL || *sep == '\0')
351 : 0 : return (false);
352 : :
353 : : /* Test type */
354 : 4983 : value = strtoul(cksum, NULL, 10);
355 [ - + ]: 4983 : if (value >= PKG_HASH_TYPE_UNKNOWN)
356 : 0 : return (false);
357 : :
358 : 4983 : return (true);
359 : 4983 : }
360 : :
361 : : /* <hashtype>$<hash> */
362 : : pkg_checksum_type_t
363 : 69 : pkg_checksum_file_get_type(const char *cksum, size_t clen __unused)
364 : : {
365 : : unsigned int value;
366 : :
367 [ + + ]: 69 : if (strchr(cksum, PKG_CKSUM_SEPARATOR) == NULL)
368 : 30 : return (PKG_HASH_TYPE_UNKNOWN);
369 : :
370 : 39 : value = strtoul(cksum, NULL, 10);
371 [ + - ]: 39 : if (value < PKG_HASH_TYPE_UNKNOWN)
372 : 39 : return (value);
373 : :
374 : 0 : return (PKG_HASH_TYPE_UNKNOWN);
375 : 69 : }
376 : :
377 : : /* <version>$<hashtype>$<hash> */
378 : : pkg_checksum_type_t
379 : 0 : pkg_checksum_get_type(const char *cksum, size_t clen __unused)
380 : : {
381 : : const char *sep;
382 : : unsigned int value;
383 : :
384 : 0 : sep = strchr(cksum, PKG_CKSUM_SEPARATOR);
385 [ # # # # ]: 0 : if (sep != NULL && *sep != '\0') {
386 : 0 : value = strtoul(sep + 1, NULL, 10);
387 [ # # ]: 0 : if (value < PKG_HASH_TYPE_UNKNOWN)
388 : 0 : return (value);
389 : 0 : }
390 : :
391 : 0 : return (PKG_HASH_TYPE_UNKNOWN);
392 : 0 : }
393 : :
394 : : static void
395 : 0 : pkg_checksum_hash_sha256(struct pkg_checksum_entry *entries,
396 : : unsigned char **out, size_t *outlen)
397 : : {
398 : : SHA256_CTX sign_ctx;
399 : :
400 : 0 : sha256_init(&sign_ctx);
401 : :
402 [ # # ]: 0 : while(entries) {
403 : 0 : sha256_update(&sign_ctx, entries->field, strlen(entries->field));
404 : 0 : sha256_update(&sign_ctx, entries->value, strlen(entries->value));
405 : 0 : entries = entries->next;
406 : : }
407 : 0 : *out = xmalloc(SHA256_BLOCK_SIZE);
408 : 0 : sha256_final(&sign_ctx, *out);
409 : 0 : *outlen = SHA256_BLOCK_SIZE;
410 : 0 : }
411 : :
412 : : static void
413 : 116 : pkg_checksum_hash_sha256_bulk(const unsigned char *in, size_t inlen,
414 : : unsigned char **out, size_t *outlen)
415 : : {
416 : : SHA256_CTX sign_ctx;
417 : :
418 : 116 : *out = xmalloc(SHA256_BLOCK_SIZE);
419 : 116 : sha256_init(&sign_ctx);
420 : 116 : sha256_update(&sign_ctx, in, inlen);
421 : 116 : sha256_final(&sign_ctx, *out);
422 : 116 : *outlen = SHA256_BLOCK_SIZE;
423 : 116 : }
424 : :
425 : : static void
426 : 1050 : pkg_checksum_hash_sha256_file(int fd, unsigned char **out, size_t *outlen)
427 : : {
428 : : char buffer[8192];
429 : : ssize_t r;
430 : :
431 : : SHA256_CTX sign_ctx;
432 : 1050 : *out = xmalloc(SHA256_BLOCK_SIZE);
433 : 1050 : sha256_init(&sign_ctx);
434 [ + + ]: 1527 : while ((r = read(fd, buffer, sizeof(buffer))) > 0)
435 : 477 : sha256_update(&sign_ctx, buffer, r);
436 [ - + ]: 1050 : if (r < 0) {
437 : 0 : pkg_emit_errno(__func__, "read failed");
438 : 0 : free(*out);
439 : 0 : *out = NULL;
440 : 0 : return;
441 : : }
442 : 1050 : sha256_final(&sign_ctx, *out);
443 : 1050 : *outlen = SHA256_BLOCK_SIZE;
444 : 1050 : }
445 : :
446 : : static void
447 : 935 : pkg_checksum_hash_blake2(struct pkg_checksum_entry *entries,
448 : : unsigned char **out, size_t *outlen)
449 : : {
450 : : blake2b_state st;
451 : :
452 : 935 : blake2b_init (&st, BLAKE2B_OUTBYTES);
453 : :
454 [ + + ]: 5271 : while(entries) {
455 : 4336 : blake2b_update (&st, entries->field, strlen(entries->field));
456 : 4336 : blake2b_update (&st, entries->value, strlen(entries->value));
457 : 4336 : entries = entries->next;
458 : : }
459 : 935 : *out = xmalloc(BLAKE2B_OUTBYTES);
460 : 935 : blake2b_final (&st, *out, BLAKE2B_OUTBYTES);
461 : 935 : *outlen = BLAKE2B_OUTBYTES;
462 : 935 : }
463 : :
464 : : static void
465 : 26 : pkg_checksum_hash_blake2_bulk(const unsigned char *in, size_t inlen,
466 : : unsigned char **out, size_t *outlen)
467 : : {
468 : 26 : *out = xmalloc(BLAKE2B_OUTBYTES);
469 : 26 : blake2b(*out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0);
470 : 26 : *outlen = BLAKE2B_OUTBYTES;
471 : 26 : }
472 : :
473 : : static void
474 : 0 : pkg_checksum_hash_blake2_file(int fd, unsigned char **out, size_t *outlen)
475 : : {
476 : : char buffer[8192];
477 : : ssize_t r;
478 : :
479 : : blake2b_state st;
480 : 0 : blake2b_init(&st, BLAKE2B_OUTBYTES);
481 : :
482 [ # # ]: 0 : while ((r = read(fd, buffer, sizeof(buffer))) > 0)
483 : 0 : blake2b_update(&st, buffer, r);
484 [ # # ]: 0 : if (r < 0) {
485 : 0 : pkg_emit_errno(__func__, "read failed");
486 : 0 : free(*out);
487 : 0 : *out = NULL;
488 : 0 : return;
489 : : }
490 : 0 : *out = xmalloc(BLAKE2B_OUTBYTES);
491 : 0 : blake2b_final(&st, *out, BLAKE2B_OUTBYTES);
492 : 0 : *outlen = BLAKE2B_OUTBYTES;
493 : 0 : }
494 : :
495 : : static void
496 : 0 : pkg_checksum_hash_blake2s(struct pkg_checksum_entry *entries,
497 : : unsigned char **out, size_t *outlen)
498 : : {
499 : : blake2s_state st;
500 : :
501 : 0 : blake2s_init (&st, BLAKE2S_OUTBYTES);
502 : :
503 [ # # ]: 0 : while(entries) {
504 : 0 : blake2s_update (&st, entries->field, strlen(entries->field));
505 : 0 : blake2s_update (&st, entries->value, strlen(entries->value));
506 : 0 : entries = entries->next;
507 : : }
508 : 0 : *out = xmalloc(BLAKE2S_OUTBYTES);
509 : 0 : blake2s_final (&st, *out, BLAKE2S_OUTBYTES);
510 : 0 : *outlen = BLAKE2S_OUTBYTES;
511 : 0 : }
512 : :
513 : : static void
514 : 26 : pkg_checksum_hash_blake2s_bulk(const unsigned char *in, size_t inlen,
515 : : unsigned char **out, size_t *outlen)
516 : : {
517 : 26 : *out = xmalloc(BLAKE2S_OUTBYTES);
518 : 26 : blake2s(*out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0);
519 : 26 : *outlen = BLAKE2S_OUTBYTES;
520 : 26 : }
521 : :
522 : : static void
523 : 0 : pkg_checksum_hash_blake2s_file(int fd, unsigned char **out, size_t *outlen)
524 : : {
525 : : char buffer[8192];
526 : : ssize_t r;
527 : :
528 : : blake2s_state st;
529 : 0 : blake2s_init(&st, BLAKE2S_OUTBYTES);
530 : :
531 [ # # ]: 0 : while ((r = read(fd, buffer, sizeof(buffer))) > 0)
532 : 0 : blake2s_update(&st, buffer, r);
533 [ # # ]: 0 : if (r < 0) {
534 : 0 : pkg_emit_errno(__func__, "read failed");
535 : 0 : free(*out);
536 : 0 : *out = NULL;
537 : 0 : return;
538 : : }
539 : 0 : *out = xmalloc(BLAKE2S_OUTBYTES);
540 : 0 : blake2s_final(&st, *out, BLAKE2S_OUTBYTES);
541 : 0 : *outlen = BLAKE2S_OUTBYTES;
542 : 0 : }
543 : :
544 : : /*
545 : : * We use here z-base32 encoding described here:
546 : : * http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
547 : : */
548 : : static const char b32[]="ybndrfg8ejkmcpqxot1uwisza345h769";
549 : :
550 : :
551 : : static void
552 : 987 : pkg_checksum_encode_base32(unsigned char *in, size_t inlen,
553 : : char *out, size_t outlen)
554 : : {
555 : 987 : int i, remain = -1, r, x;
556 : :
557 [ - + ]: 987 : if (outlen < inlen * 8 / 5) {
558 : 0 : pkg_emit_error("cannot encode base32 as outlen is not sufficient");
559 : 0 : return;
560 : : }
561 : :
562 [ + + ]: 63323 : for (i = 0, r = 0; i < inlen; i++) {
563 [ - + + + : 62336 : switch (i % 5) {
+ + ]
564 : : case 0:
565 : : /* 8 bits of input and 3 to remain */
566 : 12675 : x = in[i];
567 : 12675 : remain = in[i] >> 5;
568 : 12675 : out[r++] = b32[x & 0x1F];
569 : 12675 : break;
570 : : case 1:
571 : : /* 11 bits of input, 1 to remain */
572 : 12675 : x = remain | in[i] << 3;
573 : 12675 : out[r++] = b32[x & 0x1F];
574 : 12675 : out[r++] = b32[x >> 5 & 0x1F];
575 : 12675 : remain = x >> 10;
576 : 12675 : break;
577 : : case 2:
578 : : /* 9 bits of input, 4 to remain */
579 : 12649 : x = remain | in[i] << 1;
580 : 12649 : out[r++] = b32[x & 0x1F];
581 : 12649 : remain = x >> 5;
582 : 12649 : break;
583 : : case 3:
584 : : /* 12 bits of input, 2 to remain */
585 : 12649 : x = remain | in[i] << 4;
586 : 12649 : out[r++] = b32[x & 0x1F];
587 : 12649 : out[r++] = b32[x >> 5 & 0x1F];
588 : 12649 : remain = x >> 10 & 0x3;
589 : 12649 : break;
590 : : case 4:
591 : : /* 10 bits of output, nothing to remain */
592 : 11688 : x = remain | in[i] << 2;
593 : 11688 : out[r++] = b32[x & 0x1F];
594 : 11688 : out[r++] = b32[x >> 5 & 0x1F];
595 : 11688 : remain = -1;
596 : 11688 : break;
597 : : default:
598 : : /* Not to be happen */
599 : 0 : break;
600 : : }
601 : :
602 : 62336 : }
603 [ - + ]: 987 : if (remain >= 0)
604 : 987 : out[r++] = b32[remain];
605 : :
606 : 987 : out[r] = 0;
607 : 987 : }
608 : :
609 : : static void
610 : 1166 : pkg_checksum_encode_hex(unsigned char *in, size_t inlen,
611 : : char *out, size_t outlen)
612 : : {
613 : : int i;
614 : :
615 [ - + ]: 1166 : if (outlen < inlen * 2) {
616 : 0 : pkg_emit_error("cannot encode hex as outlen is not sufficient");
617 : 0 : return;
618 : : }
619 : :
620 [ + + ]: 38478 : for (i = 0; i < inlen; i++)
621 : 37312 : sprintf(out + (i * 2), "%02x", in[i]);
622 : :
623 : 1166 : out[inlen * 2] = '\0';
624 : 1166 : }
625 : :
626 : : pkg_checksum_type_t
627 : 8 : pkg_checksum_type_from_string(const char *name)
628 : : {
629 : : int i;
630 [ + - ]: 8 : for (i = 0; i < PKG_HASH_TYPE_UNKNOWN; i ++) {
631 [ + - ]: 8 : if (strcasecmp(name, checksum_types[i].name) == 0)
632 : 8 : return (i);
633 : 0 : }
634 : :
635 : 0 : return (PKG_HASH_TYPE_UNKNOWN);
636 : 8 : }
637 : :
638 : : const char*
639 : 16 : pkg_checksum_type_to_string(pkg_checksum_type_t type)
640 : : {
641 : 16 : return (checksum_types[type].name);
642 : : }
643 : :
644 : : size_t
645 : 1894 : pkg_checksum_type_size(pkg_checksum_type_t type)
646 : : {
647 : 1894 : return (checksum_types[type].hlen);
648 : : }
649 : :
650 : : int
651 : 935 : pkg_checksum_calculate(struct pkg *pkg, struct pkgdb *db, bool inc_scripts,
652 : : bool inc_version, bool inc_files)
653 : : {
654 : : char *new_digest;
655 : : struct pkg_repo *repo;
656 : 935 : int rc = EPKG_OK;
657 : : pkg_checksum_type_t type;
658 : :
659 : : if (sizeof(void *) == 8)
660 : 935 : type = PKG_HASH_TYPE_BLAKE2_BASE32;
661 : : else
662 : : type = PKG_HASH_TYPE_BLAKE2S_BASE32;
663 : :
664 [ + - ]: 935 : if (pkg->reponame != NULL) {
665 : 0 : repo = pkg_repo_find(pkg->reponame);
666 : :
667 [ # # ]: 0 : if (repo != NULL)
668 : 0 : type = repo->meta->digest_format;
669 : 0 : }
670 : :
671 : 935 : new_digest = xmalloc(pkg_checksum_type_size(type));
672 [ - + - + : 2805 : if (pkg_checksum_generate(pkg, new_digest, pkg_checksum_type_size(type),
- + ]
673 : 935 : type, inc_scripts, inc_version, inc_files)
674 : 935 : != EPKG_OK) {
675 : 0 : free(new_digest);
676 : 0 : return (EPKG_FATAL);
677 : : }
678 : :
679 : 935 : free(pkg->digest);
680 : 935 : pkg->digest = new_digest;
681 : :
682 [ + + ]: 935 : if (db != NULL)
683 : 216 : pkgdb_set_pkg_digest(db, pkg);
684 : :
685 : 935 : return (rc);
686 : 935 : }
687 : :
688 : :
689 : : unsigned char *
690 : 168 : pkg_checksum_data(const unsigned char *in, size_t inlen,
691 : : pkg_checksum_type_t type)
692 : : {
693 : : const struct _pkg_cksum_type *cksum;
694 : 168 : unsigned char *out, *res = NULL;
695 : : size_t outlen;
696 : :
697 [ + - + - ]: 168 : if (type >= PKG_HASH_TYPE_UNKNOWN || in == NULL)
698 : 0 : return (NULL);
699 : :
700 : : /* Zero terminated string */
701 [ + - ]: 168 : if (inlen == 0) {
702 : 0 : inlen = strlen(in);
703 : 0 : }
704 : :
705 : 168 : cksum = &checksum_types[type];
706 : :
707 : 168 : cksum->hbulkfunc(in, inlen, &out, &outlen);
708 [ - + ]: 168 : if (out != NULL) {
709 [ - + ]: 168 : if (cksum->encfunc != NULL) {
710 : 168 : res = xmalloc(cksum->hlen);
711 : 168 : cksum->encfunc(out, outlen, res, cksum->hlen);
712 : 168 : free(out);
713 : 168 : }
714 : : else {
715 : 0 : res = out;
716 : : }
717 : 168 : }
718 : :
719 : 168 : return (res);
720 : 168 : }
721 : :
722 : : unsigned char *
723 : 258 : pkg_checksum_fileat(int rootfd, const char *path, pkg_checksum_type_t type)
724 : : {
725 : : int fd;
726 : : unsigned char *ret;
727 : :
728 [ - + ]: 258 : if ((fd = openat(rootfd, path, O_RDONLY)) == -1) {
729 : 0 : pkg_emit_errno("open", path);
730 : 0 : return (NULL);
731 : : }
732 : :
733 : 258 : ret = pkg_checksum_fd(fd, type);
734 : :
735 : 258 : close(fd);
736 : :
737 : 258 : return (ret);
738 : 258 : }
739 : :
740 : : unsigned char *
741 : 792 : pkg_checksum_file(const char *path, pkg_checksum_type_t type)
742 : : {
743 : : int fd;
744 : : unsigned char *ret;
745 : :
746 [ - + ]: 792 : if ((fd = open(path, O_RDONLY)) == -1) {
747 : 0 : pkg_emit_errno("open", path);
748 : 0 : return (NULL);
749 : : }
750 : :
751 : 792 : ret = pkg_checksum_fd(fd, type);
752 : :
753 : 792 : close(fd);
754 : :
755 : 792 : return (ret);
756 : 792 : }
757 : :
758 : : unsigned char *
759 : 1050 : pkg_checksum_fd(int fd, pkg_checksum_type_t type)
760 : : {
761 : : const struct _pkg_cksum_type *cksum;
762 : 1050 : unsigned char *out, *res = NULL;
763 : : size_t outlen;
764 : :
765 [ + - + - ]: 1050 : if (type >= PKG_HASH_TYPE_UNKNOWN || fd < 0)
766 : 0 : return (NULL);
767 : :
768 : 1050 : cksum = &checksum_types[type];
769 : 1050 : cksum->hfilefunc(fd, &out, &outlen);
770 [ - + ]: 1050 : if (out != NULL) {
771 [ - + ]: 1050 : if (cksum->encfunc != NULL) {
772 : 1050 : res = xmalloc(cksum->hlen);
773 : 1050 : cksum->encfunc(out, outlen, res, cksum->hlen);
774 : 1050 : free(out);
775 : 1050 : } else {
776 : 0 : res = out;
777 : : }
778 : 1050 : }
779 : :
780 : 1050 : return (res);
781 : 1050 : }
782 : :
783 : : static unsigned char *
784 : 160 : pkg_checksum_symlink_readlink(const char *linkbuf, int linklen,
785 : : pkg_checksum_type_t type)
786 : : {
787 : : const char *lnk;
788 : :
789 : 160 : lnk = linkbuf;
790 : :
791 : : /*
792 : : * It is known that \0 is added to the checksum in case the symlink
793 : : * targets an absolute path but the behaviour is kept for compat
794 : : */
795 : 160 : return (pkg_checksum_data(RELATIVE_PATH(lnk), linklen, type));
796 : : }
797 : :
798 : : unsigned char *
799 : 144 : pkg_checksum_symlink(const char *path, pkg_checksum_type_t type)
800 : : {
801 : : char linkbuf[MAXPATHLEN];
802 : : int linklen;
803 : :
804 [ - + ]: 144 : if ((linklen = readlink(path, linkbuf, sizeof(linkbuf) - 1)) == -1) {
805 : 0 : pkg_emit_errno("pkg_checksum_symlink", "readlink failed");
806 : 0 : return (NULL);
807 : : }
808 : 144 : linkbuf[linklen] = '\0';
809 : :
810 : 144 : return (pkg_checksum_symlink_readlink(linkbuf, linklen, type));
811 : 144 : }
812 : :
813 : : unsigned char *
814 : 16 : pkg_checksum_symlinkat(int fd, const char *path, pkg_checksum_type_t type)
815 : : {
816 : : char linkbuf[MAXPATHLEN];
817 : : int linklen;
818 : :
819 [ - + ]: 16 : if ((linklen = readlinkat(fd, path, linkbuf, sizeof(linkbuf) - 1)) == -1) {
820 : 0 : pkg_emit_errno("pkg_checksum_symlinkat", "readlink failed");
821 : 0 : return (NULL);
822 : : }
823 : 16 : linkbuf[linklen] = '\0';
824 : :
825 : 16 : return (pkg_checksum_symlink_readlink(linkbuf, linklen, type));
826 : 16 : }
827 : :
828 : : int
829 : 69 : pkg_checksum_validate_file(const char *path, const char *sum)
830 : : {
831 : : struct stat st;
832 : : char *newsum;
833 : : pkg_checksum_type_t type;
834 : :
835 : 69 : type = pkg_checksum_file_get_type(sum, strlen(sum));
836 [ + + ]: 69 : if (type == PKG_HASH_TYPE_UNKNOWN) {
837 : 30 : type = PKG_HASH_TYPE_SHA256_HEX;
838 : 30 : } else {
839 : 39 : sum = strchr(sum, PKG_CKSUM_SEPARATOR);
840 [ + - ]: 39 : if (sum != NULL)
841 : 39 : sum++;
842 : : }
843 : :
844 [ - + ]: 69 : if (lstat(path, &st) == -1) {
845 : 0 : return (errno);
846 : : }
847 : :
848 [ + + ]: 69 : if (S_ISLNK(st.st_mode))
849 : 52 : newsum = pkg_checksum_symlink(path, type);
850 : : else
851 : 17 : newsum = pkg_checksum_file(path, type);
852 : :
853 [ + - ]: 69 : if (newsum == NULL)
854 : 0 : return (-1);
855 : :
856 [ + - ]: 69 : if (strcmp(sum, newsum) != 0) {
857 : 0 : free(newsum);
858 : 0 : return (-1);
859 : : }
860 : :
861 : 69 : free(newsum);
862 : :
863 : 69 : return (0);
864 : 69 : }
865 : :
866 : : char *
867 : 805 : pkg_checksum_generate_file(const char *path, pkg_checksum_type_t type)
868 : : {
869 : : struct stat st;
870 : : unsigned char *sum;
871 : : char *cksum;
872 : :
873 [ + - ]: 805 : if (lstat(path, &st) == -1) {
874 : 0 : pkg_emit_errno("pkg_checksum_generate_file", "lstat");
875 : 0 : return (NULL);
876 : : }
877 : :
878 [ + + ]: 805 : if (S_ISLNK(st.st_mode))
879 : 79 : sum = pkg_checksum_symlink(path, type);
880 : : else
881 : 726 : sum = pkg_checksum_file(path, type);
882 : :
883 [ - + ]: 805 : if (sum == NULL)
884 : 0 : return (NULL);
885 : :
886 : 805 : xasprintf(&cksum, "%d%c%s", type, PKG_CKSUM_SEPARATOR, sum);
887 : 805 : free(sum);
888 : :
889 : 805 : return (cksum);
890 : 805 : }
891 : :
892 : : int
893 : 0 : pkg_checksum_validate_fileat(int rootfd, const char *path, const char *sum)
894 : : {
895 : : struct stat st;
896 : : char *newsum;
897 : : pkg_checksum_type_t type;
898 : :
899 : 0 : type = pkg_checksum_file_get_type(sum, strlen(sum));
900 [ # # ]: 0 : if (type == PKG_HASH_TYPE_UNKNOWN) {
901 : 0 : type = PKG_HASH_TYPE_SHA256_HEX;
902 : 0 : } else {
903 : 0 : sum = strchr(sum, PKG_CKSUM_SEPARATOR);
904 [ # # ]: 0 : if (sum != NULL)
905 : 0 : sum++;
906 : : }
907 : :
908 [ # # ]: 0 : if (fstatat(rootfd, path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
909 : 0 : return (errno);
910 : : }
911 : :
912 [ # # ]: 0 : if (S_ISLNK(st.st_mode))
913 : 0 : newsum = pkg_checksum_symlinkat(rootfd, path, type);
914 : : else
915 : 0 : newsum = pkg_checksum_fileat(rootfd, path, type);
916 : :
917 [ # # ]: 0 : if (newsum == NULL)
918 : 0 : return (-1);
919 : :
920 [ # # ]: 0 : if (strcmp(sum, newsum) != 0) {
921 : 0 : free(newsum);
922 : 0 : return (-1);
923 : : }
924 : :
925 : 0 : free(newsum);
926 : :
927 : 0 : return (0);
928 : 0 : }
929 : :
930 : : char *
931 : 274 : pkg_checksum_generate_fileat(int rootfd, const char *path,
932 : : pkg_checksum_type_t type)
933 : : {
934 : : struct stat st;
935 : : unsigned char *sum;
936 : : char *cksum;
937 : :
938 [ + - ]: 274 : if (fstatat(rootfd, path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
939 : 0 : pkg_emit_errno("pkg_checksum_generate_file", "lstat");
940 : 0 : return (NULL);
941 : : }
942 : :
943 [ + + ]: 274 : if (S_ISLNK(st.st_mode))
944 : 16 : sum = pkg_checksum_symlinkat(rootfd, path, type);
945 : : else
946 : 258 : sum = pkg_checksum_fileat(rootfd, path, type);
947 : :
948 [ - + ]: 274 : if (sum == NULL)
949 : 0 : return (NULL);
950 : :
951 : 274 : xasprintf(&cksum, "%d%c%s", type, PKG_CKSUM_SEPARATOR, sum);
952 : 274 : free(sum);
953 : :
954 : 274 : return (cksum);
955 : 274 : }
|