XBPS Library API 20240111
The X Binary Package System
util_hash.c
1/*-
2 * Copyright (c) 2008-2015 Juan Romero Pardines.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/mman.h>
27#include <sys/stat.h>
28
29#include <errno.h>
30#include <fcntl.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37
38#include <openssl/sha.h>
39
40#include "xbps_api_impl.h"
41
42/**
43 * @file lib/util.c
44 * @brief Utility routines
45 * @defgroup util Utility functions
46 */
47static void
48digest2string(const uint8_t *digest, char *string, size_t len)
49{
50 while (len--) {
51 if (*digest / 16 < 10)
52 *string++ = '0' + *digest / 16;
53 else
54 *string++ = 'a' + *digest / 16 - 10;
55 if (*digest % 16 < 10)
56 *string++ = '0' + *digest % 16;
57 else
58 *string++ = 'a' + *digest % 16 - 10;
59 ++digest;
60 }
61 *string = '\0';
62}
63
64bool
65xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen)
66{
67 struct stat st;
68 size_t pgsize = (size_t)sysconf(_SC_PAGESIZE);
69 size_t pgmask = pgsize - 1, mapsize;
70 unsigned char *mf;
71 bool need_guard = false;
72 int fd;
73
74 assert(file);
75
76 if ((fd = open(file, O_RDONLY|O_CLOEXEC)) == -1)
77 return false;
78
79 if (fstat(fd, &st) == -1) {
80 (void)close(fd);
81 return false;
82 }
83 if (st.st_size > SSIZE_MAX - 1) {
84 (void)close(fd);
85 return false;
86 }
87 mapsize = ((size_t)st.st_size + pgmask) & ~pgmask;
88 if (mapsize < (size_t)st.st_size) {
89 (void)close(fd);
90 return false;
91 }
92 /*
93 * If the file length is an integral number of pages, then we
94 * need to map a guard page at the end in order to provide the
95 * necessary NUL-termination of the buffer.
96 */
97 if ((st.st_size & pgmask) == 0)
98 need_guard = true;
99
100 mf = mmap(NULL, need_guard ? mapsize + pgsize : mapsize,
101 PROT_READ, MAP_PRIVATE, fd, 0);
102 (void)close(fd);
103 if (mf == MAP_FAILED) {
104 (void)munmap(mf, mapsize);
105 return false;
106 }
107
108 *mmf = mf;
109 *mmflen = mapsize;
110 *filelen = st.st_size;
111
112 return true;
113}
114
115bool
116xbps_file_sha256_raw(unsigned char *dst, size_t dstlen, const char *file)
117{
118 int fd;
119 ssize_t len;
120 char buf[65536];
121 SHA256_CTX sha256;
122
123 assert(dstlen >= XBPS_SHA256_DIGEST_SIZE);
124 if (dstlen < XBPS_SHA256_DIGEST_SIZE) {
125 errno = ENOBUFS;
126 return false;
127 }
128
129 if ((fd = open(file, O_RDONLY)) < 0)
130 return false;
131
132 SHA256_Init(&sha256);
133
134 while ((len = read(fd, buf, sizeof(buf))) > 0)
135 SHA256_Update(&sha256, buf, len);
136
137 (void)close(fd);
138
139 if(len == -1)
140 return false;
141
142 SHA256_Final(dst, &sha256);
143
144 return true;
145}
146
147bool
148xbps_file_sha256(char *dst, size_t dstlen, const char *file)
149{
150 unsigned char digest[XBPS_SHA256_DIGEST_SIZE];
151
152 assert(dstlen >= XBPS_SHA256_SIZE);
153 if (dstlen < XBPS_SHA256_SIZE) {
154 errno = ENOBUFS;
155 return false;
156 }
157
158 if (!xbps_file_sha256_raw(digest, sizeof digest, file))
159 return false;
160
161 digest2string(digest, dst, XBPS_SHA256_DIGEST_SIZE);
162
163 return true;
164}
165
166static bool
167sha256_digest_compare(const char *sha256, size_t shalen,
168 const unsigned char *digest, size_t digestlen)
169{
170
171 assert(shalen == XBPS_SHA256_SIZE - 1);
172 if (shalen != XBPS_SHA256_SIZE -1)
173 return false;
174
175 assert(digestlen == XBPS_SHA256_DIGEST_SIZE);
176 if (digestlen != XBPS_SHA256_DIGEST_SIZE)
177 return false;
178
179 for (; *sha256;) {
180 if (*digest / 16 < 10) {
181 if (*sha256++ != '0' + *digest / 16)
182 return false;
183 } else {
184 if (*sha256++ != 'a' + *digest / 16 - 10)
185 return false;
186 }
187 if (*digest % 16 < 10) {
188 if (*sha256++ != '0' + *digest % 16)
189 return false;
190 } else {
191 if (*sha256++ != 'a' + *digest % 16 - 10)
192 return false;
193 }
194 digest++;
195 }
196
197 return true;
198}
199
200int
201xbps_file_sha256_check(const char *file, const char *sha256)
202{
203 unsigned char digest[XBPS_SHA256_DIGEST_SIZE];
204
205 assert(file != NULL);
206 assert(sha256 != NULL);
207
208 if (!xbps_file_sha256_raw(digest, sizeof digest, file))
209 return errno;
210
211 if (!sha256_digest_compare(sha256, strlen(sha256), digest, sizeof digest))
212 return ERANGE;
213
214 return 0;
215}
216
217static const char *
218file_hash_dictionary(xbps_dictionary_t d, const char *key, const char *file)
219{
220 xbps_object_t obj;
221 xbps_object_iterator_t iter;
222 const char *curfile = NULL, *sha256 = NULL;
223
224 assert(xbps_object_type(d) == XBPS_TYPE_DICTIONARY);
225 assert(key != NULL);
226 assert(file != NULL);
227
228 iter = xbps_array_iter_from_dict(d, key);
229 if (iter == NULL) {
230 errno = ENOENT;
231 return NULL;
232 }
233 while ((obj = xbps_object_iterator_next(iter)) != NULL) {
234 xbps_dictionary_get_cstring_nocopy(obj,
235 "file", &curfile);
236 if (strcmp(file, curfile) == 0) {
237 /* file matched */
238 xbps_dictionary_get_cstring_nocopy(obj,
239 "sha256", &sha256);
240 break;
241 }
242 }
243 xbps_object_iterator_release(iter);
244 if (sha256 == NULL)
245 errno = ENOENT;
246
247 return sha256;
248}
249
250int HIDDEN
251xbps_file_hash_check_dictionary(struct xbps_handle *xhp,
252 xbps_dictionary_t d,
253 const char *key,
254 const char *file)
255{
256 const char *sha256d = NULL;
257 char *buf;
258 int rv;
259
260 assert(xbps_object_type(d) == XBPS_TYPE_DICTIONARY);
261 assert(key != NULL);
262 assert(file != NULL);
263
264 if ((sha256d = file_hash_dictionary(d, key, file)) == NULL) {
265 if (errno == ENOENT)
266 return 1; /* no match, file not found */
267
268 return -1; /* error */
269 }
270
271 if (strcmp(xhp->rootdir, "/") == 0) {
272 rv = xbps_file_sha256_check(file, sha256d);
273 } else {
274 buf = xbps_xasprintf("%s/%s", xhp->rootdir, file);
275 rv = xbps_file_sha256_check(buf, sha256d);
276 free(buf);
277 }
278 if (rv == 0)
279 return 0; /* matched */
280 else if (rv == ERANGE || rv == ENOENT)
281 return 1; /* no match */
282 else
283 return -1; /* error */
284}
char rootdir[XBPS_MAXPATH]
Definition xbps.h:650
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_object_iterator_t xbps_array_iter_from_dict(xbps_dictionary_t dict, const char *key)
Definition plist.c:202
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
int xbps_file_sha256_check(const char *file, const char *sha256)
Definition util_hash.c:201
bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen)
Definition util_hash.c:65
bool xbps_file_sha256(char *dst, size_t dstlen, const char *file)
Definition util_hash.c:148
bool xbps_file_sha256_raw(unsigned char *dst, size_t dstlen, const char *file)
Definition util_hash.c:116