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 : }
|