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