XBPS Library API 20260225
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 <string.h>
30#include <unistd.h>
31
32#include "xbps_api_impl.h"
33#include "fetch.h"
34
35static int
36verify_binpkg(struct xbps_handle *xhp, xbps_dictionary_t pkgd)
37{
38 char binfile[PATH_MAX];
39 struct xbps_repo *repo;
40 const char *pkgver, *repoloc, *sha256;
41 ssize_t l;
42 int rv = 0;
43
44 xbps_dictionary_get_cstring_nocopy(pkgd, "repository", &repoloc);
45 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
46
47 l = xbps_pkg_path(xhp, binfile, sizeof(binfile), pkgd);
48 if (l < 0)
49 return -l;
50
51 /*
52 * For pkgs in local repos check the sha256 hash.
53 * For pkgs in remote repos check the RSA signature.
54 */
55 if ((repo = xbps_rpool_get_repo(repoloc)) == NULL) {
56 rv = errno;
57 xbps_dbg_printf("%s: failed to get repository "
58 "%s: %s\n", pkgver, repoloc, strerror(errno));
59 return rv;
60 }
61 if (repo->is_remote) {
62 /* remote repo */
63 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver,
64 "%s: verifying RSA signature...", pkgver);
65
66 if (!xbps_verify_file_signature(repo, binfile)) {
67 rv = EPERM;
68 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
69 "%s: the RSA signature is not valid!", pkgver);
70 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
71 "%s: removed pkg archive and its signature.", pkgver);
72 (void)remove(binfile);
73 if (xbps_strlcat(binfile, ".sig2", sizeof(binfile)) < sizeof(binfile))
74 (void)remove(binfile);
75 return rv;
76 }
77 } else {
78 /* local repo */
79 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver,
80 "%s: verifying SHA256 hash...", pkgver);
81 xbps_dictionary_get_cstring_nocopy(pkgd, "filename-sha256", &sha256);
82 if ((rv = xbps_file_sha256_check(binfile, sha256)) != 0) {
83 if (rv == ERANGE) {
84 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL,
85 rv, pkgver,
86 "%s: checksum does not match repository index",
87 pkgver);
88 } else {
89 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL,
90 rv, pkgver, "%s: failed to checksum: %s",
91 pkgver, strerror(errno));
92 }
93 return rv;
94 }
95
96 }
97
98 return 0;
99}
100
101static int
102download_binpkg(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd)
103{
104 struct xbps_repo *repo;
105 char buf[PATH_MAX];
106 char *sigsuffix;
107 const char *pkgver, *arch, *fetchstr, *repoloc;
108 unsigned char digest[XBPS_SHA256_DIGEST_SIZE] = {0};
109 int rv = 0;
110
111 xbps_dictionary_get_cstring_nocopy(repo_pkgd, "repository", &repoloc);
112 if (!xbps_repository_is_remote(repoloc))
113 return ENOTSUP;
114
115 xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver);
116 xbps_dictionary_get_cstring_nocopy(repo_pkgd, "architecture", &arch);
117
118 snprintf(buf, sizeof buf, "%s/%s.%s.xbps.sig2", repoloc, pkgver, arch);
119 sigsuffix = buf+(strlen(buf)-sizeof (".sig2")+1);
120
121 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD, 0, pkgver,
122 "Downloading `%s' signature (from `%s')...", pkgver, repoloc);
123
124 if (xbps_fetch_file(xhp, buf, NULL) == -1) {
125 rv = fetchLastErrCode ? fetchLastErrCode : errno;
126 fetchstr = xbps_fetch_error_string();
127 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD_FAIL, rv,
128 pkgver, "[trans] failed to download `%s' signature from `%s': %s",
129 pkgver, repoloc, fetchstr ? fetchstr : strerror(rv));
130 return rv;
131 }
132
133 *sigsuffix = '\0';
134
135 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD, 0, pkgver,
136 "Downloading `%s' package (from `%s')...", pkgver, repoloc);
137
138 if (xbps_fetch_file_sha256(xhp, buf, NULL, digest, sizeof digest) == -1) {
139 rv = fetchLastErrCode ? fetchLastErrCode : errno;
140 fetchstr = xbps_fetch_error_string();
141 xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD_FAIL, rv,
142 pkgver, "[trans] failed to download `%s' package from `%s': %s",
143 pkgver, repoloc, fetchstr ? fetchstr : strerror(rv));
144 return rv;
145 }
146
147 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver,
148 "%s: verifying RSA signature...", pkgver);
149
150 snprintf(buf, sizeof buf, "%s/%s.%s.xbps.sig2", xhp->cachedir, pkgver, arch);
151 sigsuffix = buf+(strlen(buf)-sizeof (".sig2")+1);
152
153 if ((repo = xbps_rpool_get_repo(repoloc)) == NULL) {
154 rv = errno;
155 xbps_dbg_printf("%s: failed to get repository "
156 "%s: %s\n", pkgver, repoloc, strerror(errno));
157 return rv;
158 }
159
160 /*
161 * If digest is not set, binary package was not downloaded,
162 * i.e. 304 not modified, verify by file instead.
163 */
164 rv = 0;
165 if (fetchLastErrCode == FETCH_UNCHANGED) {
166 *sigsuffix = '\0';
167 if (!xbps_verify_file_signature(repo, buf)) {
168 rv = EPERM;
169 /* remove binpkg */
170 (void)remove(buf);
171 /* remove signature */
172 *sigsuffix = '.';
173 (void)remove(buf);
174 }
175 } else {
176 if (!xbps_verify_signature(repo, buf, digest)) {
177 rv = EPERM;
178 /* remove signature */
179 (void)remove(buf);
180 /* remove binpkg */
181 *sigsuffix = '\0';
182 (void)remove(buf);
183 }
184 }
185
186 if (rv == EPERM) {
187 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
188 "%s: the RSA signature is not valid!", pkgver);
189 xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver,
190 "%s: removed pkg archive and its signature.", pkgver);
191 }
192
193 return rv;
194}
195
196int
197xbps_transaction_fetch(struct xbps_handle *xhp, xbps_object_iterator_t iter)
198{
199 xbps_array_t fetch = NULL, verify = NULL;
200 xbps_object_t obj;
201 xbps_trans_type_t ttype;
202 const char *repoloc;
203 int rv = 0;
204 unsigned int i, n;
205
206 xbps_object_iterator_reset(iter);
207
208 while ((obj = xbps_object_iterator_next(iter)) != NULL) {
209 ttype = xbps_transaction_pkg_type(obj);
210 if (ttype == XBPS_TRANS_REMOVE || ttype == XBPS_TRANS_HOLD ||
211 ttype == XBPS_TRANS_CONFIGURE) {
212 continue;
213 }
214 xbps_dictionary_get_cstring_nocopy(obj, "repository", &repoloc);
215
216 /*
217 * Download binary package and signature if either one
218 * of them don't exist.
219 */
220 if (xbps_repository_is_remote(repoloc) &&
222 if (!fetch && !(fetch = xbps_array_create())) {
223 rv = errno;
224 goto out;
225 }
226 xbps_array_add(fetch, obj);
227 continue;
228 }
229
230 /*
231 * Verify binary package from local repository or cache.
232 */
233 if (!verify && !(verify = xbps_array_create())) {
234 rv = errno;
235 goto out;
236 }
237 xbps_array_add(verify, obj);
238 }
239 xbps_object_iterator_reset(iter);
240
241 /*
242 * Download binary packages (if they come from a remote repository)
243 * and don't exist already.
244 */
245 n = xbps_array_count(fetch);
246 if (n) {
247 xbps_set_cb_state(xhp, XBPS_STATE_TRANS_DOWNLOAD, 0, NULL, NULL);
248 xbps_dbg_printf("[trans] downloading %d packages.\n", n);
249 }
250 for (i = 0; i < n; i++) {
251 if ((rv = download_binpkg(xhp, xbps_array_get(fetch, i))) != 0) {
252 xbps_dbg_printf("[trans] failed to download binpkgs: "
253 "%s\n", strerror(rv));
254 goto out;
255 }
256 }
257
258 /*
259 * Check binary package integrity.
260 */
261 n = xbps_array_count(verify);
262 if (n) {
263 xbps_set_cb_state(xhp, XBPS_STATE_TRANS_VERIFY, 0, NULL, NULL);
264 xbps_dbg_printf("[trans] verifying %d packages.\n", n);
265 }
266 for (i = 0; i < n; i++) {
267 if ((rv = verify_binpkg(xhp, xbps_array_get(verify, i))) != 0) {
268 xbps_dbg_printf("[trans] failed to check binpkgs: "
269 "%s\n", strerror(rv));
270 goto out;
271 }
272 }
273
274out:
275 if (fetch)
276 xbps_object_release(fetch);
277 if (verify)
278 xbps_object_release(verify);
279 return rv;
280}
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:1543
struct xbps_handle * xhp
Definition xbps.h:1501
const char * arch
Definition xbps.h:1507
Repository structure.
Definition xbps.h:1489
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:1400
bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname)
Definition verifysig.c:137
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:76
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