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