XBPS Library API 20250813
The X Binary Package System
transaction_fetch.c
1/*-
2 * Copyright (c) 2009-2015 Juan Romero Pardines.
3 * Copyright (c) 2019 Duncan Overbruck <mail@duncano.de>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <errno.h>
28#include <limits.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "xbps_api_impl.h"
34#include "fetch.h"
35
36static int
37verify_binpkg(struct xbps_handle *xhp, xbps_dictionary_t pkgd)
38{
39 char binfile[PATH_MAX];
40 struct xbps_repo *repo;
41 const char *pkgver, *repoloc, *sha256;
42 ssize_t l;
43 int rv = 0;
44
45 xbps_dictionary_get_cstring_nocopy(pkgd, "repository", &repoloc);
46 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
47
48 l = xbps_pkg_path(xhp, binfile, sizeof(binfile), pkgd);
49 if (l < 0)
50 return -l;
51
52 /*
53 * For pkgs in local repos check the sha256 hash.
54 * For pkgs in remote repos check the RSA signature.
55 */
56 if ((repo = xbps_rpool_get_repo(repoloc)) == NULL) {
57 rv = errno;
58 xbps_dbg_printf("%s: failed to get repository "
59 "%s: %s\n", pkgver, repoloc, strerror(errno));
60 return rv;
61 }
62 if (repo->is_remote) {
63 /* remote repo */
64 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver,
65 "%s: verifying RSA signature...", pkgver);
66
67 if (!xbps_verify_file_signature(repo, binfile)) {
68 rv = EPERM;
69 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
70 "%s: the RSA signature is not valid!", pkgver);
71 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
72 "%s: removed pkg archive and its signature.", pkgver);
73 (void)remove(binfile);
74 if (xbps_strlcat(binfile, ".sig2", sizeof(binfile)) < sizeof(binfile))
75 (void)remove(binfile);
76 return rv;
77 }
78 } else {
79 /* local repo */
80 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver,
81 "%s: verifying SHA256 hash...", pkgver);
82 xbps_dictionary_get_cstring_nocopy(pkgd, "filename-sha256", &sha256);
83 if ((rv = xbps_file_sha256_check(binfile, sha256)) != 0) {
84 if (rv == ERANGE) {
85 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL,
86 rv, pkgver,
87 "%s: checksum does not match repository index",
88 pkgver);
89 } else {
90 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL,
91 rv, pkgver, "%s: failed to checksum: %s",
92 pkgver, strerror(errno));
93 }
94 return rv;
95 }
96
97 }
98
99 return 0;
100}
101
102static int
103download_binpkg(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd)
104{
105 struct xbps_repo *repo;
106 char buf[PATH_MAX];
107 char *sigsuffix;
108 const char *pkgver, *arch, *fetchstr, *repoloc;
109 unsigned char digest[XBPS_SHA256_DIGEST_SIZE] = {0};
110 int rv = 0;
111
112 xbps_dictionary_get_cstring_nocopy(repo_pkgd, "repository", &repoloc);
113 if (!xbps_repository_is_remote(repoloc))
114 return ENOTSUP;
115
116 xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver);
117 xbps_dictionary_get_cstring_nocopy(repo_pkgd, "architecture", &arch);
118
119 snprintf(buf, sizeof buf, "%s/%s.%s.xbps.sig2", repoloc, pkgver, arch);
120 sigsuffix = buf+(strlen(buf)-sizeof (".sig2")+1);
121
122 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD, 0, pkgver,
123 "Downloading `%s' signature (from `%s')...", pkgver, repoloc);
124
125 if ((rv = xbps_fetch_file(xhp, buf, NULL)) == -1) {
126 rv = fetchLastErrCode ? fetchLastErrCode : errno;
127 fetchstr = xbps_fetch_error_string();
128 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD_FAIL, rv,
129 pkgver, "[trans] failed to download `%s' signature from `%s': %s",
130 pkgver, repoloc, fetchstr ? fetchstr : strerror(rv));
131 return rv;
132 }
133 rv = 0;
134
135 *sigsuffix = '\0';
136
137 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD, 0, pkgver,
138 "Downloading `%s' package (from `%s')...", pkgver, repoloc);
139
140 if ((rv = xbps_fetch_file_sha256(xhp, buf, NULL, digest,
141 sizeof digest)) == -1) {
142 rv = fetchLastErrCode ? fetchLastErrCode : errno;
143 fetchstr = xbps_fetch_error_string();
144 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD_FAIL, rv,
145 pkgver, "[trans] failed to download `%s' package from `%s': %s",
146 pkgver, repoloc, fetchstr ? fetchstr : strerror(rv));
147 return rv;
148 }
149 rv = 0;
150
151 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver,
152 "%s: verifying RSA signature...", pkgver);
153
154 snprintf(buf, sizeof buf, "%s/%s.%s.xbps.sig2", xhp->cachedir, pkgver, arch);
155 sigsuffix = buf+(strlen(buf)-sizeof (".sig2")+1);
156
157 if ((repo = xbps_rpool_get_repo(repoloc)) == NULL) {
158 rv = errno;
159 xbps_dbg_printf("%s: failed to get repository "
160 "%s: %s\n", pkgver, repoloc, strerror(errno));
161 return rv;
162 }
163
164 /*
165 * If digest is not set, binary package was not downloaded,
166 * i.e. 304 not modified, verify by file instead.
167 */
168 if (fetchLastErrCode == FETCH_UNCHANGED) {
169 *sigsuffix = '\0';
170 if (!xbps_verify_file_signature(repo, buf)) {
171 rv = EPERM;
172 /* remove binpkg */
173 (void)remove(buf);
174 /* remove signature */
175 *sigsuffix = '.';
176 (void)remove(buf);
177 }
178 } else {
179 if (!xbps_verify_signature(repo, buf, digest)) {
180 rv = EPERM;
181 /* remove signature */
182 (void)remove(buf);
183 /* remove binpkg */
184 *sigsuffix = '\0';
185 (void)remove(buf);
186 }
187 }
188
189 if (rv == EPERM) {
190 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
191 "%s: the RSA signature is not valid!", pkgver);
192 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
193 "%s: removed pkg archive and its signature.", pkgver);
194 }
195
196 return rv;
197}
198
199int
200xbps_transaction_fetch(struct xbps_handle *xhp, xbps_object_iterator_t iter)
201{
202 xbps_array_t fetch = NULL, verify = NULL;
203 xbps_object_t obj;
204 xbps_trans_type_t ttype;
205 const char *repoloc;
206 int rv = 0;
207 unsigned int i, n;
208
209 xbps_object_iterator_reset(iter);
210
211 while ((obj = xbps_object_iterator_next(iter)) != NULL) {
212 ttype = xbps_transaction_pkg_type(obj);
213 if (ttype == XBPS_TRANS_REMOVE || ttype == XBPS_TRANS_HOLD ||
214 ttype == XBPS_TRANS_CONFIGURE) {
215 continue;
216 }
217 xbps_dictionary_get_cstring_nocopy(obj, "repository", &repoloc);
218
219 /*
220 * Download binary package and signature if either one
221 * of them don't exist.
222 */
223 if (xbps_repository_is_remote(repoloc) &&
225 if (!fetch && !(fetch = xbps_array_create())) {
226 rv = errno;
227 goto out;
228 }
229 xbps_array_add(fetch, obj);
230 continue;
231 }
232
233 /*
234 * Verify binary package from local repository or cache.
235 */
236 if (!verify && !(verify = xbps_array_create())) {
237 rv = errno;
238 goto out;
239 }
240 xbps_array_add(verify, obj);
241 }
242 xbps_object_iterator_reset(iter);
243
244 /*
245 * Download binary packages (if they come from a remote repository)
246 * and don't exist already.
247 */
248 n = xbps_array_count(fetch);
249 if (n) {
250 xbps_set_cb_state(xhp, XBPS_STATE_TRANS_DOWNLOAD, 0, NULL, NULL);
251 xbps_dbg_printf("[trans] downloading %d packages.\n", n);
252 }
253 for (i = 0; i < n; i++) {
254 if ((rv = download_binpkg(xhp, xbps_array_get(fetch, i))) != 0) {
255 xbps_dbg_printf("[trans] failed to download binpkgs: "
256 "%s\n", strerror(rv));
257 goto out;
258 }
259 }
260
261 /*
262 * Check binary package integrity.
263 */
264 n = xbps_array_count(verify);
265 if (n) {
266 xbps_set_cb_state(xhp, XBPS_STATE_TRANS_VERIFY, 0, NULL, NULL);
267 xbps_dbg_printf("[trans] verifying %d packages.\n", n);
268 }
269 for (i = 0; i < n; i++) {
270 if ((rv = verify_binpkg(xhp, xbps_array_get(verify, i))) != 0) {
271 xbps_dbg_printf("[trans] failed to check binpkgs: "
272 "%s\n", strerror(rv));
273 goto out;
274 }
275 }
276
277out:
278 if (fetch)
279 xbps_object_release(fetch);
280 if (verify)
281 xbps_object_release(verify);
282 return rv;
283}
int xbps_fetch_file_sha256(struct xbps_handle *xhp, const char *uri, const char *flags, unsigned char *digest, size_t digestlen)
Definition download.c:346
const char * xbps_fetch_error_string(void)
Definition download.c:89
int xbps_fetch_file(struct xbps_handle *xhp, const char *uri, const char *flags)
Definition download.c:362
char cachedir[XBPS_MAXPATH]
Definition xbps.h:671
Generic XBPS structure handler for initialization.
Definition xbps.h:560
void xbps_dbg_printf(const char *fmt,...)
Prints debug messages to stderr.
Definition log.c:67
bool is_remote
Definition xbps.h:1533
struct xbps_handle * xhp
Definition xbps.h:1491
const char * arch
Definition xbps.h:1497
Repository structure.
Definition xbps.h:1479
struct xbps_repo * xbps_rpool_get_repo(const char *url)
Definition rpool.c:112
xbps_trans_type_t xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
xbps_trans_type_t
Definition xbps.h:1390
bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname)
Definition verifysig.c:136
int xbps_file_sha256_check(const char *file, const char *sha256)
Definition util_hash.c:201
bool xbps_verify_signature(struct xbps_repo *repo, const char *sigfile, unsigned char *digest)
Definition verifysig.c:75
bool xbps_remote_binpkg_exists(struct xbps_handle *xhp, xbps_dictionary_t pkgd)
Definition util.c:451
ssize_t xbps_pkg_path(struct xbps_handle *xhp, char *dst, size_t dstsz, xbps_dictionary_t pkgd)
Definition util.c:321
bool xbps_repository_is_remote(const char *uri)
Definition util.c:62
size_t xbps_strlcat(char *dst, const char *src, size_t dstsize)
Definition util.c:562