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