pkg_install-20090301: Plug a number of file descriptor leaks.diff -r1.81 -r1.82 pkgsrc/pkgtools/pkg_install/files/add/perform.c
(joerg)
@@ -1,1441 +1,1445 @@ | @@ -1,1441 +1,1445 @@ | |||
1 | /* $NetBSD: perform.c,v 1.81 2009/02/28 16:03:56 joerg Exp $ */ | 1 | /* $NetBSD: perform.c,v 1.82 2009/03/02 14:59:14 joerg Exp $ */ | |
2 | #if HAVE_CONFIG_H | 2 | #if HAVE_CONFIG_H | |
3 | #include "config.h" | 3 | #include "config.h" | |
4 | #endif | 4 | #endif | |
5 | #include <nbcompat.h> | 5 | #include <nbcompat.h> | |
6 | #if HAVE_SYS_CDEFS_H | 6 | #if HAVE_SYS_CDEFS_H | |
7 | #include <sys/cdefs.h> | 7 | #include <sys/cdefs.h> | |
8 | #endif | 8 | #endif | |
9 | __RCSID("$NetBSD: perform.c,v 1.81 2009/02/28 16:03:56 joerg Exp $"); | 9 | __RCSID("$NetBSD: perform.c,v 1.82 2009/03/02 14:59:14 joerg Exp $"); | |
10 | 10 | |||
11 | /*- | 11 | /*- | |
12 | * Copyright (c) 2003 Grant Beattie <grant@NetBSD.org> | 12 | * Copyright (c) 2003 Grant Beattie <grant@NetBSD.org> | |
13 | * Copyright (c) 2005 Dieter Baron <dillo@NetBSD.org> | 13 | * Copyright (c) 2005 Dieter Baron <dillo@NetBSD.org> | |
14 | * Copyright (c) 2007 Roland Illig <rillig@NetBSD.org> | 14 | * Copyright (c) 2007 Roland Illig <rillig@NetBSD.org> | |
15 | * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org> | 15 | * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org> | |
16 | * All rights reserved. | 16 | * All rights reserved. | |
17 | * | 17 | * | |
18 | * Redistribution and use in source and binary forms, with or without | 18 | * Redistribution and use in source and binary forms, with or without | |
19 | * modification, are permitted provided that the following conditions | 19 | * modification, are permitted provided that the following conditions | |
20 | * are met: | 20 | * are met: | |
21 | * | 21 | * | |
22 | * 1. Redistributions of source code must retain the above copyright | 22 | * 1. Redistributions of source code must retain the above copyright | |
23 | * notice, this list of conditions and the following disclaimer. | 23 | * notice, this list of conditions and the following disclaimer. | |
24 | * 2. Redistributions in binary form must reproduce the above copyright | 24 | * 2. Redistributions in binary form must reproduce the above copyright | |
25 | * notice, this list of conditions and the following disclaimer in | 25 | * notice, this list of conditions and the following disclaimer in | |
26 | * the documentation and/or other materials provided with the | 26 | * the documentation and/or other materials provided with the | |
27 | * distribution. | 27 | * distribution. | |
28 | * | 28 | * | |
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
30 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 30 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
33 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 33 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
34 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | 34 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
35 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 35 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
36 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 36 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
37 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 37 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
38 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 38 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
39 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 39 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
40 | * SUCH DAMAGE. | 40 | * SUCH DAMAGE. | |
41 | */ | 41 | */ | |
42 | 42 | |||
43 | #include <sys/utsname.h> | 43 | #include <sys/utsname.h> | |
44 | #if HAVE_ERR_H | 44 | #if HAVE_ERR_H | |
45 | #include <err.h> | 45 | #include <err.h> | |
46 | #endif | 46 | #endif | |
47 | #include <errno.h> | 47 | #include <errno.h> | |
48 | #if HAVE_FCNTL_H | 48 | #if HAVE_FCNTL_H | |
49 | #include <fcntl.h> | 49 | #include <fcntl.h> | |
50 | #endif | 50 | #endif | |
51 | #include <stdlib.h> | 51 | #include <stdlib.h> | |
52 | #include <string.h> | 52 | #include <string.h> | |
53 | #include <unistd.h> | 53 | #include <unistd.h> | |
54 | 54 | |||
55 | #include <archive.h> | 55 | #include <archive.h> | |
56 | #include <archive_entry.h> | 56 | #include <archive_entry.h> | |
57 | 57 | |||
58 | #include "lib.h" | 58 | #include "lib.h" | |
59 | #include "add.h" | 59 | #include "add.h" | |
60 | 60 | |||
61 | struct pkg_meta { | 61 | struct pkg_meta { | |
62 | char *meta_contents; | 62 | char *meta_contents; | |
63 | char *meta_comment; | 63 | char *meta_comment; | |
64 | char *meta_desc; | 64 | char *meta_desc; | |
65 | char *meta_mtree; | 65 | char *meta_mtree; | |
66 | char *meta_build_version; | 66 | char *meta_build_version; | |
67 | char *meta_build_info; | 67 | char *meta_build_info; | |
68 | char *meta_size_pkg; | 68 | char *meta_size_pkg; | |
69 | char *meta_size_all; | 69 | char *meta_size_all; | |
70 | char *meta_required_by; | 70 | char *meta_required_by; | |
71 | char *meta_display; | 71 | char *meta_display; | |
72 | char *meta_install; | 72 | char *meta_install; | |
73 | char *meta_deinstall; | 73 | char *meta_deinstall; | |
74 | char *meta_preserve; | 74 | char *meta_preserve; | |
75 | char *meta_views; | 75 | char *meta_views; | |
76 | char *meta_installed_info; | 76 | char *meta_installed_info; | |
77 | }; | 77 | }; | |
78 | 78 | |||
79 | struct pkg_task { | 79 | struct pkg_task { | |
80 | char *pkgname; | 80 | char *pkgname; | |
81 | 81 | |||
82 | const char *prefix; | 82 | const char *prefix; | |
83 | char *install_prefix; | 83 | char *install_prefix; | |
84 | 84 | |||
85 | char *logdir; | 85 | char *logdir; | |
86 | char *install_logdir; | 86 | char *install_logdir; | |
87 | char *other_version; | 87 | char *other_version; | |
88 | 88 | |||
89 | package_t plist; | 89 | package_t plist; | |
90 | 90 | |||
91 | struct pkg_meta meta_data; | 91 | struct pkg_meta meta_data; | |
92 | 92 | |||
93 | struct archive *archive; | 93 | struct archive *archive; | |
94 | struct archive_entry *entry; | 94 | struct archive_entry *entry; | |
95 | 95 | |||
96 | char *buildinfo[BI_ENUM_COUNT]; | 96 | char *buildinfo[BI_ENUM_COUNT]; | |
97 | 97 | |||
98 | size_t dep_length, dep_allocated; | 98 | size_t dep_length, dep_allocated; | |
99 | char **dependencies; | 99 | char **dependencies; | |
100 | }; | 100 | }; | |
101 | 101 | |||
102 | static const struct pkg_meta_desc { | 102 | static const struct pkg_meta_desc { | |
103 | size_t entry_offset; | 103 | size_t entry_offset; | |
104 | const char *entry_filename; | 104 | const char *entry_filename; | |
105 | int required_file; | 105 | int required_file; | |
106 | mode_t perm; | 106 | mode_t perm; | |
107 | } pkg_meta_descriptors[] = { | 107 | } pkg_meta_descriptors[] = { | |
108 | { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 1, 0644 }, | 108 | { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 1, 0644 }, | |
109 | { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 1, 0444}, | 109 | { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 1, 0444}, | |
110 | { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 1, 0444}, | 110 | { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 1, 0444}, | |
111 | { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 0, 0555 }, | 111 | { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 0, 0555 }, | |
112 | { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 0, 0555 }, | 112 | { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 0, 0555 }, | |
113 | { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 0, 0444 }, | 113 | { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 0, 0444 }, | |
114 | { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 0, 0444 }, | 114 | { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 0, 0444 }, | |
115 | { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME, 0, 0444 }, | 115 | { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME, 0, 0444 }, | |
116 | { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME, 0, 0444 }, | 116 | { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME, 0, 0444 }, | |
117 | { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME, 0, 0444 }, | 117 | { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME, 0, 0444 }, | |
118 | { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME, 0, 0444 }, | 118 | { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME, 0, 0444 }, | |
119 | { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME, 0, 0444 }, | 119 | { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME, 0, 0444 }, | |
120 | { offsetof(struct pkg_meta, meta_views), VIEWS_FNAME, 0, 0444 }, | 120 | { offsetof(struct pkg_meta, meta_views), VIEWS_FNAME, 0, 0444 }, | |
121 | { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME, 0, 0644 }, | 121 | { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME, 0, 0644 }, | |
122 | { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME, 0, 0644 }, | 122 | { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME, 0, 0644 }, | |
123 | { 0, NULL, 0 }, | 123 | { 0, NULL, 0 }, | |
124 | }; | 124 | }; | |
125 | 125 | |||
126 | static int pkg_do(const char *, int, int); | 126 | static int pkg_do(const char *, int, int); | |
127 | 127 | |||
128 | static int | 128 | static int | |
129 | mkdir_p(const char *path) | 129 | mkdir_p(const char *path) | |
130 | { | 130 | { | |
131 | char *p, *cur_end; | 131 | char *p, *cur_end; | |
132 | int done; | 132 | int done; | |
133 | 133 | |||
134 | /* | 134 | /* | |
135 | * Handle the easy case of direct success or | 135 | * Handle the easy case of direct success or | |
136 | * pre-existing directory first. | 136 | * pre-existing directory first. | |
137 | */ | 137 | */ | |
138 | if (mkdir(path, 0777) == 0 || errno == EEXIST) | 138 | if (mkdir(path, 0777) == 0 || errno == EEXIST) | |
139 | return 0; | 139 | return 0; | |
140 | if (errno != ENOENT) | 140 | if (errno != ENOENT) | |
141 | return -1; | 141 | return -1; | |
142 | 142 | |||
143 | cur_end = p = xstrdup(path); | 143 | cur_end = p = xstrdup(path); | |
144 | 144 | |||
145 | for (;;) { | 145 | for (;;) { | |
146 | /* | 146 | /* | |
147 | * First skip leading slashes either from / or | 147 | * First skip leading slashes either from / or | |
148 | * from the last iteration. | 148 | * from the last iteration. | |
149 | */ | 149 | */ | |
150 | cur_end += strspn(cur_end, "/"); | 150 | cur_end += strspn(cur_end, "/"); | |
151 | /* Find end of actual directory name. */ | 151 | /* Find end of actual directory name. */ | |
152 | cur_end += strcspn(cur_end, "/"); | 152 | cur_end += strcspn(cur_end, "/"); | |
153 | 153 | |||
154 | /* | 154 | /* | |
155 | * Remember if this is the last component and | 155 | * Remember if this is the last component and | |
156 | * overwrite / if needed. | 156 | * overwrite / if needed. | |
157 | */ | 157 | */ | |
158 | done = (*cur_end == '\0'); | 158 | done = (*cur_end == '\0'); | |
159 | *cur_end = '\0'; | 159 | *cur_end = '\0'; | |
160 | 160 | |||
161 | /* | 161 | /* | |
162 | * ENOENT can only happen if something else races us, | 162 | * ENOENT can only happen if something else races us, | |
163 | * in which case we should better give up. | 163 | * in which case we should better give up. | |
164 | */ | 164 | */ | |
165 | if (mkdir(p, 0777) == -1 && errno != EEXIST) { | 165 | if (mkdir(p, 0777) == -1 && errno != EEXIST) { | |
166 | free(p); | 166 | free(p); | |
167 | return -1; | 167 | return -1; | |
168 | } | 168 | } | |
169 | if (done) | 169 | if (done) | |
170 | break; | 170 | break; | |
171 | *cur_end = '/'; | 171 | *cur_end = '/'; | |
172 | } | 172 | } | |
173 | 173 | |||
174 | free(p); | 174 | free(p); | |
175 | return 0; | 175 | return 0; | |
176 | } | 176 | } | |
177 | 177 | |||
178 | /* | 178 | /* | |
179 | * Read meta data from archive. | 179 | * Read meta data from archive. | |
180 | * Bail out if a required entry is missing or entries are in the wrong order. | 180 | * Bail out if a required entry is missing or entries are in the wrong order. | |
181 | */ | 181 | */ | |
182 | static int | 182 | static int | |
183 | read_meta_data(struct pkg_task *pkg) | 183 | read_meta_data(struct pkg_task *pkg) | |
184 | { | 184 | { | |
185 | const struct pkg_meta_desc *descr, *last_descr; | 185 | const struct pkg_meta_desc *descr, *last_descr; | |
186 | const char *fname; | 186 | const char *fname; | |
187 | char **target; | 187 | char **target; | |
188 | int64_t size; | 188 | int64_t size; | |
189 | int r, found_required; | 189 | int r, found_required; | |
190 | 190 | |||
191 | found_required = 0; | 191 | found_required = 0; | |
192 | 192 | |||
193 | r = ARCHIVE_OK; | 193 | r = ARCHIVE_OK; | |
194 | last_descr = 0; | 194 | last_descr = 0; | |
195 | 195 | |||
196 | if (pkg->entry != NULL) | 196 | if (pkg->entry != NULL) | |
197 | goto skip_header; | 197 | goto skip_header; | |
198 | 198 | |||
199 | for (;;) { | 199 | for (;;) { | |
200 | r = archive_read_next_header(pkg->archive, &pkg->entry); | 200 | r = archive_read_next_header(pkg->archive, &pkg->entry); | |
201 | if (r != ARCHIVE_OK) | 201 | if (r != ARCHIVE_OK) | |
202 | break; | 202 | break; | |
203 | skip_header: | 203 | skip_header: | |
204 | fname = archive_entry_pathname(pkg->entry); | 204 | fname = archive_entry_pathname(pkg->entry); | |
205 | 205 | |||
206 | for (descr = pkg_meta_descriptors; descr->entry_filename; | 206 | for (descr = pkg_meta_descriptors; descr->entry_filename; | |
207 | ++descr) { | 207 | ++descr) { | |
208 | if (strcmp(descr->entry_filename, fname) == 0) | 208 | if (strcmp(descr->entry_filename, fname) == 0) | |
209 | break; | 209 | break; | |
210 | } | 210 | } | |
211 | if (descr->entry_filename == NULL) | 211 | if (descr->entry_filename == NULL) | |
212 | break; | 212 | break; | |
213 | 213 | |||
214 | if (descr->required_file) | 214 | if (descr->required_file) | |
215 | ++found_required; | 215 | ++found_required; | |
216 | 216 | |||
217 | target = (char **)((char *)&pkg->meta_data + | 217 | target = (char **)((char *)&pkg->meta_data + | |
218 | descr->entry_offset); | 218 | descr->entry_offset); | |
219 | if (*target) { | 219 | if (*target) { | |
220 | warnx("duplicate entry, package corrupt"); | 220 | warnx("duplicate entry, package corrupt"); | |
221 | return -1; | 221 | return -1; | |
222 | } | 222 | } | |
223 | if (descr < last_descr) { | 223 | if (descr < last_descr) { | |
224 | warnx("misordered package"); | 224 | warnx("misordered package"); | |
225 | return -1; | 225 | return -1; | |
226 | } | 226 | } | |
227 | last_descr = descr; | 227 | last_descr = descr; | |
228 | 228 | |||
229 | size = archive_entry_size(pkg->entry); | 229 | size = archive_entry_size(pkg->entry); | |
230 | if (size > SSIZE_MAX - 1) { | 230 | if (size > SSIZE_MAX - 1) { | |
231 | warnx("package meta data too large to process"); | 231 | warnx("package meta data too large to process"); | |
232 | return -1; | 232 | return -1; | |
233 | } | 233 | } | |
234 | *target = xmalloc(size + 1); | 234 | *target = xmalloc(size + 1); | |
235 | if (archive_read_data(pkg->archive, *target, size) != size) { | 235 | if (archive_read_data(pkg->archive, *target, size) != size) { | |
236 | warnx("cannot read package meta data"); | 236 | warnx("cannot read package meta data"); | |
237 | return -1; | 237 | return -1; | |
238 | } | 238 | } | |
239 | (*target)[size] = '\0'; | 239 | (*target)[size] = '\0'; | |
240 | } | 240 | } | |
241 | 241 | |||
242 | if (r != ARCHIVE_OK) | 242 | if (r != ARCHIVE_OK) | |
243 | pkg->entry = NULL; | 243 | pkg->entry = NULL; | |
244 | if (r == ARCHIVE_EOF) | 244 | if (r == ARCHIVE_EOF) | |
245 | r = ARCHIVE_OK; | 245 | r = ARCHIVE_OK; | |
246 | 246 | |||
247 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | 247 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | |
248 | if (descr->required_file) | 248 | if (descr->required_file) | |
249 | --found_required; | 249 | --found_required; | |
250 | } | 250 | } | |
251 | 251 | |||
252 | return !found_required && r == ARCHIVE_OK ? 0 : -1; | 252 | return !found_required && r == ARCHIVE_OK ? 0 : -1; | |
253 | } | 253 | } | |
254 | 254 | |||
255 | /* | 255 | /* | |
256 | * Free meta data. | 256 | * Free meta data. | |
257 | */ | 257 | */ | |
258 | static void | 258 | static void | |
259 | free_meta_data(struct pkg_task *pkg) | 259 | free_meta_data(struct pkg_task *pkg) | |
260 | { | 260 | { | |
261 | const struct pkg_meta_desc *descr; | 261 | const struct pkg_meta_desc *descr; | |
262 | char **target; | 262 | char **target; | |
263 | 263 | |||
264 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | 264 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | |
265 | target = (char **)((char *)&pkg->meta_data + | 265 | target = (char **)((char *)&pkg->meta_data + | |
266 | descr->entry_offset); | 266 | descr->entry_offset); | |
267 | free(*target); | 267 | free(*target); | |
268 | *target = NULL; | 268 | *target = NULL; | |
269 | } | 269 | } | |
270 | } | 270 | } | |
271 | 271 | |||
272 | /* | 272 | /* | |
273 | * Parse PLIST and populate pkg. | 273 | * Parse PLIST and populate pkg. | |
274 | */ | 274 | */ | |
275 | static int | 275 | static int | |
276 | pkg_parse_plist(struct pkg_task *pkg) | 276 | pkg_parse_plist(struct pkg_task *pkg) | |
277 | { | 277 | { | |
278 | plist_t *p; | 278 | plist_t *p; | |
279 | 279 | |||
280 | parse_plist(&pkg->plist, pkg->meta_data.meta_contents); | 280 | parse_plist(&pkg->plist, pkg->meta_data.meta_contents); | |
281 | if ((p = find_plist(&pkg->plist, PLIST_NAME)) == NULL) { | 281 | if ((p = find_plist(&pkg->plist, PLIST_NAME)) == NULL) { | |
282 | warnx("Invalid PLIST: missing @name"); | 282 | warnx("Invalid PLIST: missing @name"); | |
283 | return -1; | 283 | return -1; | |
284 | } | 284 | } | |
285 | if (pkg->pkgname == NULL) | 285 | if (pkg->pkgname == NULL) | |
286 | pkg->pkgname = xstrdup(p->name); | 286 | pkg->pkgname = xstrdup(p->name); | |
287 | else if (strcmp(pkg->pkgname, p->name) != 0) { | 287 | else if (strcmp(pkg->pkgname, p->name) != 0) { | |
288 | warnx("Signature and PLIST differ on package name"); | 288 | warnx("Signature and PLIST differ on package name"); | |
289 | return -1; | 289 | return -1; | |
290 | } | 290 | } | |
291 | if ((p = find_plist(&pkg->plist, PLIST_CWD)) == NULL) { | 291 | if ((p = find_plist(&pkg->plist, PLIST_CWD)) == NULL) { | |
292 | warnx("Invalid PLIST: missing @cwd"); | 292 | warnx("Invalid PLIST: missing @cwd"); | |
293 | return -1; | 293 | return -1; | |
294 | } | 294 | } | |
295 | 295 | |||
296 | if (Prefix != NULL && | 296 | if (Prefix != NULL && | |
297 | strcmp(p->name, Prefix) != 0) { | 297 | strcmp(p->name, Prefix) != 0) { | |
298 | size_t len; | 298 | size_t len; | |
299 | 299 | |||
300 | delete_plist(&pkg->plist, FALSE, PLIST_CWD, NULL); | 300 | delete_plist(&pkg->plist, FALSE, PLIST_CWD, NULL); | |
301 | add_plist_top(&pkg->plist, PLIST_CWD, Prefix); | 301 | add_plist_top(&pkg->plist, PLIST_CWD, Prefix); | |
302 | free(pkg->meta_data.meta_contents); | 302 | free(pkg->meta_data.meta_contents); | |
303 | stringify_plist(&pkg->plist, &pkg->meta_data.meta_contents, &len, | 303 | stringify_plist(&pkg->plist, &pkg->meta_data.meta_contents, &len, | |
304 | Prefix); | 304 | Prefix); | |
305 | pkg->prefix = Prefix; | 305 | pkg->prefix = Prefix; | |
306 | } else | 306 | } else | |
307 | pkg->prefix = p->name; | 307 | pkg->prefix = p->name; | |
308 | 308 | |||
309 | if (Destdir != NULL) | 309 | if (Destdir != NULL) | |
310 | pkg->install_prefix = xasprintf("%s/%s", Destdir, pkg->prefix); | 310 | pkg->install_prefix = xasprintf("%s/%s", Destdir, pkg->prefix); | |
311 | else | 311 | else | |
312 | pkg->install_prefix = xstrdup(pkg->prefix); | 312 | pkg->install_prefix = xstrdup(pkg->prefix); | |
313 | 313 | |||
314 | return 0; | 314 | return 0; | |
315 | } | 315 | } | |
316 | 316 | |||
317 | /* | 317 | /* | |
318 | * Helper function to extract value from a string of the | 318 | * Helper function to extract value from a string of the | |
319 | * form key=value ending at eol. | 319 | * form key=value ending at eol. | |
320 | */ | 320 | */ | |
321 | static char * | 321 | static char * | |
322 | dup_value(const char *line, const char *eol) | 322 | dup_value(const char *line, const char *eol) | |
323 | { | 323 | { | |
324 | const char *key; | 324 | const char *key; | |
325 | char *val; | 325 | char *val; | |
326 | 326 | |||
327 | key = strchr(line, '='); | 327 | key = strchr(line, '='); | |
328 | val = xmalloc(eol - key); | 328 | val = xmalloc(eol - key); | |
329 | memcpy(val, key + 1, eol - key - 1); | 329 | memcpy(val, key + 1, eol - key - 1); | |
330 | val[eol - key - 1] = '\0'; | 330 | val[eol - key - 1] = '\0'; | |
331 | return val; | 331 | return val; | |
332 | } | 332 | } | |
333 | 333 | |||
334 | static int | 334 | static int | |
335 | check_already_installed(struct pkg_task *pkg) | 335 | check_already_installed(struct pkg_task *pkg) | |
336 | { | 336 | { | |
337 | char *filename; | 337 | char *filename; | |
338 | int fd; | 338 | int fd; | |
339 | 339 | |||
340 | if (Force) | 340 | if (Force) | |
341 | return -1; | 341 | return -1; | |
342 | 342 | |||
343 | filename = pkgdb_pkg_file(pkg->pkgname, CONTENTS_FNAME); | 343 | filename = pkgdb_pkg_file(pkg->pkgname, CONTENTS_FNAME); | |
344 | fd = open(filename, O_RDONLY); | 344 | fd = open(filename, O_RDONLY); | |
345 | free(filename); | 345 | free(filename); | |
346 | if (fd == -1) | 346 | if (fd == -1) | |
347 | return -1; | 347 | return -1; | |
348 | 348 | |||
349 | /* We can only arrive here for explicitly requested packages. */ | 349 | /* We can only arrive here for explicitly requested packages. */ | |
350 | if (!Automatic && is_automatic_installed(pkg->pkgname)) { | 350 | if (!Automatic && is_automatic_installed(pkg->pkgname)) { | |
351 | if (Fake || | 351 | if (Fake || | |
352 | mark_as_automatic_installed(pkg->pkgname, 0) == 0) | 352 | mark_as_automatic_installed(pkg->pkgname, 0) == 0) | |
353 | warnx("package `%s' was already installed as " | 353 | warnx("package `%s' was already installed as " | |
354 | "dependency, now marked as installed " | 354 | "dependency, now marked as installed " | |
355 | "manually", pkg->pkgname); | 355 | "manually", pkg->pkgname); | |
356 | } else { | 356 | } else { | |
357 | warnx("package `%s' already recorded as installed", | 357 | warnx("package `%s' already recorded as installed", | |
358 | pkg->pkgname); | 358 | pkg->pkgname); | |
359 | } | 359 | } | |
360 | close(fd); | |||
360 | return 0; | 361 | return 0; | |
361 | 362 | |||
362 | } | 363 | } | |
363 | 364 | |||
364 | static int | 365 | static int | |
365 | check_other_installed(struct pkg_task *pkg) | 366 | check_other_installed(struct pkg_task *pkg) | |
366 | { | 367 | { | |
367 | FILE *f, *f_pkg; | 368 | FILE *f, *f_pkg; | |
368 | size_t len; | 369 | size_t len; | |
369 | char *pkgbase, *iter, *filename; | 370 | char *pkgbase, *iter, *filename; | |
370 | package_t plist; | 371 | package_t plist; | |
371 | plist_t *p; | 372 | plist_t *p; | |
372 | int status; | 373 | int status; | |
373 | 374 | |||
374 | pkgbase = xstrdup(pkg->pkgname); | 375 | pkgbase = xstrdup(pkg->pkgname); | |
375 | 376 | |||
376 | if ((iter = strrchr(pkgbase, '-')) == NULL) { | 377 | if ((iter = strrchr(pkgbase, '-')) == NULL) { | |
377 | free(pkgbase); | 378 | free(pkgbase); | |
378 | warnx("Invalid package name %s", pkg->pkgname); | 379 | warnx("Invalid package name %s", pkg->pkgname); | |
379 | return -1; | 380 | return -1; | |
380 | } | 381 | } | |
381 | *iter = '\0'; | 382 | *iter = '\0'; | |
382 | pkg->other_version = find_best_matching_installed_pkg(pkgbase); | 383 | pkg->other_version = find_best_matching_installed_pkg(pkgbase); | |
383 | free(pkgbase); | 384 | free(pkgbase); | |
384 | if (pkg->other_version == NULL) | 385 | if (pkg->other_version == NULL) | |
385 | return 0; | 386 | return 0; | |
386 | 387 | |||
387 | if (!Replace) { | 388 | if (!Replace) { | |
388 | /* XXX This is redundant to the implicit conflict check. */ | 389 | /* XXX This is redundant to the implicit conflict check. */ | |
389 | warnx("A different version of %s is already installed: %s", | 390 | warnx("A different version of %s is already installed: %s", | |
390 | pkg->pkgname, pkg->other_version); | 391 | pkg->pkgname, pkg->other_version); | |
391 | return -1; | 392 | return -1; | |
392 | } | 393 | } | |
393 | 394 | |||
394 | filename = pkgdb_pkg_file(pkg->other_version, REQUIRED_BY_FNAME); | 395 | filename = pkgdb_pkg_file(pkg->other_version, REQUIRED_BY_FNAME); | |
395 | errno = 0; | 396 | errno = 0; | |
396 | f = fopen(filename, "r"); | 397 | f = fopen(filename, "r"); | |
397 | free(filename); | 398 | free(filename); | |
398 | if (f == NULL) { | 399 | if (f == NULL) { | |
399 | if (errno == ENOENT) { | 400 | if (errno == ENOENT) { | |
400 | /* No packages depend on this, so everything is well. */ | 401 | /* No packages depend on this, so everything is well. */ | |
401 | return 0; | 402 | return 0; | |
402 | } | 403 | } | |
403 | warnx("Can't open +REQUIRED_BY of %s", pkg->other_version); | 404 | warnx("Can't open +REQUIRED_BY of %s", pkg->other_version); | |
404 | return -1; | 405 | return -1; | |
405 | } | 406 | } | |
406 | 407 | |||
407 | status = 0; | 408 | status = 0; | |
408 | 409 | |||
409 | while ((iter = fgetln(f, &len)) != NULL) { | 410 | while ((iter = fgetln(f, &len)) != NULL) { | |
410 | if (iter[len - 1] == '\n') | 411 | if (iter[len - 1] == '\n') | |
411 | iter[len - 1] = '\0'; | 412 | iter[len - 1] = '\0'; | |
412 | filename = pkgdb_pkg_file(iter, CONTENTS_FNAME); | 413 | filename = pkgdb_pkg_file(iter, CONTENTS_FNAME); | |
413 | if ((f_pkg = fopen(filename, "r")) == NULL) { | 414 | if ((f_pkg = fopen(filename, "r")) == NULL) { | |
414 | warnx("Can't open +CONTENTS of depending package %s", | 415 | warnx("Can't open +CONTENTS of depending package %s", | |
415 | iter); | 416 | iter); | |
416 | fclose(f); | 417 | fclose(f); | |
417 | return -1; | 418 | return -1; | |
418 | } | 419 | } | |
419 | read_plist(&plist, f_pkg); | 420 | read_plist(&plist, f_pkg); | |
420 | fclose(f_pkg); | 421 | fclose(f_pkg); | |
421 | for (p = plist.head; p != NULL; p = p->next) { | 422 | for (p = plist.head; p != NULL; p = p->next) { | |
422 | if (p->type == PLIST_IGNORE) { | 423 | if (p->type == PLIST_IGNORE) { | |
423 | p = p->next; | 424 | p = p->next; | |
424 | continue; | 425 | continue; | |
425 | } else if (p->type != PLIST_PKGDEP) | 426 | } else if (p->type != PLIST_PKGDEP) | |
426 | continue; | 427 | continue; | |
427 | /* | 428 | /* | |
428 | * XXX This is stricter than necessary. | 429 | * XXX This is stricter than necessary. | |
429 | * XXX One pattern might be fulfilled by | 430 | * XXX One pattern might be fulfilled by | |
430 | * XXX a different package and still need this | 431 | * XXX a different package and still need this | |
431 | * XXX one for a different pattern. | 432 | * XXX one for a different pattern. | |
432 | */ | 433 | */ | |
433 | if (pkg_match(p->name, pkg->other_version) == 0) | 434 | if (pkg_match(p->name, pkg->other_version) == 0) | |
434 | continue; | 435 | continue; | |
435 | if (pkg_match(p->name, pkg->pkgname) == 1) | 436 | if (pkg_match(p->name, pkg->pkgname) == 1) | |
436 | continue; /* Both match, ok. */ | 437 | continue; /* Both match, ok. */ | |
437 | warnx("Dependency of %s fulfilled by %s, but not by %s", | 438 | warnx("Dependency of %s fulfilled by %s, but not by %s", | |
438 | iter, pkg->other_version, pkg->pkgname); | 439 | iter, pkg->other_version, pkg->pkgname); | |
439 | if (!Force) | 440 | if (!Force) | |
440 | status = -1; | 441 | status = -1; | |
441 | break; | 442 | break; | |
442 | } | 443 | } | |
443 | free_plist(&plist); | 444 | free_plist(&plist); | |
444 | } | 445 | } | |
445 | 446 | |||
446 | fclose(f); | 447 | fclose(f); | |
447 | 448 | |||
448 | return status; | 449 | return status; | |
449 | } | 450 | } | |
450 | 451 | |||
451 | /* | 452 | /* | |
452 | * Read package build information from meta data. | 453 | * Read package build information from meta data. | |
453 | */ | 454 | */ | |
454 | static int | 455 | static int | |
455 | read_buildinfo(struct pkg_task *pkg) | 456 | read_buildinfo(struct pkg_task *pkg) | |
456 | { | 457 | { | |
457 | const char *data, *eol, *next_line; | 458 | const char *data, *eol, *next_line; | |
458 | 459 | |||
459 | data = pkg->meta_data.meta_build_info; | 460 | data = pkg->meta_data.meta_build_info; | |
460 | 461 | |||
461 | for (; data != NULL && *data != '\0'; data = next_line) { | 462 | for (; data != NULL && *data != '\0'; data = next_line) { | |
462 | if ((eol = strchr(data, '\n')) == NULL) { | 463 | if ((eol = strchr(data, '\n')) == NULL) { | |
463 | eol = data + strlen(data); | 464 | eol = data + strlen(data); | |
464 | next_line = eol; | 465 | next_line = eol; | |
465 | } else | 466 | } else | |
466 | next_line = eol + 1; | 467 | next_line = eol + 1; | |
467 | 468 | |||
468 | if (strncmp(data, "OPSYS=", 6) == 0) | 469 | if (strncmp(data, "OPSYS=", 6) == 0) | |
469 | pkg->buildinfo[BI_OPSYS] = dup_value(data, eol); | 470 | pkg->buildinfo[BI_OPSYS] = dup_value(data, eol); | |
470 | else if (strncmp(data, "OS_VERSION=", 11) == 0) | 471 | else if (strncmp(data, "OS_VERSION=", 11) == 0) | |
471 | pkg->buildinfo[BI_OS_VERSION] = dup_value(data, eol); | 472 | pkg->buildinfo[BI_OS_VERSION] = dup_value(data, eol); | |
472 | else if (strncmp(data, "MACHINE_ARCH=", 13) == 0) | 473 | else if (strncmp(data, "MACHINE_ARCH=", 13) == 0) | |
473 | pkg->buildinfo[BI_MACHINE_ARCH] = dup_value(data, eol); | 474 | pkg->buildinfo[BI_MACHINE_ARCH] = dup_value(data, eol); | |
474 | else if (strncmp(data, "IGNORE_RECOMMENDED=", 19) == 0) | 475 | else if (strncmp(data, "IGNORE_RECOMMENDED=", 19) == 0) | |
475 | pkg->buildinfo[BI_IGNORE_RECOMMENDED] = dup_value(data, | 476 | pkg->buildinfo[BI_IGNORE_RECOMMENDED] = dup_value(data, | |
476 | eol); | 477 | eol); | |
477 | else if (strncmp(data, "USE_ABI_DEPENDS=", 16) == 0) | 478 | else if (strncmp(data, "USE_ABI_DEPENDS=", 16) == 0) | |
478 | pkg->buildinfo[BI_USE_ABI_DEPENDS] = dup_value(data, | 479 | pkg->buildinfo[BI_USE_ABI_DEPENDS] = dup_value(data, | |
479 | eol); | 480 | eol); | |
480 | } | 481 | } | |
481 | if (pkg->buildinfo[BI_OPSYS] == NULL || | 482 | if (pkg->buildinfo[BI_OPSYS] == NULL || | |
482 | pkg->buildinfo[BI_OS_VERSION] == NULL || | 483 | pkg->buildinfo[BI_OS_VERSION] == NULL || | |
483 | pkg->buildinfo[BI_MACHINE_ARCH] == NULL) { | 484 | pkg->buildinfo[BI_MACHINE_ARCH] == NULL) { | |
484 | warnx("Not all required build information are present."); | 485 | warnx("Not all required build information are present."); | |
485 | return -1; | 486 | return -1; | |
486 | } | 487 | } | |
487 | 488 | |||
488 | if ((pkg->buildinfo[BI_USE_ABI_DEPENDS] != NULL && | 489 | if ((pkg->buildinfo[BI_USE_ABI_DEPENDS] != NULL && | |
489 | strcasecmp(pkg->buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) || | 490 | strcasecmp(pkg->buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) || | |
490 | (pkg->buildinfo[BI_IGNORE_RECOMMENDED] != NULL && | 491 | (pkg->buildinfo[BI_IGNORE_RECOMMENDED] != NULL && | |
491 | strcasecmp(pkg->buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) { | 492 | strcasecmp(pkg->buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) { | |
492 | warnx("%s was built to ignore ABI dependencies", pkg->pkgname); | 493 | warnx("%s was built to ignore ABI dependencies", pkg->pkgname); | |
493 | } | 494 | } | |
494 | 495 | |||
495 | return 0; | 496 | return 0; | |
496 | } | 497 | } | |
497 | 498 | |||
498 | /* | 499 | /* | |
499 | * Free buildinfo. | 500 | * Free buildinfo. | |
500 | */ | 501 | */ | |
501 | static void | 502 | static void | |
502 | free_buildinfo(struct pkg_task *pkg) | 503 | free_buildinfo(struct pkg_task *pkg) | |
503 | { | 504 | { | |
504 | size_t i; | 505 | size_t i; | |
505 | 506 | |||
506 | for (i = 0; i < BI_ENUM_COUNT; ++i) { | 507 | for (i = 0; i < BI_ENUM_COUNT; ++i) { | |
507 | free(pkg->buildinfo[i]); | 508 | free(pkg->buildinfo[i]); | |
508 | pkg->buildinfo[i] = NULL; | 509 | pkg->buildinfo[i] = NULL; | |
509 | } | 510 | } | |
510 | } | 511 | } | |
511 | 512 | |||
512 | /* | 513 | /* | |
513 | * Write meta data files to pkgdb after creating the directory. | 514 | * Write meta data files to pkgdb after creating the directory. | |
514 | */ | 515 | */ | |
515 | static int | 516 | static int | |
516 | write_meta_data(struct pkg_task *pkg) | 517 | write_meta_data(struct pkg_task *pkg) | |
517 | { | 518 | { | |
518 | const struct pkg_meta_desc *descr; | 519 | const struct pkg_meta_desc *descr; | |
519 | char *filename, **target; | 520 | char *filename, **target; | |
520 | size_t len; | 521 | size_t len; | |
521 | ssize_t ret; | 522 | ssize_t ret; | |
522 | int fd; | 523 | int fd; | |
523 | 524 | |||
524 | if (Fake) | 525 | if (Fake) | |
525 | return 0; | 526 | return 0; | |
526 | 527 | |||
527 | if (mkdir_p(pkg->install_logdir)) { | 528 | if (mkdir_p(pkg->install_logdir)) { | |
528 | warn("Can't create pkgdb entry: %s", pkg->install_logdir); | 529 | warn("Can't create pkgdb entry: %s", pkg->install_logdir); | |
529 | return -1; | 530 | return -1; | |
530 | } | 531 | } | |
531 | 532 | |||
532 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | 533 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | |
533 | target = (char **)((char *)&pkg->meta_data + | 534 | target = (char **)((char *)&pkg->meta_data + | |
534 | descr->entry_offset); | 535 | descr->entry_offset); | |
535 | if (*target == NULL) | 536 | if (*target == NULL) | |
536 | continue; | 537 | continue; | |
537 | filename = xasprintf("%s/%s", pkg->install_logdir, | 538 | filename = xasprintf("%s/%s", pkg->install_logdir, | |
538 | descr->entry_filename); | 539 | descr->entry_filename); | |
539 | (void)unlink(filename); | 540 | (void)unlink(filename); | |
540 | fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, descr->perm); | 541 | fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, descr->perm); | |
541 | if (fd == -1) { | 542 | if (fd == -1) { | |
542 | warn("Can't open meta data file: %s", filename); | 543 | warn("Can't open meta data file: %s", filename); | |
543 | return -1; | 544 | return -1; | |
544 | } | 545 | } | |
545 | len = strlen(*target); | 546 | len = strlen(*target); | |
546 | do { | 547 | do { | |
547 | ret = write(fd, *target, len); | 548 | ret = write(fd, *target, len); | |
548 | if (ret == -1) { | 549 | if (ret == -1) { | |
549 | warn("Can't write meta data file: %s", | 550 | warn("Can't write meta data file: %s", | |
550 | filename); | 551 | filename); | |
551 | free(filename); | 552 | free(filename); | |
553 | close(fd); | |||
552 | return -1; | 554 | return -1; | |
553 | } | 555 | } | |
554 | len -= ret; | 556 | len -= ret; | |
555 | } while (ret > 0); | 557 | } while (ret > 0); | |
556 | if (close(fd) == -1) { | 558 | if (close(fd) == -1) { | |
557 | warn("Can't close meta data file: %s", filename); | 559 | warn("Can't close meta data file: %s", filename); | |
558 | free(filename); | 560 | free(filename); | |
559 | return -1; | 561 | return -1; | |
560 | } | 562 | } | |
561 | free(filename); | 563 | free(filename); | |
562 | } | 564 | } | |
563 | 565 | |||
564 | return 0; | 566 | return 0; | |
565 | } | 567 | } | |
566 | 568 | |||
567 | /* | 569 | /* | |
568 | * Helper function for extract_files. | 570 | * Helper function for extract_files. | |
569 | */ | 571 | */ | |
570 | static int | 572 | static int | |
571 | copy_data_to_disk(struct archive *reader, struct archive *writer, | 573 | copy_data_to_disk(struct archive *reader, struct archive *writer, | |
572 | const char *filename) | 574 | const char *filename) | |
573 | { | 575 | { | |
574 | int r; | 576 | int r; | |
575 | const void *buff; | 577 | const void *buff; | |
576 | size_t size; | 578 | size_t size; | |
577 | off_t offset; | 579 | off_t offset; | |
578 | 580 | |||
579 | for (;;) { | 581 | for (;;) { | |
580 | r = archive_read_data_block(reader, &buff, &size, &offset); | 582 | r = archive_read_data_block(reader, &buff, &size, &offset); | |
581 | if (r == ARCHIVE_EOF) | 583 | if (r == ARCHIVE_EOF) | |
582 | return 0; | 584 | return 0; | |
583 | if (r != ARCHIVE_OK) { | 585 | if (r != ARCHIVE_OK) { | |
584 | warnx("Read error for %s: %s", filename, | 586 | warnx("Read error for %s: %s", filename, | |
585 | archive_error_string(reader)); | 587 | archive_error_string(reader)); | |
586 | return -1; | 588 | return -1; | |
587 | } | 589 | } | |
588 | r = archive_write_data_block(writer, buff, size, offset); | 590 | r = archive_write_data_block(writer, buff, size, offset); | |
589 | if (r != ARCHIVE_OK) { | 591 | if (r != ARCHIVE_OK) { | |
590 | warnx("Write error for %s: %s", filename, | 592 | warnx("Write error for %s: %s", filename, | |
591 | archive_error_string(writer)); | 593 | archive_error_string(writer)); | |
592 | return -1; | 594 | return -1; | |
593 | } | 595 | } | |
594 | } | 596 | } | |
595 | } | 597 | } | |
596 | 598 | |||
597 | /* | 599 | /* | |
598 | * Extract package. | 600 | * Extract package. | |
599 | * Any misordered, missing or unlisted file in the package is an error. | 601 | * Any misordered, missing or unlisted file in the package is an error. | |
600 | */ | 602 | */ | |
601 | 603 | |||
602 | static const int extract_flags = /* ARCHIVE_EXTRACT_OWNER | */ | 604 | static const int extract_flags = /* ARCHIVE_EXTRACT_OWNER | */ | |
603 | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | | 605 | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | | |
604 | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR; | 606 | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR; | |
605 | 607 | |||
606 | static int | 608 | static int | |
607 | extract_files(struct pkg_task *pkg) | 609 | extract_files(struct pkg_task *pkg) | |
608 | { | 610 | { | |
609 | char cmd[MaxPathSize]; | 611 | char cmd[MaxPathSize]; | |
610 | const char *owner, *group, *permissions; | 612 | const char *owner, *group, *permissions; | |
611 | struct archive *writer; | 613 | struct archive *writer; | |
612 | int r; | 614 | int r; | |
613 | plist_t *p; | 615 | plist_t *p; | |
614 | const char *last_file; | 616 | const char *last_file; | |
615 | char *fullpath; | 617 | char *fullpath; | |
616 | 618 | |||
617 | if (Fake) | 619 | if (Fake) | |
618 | return 0; | 620 | return 0; | |
619 | 621 | |||
620 | if (mkdir_p(pkg->install_prefix)) { | 622 | if (mkdir_p(pkg->install_prefix)) { | |
621 | warn("Can't create prefix: %s", pkg->install_prefix); | 623 | warn("Can't create prefix: %s", pkg->install_prefix); | |
622 | return -1; | 624 | return -1; | |
623 | } | 625 | } | |
624 | 626 | |||
625 | if (!NoRecord && !pkgdb_open(ReadWrite)) { | 627 | if (!NoRecord && !pkgdb_open(ReadWrite)) { | |
626 | warn("Can't open pkgdb for writing"); | 628 | warn("Can't open pkgdb for writing"); | |
627 | return -1; | 629 | return -1; | |
628 | } | 630 | } | |
629 | 631 | |||
630 | if (chdir(pkg->install_prefix) == -1) { | 632 | if (chdir(pkg->install_prefix) == -1) { | |
631 | warn("Can't change into prefix: %s", pkg->install_prefix); | 633 | warn("Can't change into prefix: %s", pkg->install_prefix); | |
632 | return -1; | 634 | return -1; | |
633 | } | 635 | } | |
634 | 636 | |||
635 | writer = archive_write_disk_new(); | 637 | writer = archive_write_disk_new(); | |
636 | archive_write_disk_set_options(writer, extract_flags); | 638 | archive_write_disk_set_options(writer, extract_flags); | |
637 | archive_write_disk_set_standard_lookup(writer); | 639 | archive_write_disk_set_standard_lookup(writer); | |
638 | 640 | |||
639 | owner = NULL; | 641 | owner = NULL; | |
640 | group = NULL; | 642 | group = NULL; | |
641 | permissions = NULL; | 643 | permissions = NULL; | |
642 | last_file = NULL; | 644 | last_file = NULL; | |
643 | 645 | |||
644 | r = -1; | 646 | r = -1; | |
645 | 647 | |||
646 | for (p = pkg->plist.head; p != NULL; p = p->next) { | 648 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |
647 | switch (p->type) { | 649 | switch (p->type) { | |
648 | case PLIST_FILE: | 650 | case PLIST_FILE: | |
649 | last_file = p->name; | 651 | last_file = p->name; | |
650 | if (pkg->entry == NULL) { | 652 | if (pkg->entry == NULL) { | |
651 | warnx("PLIST entry not in package (%s)", | 653 | warnx("PLIST entry not in package (%s)", | |
652 | archive_entry_pathname(pkg->entry)); | 654 | archive_entry_pathname(pkg->entry)); | |
653 | goto out; | 655 | goto out; | |
654 | } | 656 | } | |
655 | if (strcmp(p->name, archive_entry_pathname(pkg->entry))) { | 657 | if (strcmp(p->name, archive_entry_pathname(pkg->entry))) { | |
656 | warnx("PLIST entry and package don't match (%s vs %s)", | 658 | warnx("PLIST entry and package don't match (%s vs %s)", | |
657 | p->name, archive_entry_pathname(pkg->entry)); | 659 | p->name, archive_entry_pathname(pkg->entry)); | |
658 | goto out; | 660 | goto out; | |
659 | } | 661 | } | |
660 | fullpath = xasprintf("%s/%s", pkg->prefix, p->name); | 662 | fullpath = xasprintf("%s/%s", pkg->prefix, p->name); | |
661 | pkgdb_store(fullpath, pkg->pkgname); | 663 | pkgdb_store(fullpath, pkg->pkgname); | |
662 | free(fullpath); | 664 | free(fullpath); | |
663 | if (Verbose) | 665 | if (Verbose) | |
664 | printf("%s", p->name); | 666 | printf("%s", p->name); | |
665 | break; | 667 | break; | |
666 | 668 | |||
667 | case PLIST_CMD: | 669 | case PLIST_CMD: | |
668 | if (format_cmd(cmd, sizeof(cmd), p->name, pkg->prefix, last_file)) | 670 | if (format_cmd(cmd, sizeof(cmd), p->name, pkg->prefix, last_file)) | |
669 | return -1; | 671 | return -1; | |
670 | printf("Executing '%s'\n", cmd); | 672 | printf("Executing '%s'\n", cmd); | |
671 | if (!Fake && system(cmd)) | 673 | if (!Fake && system(cmd)) | |
672 | warnx("command '%s' failed", cmd); /* XXX bail out? */ | 674 | warnx("command '%s' failed", cmd); /* XXX bail out? */ | |
673 | continue; | 675 | continue; | |
674 | 676 | |||
675 | case PLIST_CHMOD: | 677 | case PLIST_CHMOD: | |
676 | permissions = p->name; | 678 | permissions = p->name; | |
677 | continue; | 679 | continue; | |
678 | 680 | |||
679 | case PLIST_CHOWN: | 681 | case PLIST_CHOWN: | |
680 | owner = p->name; | 682 | owner = p->name; | |
681 | continue; | 683 | continue; | |
682 | 684 | |||
683 | case PLIST_CHGRP: | 685 | case PLIST_CHGRP: | |
684 | group = p->name; | 686 | group = p->name; | |
685 | continue; | 687 | continue; | |
686 | 688 | |||
687 | case PLIST_IGNORE: | 689 | case PLIST_IGNORE: | |
688 | p = p->next; | 690 | p = p->next; | |
689 | continue; | 691 | continue; | |
690 | 692 | |||
691 | default: | 693 | default: | |
692 | continue; | 694 | continue; | |
693 | } | 695 | } | |
694 | 696 | |||
695 | r = archive_write_header(writer, pkg->entry); | 697 | r = archive_write_header(writer, pkg->entry); | |
696 | if (r != ARCHIVE_OK) { | 698 | if (r != ARCHIVE_OK) { | |
697 | warnx("Failed to write %s: %s", | 699 | warnx("Failed to write %s: %s", | |
698 | archive_entry_pathname(pkg->entry), | 700 | archive_entry_pathname(pkg->entry), | |
699 | archive_error_string(writer)); | 701 | archive_error_string(writer)); | |
700 | goto out; | 702 | goto out; | |
701 | } | 703 | } | |
702 | 704 | |||
703 | if (owner != NULL) | 705 | if (owner != NULL) | |
704 | archive_entry_set_uname(pkg->entry, owner); | 706 | archive_entry_set_uname(pkg->entry, owner); | |
705 | if (group != NULL) | 707 | if (group != NULL) | |
706 | archive_entry_set_uname(pkg->entry, group); | 708 | archive_entry_set_uname(pkg->entry, group); | |
707 | if (permissions != NULL) { | 709 | if (permissions != NULL) { | |
708 | mode_t mode; | 710 | mode_t mode; | |
709 | 711 | |||
710 | mode = archive_entry_mode(pkg->entry); | 712 | mode = archive_entry_mode(pkg->entry); | |
711 | mode = getmode(setmode(permissions), mode); | 713 | mode = getmode(setmode(permissions), mode); | |
712 | archive_entry_set_mode(pkg->entry, mode); | 714 | archive_entry_set_mode(pkg->entry, mode); | |
713 | } | 715 | } | |
714 | 716 | |||
715 | r = copy_data_to_disk(pkg->archive, writer, | 717 | r = copy_data_to_disk(pkg->archive, writer, | |
716 | archive_entry_pathname(pkg->entry)); | 718 | archive_entry_pathname(pkg->entry)); | |
717 | if (r) | 719 | if (r) | |
718 | goto out; | 720 | goto out; | |
719 | if (Verbose) | 721 | if (Verbose) | |
720 | printf("\n"); | 722 | printf("\n"); | |
721 | 723 | |||
722 | r = archive_read_next_header(pkg->archive, &pkg->entry); | 724 | r = archive_read_next_header(pkg->archive, &pkg->entry); | |
723 | if (r == ARCHIVE_EOF) { | 725 | if (r == ARCHIVE_EOF) { | |
724 | pkg->entry = NULL; | 726 | pkg->entry = NULL; | |
725 | continue; | 727 | continue; | |
726 | } | 728 | } | |
727 | if (r != ARCHIVE_OK) { | 729 | if (r != ARCHIVE_OK) { | |
728 | warnx("Failed to read from archive: %s", | 730 | warnx("Failed to read from archive: %s", | |
729 | archive_error_string(pkg->archive)); | 731 | archive_error_string(pkg->archive)); | |
730 | goto out; | 732 | goto out; | |
731 | } | 733 | } | |
732 | } | 734 | } | |
733 | 735 | |||
734 | if (pkg->entry != NULL) { | 736 | if (pkg->entry != NULL) { | |
735 | warnx("Package contains entries not in PLIST: %s", | 737 | warnx("Package contains entries not in PLIST: %s", | |
736 | archive_entry_pathname(pkg->entry)); | 738 | archive_entry_pathname(pkg->entry)); | |
737 | goto out; | 739 | goto out; | |
738 | } | 740 | } | |
739 | 741 | |||
740 | r = 0; | 742 | r = 0; | |
741 | 743 | |||
742 | out: | 744 | out: | |
743 | if (!NoRecord) | 745 | if (!NoRecord) | |
744 | pkgdb_close(); | 746 | pkgdb_close(); | |
745 | archive_write_close(writer); | 747 | archive_write_close(writer); | |
746 | archive_write_finish(writer); | 748 | archive_write_finish(writer); | |
747 | 749 | |||
748 | return r; | 750 | return r; | |
749 | } | 751 | } | |
750 | 752 | |||
751 | /* | 753 | /* | |
752 | * Register dependencies after sucessfully installing the package. | 754 | * Register dependencies after sucessfully installing the package. | |
753 | */ | 755 | */ | |
754 | static void | 756 | static void | |
755 | pkg_register_depends(struct pkg_task *pkg) | 757 | pkg_register_depends(struct pkg_task *pkg) | |
756 | { | 758 | { | |
757 | int fd; | 759 | int fd; | |
758 | size_t text_len, i; | 760 | size_t text_len, i; | |
759 | char *required_by, *text; | 761 | char *required_by, *text; | |
760 | 762 | |||
761 | if (Fake) | 763 | if (Fake) | |
762 | return; | 764 | return; | |
763 | 765 | |||
764 | if (pkg->other_version != NULL) | 766 | if (pkg->other_version != NULL) | |
765 | return; /* XXX It's using the old dependencies. */ | 767 | return; /* XXX It's using the old dependencies. */ | |
766 | 768 | |||
767 | text = xasprintf("%s\n", pkg->pkgname); | 769 | text = xasprintf("%s\n", pkg->pkgname); | |
768 | text_len = strlen(text); | 770 | text_len = strlen(text); | |
769 | 771 | |||
770 | for (i = 0; i < pkg->dep_length; ++i) { | 772 | for (i = 0; i < pkg->dep_length; ++i) { | |
771 | required_by = pkgdb_pkg_file(pkg->dependencies[i], REQUIRED_BY_FNAME); | 773 | required_by = pkgdb_pkg_file(pkg->dependencies[i], REQUIRED_BY_FNAME); | |
772 | 774 | |||
773 | fd = open(required_by, O_WRONLY | O_APPEND | O_CREAT, 0644); | 775 | fd = open(required_by, O_WRONLY | O_APPEND | O_CREAT, 0644); | |
774 | if (fd == -1) | 776 | if (fd == -1) { | |
775 | warn("can't open dependency file '%s'," | 777 | warn("can't open dependency file '%s'," | |
776 | "registration is incomplete!", required_by); | 778 | "registration is incomplete!", required_by); | |
777 | else if (write(fd, text, text_len) != text_len) | 779 | close(fd); | |
780 | } else if (write(fd, text, text_len) != text_len) { | |||
778 | warn("can't write to dependency file `%s'", required_by); | 781 | warn("can't write to dependency file `%s'", required_by); | |
779 | else if (close(fd) == -1) | 782 | close(fd); | |
783 | } else if (close(fd) == -1) | |||
780 | warn("cannot close file %s", required_by); | 784 | warn("cannot close file %s", required_by); | |
781 | 785 | |||
782 | free(required_by); | 786 | free(required_by); | |
783 | } | 787 | } | |
784 | 788 | |||
785 | free(text); | 789 | free(text); | |
786 | } | 790 | } | |
787 | 791 | |||
788 | /* | 792 | /* | |
789 | * Reduce the result from uname(3) to a canonical form. | 793 | * Reduce the result from uname(3) to a canonical form. | |
790 | */ | 794 | */ | |
791 | static void | 795 | static void | |
792 | normalise_platform(struct utsname *host_name) | 796 | normalise_platform(struct utsname *host_name) | |
793 | { | 797 | { | |
794 | #ifdef NUMERIC_VERSION_ONLY | 798 | #ifdef NUMERIC_VERSION_ONLY | |
795 | size_t span; | 799 | size_t span; | |
796 | 800 | |||
797 | span = strspn(host_name->release, "0123456789."); | 801 | span = strspn(host_name->release, "0123456789."); | |
798 | host_name->release[span] = '\0'; | 802 | host_name->release[span] = '\0'; | |
799 | #endif | 803 | #endif | |
800 | } | 804 | } | |
801 | 805 | |||
802 | /* | 806 | /* | |
803 | * Check build platform of the package against local host. | 807 | * Check build platform of the package against local host. | |
804 | */ | 808 | */ | |
805 | static int | 809 | static int | |
806 | check_platform(struct pkg_task *pkg) | 810 | check_platform(struct pkg_task *pkg) | |
807 | { | 811 | { | |
808 | struct utsname host_uname; | 812 | struct utsname host_uname; | |
809 | const char *effective_arch; | 813 | const char *effective_arch; | |
810 | int fatal; | 814 | int fatal; | |
811 | 815 | |||
812 | if (uname(&host_uname) < 0) { | 816 | if (uname(&host_uname) < 0) { | |
813 | if (Force) { | 817 | if (Force) { | |
814 | warnx("uname() failed, continuing."); | 818 | warnx("uname() failed, continuing."); | |
815 | return 0; | 819 | return 0; | |
816 | } else { | 820 | } else { | |
817 | warnx("uname() failed, aborting."); | 821 | warnx("uname() failed, aborting."); | |
818 | return -1; | 822 | return -1; | |
819 | } | 823 | } | |
820 | } | 824 | } | |
821 | 825 | |||
822 | normalise_platform(&host_uname); | 826 | normalise_platform(&host_uname); | |
823 | 827 | |||
824 | if (OverrideMachine != NULL) | 828 | if (OverrideMachine != NULL) | |
825 | effective_arch = OverrideMachine; | 829 | effective_arch = OverrideMachine; | |
826 | else | 830 | else | |
827 | effective_arch = MACHINE_ARCH; | 831 | effective_arch = MACHINE_ARCH; | |
828 | 832 | |||
829 | /* If either the OS or arch are different, bomb */ | 833 | /* If either the OS or arch are different, bomb */ | |
830 | if (strcmp(OPSYS_NAME, pkg->buildinfo[BI_OPSYS]) || | 834 | if (strcmp(OPSYS_NAME, pkg->buildinfo[BI_OPSYS]) || | |
831 | strcmp(effective_arch, pkg->buildinfo[BI_MACHINE_ARCH]) != 0) | 835 | strcmp(effective_arch, pkg->buildinfo[BI_MACHINE_ARCH]) != 0) | |
832 | fatal = 1; | 836 | fatal = 1; | |
833 | else | 837 | else | |
834 | fatal = 0; | 838 | fatal = 0; | |
835 | 839 | |||
836 | if (fatal || | 840 | if (fatal || | |
837 | strcmp(host_uname.release, pkg->buildinfo[BI_OS_VERSION]) != 0) { | 841 | strcmp(host_uname.release, pkg->buildinfo[BI_OS_VERSION]) != 0) { | |
838 | warnx("Warning: package `%s' was built for a platform:", | 842 | warnx("Warning: package `%s' was built for a platform:", | |
839 | pkg->pkgname); | 843 | pkg->pkgname); | |
840 | warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)", | 844 | warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)", | |
841 | pkg->buildinfo[BI_OPSYS], | 845 | pkg->buildinfo[BI_OPSYS], | |
842 | pkg->buildinfo[BI_MACHINE_ARCH], | 846 | pkg->buildinfo[BI_MACHINE_ARCH], | |
843 | pkg->buildinfo[BI_OS_VERSION], | 847 | pkg->buildinfo[BI_OS_VERSION], | |
844 | OPSYS_NAME, | 848 | OPSYS_NAME, | |
845 | effective_arch, | 849 | effective_arch, | |
846 | host_uname.release); | 850 | host_uname.release); | |
847 | if (!Force && fatal) | 851 | if (!Force && fatal) | |
848 | return -1; | 852 | return -1; | |
849 | } | 853 | } | |
850 | return 0; | 854 | return 0; | |
851 | } | 855 | } | |
852 | 856 | |||
853 | /* | 857 | /* | |
854 | * Run the install script. | 858 | * Run the install script. | |
855 | */ | 859 | */ | |
856 | static int | 860 | static int | |
857 | run_install_script(struct pkg_task *pkg, const char *argument) | 861 | run_install_script(struct pkg_task *pkg, const char *argument) | |
858 | { | 862 | { | |
859 | int ret; | 863 | int ret; | |
860 | char *filename; | 864 | char *filename; | |
861 | 865 | |||
862 | if (pkg->meta_data.meta_install == NULL || NoInstall) | 866 | if (pkg->meta_data.meta_install == NULL || NoInstall) | |
863 | return 0; | 867 | return 0; | |
864 | 868 | |||
865 | if (Destdir != NULL) | 869 | if (Destdir != NULL) | |
866 | setenv(PKG_DESTDIR_VNAME, Destdir, 1); | 870 | setenv(PKG_DESTDIR_VNAME, Destdir, 1); | |
867 | setenv(PKG_PREFIX_VNAME, pkg->prefix, 1); | 871 | setenv(PKG_PREFIX_VNAME, pkg->prefix, 1); | |
868 | setenv(PKG_METADATA_DIR_VNAME, pkg->logdir, 1); | 872 | setenv(PKG_METADATA_DIR_VNAME, pkg->logdir, 1); | |
869 | setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1); | 873 | setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1); | |
870 | 874 | |||
871 | if (Verbose) | 875 | if (Verbose) | |
872 | printf("Running install with PRE-INSTALL for %s.\n", pkg->pkgname); | 876 | printf("Running install with PRE-INSTALL for %s.\n", pkg->pkgname); | |
873 | if (Fake) | 877 | if (Fake) | |
874 | return 0; | 878 | return 0; | |
875 | 879 | |||
876 | filename = pkgdb_pkg_file(pkg->pkgname, INSTALL_FNAME); | 880 | filename = pkgdb_pkg_file(pkg->pkgname, INSTALL_FNAME); | |
877 | 881 | |||
878 | ret = 0; | 882 | ret = 0; | |
879 | errno = 0; | 883 | errno = 0; | |
880 | if (fcexec(pkg->install_logdir, filename, pkg->pkgname, argument, | 884 | if (fcexec(pkg->install_logdir, filename, pkg->pkgname, argument, | |
881 | (void *)NULL)) { | 885 | (void *)NULL)) { | |
882 | if (errno != 0) | 886 | if (errno != 0) | |
883 | warn("exec of install script failed"); | 887 | warn("exec of install script failed"); | |
884 | else | 888 | else | |
885 | warnx("install script returned error status"); | 889 | warnx("install script returned error status"); | |
886 | ret = -1; | 890 | ret = -1; | |
887 | } | 891 | } | |
888 | free(filename); | 892 | free(filename); | |
889 | 893 | |||
890 | return ret; | 894 | return ret; | |
891 | } | 895 | } | |
892 | 896 | |||
893 | struct find_conflict_data { | 897 | struct find_conflict_data { | |
894 | const char *pkg; | 898 | const char *pkg; | |
895 | const char *old_pkg; | 899 | const char *old_pkg; | |
896 | const char *pattern; | 900 | const char *pattern; | |
897 | }; | 901 | }; | |
898 | 902 | |||
899 | static int | 903 | static int | |
900 | check_explicit_conflict_iter(const char *cur_pkg, void *cookie) | 904 | check_explicit_conflict_iter(const char *cur_pkg, void *cookie) | |
901 | { | 905 | { | |
902 | struct find_conflict_data *data = cookie; | 906 | struct find_conflict_data *data = cookie; | |
903 | 907 | |||
904 | if (data->old_pkg && strcmp(data->old_pkg, cur_pkg) == 0) | 908 | if (data->old_pkg && strcmp(data->old_pkg, cur_pkg) == 0) | |
905 | return 0; | 909 | return 0; | |
906 | 910 | |||
907 | warnx("Package `%s' conflicts with `%s', and `%s' is installed.", | 911 | warnx("Package `%s' conflicts with `%s', and `%s' is installed.", | |
908 | data->pkg, data->pattern, cur_pkg); | 912 | data->pkg, data->pattern, cur_pkg); | |
909 | 913 | |||
910 | return 1; | 914 | return 1; | |
911 | } | 915 | } | |
912 | 916 | |||
913 | static int | 917 | static int | |
914 | check_explicit_conflict(struct pkg_task *pkg) | 918 | check_explicit_conflict(struct pkg_task *pkg) | |
915 | { | 919 | { | |
916 | struct find_conflict_data data; | 920 | struct find_conflict_data data; | |
917 | char *installed, *installed_pattern; | 921 | char *installed, *installed_pattern; | |
918 | plist_t *p; | 922 | plist_t *p; | |
919 | int status; | 923 | int status; | |
920 | 924 | |||
921 | status = 0; | 925 | status = 0; | |
922 | 926 | |||
923 | for (p = pkg->plist.head; p != NULL; p = p->next) { | 927 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |
924 | if (p->type == PLIST_IGNORE) { | 928 | if (p->type == PLIST_IGNORE) { | |
925 | p = p->next; | 929 | p = p->next; | |
926 | continue; | 930 | continue; | |
927 | } | 931 | } | |
928 | if (p->type != PLIST_PKGCFL) | 932 | if (p->type != PLIST_PKGCFL) | |
929 | continue; | 933 | continue; | |
930 | data.pkg = pkg->pkgname; | 934 | data.pkg = pkg->pkgname; | |
931 | data.old_pkg = pkg->other_version; | 935 | data.old_pkg = pkg->other_version; | |
932 | data.pattern = p->name; | 936 | data.pattern = p->name; | |
933 | status |= match_installed_pkgs(p->name, | 937 | status |= match_installed_pkgs(p->name, | |
934 | check_explicit_conflict_iter, &data); | 938 | check_explicit_conflict_iter, &data); | |
935 | } | 939 | } | |
936 | 940 | |||
937 | if (some_installed_package_conflicts_with(pkg->pkgname, | 941 | if (some_installed_package_conflicts_with(pkg->pkgname, | |
938 | pkg->other_version, &installed, &installed_pattern)) { | 942 | pkg->other_version, &installed, &installed_pattern)) { | |
939 | warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.", | 943 | warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.", | |
940 | installed, installed_pattern, pkg->pkgname); | 944 | installed, installed_pattern, pkg->pkgname); | |
941 | free(installed); | 945 | free(installed); | |
942 | free(installed_pattern); | 946 | free(installed_pattern); | |
943 | status |= -1; | 947 | status |= -1; | |
944 | } | 948 | } | |
945 | 949 | |||
946 | return status; | 950 | return status; | |
947 | } | 951 | } | |
948 | 952 | |||
949 | static int | 953 | static int | |
950 | check_implicit_conflict(struct pkg_task *pkg) | 954 | check_implicit_conflict(struct pkg_task *pkg) | |
951 | { | 955 | { | |
952 | plist_t *p; | 956 | plist_t *p; | |
953 | char *fullpath, *existing; | 957 | char *fullpath, *existing; | |
954 | int status; | 958 | int status; | |
955 | 959 | |||
956 | if (!pkgdb_open(ReadOnly)) { | 960 | if (!pkgdb_open(ReadOnly)) { | |
957 | #if notyet /* XXX empty pkgdb without database? */ | 961 | #if notyet /* XXX empty pkgdb without database? */ | |
958 | warn("Can't open pkgdb for reading"); | 962 | warn("Can't open pkgdb for reading"); | |
959 | return -1; | 963 | return -1; | |
960 | #else | 964 | #else | |
961 | return 0; | 965 | return 0; | |
962 | #endif | 966 | #endif | |
963 | } | 967 | } | |
964 | 968 | |||
965 | status = 0; | 969 | status = 0; | |
966 | 970 | |||
967 | for (p = pkg->plist.head; p != NULL; p = p->next) { | 971 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |
968 | if (p->type == PLIST_IGNORE) { | 972 | if (p->type == PLIST_IGNORE) { | |
969 | p = p->next; | 973 | p = p->next; | |
970 | continue; | 974 | continue; | |
971 | } else if (p->type != PLIST_FILE) | 975 | } else if (p->type != PLIST_FILE) | |
972 | continue; | 976 | continue; | |
973 | 977 | |||
974 | fullpath = xasprintf("%s/%s", pkg->prefix, p->name); | 978 | fullpath = xasprintf("%s/%s", pkg->prefix, p->name); | |
975 | existing = pkgdb_retrieve(fullpath); | 979 | existing = pkgdb_retrieve(fullpath); | |
976 | free(fullpath); | 980 | free(fullpath); | |
977 | if (existing == NULL) | 981 | if (existing == NULL) | |
978 | continue; | 982 | continue; | |
979 | if (pkg->other_version != NULL && | 983 | if (pkg->other_version != NULL && | |
980 | strcmp(pkg->other_version, existing) == 0) | 984 | strcmp(pkg->other_version, existing) == 0) | |
981 | continue; | 985 | continue; | |
982 | 986 | |||
983 | warnx("Conflicting PLIST with %s: %s", existing, p->name); | 987 | warnx("Conflicting PLIST with %s: %s", existing, p->name); | |
984 | if (!Force) { | 988 | if (!Force) { | |
985 | status = -1; | 989 | status = -1; | |
986 | if (!Verbose) | 990 | if (!Verbose) | |
987 | break; | 991 | break; | |
988 | } | 992 | } | |
989 | } | 993 | } | |
990 | 994 | |||
991 | pkgdb_close(); | 995 | pkgdb_close(); | |
992 | return status; | 996 | return status; | |
993 | } | 997 | } | |
994 | 998 | |||
995 | static int | 999 | static int | |
996 | check_dependencies(struct pkg_task *pkg) | 1000 | check_dependencies(struct pkg_task *pkg) | |
997 | { | 1001 | { | |
998 | plist_t *p; | 1002 | plist_t *p; | |
999 | char *best_installed; | 1003 | char *best_installed; | |
1000 | int status; | 1004 | int status; | |
1001 | size_t i; | 1005 | size_t i; | |
1002 | 1006 | |||
1003 | status = 0; | 1007 | status = 0; | |
1004 | 1008 | |||
1005 | for (p = pkg->plist.head; p != NULL; p = p->next) { | 1009 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |
1006 | if (p->type == PLIST_IGNORE) { | 1010 | if (p->type == PLIST_IGNORE) { | |
1007 | p = p->next; | 1011 | p = p->next; | |
1008 | continue; | 1012 | continue; | |
1009 | } else if (p->type != PLIST_PKGDEP) | 1013 | } else if (p->type != PLIST_PKGDEP) | |
1010 | continue; | 1014 | continue; | |
1011 | 1015 | |||
1012 | best_installed = find_best_matching_installed_pkg(p->name); | 1016 | best_installed = find_best_matching_installed_pkg(p->name); | |
1013 | 1017 | |||
1014 | if (best_installed == NULL) { | 1018 | if (best_installed == NULL) { | |
1015 | /* XXX check cyclic dependencies? */ | 1019 | /* XXX check cyclic dependencies? */ | |
1016 | if (Fake || NoRecord) { | 1020 | if (Fake || NoRecord) { | |
1017 | if (!Force) { | 1021 | if (!Force) { | |
1018 | warnx("Missing dependency %s\n", | 1022 | warnx("Missing dependency %s\n", | |
1019 | p->name); | 1023 | p->name); | |
1020 | status = -1; | 1024 | status = -1; | |
1021 | break; | 1025 | break; | |
1022 | } | 1026 | } | |
1023 | warnx("Missing dependency %s, continuing", | 1027 | warnx("Missing dependency %s, continuing", | |
1024 | p->name); | 1028 | p->name); | |
1025 | continue; | 1029 | continue; | |
1026 | } | 1030 | } | |
1027 | if (pkg_do(p->name, 1, 0)) { | 1031 | if (pkg_do(p->name, 1, 0)) { | |
1028 | warnx("Can't install dependency %s", p->name); | 1032 | warnx("Can't install dependency %s", p->name); | |
1029 | status = -1; | 1033 | status = -1; | |
1030 | break; | 1034 | break; | |
1031 | } | 1035 | } | |
1032 | best_installed = find_best_matching_installed_pkg(p->name); | 1036 | best_installed = find_best_matching_installed_pkg(p->name); | |
1033 | if (best_installed == NULL && Force) { | 1037 | if (best_installed == NULL && Force) { | |
1034 | warnx("Missing dependency %s ignored", p->name); | 1038 | warnx("Missing dependency %s ignored", p->name); | |
1035 | continue; | 1039 | continue; | |
1036 | } else if (best_installed == NULL) { | 1040 | } else if (best_installed == NULL) { | |
1037 | warnx("Just installed dependency %s disappeared", p->name); | 1041 | warnx("Just installed dependency %s disappeared", p->name); | |
1038 | status = -1; | 1042 | status = -1; | |
1039 | break; | 1043 | break; | |
1040 | } | 1044 | } | |
1041 | } | 1045 | } | |
1042 | for (i = 0; i < pkg->dep_length; ++i) { | 1046 | for (i = 0; i < pkg->dep_length; ++i) { | |
1043 | if (strcmp(best_installed, pkg->dependencies[i]) == 0) | 1047 | if (strcmp(best_installed, pkg->dependencies[i]) == 0) | |
1044 | break; | 1048 | break; | |
1045 | } | 1049 | } | |
1046 | if (i < pkg->dep_length) { | 1050 | if (i < pkg->dep_length) { | |
1047 | /* Already used as dependency, so skip it. */ | 1051 | /* Already used as dependency, so skip it. */ | |
1048 | free(best_installed); | 1052 | free(best_installed); | |
1049 | continue; | 1053 | continue; | |
1050 | } | 1054 | } | |
1051 | if (pkg->dep_length + 1 >= pkg->dep_allocated) { | 1055 | if (pkg->dep_length + 1 >= pkg->dep_allocated) { | |
1052 | char **tmp; | 1056 | char **tmp; | |
1053 | pkg->dep_allocated = 2 * pkg->dep_allocated + 1; | 1057 | pkg->dep_allocated = 2 * pkg->dep_allocated + 1; | |
1054 | pkg->dependencies = xrealloc(pkg->dependencies, | 1058 | pkg->dependencies = xrealloc(pkg->dependencies, | |
1055 | pkg->dep_allocated * sizeof(*tmp)); | 1059 | pkg->dep_allocated * sizeof(*tmp)); | |
1056 | } | 1060 | } | |
1057 | pkg->dependencies[pkg->dep_length++] = best_installed; | 1061 | pkg->dependencies[pkg->dep_length++] = best_installed; | |
1058 | } | 1062 | } | |
1059 | 1063 | |||
1060 | return status; | 1064 | return status; | |
1061 | } | 1065 | } | |
1062 | 1066 | |||
1063 | /* | 1067 | /* | |
1064 | * If this package uses pkg_views, register it in the default view. | 1068 | * If this package uses pkg_views, register it in the default view. | |
1065 | */ | 1069 | */ | |
1066 | static void | 1070 | static void | |
1067 | pkg_register_views(struct pkg_task *pkg) | 1071 | pkg_register_views(struct pkg_task *pkg) | |
1068 | { | 1072 | { | |
1069 | if (Fake || NoView || pkg->meta_data.meta_views == NULL) | 1073 | if (Fake || NoView || pkg->meta_data.meta_views == NULL) | |
1070 | return; | 1074 | return; | |
1071 | 1075 | |||
1072 | if (Verbose) { | 1076 | if (Verbose) { | |
1073 | printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n", | 1077 | printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n", | |
1074 | BINDIR, _pkgdb_getPKGDB_DIR(), | 1078 | BINDIR, _pkgdb_getPKGDB_DIR(), | |
1075 | View ? "-w " : "", View ? View : "", | 1079 | View ? "-w " : "", View ? View : "", | |
1076 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | 1080 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | |
1077 | Verbose ? "-v " : "", pkg->pkgname); | 1081 | Verbose ? "-v " : "", pkg->pkgname); | |
1078 | } | 1082 | } | |
1079 | 1083 | |||
1080 | fexec_skipempty(BINDIR "/pkg_view", "-d", _pkgdb_getPKGDB_DIR(), | 1084 | fexec_skipempty(BINDIR "/pkg_view", "-d", _pkgdb_getPKGDB_DIR(), | |
1081 | View ? "-w " : "", View ? View : "", | 1085 | View ? "-w " : "", View ? View : "", | |
1082 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | 1086 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | |
1083 | Verbose ? "-v " : "", "add", pkg->pkgname, | 1087 | Verbose ? "-v " : "", "add", pkg->pkgname, | |
1084 | (void *)NULL); | 1088 | (void *)NULL); | |
1085 | } | 1089 | } | |
1086 | 1090 | |||
1087 | static int | 1091 | static int | |
1088 | preserve_meta_data_file(struct pkg_task *pkg, const char *name) | 1092 | preserve_meta_data_file(struct pkg_task *pkg, const char *name) | |
1089 | { | 1093 | { | |
1090 | char *old_file, *new_file; | 1094 | char *old_file, *new_file; | |
1091 | int rv; | 1095 | int rv; | |
1092 | 1096 | |||
1093 | if (Fake) | 1097 | if (Fake) | |
1094 | return 0; | 1098 | return 0; | |
1095 | 1099 | |||
1096 | old_file = pkgdb_pkg_file(pkg->other_version, name); | 1100 | old_file = pkgdb_pkg_file(pkg->other_version, name); | |
1097 | new_file = pkgdb_pkg_file(pkg->pkgname, name); | 1101 | new_file = pkgdb_pkg_file(pkg->pkgname, name); | |
1098 | rv = 0; | 1102 | rv = 0; | |
1099 | if (rename(old_file, new_file) == -1 && errno != ENOENT) { | 1103 | if (rename(old_file, new_file) == -1 && errno != ENOENT) { | |
1100 | warn("Can't move %s from %s to %s", name, old_file, new_file); | 1104 | warn("Can't move %s from %s to %s", name, old_file, new_file); | |
1101 | rv = -1; | 1105 | rv = -1; | |
1102 | } | 1106 | } | |
1103 | free(old_file); | 1107 | free(old_file); | |
1104 | free(new_file); | 1108 | free(new_file); | |
1105 | return rv; | 1109 | return rv; | |
1106 | } | 1110 | } | |
1107 | 1111 | |||
1108 | static int | 1112 | static int | |
1109 | start_replacing(struct pkg_task *pkg) | 1113 | start_replacing(struct pkg_task *pkg) | |
1110 | { | 1114 | { | |
1111 | if (preserve_meta_data_file(pkg, REQUIRED_BY_FNAME)) | 1115 | if (preserve_meta_data_file(pkg, REQUIRED_BY_FNAME)) | |
1112 | return -1; | 1116 | return -1; | |
1113 | 1117 | |||
1114 | if (preserve_meta_data_file(pkg, PRESERVE_FNAME)) | 1118 | if (preserve_meta_data_file(pkg, PRESERVE_FNAME)) | |
1115 | return -1; | 1119 | return -1; | |
1116 | 1120 | |||
1117 | if (pkg->meta_data.meta_installed_info == NULL && | 1121 | if (pkg->meta_data.meta_installed_info == NULL && | |
1118 | preserve_meta_data_file(pkg, INSTALLED_INFO_FNAME)) | 1122 | preserve_meta_data_file(pkg, INSTALLED_INFO_FNAME)) | |
1119 | return -1; | 1123 | return -1; | |
1120 | 1124 | |||
1121 | if (Verbose || Fake) { | 1125 | if (Verbose || Fake) { | |
1122 | printf("%s/pkg_delete -K %s -p %s%s%s '%s'\n", | 1126 | printf("%s/pkg_delete -K %s -p %s%s%s '%s'\n", | |
1123 | BINDIR, _pkgdb_getPKGDB_DIR(), pkg->prefix, | 1127 | BINDIR, _pkgdb_getPKGDB_DIR(), pkg->prefix, | |
1124 | Destdir ? " -P ": "", Destdir ? Destdir : "", | 1128 | Destdir ? " -P ": "", Destdir ? Destdir : "", | |
1125 | pkg->other_version); | 1129 | pkg->other_version); | |
1126 | } | 1130 | } | |
1127 | if (!Fake) | 1131 | if (!Fake) | |
1128 | fexec_skipempty(BINDIR "/pkg_delete", "-K", _pkgdb_getPKGDB_DIR(), | 1132 | fexec_skipempty(BINDIR "/pkg_delete", "-K", _pkgdb_getPKGDB_DIR(), | |
1129 | "-p", pkg->prefix, | 1133 | "-p", pkg->prefix, | |
1130 | Destdir ? "-P": "", Destdir ? Destdir : "", | 1134 | Destdir ? "-P": "", Destdir ? Destdir : "", | |
1131 | pkg->other_version, NULL); | 1135 | pkg->other_version, NULL); | |
1132 | 1136 | |||
1133 | /* XXX Check return value and do what? */ | 1137 | /* XXX Check return value and do what? */ | |
1134 | return 0; | 1138 | return 0; | |
1135 | } | 1139 | } | |
1136 | 1140 | |||
1137 | static int check_input(const char *line, size_t len) | 1141 | static int check_input(const char *line, size_t len) | |
1138 | { | 1142 | { | |
1139 | if (line == NULL || len == 0) | 1143 | if (line == NULL || len == 0) | |
1140 | return 1; | 1144 | return 1; | |
1141 | switch (*line) { | 1145 | switch (*line) { | |
1142 | case 'Y': | 1146 | case 'Y': | |
1143 | case 'y': | 1147 | case 'y': | |
1144 | case 'T': | 1148 | case 'T': | |
1145 | case 't': | 1149 | case 't': | |
1146 | case '1': | 1150 | case '1': | |
1147 | return 0; | 1151 | return 0; | |
1148 | default: | 1152 | default: | |
1149 | return 1; | 1153 | return 1; | |
1150 | } | 1154 | } | |
1151 | } | 1155 | } | |
1152 | 1156 | |||
1153 | static int | 1157 | static int | |
1154 | check_signature(struct pkg_task *pkg, void *signature_cookie, int invalid_sig) | 1158 | check_signature(struct pkg_task *pkg, void *signature_cookie, int invalid_sig) | |
1155 | { | 1159 | { | |
1156 | char *line; | 1160 | char *line; | |
1157 | size_t len; | 1161 | size_t len; | |
1158 | 1162 | |||
1159 | if (strcasecmp(verified_installation, "never") == 0) | 1163 | if (strcasecmp(verified_installation, "never") == 0) | |
1160 | return 0; | 1164 | return 0; | |
1161 | if (strcasecmp(verified_installation, "always") == 0) { | 1165 | if (strcasecmp(verified_installation, "always") == 0) { | |
1162 | if (invalid_sig) | 1166 | if (invalid_sig) | |
1163 | warnx("No valid signature found, rejected"); | 1167 | warnx("No valid signature found, rejected"); | |
1164 | return invalid_sig; | 1168 | return invalid_sig; | |
1165 | } | 1169 | } | |
1166 | if (strcasecmp(verified_installation, "trusted") == 0) { | 1170 | if (strcasecmp(verified_installation, "trusted") == 0) { | |
1167 | if (!invalid_sig) | 1171 | if (!invalid_sig) | |
1168 | return 0; | 1172 | return 0; | |
1169 | fprintf(stderr, "No valid signature found for %s.\n", | 1173 | fprintf(stderr, "No valid signature found for %s.\n", | |
1170 | pkg->pkgname); | 1174 | pkg->pkgname); | |
1171 | fprintf(stderr, | 1175 | fprintf(stderr, | |
1172 | "Do you want to proceed with the installation [y/n]?\n"); | 1176 | "Do you want to proceed with the installation [y/n]?\n"); | |
1173 | line = fgetln(stdin, &len); | 1177 | line = fgetln(stdin, &len); | |
1174 | if (check_input(line, len)) { | 1178 | if (check_input(line, len)) { | |
1175 | fprintf(stderr, "Cancelling installation\n"); | 1179 | fprintf(stderr, "Cancelling installation\n"); | |
1176 | return 1; | 1180 | return 1; | |
1177 | } | 1181 | } | |
1178 | return 0; | 1182 | return 0; | |
1179 | } | 1183 | } | |
1180 | if (strcasecmp(verified_installation, "interactive") == 0) { | 1184 | if (strcasecmp(verified_installation, "interactive") == 0) { | |
1181 | fprintf(stderr, "Do you want to proceed with " | 1185 | fprintf(stderr, "Do you want to proceed with " | |
1182 | "the installation of %s [y/n]?\n", pkg->pkgname); | 1186 | "the installation of %s [y/n]?\n", pkg->pkgname); | |
1183 | line = fgetln(stdin, &len); | 1187 | line = fgetln(stdin, &len); | |
1184 | if (check_input(line, len)) { | 1188 | if (check_input(line, len)) { | |
1185 | fprintf(stderr, "Cancelling installation\n"); | 1189 | fprintf(stderr, "Cancelling installation\n"); | |
1186 | return 1; | 1190 | return 1; | |
1187 | } | 1191 | } | |
1188 | return 0; | 1192 | return 0; | |
1189 | } | 1193 | } | |
1190 | warnx("Unknown value of configuration variable VERIFIED_INSTALLATION"); | 1194 | warnx("Unknown value of configuration variable VERIFIED_INSTALLATION"); | |
1191 | return 1; | 1195 | return 1; | |
1192 | } | 1196 | } | |
1193 | 1197 | |||
1194 | static int | 1198 | static int | |
1195 | check_vulnerable(struct pkg_task *pkg) | 1199 | check_vulnerable(struct pkg_task *pkg) | |
1196 | { | 1200 | { | |
1197 | static struct pkg_vulnerabilities *pv; | 1201 | static struct pkg_vulnerabilities *pv; | |
1198 | int require_check; | 1202 | int require_check; | |
1199 | char *line; | 1203 | char *line; | |
1200 | size_t len; | 1204 | size_t len; | |
1201 | 1205 | |||
1202 | if (strcasecmp(check_vulnerabilities, "never") == 0) | 1206 | if (strcasecmp(check_vulnerabilities, "never") == 0) | |
1203 | return 0; | 1207 | return 0; | |
1204 | else if (strcasecmp(check_vulnerabilities, "always")) | 1208 | else if (strcasecmp(check_vulnerabilities, "always")) | |
1205 | require_check = 1; | 1209 | require_check = 1; | |
1206 | else if (strcasecmp(check_vulnerabilities, "interactive")) | 1210 | else if (strcasecmp(check_vulnerabilities, "interactive")) | |
1207 | require_check = 0; | 1211 | require_check = 0; | |
1208 | else { | 1212 | else { | |
1209 | warnx("Unknown value of the configuration variable" | 1213 | warnx("Unknown value of the configuration variable" | |
1210 | "CHECK_VULNERABILITIES"); | 1214 | "CHECK_VULNERABILITIES"); | |
1211 | return 1; | 1215 | return 1; | |
1212 | } | 1216 | } | |
1213 | 1217 | |||
1214 | if (pv == NULL) { | 1218 | if (pv == NULL) { | |
1215 | pv = read_pkg_vulnerabilities(pkg_vulnerabilities_file, | 1219 | pv = read_pkg_vulnerabilities(pkg_vulnerabilities_file, | |
1216 | require_check, 0); | 1220 | require_check, 0); | |
1217 | if (pv == NULL) | 1221 | if (pv == NULL) | |
1218 | return require_check; | 1222 | return require_check; | |
1219 | } | 1223 | } | |
1220 | 1224 | |||
1221 | if (!audit_package(pv, pkg->pkgname, NULL, 0, 2)) | 1225 | if (!audit_package(pv, pkg->pkgname, NULL, 0, 2)) | |
1222 | return 0; | 1226 | return 0; | |
1223 | 1227 | |||
1224 | if (require_check) | 1228 | if (require_check) | |
1225 | return 1; | 1229 | return 1; | |
1226 | 1230 | |||
1227 | fprintf(stderr, "Do you want to proceed with the installation of %s" | 1231 | fprintf(stderr, "Do you want to proceed with the installation of %s" | |
1228 | " [y/n]?\n", pkg->pkgname); | 1232 | " [y/n]?\n", pkg->pkgname); | |
1229 | line = fgetln(stdin, &len); | 1233 | line = fgetln(stdin, &len); | |
1230 | if (check_input(line, len)) { | 1234 | if (check_input(line, len)) { | |
1231 | fprintf(stderr, "Cancelling installation\n"); | 1235 | fprintf(stderr, "Cancelling installation\n"); | |
1232 | return 1; | 1236 | return 1; | |
1233 | } | 1237 | } | |
1234 | return 0; | 1238 | return 0; | |
1235 | } | 1239 | } | |
1236 | 1240 | |||
1237 | /* | 1241 | /* | |
1238 | * Install a single package. | 1242 | * Install a single package. | |
1239 | */ | 1243 | */ | |
1240 | static int | 1244 | static int | |
1241 | pkg_do(const char *pkgpath, int mark_automatic, int top_level) | 1245 | pkg_do(const char *pkgpath, int mark_automatic, int top_level) | |
1242 | { | 1246 | { | |
1243 | int status, invalid_sig; | 1247 | int status, invalid_sig; | |
1244 | void *archive_cookie; | 1248 | void *archive_cookie; | |
1245 | void *signature_cookie; | 1249 | void *signature_cookie; | |
1246 | struct pkg_task *pkg; | 1250 | struct pkg_task *pkg; | |
1247 | 1251 | |||
1248 | pkg = xcalloc(1, sizeof(*pkg)); | 1252 | pkg = xcalloc(1, sizeof(*pkg)); | |
1249 | 1253 | |||
1250 | status = -1; | 1254 | status = -1; | |
1251 | 1255 | |||
1252 | pkg->archive = find_archive(pkgpath, &archive_cookie, top_level); | 1256 | pkg->archive = find_archive(pkgpath, &archive_cookie, top_level); | |
1253 | if (pkg->archive == NULL) { | 1257 | if (pkg->archive == NULL) { | |
1254 | warnx("no pkg found for '%s', sorry.", pkgpath); | 1258 | warnx("no pkg found for '%s', sorry.", pkgpath); | |
1255 | goto clean_find_archive; | 1259 | goto clean_find_archive; | |
1256 | } | 1260 | } | |
1257 | 1261 | |||
1258 | invalid_sig = pkg_verify_signature(&pkg->archive, &pkg->entry, | 1262 | invalid_sig = pkg_verify_signature(&pkg->archive, &pkg->entry, | |
1259 | &pkg->pkgname, &signature_cookie); | 1263 | &pkg->pkgname, &signature_cookie); | |
1260 | 1264 | |||
1261 | if (pkg->archive == NULL) | 1265 | if (pkg->archive == NULL) | |
1262 | goto clean_memory; | 1266 | goto clean_memory; | |
1263 | 1267 | |||
1264 | if (read_meta_data(pkg)) | 1268 | if (read_meta_data(pkg)) | |
1265 | goto clean_memory; | 1269 | goto clean_memory; | |
1266 | 1270 | |||
1267 | /* Parse PLIST early, so that messages can use real package name. */ | 1271 | /* Parse PLIST early, so that messages can use real package name. */ | |
1268 | if (pkg_parse_plist(pkg)) | 1272 | if (pkg_parse_plist(pkg)) | |
1269 | goto clean_memory; | 1273 | goto clean_memory; | |
1270 | 1274 | |||
1271 | if (check_signature(pkg, &signature_cookie, invalid_sig)) | 1275 | if (check_signature(pkg, &signature_cookie, invalid_sig)) | |
1272 | goto clean_memory; | 1276 | goto clean_memory; | |
1273 | 1277 | |||
1274 | if (check_vulnerable(pkg)) | 1278 | if (check_vulnerable(pkg)) | |
1275 | goto clean_memory; | 1279 | goto clean_memory; | |
1276 | 1280 | |||
1277 | if (pkg->meta_data.meta_mtree != NULL) | 1281 | if (pkg->meta_data.meta_mtree != NULL) | |
1278 | warnx("mtree specification in pkg `%s' ignored", pkg->pkgname); | 1282 | warnx("mtree specification in pkg `%s' ignored", pkg->pkgname); | |
1279 | 1283 | |||
1280 | if (pkg->meta_data.meta_views != NULL) { | 1284 | if (pkg->meta_data.meta_views != NULL) { | |
1281 | pkg->logdir = xstrdup(pkg->prefix); | 1285 | pkg->logdir = xstrdup(pkg->prefix); | |
1282 | _pkgdb_setPKGDB_DIR(dirname_of(pkg->logdir)); | 1286 | _pkgdb_setPKGDB_DIR(dirname_of(pkg->logdir)); | |
1283 | } else { | 1287 | } else { | |
1284 | pkg->logdir = xasprintf("%s/%s", _pkgdb_getPKGDB_DIR(), | 1288 | pkg->logdir = xasprintf("%s/%s", _pkgdb_getPKGDB_DIR(), | |
1285 | pkg->pkgname); | 1289 | pkg->pkgname); | |
1286 | } | 1290 | } | |
1287 | 1291 | |||
1288 | if (Destdir != NULL) { | 1292 | if (Destdir != NULL) { | |
1289 | pkg->install_logdir = xasprintf("%s/%s", Destdir, pkg->logdir); | 1293 | pkg->install_logdir = xasprintf("%s/%s", Destdir, pkg->logdir); | |
1290 | _pkgdb_setPKGDB_DIR(dirname_of(pkg->install_logdir)); | 1294 | _pkgdb_setPKGDB_DIR(dirname_of(pkg->install_logdir)); | |
1291 | } else | 1295 | } else | |
1292 | pkg->install_logdir = xstrdup(pkg->logdir); | 1296 | pkg->install_logdir = xstrdup(pkg->logdir); | |
1293 | 1297 | |||
1294 | if (NoRecord && !Fake) { | 1298 | if (NoRecord && !Fake) { | |
1295 | const char *tmpdir; | 1299 | const char *tmpdir; | |
1296 | 1300 | |||
1297 | tmpdir = getenv("TMPDIR"); | 1301 | tmpdir = getenv("TMPDIR"); | |
1298 | if (tmpdir == NULL) | 1302 | if (tmpdir == NULL) | |
1299 | tmpdir = "/tmp"; | 1303 | tmpdir = "/tmp"; | |
1300 | 1304 | |||
1301 | free(pkg->install_logdir); | 1305 | free(pkg->install_logdir); | |
1302 | pkg->install_logdir = xasprintf("%s/pkg_install.XXXXXX", tmpdir); | 1306 | pkg->install_logdir = xasprintf("%s/pkg_install.XXXXXX", tmpdir); | |
1303 | /* XXX pkg_add -u... */ | 1307 | /* XXX pkg_add -u... */ | |
1304 | if (mkdtemp(pkg->install_logdir) == NULL) { | 1308 | if (mkdtemp(pkg->install_logdir) == NULL) { | |
1305 | warn("mkdtemp failed"); | 1309 | warn("mkdtemp failed"); | |
1306 | goto clean_memory; | 1310 | goto clean_memory; | |
1307 | } | 1311 | } | |
1308 | } | 1312 | } | |
1309 | 1313 | |||
1310 | if (check_already_installed(pkg) == 0) { | 1314 | if (check_already_installed(pkg) == 0) { | |
1311 | status = 0; | 1315 | status = 0; | |
1312 | goto clean_memory; | 1316 | goto clean_memory; | |
1313 | } | 1317 | } | |
1314 | 1318 | |||
1315 | if (read_buildinfo(pkg)) | 1319 | if (read_buildinfo(pkg)) | |
1316 | goto clean_memory; | 1320 | goto clean_memory; | |
1317 | 1321 | |||
1318 | if (check_platform(pkg)) | 1322 | if (check_platform(pkg)) | |
1319 | goto clean_memory; | 1323 | goto clean_memory; | |
1320 | 1324 | |||
1321 | if (check_other_installed(pkg)) | 1325 | if (check_other_installed(pkg)) | |
1322 | goto clean_memory; | 1326 | goto clean_memory; | |
1323 | 1327 | |||
1324 | if (check_explicit_conflict(pkg)) | 1328 | if (check_explicit_conflict(pkg)) | |
1325 | goto clean_memory; | 1329 | goto clean_memory; | |
1326 | 1330 | |||
1327 | if (check_implicit_conflict(pkg)) | 1331 | if (check_implicit_conflict(pkg)) | |
1328 | goto clean_memory; | 1332 | goto clean_memory; | |
1329 | 1333 | |||
1330 | if (pkg->other_version != NULL) { | 1334 | if (pkg->other_version != NULL) { | |
1331 | /* | 1335 | /* | |
1332 | * Replacing an existing package. | 1336 | * Replacing an existing package. | |
1333 | * Write meta-data, get rid of the old version, | 1337 | * Write meta-data, get rid of the old version, | |
1334 | * install/update dependencies and finally extract. | 1338 | * install/update dependencies and finally extract. | |
1335 | */ | 1339 | */ | |
1336 | if (write_meta_data(pkg)) | 1340 | if (write_meta_data(pkg)) | |
1337 | goto nuke_pkgdb; | 1341 | goto nuke_pkgdb; | |
1338 | 1342 | |||
1339 | if (start_replacing(pkg)) | 1343 | if (start_replacing(pkg)) | |
1340 | goto nuke_pkgdb; | 1344 | goto nuke_pkgdb; | |
1341 | 1345 | |||
1342 | if (check_dependencies(pkg)) | 1346 | if (check_dependencies(pkg)) | |
1343 | goto nuke_pkgdb; | 1347 | goto nuke_pkgdb; | |
1344 | } else { | 1348 | } else { | |
1345 | /* | 1349 | /* | |
1346 | * Normal installation. | 1350 | * Normal installation. | |
1347 | * Install/update dependencies first and | 1351 | * Install/update dependencies first and | |
1348 | * write the current package to disk afterwards. | 1352 | * write the current package to disk afterwards. | |
1349 | */ | 1353 | */ | |
1350 | if (check_dependencies(pkg)) | 1354 | if (check_dependencies(pkg)) | |
1351 | goto clean_memory; | 1355 | goto clean_memory; | |
1352 | 1356 | |||
1353 | if (write_meta_data(pkg)) | 1357 | if (write_meta_data(pkg)) | |
1354 | goto nuke_pkgdb; | 1358 | goto nuke_pkgdb; | |
1355 | } | 1359 | } | |
1356 | 1360 | |||
1357 | if (run_install_script(pkg, "PRE-INSTALL")) | 1361 | if (run_install_script(pkg, "PRE-INSTALL")) | |
1358 | goto nuke_pkgdb; | 1362 | goto nuke_pkgdb; | |
1359 | 1363 | |||
1360 | if (extract_files(pkg)) | 1364 | if (extract_files(pkg)) | |
1361 | goto nuke_pkg; | 1365 | goto nuke_pkg; | |
1362 | 1366 | |||
1363 | if (run_install_script(pkg, "POST-INSTALL")) | 1367 | if (run_install_script(pkg, "POST-INSTALL")) | |
1364 | goto nuke_pkgdb; | 1368 | goto nuke_pkgdb; | |
1365 | 1369 | |||
1366 | /* XXX keep +INSTALL_INFO for updates? */ | 1370 | /* XXX keep +INSTALL_INFO for updates? */ | |
1367 | /* XXX keep +PRESERVE for updates? */ | 1371 | /* XXX keep +PRESERVE for updates? */ | |
1368 | if (mark_automatic) | 1372 | if (mark_automatic) | |
1369 | mark_as_automatic_installed(pkg->pkgname, 1); | 1373 | mark_as_automatic_installed(pkg->pkgname, 1); | |
1370 | 1374 | |||
1371 | pkg_register_depends(pkg); | 1375 | pkg_register_depends(pkg); | |
1372 | 1376 | |||
1373 | if (Verbose) | 1377 | if (Verbose) | |
1374 | printf("Package %s registered in %s\n", pkg->pkgname, pkg->install_logdir); | 1378 | printf("Package %s registered in %s\n", pkg->pkgname, pkg->install_logdir); | |
1375 | 1379 | |||
1376 | if (pkg->meta_data.meta_display != NULL) | 1380 | if (pkg->meta_data.meta_display != NULL) | |
1377 | fputs(pkg->meta_data.meta_display, stdout); | 1381 | fputs(pkg->meta_data.meta_display, stdout); | |
1378 | 1382 | |||
1379 | pkg_register_views(pkg); | 1383 | pkg_register_views(pkg); | |
1380 | 1384 | |||
1381 | status = 0; | 1385 | status = 0; | |
1382 | goto clean_memory; | 1386 | goto clean_memory; | |
1383 | 1387 | |||
1384 | nuke_pkg: | 1388 | nuke_pkg: | |
1385 | if (!Fake) { | 1389 | if (!Fake) { | |
1386 | if (pkg->other_version) { | 1390 | if (pkg->other_version) { | |
1387 | warnx("Updating of %s to %s failed.", | 1391 | warnx("Updating of %s to %s failed.", | |
1388 | pkg->other_version, pkg->pkgname); | 1392 | pkg->other_version, pkg->pkgname); | |
1389 | warnx("Remember to run pkg_admin rebuild-tree after fixing this."); | 1393 | warnx("Remember to run pkg_admin rebuild-tree after fixing this."); | |
1390 | } | 1394 | } | |
1391 | delete_package(FALSE, FALSE, &pkg->plist, FALSE, Destdir); | 1395 | delete_package(FALSE, FALSE, &pkg->plist, FALSE, Destdir); | |
1392 | } | 1396 | } | |
1393 | 1397 | |||
1394 | nuke_pkgdb: | 1398 | nuke_pkgdb: | |
1395 | if (!Fake) { | 1399 | if (!Fake) { | |
1396 | if (recursive_remove(pkg->install_logdir, 1)) | 1400 | if (recursive_remove(pkg->install_logdir, 1)) | |
1397 | warn("Couldn't remove %s", pkg->install_logdir); | 1401 | warn("Couldn't remove %s", pkg->install_logdir); | |
1398 | free(pkg->install_logdir); | 1402 | free(pkg->install_logdir); | |
1399 | free(pkg->logdir); | 1403 | free(pkg->logdir); | |
1400 | pkg->install_logdir = NULL; | 1404 | pkg->install_logdir = NULL; | |
1401 | pkg->logdir = NULL; | 1405 | pkg->logdir = NULL; | |
1402 | } | 1406 | } | |
1403 | 1407 | |||
1404 | clean_memory: | 1408 | clean_memory: | |
1405 | if (pkg->logdir != NULL && NoRecord && !Fake) { | 1409 | if (pkg->logdir != NULL && NoRecord && !Fake) { | |
1406 | if (recursive_remove(pkg->install_logdir, 1)) | 1410 | if (recursive_remove(pkg->install_logdir, 1)) | |
1407 | warn("Couldn't remove %s", pkg->install_logdir); | 1411 | warn("Couldn't remove %s", pkg->install_logdir); | |
1408 | } | 1412 | } | |
1409 | free(pkg->install_prefix); | 1413 | free(pkg->install_prefix); | |
1410 | free(pkg->install_logdir); | 1414 | free(pkg->install_logdir); | |
1411 | free(pkg->logdir); | 1415 | free(pkg->logdir); | |
1412 | free_buildinfo(pkg); | 1416 | free_buildinfo(pkg); | |
1413 | free_plist(&pkg->plist); | 1417 | free_plist(&pkg->plist); | |
1414 | free_meta_data(pkg); | 1418 | free_meta_data(pkg); | |
1415 | if (pkg->archive) { | 1419 | if (pkg->archive) { | |
1416 | archive_read_close(pkg->archive); | 1420 | archive_read_close(pkg->archive); | |
1417 | close_archive(archive_cookie); | 1421 | close_archive(archive_cookie); | |
1418 | } | 1422 | } | |
1419 | free(pkg->other_version); | 1423 | free(pkg->other_version); | |
1420 | free(pkg->pkgname); | 1424 | free(pkg->pkgname); | |
1421 | pkg_free_signature(signature_cookie); | 1425 | pkg_free_signature(signature_cookie); | |
1422 | clean_find_archive: | 1426 | clean_find_archive: | |
1423 | free(pkg); | 1427 | free(pkg); | |
1424 | return status; | 1428 | return status; | |
1425 | } | 1429 | } | |
1426 | 1430 | |||
1427 | int | 1431 | int | |
1428 | pkg_perform(lpkg_head_t *pkgs) | 1432 | pkg_perform(lpkg_head_t *pkgs) | |
1429 | { | 1433 | { | |
1430 | int errors = 0; | 1434 | int errors = 0; | |
1431 | lpkg_t *lpp; | 1435 | lpkg_t *lpp; | |
1432 | 1436 | |||
1433 | while ((lpp = TAILQ_FIRST(pkgs)) != NULL) { | 1437 | while ((lpp = TAILQ_FIRST(pkgs)) != NULL) { | |
1434 | if (pkg_do(lpp->lp_name, Automatic, 1)) | 1438 | if (pkg_do(lpp->lp_name, Automatic, 1)) | |
1435 | ++errors; | 1439 | ++errors; | |
1436 | TAILQ_REMOVE(pkgs, lpp, lp_link); | 1440 | TAILQ_REMOVE(pkgs, lpp, lp_link); | |
1437 | free_lpkg(lpp); | 1441 | free_lpkg(lpp); | |
1438 | } | 1442 | } | |
1439 | 1443 | |||
1440 | return errors; | 1444 | return errors; | |
1441 | } | 1445 | } |
@@ -1,335 +1,336 @@ | @@ -1,335 +1,336 @@ | |||
1 | /* $NetBSD: pkcs7.c,v 1.3 2009/02/16 20:59:11 joerg Exp $ */ | 1 | /* $NetBSD: pkcs7.c,v 1.4 2009/03/02 14:59:14 joerg Exp $ */ | |
2 | #if HAVE_CONFIG_H | 2 | #if HAVE_CONFIG_H | |
3 | #include "config.h" | 3 | #include "config.h" | |
4 | #endif | 4 | #endif | |
5 | #include <nbcompat.h> | 5 | #include <nbcompat.h> | |
6 | #if HAVE_SYS_CDEFS_H | 6 | #if HAVE_SYS_CDEFS_H | |
7 | #include <sys/cdefs.h> | 7 | #include <sys/cdefs.h> | |
8 | #endif | 8 | #endif | |
9 | 9 | |||
10 | __RCSID("$NetBSD: pkcs7.c,v 1.3 2009/02/16 20:59:11 joerg Exp $"); | 10 | __RCSID("$NetBSD: pkcs7.c,v 1.4 2009/03/02 14:59:14 joerg Exp $"); | |
11 | 11 | |||
12 | /*- | 12 | /*- | |
13 | * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc. | 13 | * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc. | |
14 | * All rights reserved. | 14 | * All rights reserved. | |
15 | * | 15 | * | |
16 | * This code is derived from software contributed to The NetBSD Foundation | 16 | * This code is derived from software contributed to The NetBSD Foundation | |
17 | * by Love Hörnquist Åstrand <lha@it.su.se> | 17 | * by Love Hörnquist Åstrand <lha@it.su.se> | |
18 | * | 18 | * | |
19 | * Redistribution and use in source and binary forms, with or without | 19 | * Redistribution and use in source and binary forms, with or without | |
20 | * modification, are permitted provided that the following conditions | 20 | * modification, are permitted provided that the following conditions | |
21 | * are met: | 21 | * are met: | |
22 | * 1. Redistributions of source code must retain the above copyright | 22 | * 1. Redistributions of source code must retain the above copyright | |
23 | * notice, this list of conditions and the following disclaimer. | 23 | * notice, this list of conditions and the following disclaimer. | |
24 | * 2. Redistributions in binary form must reproduce the above copyright | 24 | * 2. Redistributions in binary form must reproduce the above copyright | |
25 | * notice, this list of conditions and the following disclaimer in the | 25 | * notice, this list of conditions and the following disclaimer in the | |
26 | * documentation and/or other materials provided with the distribution. | 26 | * documentation and/or other materials provided with the distribution. | |
27 | * | 27 | * | |
28 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 28 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
29 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 29 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
31 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 31 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
32 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 32 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
34 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 34 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
35 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 35 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
36 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 36 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
37 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 37 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
38 | * POSSIBILITY OF SUCH DAMAGE. | 38 | * POSSIBILITY OF SUCH DAMAGE. | |
39 | */ | 39 | */ | |
40 | 40 | |||
41 | #if HAVE_ERR_H | 41 | #if HAVE_ERR_H | |
42 | #include <err.h> | 42 | #include <err.h> | |
43 | #endif | 43 | #endif | |
44 | 44 | |||
45 | #include <openssl/pkcs7.h> | 45 | #include <openssl/pkcs7.h> | |
46 | #include <openssl/evp.h> | 46 | #include <openssl/evp.h> | |
47 | #include <openssl/x509.h> | 47 | #include <openssl/x509.h> | |
48 | #include <openssl/x509v3.h> | 48 | #include <openssl/x509v3.h> | |
49 | #include <openssl/pem.h> | 49 | #include <openssl/pem.h> | |
50 | #include <openssl/err.h> | 50 | #include <openssl/err.h> | |
51 | 51 | |||
52 | #include "lib.h" | 52 | #include "lib.h" | |
53 | 53 | |||
54 | #ifndef __UNCONST | 54 | #ifndef __UNCONST | |
55 | #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) | 55 | #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) | |
56 | #endif | 56 | #endif | |
57 | 57 | |||
58 | #ifndef NS_ANY_CA | 58 | #ifndef NS_ANY_CA | |
59 | #define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) | 59 | #define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) | |
60 | #endif | 60 | #endif | |
61 | 61 | |||
62 | static const int pkg_key_usage = XKU_CODE_SIGN | XKU_SMIME; | 62 | static const int pkg_key_usage = XKU_CODE_SIGN | XKU_SMIME; | |
63 | 63 | |||
64 | static int | 64 | static int | |
65 | check_ca(X509 *cert) | 65 | check_ca(X509 *cert) | |
66 | { | 66 | { | |
67 | if ((cert->ex_flags & EXFLAG_KUSAGE) != 0 && | 67 | if ((cert->ex_flags & EXFLAG_KUSAGE) != 0 && | |
68 | (cert->ex_kusage & KU_KEY_CERT_SIGN) != KU_KEY_CERT_SIGN) | 68 | (cert->ex_kusage & KU_KEY_CERT_SIGN) != KU_KEY_CERT_SIGN) | |
69 | return 0; | 69 | return 0; | |
70 | if ((cert->ex_flags & EXFLAG_BCONS) != 0) | 70 | if ((cert->ex_flags & EXFLAG_BCONS) != 0) | |
71 | return (cert->ex_flags & EXFLAG_CA) == EXFLAG_CA; | 71 | return (cert->ex_flags & EXFLAG_CA) == EXFLAG_CA; | |
72 | if ((cert->ex_flags & (EXFLAG_V1|EXFLAG_SS)) == (EXFLAG_V1|EXFLAG_SS)) | 72 | if ((cert->ex_flags & (EXFLAG_V1|EXFLAG_SS)) == (EXFLAG_V1|EXFLAG_SS)) | |
73 | return 1; | 73 | return 1; | |
74 | if ((cert->ex_flags & EXFLAG_KUSAGE) != 0) | 74 | if ((cert->ex_flags & EXFLAG_KUSAGE) != 0) | |
75 | return 1; | 75 | return 1; | |
76 | if ((cert->ex_flags & EXFLAG_NSCERT) != 0 && | 76 | if ((cert->ex_flags & EXFLAG_NSCERT) != 0 && | |
77 | (cert->ex_nscert & NS_ANY_CA) != 0) | 77 | (cert->ex_nscert & NS_ANY_CA) != 0) | |
78 | return 1; | 78 | return 1; | |
79 | return 0; | 79 | return 0; | |
80 | } | 80 | } | |
81 | 81 | |||
82 | static STACK_OF(X509) * | 82 | static STACK_OF(X509) * | |
83 | file_to_certs(const char *file) | 83 | file_to_certs(const char *file) | |
84 | { | 84 | { | |
85 | unsigned long ret; | 85 | unsigned long ret; | |
86 | STACK_OF(X509) *certs; | 86 | STACK_OF(X509) *certs; | |
87 | FILE *f; | 87 | FILE *f; | |
88 | 88 | |||
89 | if ((f = fopen(file, "r")) == NULL) { | 89 | if ((f = fopen(file, "r")) == NULL) { | |
90 | warn("open failed %s", file); | 90 | warn("open failed %s", file); | |
91 | return NULL; | 91 | return NULL; | |
92 | } | 92 | } | |
93 | 93 | |||
94 | certs = sk_X509_new_null(); | 94 | certs = sk_X509_new_null(); | |
95 | for (;;) { | 95 | for (;;) { | |
96 | X509 *cert; | 96 | X509 *cert; | |
97 | 97 | |||
98 | cert = PEM_read_X509(f, NULL, NULL, NULL); | 98 | cert = PEM_read_X509(f, NULL, NULL, NULL); | |
99 | if (cert == NULL) { | 99 | if (cert == NULL) { | |
100 | ret = ERR_GET_REASON(ERR_peek_error()); | 100 | ret = ERR_GET_REASON(ERR_peek_error()); | |
101 | if (ret == PEM_R_NO_START_LINE) { | 101 | if (ret == PEM_R_NO_START_LINE) { | |
102 | /* End of file reached. no error */ | 102 | /* End of file reached. no error */ | |
103 | ERR_clear_error(); | 103 | ERR_clear_error(); | |
104 | break; | 104 | break; | |
105 | } | 105 | } | |
106 | sk_X509_free(certs); | 106 | sk_X509_free(certs); | |
107 | warnx("Can't read certificate in file: %s", file); | 107 | warnx("Can't read certificate in file: %s", file); | |
108 | fclose(f); | |||
108 | return NULL; | 109 | return NULL; | |
109 | } | 110 | } | |
110 | sk_X509_insert(certs, cert, sk_X509_num(certs)); | 111 | sk_X509_insert(certs, cert, sk_X509_num(certs)); | |
111 | } | 112 | } | |
112 | 113 | |||
113 | fclose(f); | 114 | fclose(f); | |
114 | 115 | |||
115 | if (sk_X509_num(certs) == 0) { | 116 | if (sk_X509_num(certs) == 0) { | |
116 | sk_X509_free(certs); | 117 | sk_X509_free(certs); | |
117 | certs = NULL; | 118 | certs = NULL; | |
118 | warnx("No certificate found in file %s", file); | 119 | warnx("No certificate found in file %s", file); | |
119 | } | 120 | } | |
120 | 121 | |||
121 | return certs; | 122 | return certs; | |
122 | } | 123 | } | |
123 | 124 | |||
124 | int | 125 | int | |
125 | easy_pkcs7_verify(const char *content, size_t len, | 126 | easy_pkcs7_verify(const char *content, size_t len, | |
126 | const char *signature, size_t signature_len, | 127 | const char *signature, size_t signature_len, | |
127 | const char *anchor, int is_pkg) | 128 | const char *anchor, int is_pkg) | |
128 | { | 129 | { | |
129 | STACK_OF(X509) *cert_chain, *signers; | 130 | STACK_OF(X509) *cert_chain, *signers; | |
130 | X509_STORE *store; | 131 | X509_STORE *store; | |
131 | BIO *sig, *in; | 132 | BIO *sig, *in; | |
132 | PKCS7 *p7; | 133 | PKCS7 *p7; | |
133 | int i, status; | 134 | int i, status; | |
134 | X509_NAME *name; | 135 | X509_NAME *name; | |
135 | char *subject; | 136 | char *subject; | |
136 | 137 | |||
137 | OpenSSL_add_all_algorithms(); | 138 | OpenSSL_add_all_algorithms(); | |
138 | ERR_load_crypto_strings(); | 139 | ERR_load_crypto_strings(); | |
139 | 140 | |||
140 | status = -1; | 141 | status = -1; | |
141 | 142 | |||
142 | if (cert_chain_file) | 143 | if (cert_chain_file) | |
143 | cert_chain = file_to_certs(cert_chain_file); | 144 | cert_chain = file_to_certs(cert_chain_file); | |
144 | else | 145 | else | |
145 | cert_chain = NULL; | 146 | cert_chain = NULL; | |
146 | 147 | |||
147 | store = X509_STORE_new(); | 148 | store = X509_STORE_new(); | |
148 | if (store == NULL) { | 149 | if (store == NULL) { | |
149 | sk_X509_free(cert_chain); | 150 | sk_X509_free(cert_chain); | |
150 | warnx("Failed to create certificate store"); | 151 | warnx("Failed to create certificate store"); | |
151 | return -1; | 152 | return -1; | |
152 | } | 153 | } | |
153 | 154 | |||
154 | X509_STORE_load_locations(store, anchor, NULL); | 155 | X509_STORE_load_locations(store, anchor, NULL); | |
155 | 156 | |||
156 | in = BIO_new_mem_buf(__UNCONST(content), len); | 157 | in = BIO_new_mem_buf(__UNCONST(content), len); | |
157 | sig = BIO_new_mem_buf(__UNCONST(signature), signature_len); | 158 | sig = BIO_new_mem_buf(__UNCONST(signature), signature_len); | |
158 | signers = NULL; | 159 | signers = NULL; | |
159 | 160 | |||
160 | p7 = PEM_read_bio_PKCS7(sig, NULL, NULL, NULL); | 161 | p7 = PEM_read_bio_PKCS7(sig, NULL, NULL, NULL); | |
161 | if (p7 == NULL) { | 162 | if (p7 == NULL) { | |
162 | warnx("Failed to parse the signature"); | 163 | warnx("Failed to parse the signature"); | |
163 | goto cleanup; | 164 | goto cleanup; | |
164 | } | 165 | } | |
165 | 166 | |||
166 | if (PKCS7_verify(p7, cert_chain, store, in, NULL, 0) != 1) { | 167 | if (PKCS7_verify(p7, cert_chain, store, in, NULL, 0) != 1) { | |
167 | warnx("Failed to verify signature"); | 168 | warnx("Failed to verify signature"); | |
168 | goto cleanup; | 169 | goto cleanup; | |
169 | } | 170 | } | |
170 | 171 | |||
171 | signers = PKCS7_get0_signers(p7, NULL, 0); | 172 | signers = PKCS7_get0_signers(p7, NULL, 0); | |
172 | if (signers == NULL) { | 173 | if (signers == NULL) { | |
173 | warnx("Failed to get signers"); | 174 | warnx("Failed to get signers"); | |
174 | goto cleanup; | 175 | goto cleanup; | |
175 | } | 176 | } | |
176 | 177 | |||
177 | if (sk_X509_num(signers) == 0) { | 178 | if (sk_X509_num(signers) == 0) { | |
178 | warnx("No signers found"); | 179 | warnx("No signers found"); | |
179 | goto cleanup; | 180 | goto cleanup; | |
180 | } | 181 | } | |
181 | 182 | |||
182 | for (i = 0; i < sk_X509_num(signers); i++) { | 183 | for (i = 0; i < sk_X509_num(signers); i++) { | |
183 | /* Compute ex_xkusage */ | 184 | /* Compute ex_xkusage */ | |
184 | X509_check_purpose(sk_X509_value(signers, i), -1, -1); | 185 | X509_check_purpose(sk_X509_value(signers, i), -1, -1); | |
185 | 186 | |||
186 | if (check_ca(sk_X509_value(signers, i))) { | 187 | if (check_ca(sk_X509_value(signers, i))) { | |
187 | warnx("CA keys are not valid for signatures"); | 188 | warnx("CA keys are not valid for signatures"); | |
188 | goto cleanup; | 189 | goto cleanup; | |
189 | } | 190 | } | |
190 | if (is_pkg) { | 191 | if (is_pkg) { | |
191 | if (sk_X509_value(signers, i)->ex_xkusage != pkg_key_usage) { | 192 | if (sk_X509_value(signers, i)->ex_xkusage != pkg_key_usage) { | |
192 | warnx("Certificate must have CODE SIGNING " | 193 | warnx("Certificate must have CODE SIGNING " | |
193 | "and EMAIL PROTECTION property"); | 194 | "and EMAIL PROTECTION property"); | |
194 | goto cleanup; | 195 | goto cleanup; | |
195 | } | 196 | } | |
196 | } else { | 197 | } else { | |
197 | if (sk_X509_value(signers, i)->ex_xkusage != 0) { | 198 | if (sk_X509_value(signers, i)->ex_xkusage != 0) { | |
198 | warnx("Certificate must not have any property"); | 199 | warnx("Certificate must not have any property"); | |
199 | goto cleanup; | 200 | goto cleanup; | |
200 | } | 201 | } | |
201 | } | 202 | } | |
202 | } | 203 | } | |
203 | 204 | |||
204 | printf("Sigature ok, signed by:\n"); | 205 | printf("Sigature ok, signed by:\n"); | |
205 | 206 | |||
206 | for (i = 0; i < sk_X509_num(signers); i++) { | 207 | for (i = 0; i < sk_X509_num(signers); i++) { | |
207 | name = X509_get_subject_name(sk_X509_value(signers, i)); | 208 | name = X509_get_subject_name(sk_X509_value(signers, i)); | |
208 | subject = X509_NAME_oneline(name, NULL, 0); | 209 | subject = X509_NAME_oneline(name, NULL, 0); | |
209 | 210 | |||
210 | printf("\t%s\n", subject); | 211 | printf("\t%s\n", subject); | |
211 | 212 | |||
212 | OPENSSL_free(subject); | 213 | OPENSSL_free(subject); | |
213 | } | 214 | } | |
214 | 215 | |||
215 | status = 0; | 216 | status = 0; | |
216 | 217 | |||
217 | cleanup: | 218 | cleanup: | |
218 | sk_X509_free(cert_chain); | 219 | sk_X509_free(cert_chain); | |
219 | sk_X509_free(signers); | 220 | sk_X509_free(signers); | |
220 | X509_STORE_free(store); | 221 | X509_STORE_free(store); | |
221 | 222 | |||
222 | PKCS7_free(p7); | 223 | PKCS7_free(p7); | |
223 | BIO_free(in); | 224 | BIO_free(in); | |
224 | BIO_free(sig); | 225 | BIO_free(sig); | |
225 | 226 | |||
226 | return status; | 227 | return status; | |
227 | } | 228 | } | |
228 | 229 | |||
229 | static int | 230 | static int | |
230 | ssl_pass_cb(char *buf, int size, int rwflag, void *u) | 231 | ssl_pass_cb(char *buf, int size, int rwflag, void *u) | |
231 | { | 232 | { | |
232 | 233 | |||
233 | if (EVP_read_pw_string(buf, size, "Passphrase :", 0)) { | 234 | if (EVP_read_pw_string(buf, size, "Passphrase :", 0)) { | |
234 | #if OPENSSL_VERSION >= 0x0090608fL | 235 | #if OPENSSL_VERSION >= 0x0090608fL | |
235 | OPENSSL_cleanse(buf, size); | 236 | OPENSSL_cleanse(buf, size); | |
236 | #else | 237 | #else | |
237 | memset(buf, 0, size); | 238 | memset(buf, 0, size); | |
238 | #endif | 239 | #endif | |
239 | return 0; | 240 | return 0; | |
240 | } | 241 | } | |
241 | return strlen(buf); | 242 | return strlen(buf); | |
242 | } | 243 | } | |
243 | 244 | |||
244 | int | 245 | int | |
245 | easy_pkcs7_sign(const char *content, size_t len, | 246 | easy_pkcs7_sign(const char *content, size_t len, | |
246 | char **signature, size_t *signature_len, | 247 | char **signature, size_t *signature_len, | |
247 | const char *key_file, const char *cert_file) | 248 | const char *key_file, const char *cert_file) | |
248 | { | 249 | { | |
249 | FILE *f; | 250 | FILE *f; | |
250 | X509 *certificate; | 251 | X509 *certificate; | |
251 | STACK_OF(X509) *c, *cert_chain; | 252 | STACK_OF(X509) *c, *cert_chain; | |
252 | EVP_PKEY *private_key; | 253 | EVP_PKEY *private_key; | |
253 | char *tmp_sig; | 254 | char *tmp_sig; | |
254 | BIO *out, *in; | 255 | BIO *out, *in; | |
255 | PKCS7 *p7; | 256 | PKCS7 *p7; | |
256 | int status; | 257 | int status; | |
257 | 258 | |||
258 | OpenSSL_add_all_algorithms(); | 259 | OpenSSL_add_all_algorithms(); | |
259 | ERR_load_crypto_strings(); | 260 | ERR_load_crypto_strings(); | |
260 | 261 | |||
261 | status = -1; | 262 | status = -1; | |
262 | private_key = NULL; | 263 | private_key = NULL; | |
263 | cert_chain = NULL; | 264 | cert_chain = NULL; | |
264 | in = NULL; | 265 | in = NULL; | |
265 | 266 | |||
266 | c = file_to_certs(cert_file); | 267 | c = file_to_certs(cert_file); | |
267 | 268 | |||
268 | if (sk_X509_num(c) != 1) { | 269 | if (sk_X509_num(c) != 1) { | |
269 | warnx("More then one certificate in the certificate file"); | 270 | warnx("More then one certificate in the certificate file"); | |
270 | goto cleanup; | 271 | goto cleanup; | |
271 | } | 272 | } | |
272 | certificate = sk_X509_value(c, 0); | 273 | certificate = sk_X509_value(c, 0); | |
273 | 274 | |||
274 | /* Compute ex_kusage */ | 275 | /* Compute ex_kusage */ | |
275 | X509_check_purpose(certificate, -1, 0); | 276 | X509_check_purpose(certificate, -1, 0); | |
276 | 277 | |||
277 | if (check_ca(certificate)) { | 278 | if (check_ca(certificate)) { | |
278 | warnx("CA keys are not valid for signatures"); | 279 | warnx("CA keys are not valid for signatures"); | |
279 | goto cleanup; | 280 | goto cleanup; | |
280 | } | 281 | } | |
281 | 282 | |||
282 | if (certificate->ex_xkusage != pkg_key_usage) { | 283 | if (certificate->ex_xkusage != pkg_key_usage) { | |
283 | warnx("Certificate must have CODE SIGNING " | 284 | warnx("Certificate must have CODE SIGNING " | |
284 | "and EMAIL PROTECTION property"); | 285 | "and EMAIL PROTECTION property"); | |
285 | goto cleanup; | 286 | goto cleanup; | |
286 | } | 287 | } | |
287 | 288 | |||
288 | if (cert_chain_file) | 289 | if (cert_chain_file) | |
289 | cert_chain = file_to_certs(cert_chain_file); | 290 | cert_chain = file_to_certs(cert_chain_file); | |
290 | 291 | |||
291 | if ((f = fopen(key_file, "r")) == NULL) { | 292 | if ((f = fopen(key_file, "r")) == NULL) { | |
292 | warn("Failed to open private key file %s", key_file); | 293 | warn("Failed to open private key file %s", key_file); | |
293 | goto cleanup; | 294 | goto cleanup; | |
294 | } | 295 | } | |
295 | private_key = PEM_read_PrivateKey(f, NULL, ssl_pass_cb, NULL); | 296 | private_key = PEM_read_PrivateKey(f, NULL, ssl_pass_cb, NULL); | |
296 | fclose(f); | 297 | fclose(f); | |
297 | if (private_key == NULL) { | 298 | if (private_key == NULL) { | |
298 | warnx("Can't read private key: %s", key_file); | 299 | warnx("Can't read private key: %s", key_file); | |
299 | goto cleanup; | 300 | goto cleanup; | |
300 | } | 301 | } | |
301 | 302 | |||
302 | if (X509_check_private_key(certificate, private_key) != 1) { | 303 | if (X509_check_private_key(certificate, private_key) != 1) { | |
303 | warnx("The private key %s doesn't match the certificate %s", | 304 | warnx("The private key %s doesn't match the certificate %s", | |
304 | key_file, cert_file); | 305 | key_file, cert_file); | |
305 | goto cleanup; | 306 | goto cleanup; | |
306 | } | 307 | } | |
307 | 308 | |||
308 | in = BIO_new_mem_buf(__UNCONST(content), len); | 309 | in = BIO_new_mem_buf(__UNCONST(content), len); | |
309 | 310 | |||
310 | p7 = PKCS7_sign(certificate, private_key, cert_chain, in, | 311 | p7 = PKCS7_sign(certificate, private_key, cert_chain, in, | |
311 | PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY); | 312 | PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY); | |
312 | if (p7 == NULL) { | 313 | if (p7 == NULL) { | |
313 | warnx("Failed to create signature structure"); | 314 | warnx("Failed to create signature structure"); | |
314 | goto cleanup; | 315 | goto cleanup; | |
315 | } | 316 | } | |
316 | 317 | |||
317 | out = BIO_new(BIO_s_mem()); | 318 | out = BIO_new(BIO_s_mem()); | |
318 | PEM_write_bio_PKCS7(out, p7); | 319 | PEM_write_bio_PKCS7(out, p7); | |
319 | *signature_len = BIO_get_mem_data(out, &tmp_sig); | 320 | *signature_len = BIO_get_mem_data(out, &tmp_sig); | |
320 | *signature = xmalloc(*signature_len); | 321 | *signature = xmalloc(*signature_len); | |
321 | memcpy(*signature, tmp_sig, *signature_len); | 322 | memcpy(*signature, tmp_sig, *signature_len); | |
322 | BIO_free_all(out); | 323 | BIO_free_all(out); | |
323 | 324 | |||
324 | PKCS7_free(p7); | 325 | PKCS7_free(p7); | |
325 | 326 | |||
326 | status = 0; | 327 | status = 0; | |
327 | 328 | |||
328 | cleanup: | 329 | cleanup: | |
329 | sk_X509_free(c); | 330 | sk_X509_free(c); | |
330 | sk_X509_free(cert_chain); | 331 | sk_X509_free(cert_chain); | |
331 | EVP_PKEY_free(private_key); | 332 | EVP_PKEY_free(private_key); | |
332 | BIO_free(in); | 333 | BIO_free(in); | |
333 | 334 | |||
334 | return status; | 335 | return status; | |
335 | } | 336 | } |
@@ -1,710 +1,714 @@ | @@ -1,710 +1,714 @@ | |||
1 | /* $NetBSD: pkg_signature.c,v 1.5 2009/02/13 13:17:41 joerg Exp $ */ | 1 | /* $NetBSD: pkg_signature.c,v 1.6 2009/03/02 14:59:14 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | __RCSID("$NetBSD: pkg_signature.c,v 1.5 2009/02/13 13:17:41 joerg Exp $"); | 10 | __RCSID("$NetBSD: pkg_signature.c,v 1.6 2009/03/02 14:59:14 joerg Exp $"); | |
11 | 11 | |||
12 | /*- | 12 | /*- | |
13 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | 13 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | |
14 | * All rights reserved. | 14 | * All rights reserved. | |
15 | * | 15 | * | |
16 | * Redistribution and use in source and binary forms, with or without | 16 | * Redistribution and use in source and binary forms, with or without | |
17 | * modification, are permitted provided that the following conditions | 17 | * modification, are permitted provided that the following conditions | |
18 | * are met: | 18 | * are met: | |
19 | * | 19 | * | |
20 | * 1. Redistributions of source code must retain the above copyright | 20 | * 1. Redistributions of source code must retain the above copyright | |
21 | * notice, this list of conditions and the following disclaimer. | 21 | * notice, this list of conditions and the following disclaimer. | |
22 | * 2. Redistributions in binary form must reproduce the above copyright | 22 | * 2. Redistributions in binary form must reproduce the above copyright | |
23 | * notice, this list of conditions and the following disclaimer in | 23 | * notice, this list of conditions and the following disclaimer in | |
24 | * the documentation and/or other materials provided with the | 24 | * the documentation and/or other materials provided with the | |
25 | * distribution. | 25 | * distribution. | |
26 | * | 26 | * | |
27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
28 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 28 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
30 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 30 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
31 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 31 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
32 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | 32 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
33 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 33 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
34 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 34 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
35 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 35 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
36 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 36 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
37 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 37 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
38 | * SUCH DAMAGE. | 38 | * SUCH DAMAGE. | |
39 | */ | 39 | */ | |
40 | 40 | |||
41 | #if HAVE_SYS_WAIT_H | 41 | #if HAVE_SYS_WAIT_H | |
42 | #include <sys/wait.h> | 42 | #include <sys/wait.h> | |
43 | #endif | 43 | #endif | |
44 | #include <ctype.h> | 44 | #include <ctype.h> | |
45 | #if HAVE_ERR_H | 45 | #if HAVE_ERR_H | |
46 | #include <err.h> | 46 | #include <err.h> | |
47 | #endif | 47 | #endif | |
48 | #include <errno.h> | 48 | #include <errno.h> | |
49 | #include <fcntl.h> | 49 | #include <fcntl.h> | |
50 | #include <stdlib.h> | 50 | #include <stdlib.h> | |
51 | #ifndef NETBSD | 51 | #ifndef NETBSD | |
52 | #include <nbcompat/sha2.h> | 52 | #include <nbcompat/sha2.h> | |
53 | #else | 53 | #else | |
54 | #include <sha2.h> | 54 | #include <sha2.h> | |
55 | #endif | 55 | #endif | |
56 | #include <signal.h> | 56 | #include <signal.h> | |
57 | #ifdef NETBSD | 57 | #ifdef NETBSD | |
58 | #include <unistd.h> | 58 | #include <unistd.h> | |
59 | #else | 59 | #else | |
60 | #include <nbcompat/unistd.h> | 60 | #include <nbcompat/unistd.h> | |
61 | #endif | 61 | #endif | |
62 | 62 | |||
63 | #include <archive.h> | 63 | #include <archive.h> | |
64 | #include <archive_entry.h> | 64 | #include <archive_entry.h> | |
65 | 65 | |||
66 | #include "lib.h" | 66 | #include "lib.h" | |
67 | 67 | |||
68 | #define HASH_FNAME "+PKG_HASH" | 68 | #define HASH_FNAME "+PKG_HASH" | |
69 | #define SIGNATURE_FNAME "+PKG_SIGNATURE" | 69 | #define SIGNATURE_FNAME "+PKG_SIGNATURE" | |
70 | #define GPG_SIGNATURE_FNAME "+PKG_GPG_SIGNATURE" | 70 | #define GPG_SIGNATURE_FNAME "+PKG_GPG_SIGNATURE" | |
71 | 71 | |||
72 | struct signature_archive { | 72 | struct signature_archive { | |
73 | struct archive *archive; | 73 | struct archive *archive; | |
74 | off_t pkg_size; | 74 | off_t pkg_size; | |
75 | size_t sign_block_len, sign_block_number, sign_cur_block; | 75 | size_t sign_block_len, sign_block_number, sign_cur_block; | |
76 | char **sign_blocks; | 76 | char **sign_blocks; | |
77 | unsigned char *sign_buf; | 77 | unsigned char *sign_buf; | |
78 | }; | 78 | }; | |
79 | 79 | |||
80 | static void | 80 | static void | |
81 | hash_block(unsigned char *buf, size_t buf_len, | 81 | hash_block(unsigned char *buf, size_t buf_len, | |
82 | char hash[SHA512_DIGEST_STRING_LENGTH]) | 82 | char hash[SHA512_DIGEST_STRING_LENGTH]) | |
83 | { | 83 | { | |
84 | unsigned char digest[SHA512_DIGEST_LENGTH]; | 84 | unsigned char digest[SHA512_DIGEST_LENGTH]; | |
85 | SHA512_CTX hash_ctx; | 85 | SHA512_CTX hash_ctx; | |
86 | int i; | 86 | int i; | |
87 | 87 | |||
88 | SHA512_Init(&hash_ctx); | 88 | SHA512_Init(&hash_ctx); | |
89 | SHA512_Update(&hash_ctx, buf, buf_len); | 89 | SHA512_Update(&hash_ctx, buf, buf_len); | |
90 | SHA512_Final(digest, &hash_ctx); | 90 | SHA512_Final(digest, &hash_ctx); | |
91 | for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) { | 91 | for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) { | |
92 | unsigned char c; | 92 | unsigned char c; | |
93 | 93 | |||
94 | c = digest[i] / 16; | 94 | c = digest[i] / 16; | |
95 | if (c < 10) | 95 | if (c < 10) | |
96 | hash[2 * i] = '0' + c; | 96 | hash[2 * i] = '0' + c; | |
97 | else | 97 | else | |
98 | hash[2 * i] = 'a' - 10 + c; | 98 | hash[2 * i] = 'a' - 10 + c; | |
99 | 99 | |||
100 | c = digest[i] % 16; | 100 | c = digest[i] % 16; | |
101 | if (c < 10) | 101 | if (c < 10) | |
102 | hash[2 * i + 1] = '0' + c; | 102 | hash[2 * i + 1] = '0' + c; | |
103 | else | 103 | else | |
104 | hash[2 * i + 1] = 'a' - 10 + c; | 104 | hash[2 * i + 1] = 'a' - 10 + c; | |
105 | } | 105 | } | |
106 | hash[2 * i] = '\0'; | 106 | hash[2 * i] = '\0'; | |
107 | } | 107 | } | |
108 | 108 | |||
109 | static ssize_t | 109 | static ssize_t | |
110 | verify_signature_read_cb(struct archive *archive, void *cookie, const void **buf) | 110 | verify_signature_read_cb(struct archive *archive, void *cookie, const void **buf) | |
111 | { | 111 | { | |
112 | struct signature_archive *state = cookie; | 112 | struct signature_archive *state = cookie; | |
113 | char hash[SHA512_DIGEST_STRING_LENGTH]; | 113 | char hash[SHA512_DIGEST_STRING_LENGTH]; | |
114 | ssize_t len, expected; | 114 | ssize_t len, expected; | |
115 | 115 | |||
116 | if (state->sign_cur_block >= state->sign_block_number) | 116 | if (state->sign_cur_block >= state->sign_block_number) | |
117 | return 0; | 117 | return 0; | |
118 | 118 | |||
119 | /* The following works for sign_block_len > 1 */ | 119 | /* The following works for sign_block_len > 1 */ | |
120 | if (state->sign_cur_block + 1 == state->sign_block_number) | 120 | if (state->sign_cur_block + 1 == state->sign_block_number) | |
121 | expected = state->pkg_size % state->sign_block_len; | 121 | expected = state->pkg_size % state->sign_block_len; | |
122 | else | 122 | else | |
123 | expected = state->sign_block_len; | 123 | expected = state->sign_block_len; | |
124 | 124 | |||
125 | len = archive_read_data(state->archive, state->sign_buf, expected); | 125 | len = archive_read_data(state->archive, state->sign_buf, expected); | |
126 | if (len != expected) { | 126 | if (len != expected) { | |
127 | warnx("Short read from package"); | 127 | warnx("Short read from package"); | |
128 | return -1; | 128 | return -1; | |
129 | } | 129 | } | |
130 | 130 | |||
131 | hash_block(state->sign_buf, len, hash); | 131 | hash_block(state->sign_buf, len, hash); | |
132 | 132 | |||
133 | if (strcmp(hash, state->sign_blocks[state->sign_cur_block]) != 0) { | 133 | if (strcmp(hash, state->sign_blocks[state->sign_cur_block]) != 0) { | |
134 | warnx("Invalid signature of block %llu", | 134 | warnx("Invalid signature of block %llu", | |
135 | (unsigned long long)state->sign_cur_block); | 135 | (unsigned long long)state->sign_cur_block); | |
136 | return -1; | 136 | return -1; | |
137 | } | 137 | } | |
138 | ++state->sign_cur_block; | 138 | ++state->sign_cur_block; | |
139 | *buf = state->sign_buf; | 139 | *buf = state->sign_buf; | |
140 | return len; | 140 | return len; | |
141 | } | 141 | } | |
142 | 142 | |||
143 | static void | 143 | static void | |
144 | free_signature_int(struct signature_archive *state) | 144 | free_signature_int(struct signature_archive *state) | |
145 | { | 145 | { | |
146 | size_t i; | 146 | size_t i; | |
147 | 147 | |||
148 | if (state->sign_blocks != NULL) { | 148 | if (state->sign_blocks != NULL) { | |
149 | for (i = 0; i < state->sign_block_number; ++i) | 149 | for (i = 0; i < state->sign_block_number; ++i) | |
150 | free(state->sign_blocks[i]); | 150 | free(state->sign_blocks[i]); | |
151 | } | 151 | } | |
152 | free(state->sign_blocks); | 152 | free(state->sign_blocks); | |
153 | free(state->sign_buf); | 153 | free(state->sign_buf); | |
154 | free(state); | 154 | free(state); | |
155 | } | 155 | } | |
156 | 156 | |||
157 | void | 157 | void | |
158 | pkg_free_signature(void *cookie) | 158 | pkg_free_signature(void *cookie) | |
159 | { | 159 | { | |
160 | struct signature_archive *state = cookie; | 160 | struct signature_archive *state = cookie; | |
161 | 161 | |||
162 | if (state == NULL) | 162 | if (state == NULL) | |
163 | return; | 163 | return; | |
164 | 164 | |||
165 | archive_read_finish(state->archive); | 165 | archive_read_finish(state->archive); | |
166 | free_signature_int(state); | 166 | free_signature_int(state); | |
167 | } | 167 | } | |
168 | 168 | |||
169 | static int | 169 | static int | |
170 | read_file_from_archive(struct archive *archive, struct archive_entry **entry, | 170 | read_file_from_archive(struct archive *archive, struct archive_entry **entry, | |
171 | const char *fname, char **content, size_t *len) | 171 | const char *fname, char **content, size_t *len) | |
172 | { | 172 | { | |
173 | int r; | 173 | int r; | |
174 | 174 | |||
175 | *content = NULL; | 175 | *content = NULL; | |
176 | *len = 0; | 176 | *len = 0; | |
177 | 177 | |||
178 | retry: | 178 | retry: | |
179 | if (*entry == NULL && | 179 | if (*entry == NULL && | |
180 | (r = archive_read_next_header(archive, entry)) != ARCHIVE_OK) { | 180 | (r = archive_read_next_header(archive, entry)) != ARCHIVE_OK) { | |
181 | if (r == ARCHIVE_FATAL) { | 181 | if (r == ARCHIVE_FATAL) { | |
182 | warnx("Cannot read from archive: %s", | 182 | warnx("Cannot read from archive: %s", | |
183 | archive_error_string(archive)); | 183 | archive_error_string(archive)); | |
184 | return -1; | 184 | return -1; | |
185 | } | 185 | } | |
186 | return 1; | 186 | return 1; | |
187 | } | 187 | } | |
188 | if (strcmp(archive_entry_pathname(*entry), "//") == 0) { | 188 | if (strcmp(archive_entry_pathname(*entry), "//") == 0) { | |
189 | archive_read_data_skip(archive); | 189 | archive_read_data_skip(archive); | |
190 | *entry = NULL; | 190 | *entry = NULL; | |
191 | goto retry; | 191 | goto retry; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | if (strcmp(fname, archive_entry_pathname(*entry)) != 0) | 194 | if (strcmp(fname, archive_entry_pathname(*entry)) != 0) | |
195 | return 1; | 195 | return 1; | |
196 | 196 | |||
197 | if (archive_entry_size(*entry) > SSIZE_MAX - 1) { | 197 | if (archive_entry_size(*entry) > SSIZE_MAX - 1) { | |
198 | warnx("signature too large to process"); | 198 | warnx("signature too large to process"); | |
199 | return 1; | 199 | return 1; | |
200 | } | 200 | } | |
201 | *len = archive_entry_size(*entry); | 201 | *len = archive_entry_size(*entry); | |
202 | *content = xmalloc(*len + 1); | 202 | *content = xmalloc(*len + 1); | |
203 | 203 | |||
204 | if (archive_read_data(archive, *content, *len) != *len) { | 204 | if (archive_read_data(archive, *content, *len) != *len) { | |
205 | warnx("cannot read complete %s from archive", fname); | 205 | warnx("cannot read complete %s from archive", fname); | |
206 | free(*content); | 206 | free(*content); | |
207 | *len = 0; | 207 | *len = 0; | |
208 | *content = NULL; | 208 | *content = NULL; | |
209 | return 1; | 209 | return 1; | |
210 | } | 210 | } | |
211 | (*content)[*len] = '\0'; | 211 | (*content)[*len] = '\0'; | |
212 | *entry = NULL; | 212 | *entry = NULL; | |
213 | 213 | |||
214 | return 0; | 214 | return 0; | |
215 | } | 215 | } | |
216 | 216 | |||
217 | static int | 217 | static int | |
218 | parse_hash_file(const char *hash_file, char **pkgname, | 218 | parse_hash_file(const char *hash_file, char **pkgname, | |
219 | struct signature_archive *state) | 219 | struct signature_archive *state) | |
220 | { | 220 | { | |
221 | static const char block1[] = "pkgsrc signature\n\nversion: 1\npkgname: "; | 221 | static const char block1[] = "pkgsrc signature\n\nversion: 1\npkgname: "; | |
222 | static const char block2[] = "algorithm: SHA512\nblock size: "; | 222 | static const char block2[] = "algorithm: SHA512\nblock size: "; | |
223 | static const char block3[] = "file size: "; | 223 | static const char block3[] = "file size: "; | |
224 | static const char block4[] = "end pkgsrc signature\n"; | 224 | static const char block4[] = "end pkgsrc signature\n"; | |
225 | char *next; | 225 | char *next; | |
226 | size_t i, len; | 226 | size_t i, len; | |
227 | 227 | |||
228 | *pkgname = NULL; | 228 | *pkgname = NULL; | |
229 | 229 | |||
230 | if (strncmp(hash_file, block1, strlen(block1)) != 0) | 230 | if (strncmp(hash_file, block1, strlen(block1)) != 0) | |
231 | goto cleanup; | 231 | goto cleanup; | |
232 | hash_file += strlen(block1); | 232 | hash_file += strlen(block1); | |
233 | 233 | |||
234 | len = strcspn(hash_file, "\n"); | 234 | len = strcspn(hash_file, "\n"); | |
235 | *pkgname = xmalloc(len + 1); | 235 | *pkgname = xmalloc(len + 1); | |
236 | memcpy(*pkgname, hash_file, len); | 236 | memcpy(*pkgname, hash_file, len); | |
237 | (*pkgname)[len] = '\0'; | 237 | (*pkgname)[len] = '\0'; | |
238 | for (i = 0; i < len; ++i) { | 238 | for (i = 0; i < len; ++i) { | |
239 | if (!isgraph((unsigned char)(*pkgname)[i])) | 239 | if (!isgraph((unsigned char)(*pkgname)[i])) | |
240 | goto cleanup; | 240 | goto cleanup; | |
241 | } | 241 | } | |
242 | hash_file += len + 1; | 242 | hash_file += len + 1; | |
243 | 243 | |||
244 | if (strncmp(hash_file, block2, strlen(block2)) != 0) | 244 | if (strncmp(hash_file, block2, strlen(block2)) != 0) | |
245 | goto cleanup; | 245 | goto cleanup; | |
246 | hash_file += strlen(block2); | 246 | hash_file += strlen(block2); | |
247 | 247 | |||
248 | errno = 0; | 248 | errno = 0; | |
249 | if (!isdigit((unsigned char)*hash_file)) | 249 | if (!isdigit((unsigned char)*hash_file)) | |
250 | goto cleanup; | 250 | goto cleanup; | |
251 | state->sign_block_len = strtoul(hash_file, &next, 10); | 251 | state->sign_block_len = strtoul(hash_file, &next, 10); | |
252 | hash_file = next; | 252 | hash_file = next; | |
253 | 253 | |||
254 | /* Assert sane minimum block size of 1KB */ | 254 | /* Assert sane minimum block size of 1KB */ | |
255 | if (*hash_file++ != '\n' || errno == ERANGE || state->sign_block_len < 1024) | 255 | if (*hash_file++ != '\n' || errno == ERANGE || state->sign_block_len < 1024) | |
256 | goto cleanup; | 256 | goto cleanup; | |
257 | 257 | |||
258 | if (strncmp(hash_file, block3, strlen(block3)) != 0) | 258 | if (strncmp(hash_file, block3, strlen(block3)) != 0) | |
259 | goto cleanup; | 259 | goto cleanup; | |
260 | hash_file += strlen(block3); | 260 | hash_file += strlen(block3); | |
261 | 261 | |||
262 | errno = 0; | 262 | errno = 0; | |
263 | if (!isdigit((unsigned char)*hash_file)) | 263 | if (!isdigit((unsigned char)*hash_file)) | |
264 | goto cleanup; | 264 | goto cleanup; | |
265 | if (sizeof(off_t) >= sizeof(long long)) | 265 | if (sizeof(off_t) >= sizeof(long long)) | |
266 | state->pkg_size = strtoll(hash_file, &next, 10); | 266 | state->pkg_size = strtoll(hash_file, &next, 10); | |
267 | else | 267 | else | |
268 | state->pkg_size = strtol(hash_file, &next, 10); | 268 | state->pkg_size = strtol(hash_file, &next, 10); | |
269 | hash_file = next; | 269 | hash_file = next; | |
270 | if (*hash_file++ != '\n' || errno == ERANGE || state->pkg_size < 1) | 270 | if (*hash_file++ != '\n' || errno == ERANGE || state->pkg_size < 1) | |
271 | goto cleanup; | 271 | goto cleanup; | |
272 | 272 | |||
273 | if (*hash_file++ != '\n') | 273 | if (*hash_file++ != '\n') | |
274 | goto cleanup; | 274 | goto cleanup; | |
275 | 275 | |||
276 | if (state->pkg_size / state->sign_block_len > SSIZE_MAX) | 276 | if (state->pkg_size / state->sign_block_len > SSIZE_MAX) | |
277 | goto cleanup; | 277 | goto cleanup; | |
278 | state->sign_block_number = (state->pkg_size + | 278 | state->sign_block_number = (state->pkg_size + | |
279 | state->sign_block_len - 1) / state->sign_block_len; | 279 | state->sign_block_len - 1) / state->sign_block_len; | |
280 | 280 | |||
281 | state->sign_buf = xmalloc(state->sign_block_len); | 281 | state->sign_buf = xmalloc(state->sign_block_len); | |
282 | state->sign_blocks = xcalloc(state->sign_block_number, sizeof(char *)); | 282 | state->sign_blocks = xcalloc(state->sign_block_number, sizeof(char *)); | |
283 | 283 | |||
284 | for (i = 0; i < state->sign_block_number; ++i) { | 284 | for (i = 0; i < state->sign_block_number; ++i) { | |
285 | len = strspn(hash_file, "01234567889abcdef"); | 285 | len = strspn(hash_file, "01234567889abcdef"); | |
286 | if (len != SHA512_DIGEST_LENGTH * 2 || hash_file[len] != '\n') | 286 | if (len != SHA512_DIGEST_LENGTH * 2 || hash_file[len] != '\n') | |
287 | goto cleanup_hashes; | 287 | goto cleanup_hashes; | |
288 | state->sign_blocks[i] = xmalloc(len + 1); | 288 | state->sign_blocks[i] = xmalloc(len + 1); | |
289 | memcpy(state->sign_blocks[i], hash_file, len); | 289 | memcpy(state->sign_blocks[i], hash_file, len); | |
290 | state->sign_blocks[i][len] = '\0'; | 290 | state->sign_blocks[i][len] = '\0'; | |
291 | hash_file += len + 1; | 291 | hash_file += len + 1; | |
292 | } | 292 | } | |
293 | 293 | |||
294 | if (strcmp(hash_file, block4) != 0) | 294 | if (strcmp(hash_file, block4) != 0) | |
295 | goto cleanup_hashes; | 295 | goto cleanup_hashes; | |
296 | 296 | |||
297 | return 0; | 297 | return 0; | |
298 | 298 | |||
299 | cleanup_hashes: | 299 | cleanup_hashes: | |
300 | for (i = 0; i < state->sign_block_number; ++i) | 300 | for (i = 0; i < state->sign_block_number; ++i) | |
301 | free(state->sign_blocks[i]); | 301 | free(state->sign_blocks[i]); | |
302 | free(state->sign_blocks); | 302 | free(state->sign_blocks); | |
303 | state->sign_blocks = NULL; | 303 | state->sign_blocks = NULL; | |
304 | 304 | |||
305 | cleanup: | 305 | cleanup: | |
306 | warnx("Unknown format of hash file"); | 306 | warnx("Unknown format of hash file"); | |
307 | free(*pkgname); | 307 | free(*pkgname); | |
308 | *pkgname = NULL; | 308 | *pkgname = NULL; | |
309 | return -1; | 309 | return -1; | |
310 | } | 310 | } | |
311 | 311 | |||
312 | int | 312 | int | |
313 | pkg_verify_signature(struct archive **archive, struct archive_entry **entry, | 313 | pkg_verify_signature(struct archive **archive, struct archive_entry **entry, | |
314 | char **pkgname, void **cookie) | 314 | char **pkgname, void **cookie) | |
315 | { | 315 | { | |
316 | struct signature_archive *state; | 316 | struct signature_archive *state; | |
317 | struct archive_entry *my_entry; | 317 | struct archive_entry *my_entry; | |
318 | struct archive *a; | 318 | struct archive *a; | |
319 | char *hash_file, *signature_file; | 319 | char *hash_file, *signature_file; | |
320 | size_t hash_len, signature_len; | 320 | size_t hash_len, signature_len; | |
321 | int r, has_sig; | 321 | int r, has_sig; | |
322 | 322 | |||
323 | *pkgname = NULL; | 323 | *pkgname = NULL; | |
324 | *cookie = NULL; | 324 | *cookie = NULL; | |
325 | 325 | |||
326 | state = xmalloc(sizeof(*state)); | 326 | state = xmalloc(sizeof(*state)); | |
327 | state->sign_blocks = NULL; | 327 | state->sign_blocks = NULL; | |
328 | state->sign_buf = NULL; | 328 | state->sign_buf = NULL; | |
329 | state->archive = NULL; | 329 | state->archive = NULL; | |
330 | 330 | |||
331 | r = read_file_from_archive(*archive, entry, HASH_FNAME, | 331 | r = read_file_from_archive(*archive, entry, HASH_FNAME, | |
332 | &hash_file, &hash_len); | 332 | &hash_file, &hash_len); | |
333 | if (r == -1) { | 333 | if (r == -1) { | |
334 | archive_read_finish(*archive); | 334 | archive_read_finish(*archive); | |
335 | *archive = NULL; | 335 | *archive = NULL; | |
336 | free(state); | 336 | free(state); | |
337 | goto no_valid_signature; | 337 | goto no_valid_signature; | |
338 | } else if (r == 1) { | 338 | } else if (r == 1) { | |
339 | free(state); | 339 | free(state); | |
340 | goto no_valid_signature; | 340 | goto no_valid_signature; | |
341 | } | 341 | } | |
342 | 342 | |||
343 | if (parse_hash_file(hash_file, pkgname, state)) | 343 | if (parse_hash_file(hash_file, pkgname, state)) | |
344 | goto no_valid_signature; | 344 | goto no_valid_signature; | |
345 | 345 | |||
346 | r = read_file_from_archive(*archive, entry, SIGNATURE_FNAME, | 346 | r = read_file_from_archive(*archive, entry, SIGNATURE_FNAME, | |
347 | &signature_file, &signature_len); | 347 | &signature_file, &signature_len); | |
348 | if (r == -1) { | 348 | if (r == -1) { | |
349 | archive_read_finish(*archive); | 349 | archive_read_finish(*archive); | |
350 | *archive = NULL; | 350 | *archive = NULL; | |
351 | free(state); | 351 | free(state); | |
352 | free(hash_file); | 352 | free(hash_file); | |
353 | goto no_valid_signature; | 353 | goto no_valid_signature; | |
354 | } else if (r != 0) { | 354 | } else if (r != 0) { | |
355 | if (*entry != NULL) | 355 | if (*entry != NULL) | |
356 | r = read_file_from_archive(*archive, entry, | 356 | r = read_file_from_archive(*archive, entry, | |
357 | GPG_SIGNATURE_FNAME, | 357 | GPG_SIGNATURE_FNAME, | |
358 | &signature_file, &signature_len); | 358 | &signature_file, &signature_len); | |
359 | if (r == -1) { | 359 | if (r == -1) { | |
360 | archive_read_finish(*archive); | 360 | archive_read_finish(*archive); | |
361 | *archive = NULL; | 361 | *archive = NULL; | |
362 | free(state); | 362 | free(state); | |
363 | free(hash_file); | 363 | free(hash_file); | |
364 | goto no_valid_signature; | 364 | goto no_valid_signature; | |
365 | } else if (r != 0) { | 365 | } else if (r != 0) { | |
366 | free(hash_file); | 366 | free(hash_file); | |
367 | free(state); | 367 | free(state); | |
368 | goto no_valid_signature; | 368 | goto no_valid_signature; | |
369 | } | 369 | } | |
370 | has_sig = !detached_gpg_verify(hash_file, hash_len, | 370 | has_sig = !detached_gpg_verify(hash_file, hash_len, | |
371 | signature_file, signature_len, gpg_keyring_verify); | 371 | signature_file, signature_len, gpg_keyring_verify); | |
372 | 372 | |||
373 | free(signature_file); | 373 | free(signature_file); | |
374 | } else { | 374 | } else { | |
375 | #ifdef HAVE_SSL | 375 | #ifdef HAVE_SSL | |
376 | has_sig = !easy_pkcs7_verify(hash_file, hash_len, signature_file, | 376 | has_sig = !easy_pkcs7_verify(hash_file, hash_len, signature_file, | |
377 | signature_len, certs_packages, 1); | 377 | signature_len, certs_packages, 1); | |
378 | 378 | |||
379 | free(signature_file); | 379 | free(signature_file); | |
380 | #else | 380 | #else | |
381 | warnx("No OpenSSL support compiled in, skipping signature"); | 381 | warnx("No OpenSSL support compiled in, skipping signature"); | |
382 | has_sig = 0; | 382 | has_sig = 0; | |
383 | free(signature_file); | 383 | free(signature_file); | |
384 | #endif | 384 | #endif | |
385 | } | 385 | } | |
386 | 386 | |||
387 | r = archive_read_next_header(*archive, &my_entry); | 387 | r = archive_read_next_header(*archive, &my_entry); | |
388 | if (r != ARCHIVE_OK) { | 388 | if (r != ARCHIVE_OK) { | |
389 | warnx("Cannot read inner package: %s", | 389 | warnx("Cannot read inner package: %s", | |
390 | archive_error_string(*archive)); | 390 | archive_error_string(*archive)); | |
391 | free_signature_int(state); | 391 | free_signature_int(state); | |
392 | goto no_valid_signature; | 392 | goto no_valid_signature; | |
393 | } | 393 | } | |
394 | 394 | |||
395 | if (archive_entry_size(my_entry) != state->pkg_size) { | 395 | if (archive_entry_size(my_entry) != state->pkg_size) { | |
396 | warnx("Package size doesn't match signature"); | 396 | warnx("Package size doesn't match signature"); | |
397 | free_signature_int(state); | 397 | free_signature_int(state); | |
398 | goto no_valid_signature; | 398 | goto no_valid_signature; | |
399 | } | 399 | } | |
400 | 400 | |||
401 | state->archive = *archive; | 401 | state->archive = *archive; | |
402 | 402 | |||
403 | a = archive_read_new(); | 403 | a = archive_read_new(); | |
404 | archive_read_support_compression_all(a); | 404 | archive_read_support_compression_all(a); | |
405 | archive_read_support_format_all(a); | 405 | archive_read_support_format_all(a); | |
406 | if (archive_read_open(a, state, NULL, verify_signature_read_cb, NULL)) { | 406 | if (archive_read_open(a, state, NULL, verify_signature_read_cb, NULL)) { | |
407 | warnx("Can't open signed package file"); | 407 | warnx("Can't open signed package file"); | |
408 | archive_read_finish(a); | 408 | archive_read_finish(a); | |
409 | free_signature_int(state); | 409 | free_signature_int(state); | |
410 | goto no_valid_signature; | 410 | goto no_valid_signature; | |
411 | } | 411 | } | |
412 | *archive = a; | 412 | *archive = a; | |
413 | *entry = NULL; | 413 | *entry = NULL; | |
414 | *cookie = state; | 414 | *cookie = state; | |
415 | 415 | |||
416 | return has_sig ? 0 : -1; | 416 | return has_sig ? 0 : -1; | |
417 | 417 | |||
418 | no_valid_signature: | 418 | no_valid_signature: | |
419 | return -1; | 419 | return -1; | |
420 | } | 420 | } | |
421 | 421 | |||
422 | int | 422 | int | |
423 | pkg_full_signature_check(struct archive **archive) | 423 | pkg_full_signature_check(struct archive **archive) | |
424 | { | 424 | { | |
425 | struct archive_entry *entry = NULL; | 425 | struct archive_entry *entry = NULL; | |
426 | char *pkgname; | 426 | char *pkgname; | |
427 | void *cookie; | 427 | void *cookie; | |
428 | int r; | 428 | int r; | |
429 | 429 | |||
430 | if (pkg_verify_signature(archive, &entry, &pkgname, &cookie)) | 430 | if (pkg_verify_signature(archive, &entry, &pkgname, &cookie)) | |
431 | return -1; | 431 | return -1; | |
432 | if (pkgname == NULL) | 432 | if (pkgname == NULL) | |
433 | return 0; | 433 | return 0; | |
434 | 434 | |||
435 | /* XXX read PLIST and compare pkgname */ | 435 | /* XXX read PLIST and compare pkgname */ | |
436 | while ((r = archive_read_next_header(*archive, &entry)) == ARCHIVE_OK) | 436 | while ((r = archive_read_next_header(*archive, &entry)) == ARCHIVE_OK) | |
437 | archive_read_data_skip(*archive); | 437 | archive_read_data_skip(*archive); | |
438 | 438 | |||
439 | pkg_free_signature(cookie); | 439 | pkg_free_signature(cookie); | |
440 | free(pkgname); | 440 | free(pkgname); | |
441 | return r == ARCHIVE_EOF ? 0 : -1; | 441 | return r == ARCHIVE_EOF ? 0 : -1; | |
442 | } | 442 | } | |
443 | 443 | |||
444 | static char * | 444 | static char * | |
445 | extract_pkgname(int fd) | 445 | extract_pkgname(int fd) | |
446 | { | 446 | { | |
447 | package_t plist; | 447 | package_t plist; | |
448 | plist_t *p; | 448 | plist_t *p; | |
449 | struct archive *a; | 449 | struct archive *a; | |
450 | struct archive_entry *entry; | 450 | struct archive_entry *entry; | |
451 | char *buf; | 451 | char *buf; | |
452 | ssize_t len; | 452 | ssize_t len; | |
453 | int r; | 453 | int r; | |
454 | 454 | |||
455 | a = archive_read_new(); | 455 | a = archive_read_new(); | |
456 | archive_read_support_compression_all(a); | 456 | archive_read_support_compression_all(a); | |
457 | archive_read_support_format_all(a); | 457 | archive_read_support_format_all(a); | |
458 | if (archive_read_open_fd(a, fd, 1024)) { | 458 | if (archive_read_open_fd(a, fd, 1024)) { | |
459 | warnx("Cannot open binary package: %s", | 459 | warnx("Cannot open binary package: %s", | |
460 | archive_error_string(a)); | 460 | archive_error_string(a)); | |
461 | archive_read_finish(a); | 461 | archive_read_finish(a); | |
462 | return NULL; | 462 | return NULL; | |
463 | } | 463 | } | |
464 | 464 | |||
465 | r = archive_read_next_header(a, &entry); | 465 | r = archive_read_next_header(a, &entry); | |
466 | if (r != ARCHIVE_OK) { | 466 | if (r != ARCHIVE_OK) { | |
467 | warnx("Cannot extract package name: %s", | 467 | warnx("Cannot extract package name: %s", | |
468 | r == ARCHIVE_EOF ? "EOF" : archive_error_string(a)); | 468 | r == ARCHIVE_EOF ? "EOF" : archive_error_string(a)); | |
469 | archive_read_finish(a); | 469 | archive_read_finish(a); | |
470 | return NULL; | 470 | return NULL; | |
471 | } | 471 | } | |
472 | if (strcmp(archive_entry_pathname(entry), "+CONTENTS") != 0) { | 472 | if (strcmp(archive_entry_pathname(entry), "+CONTENTS") != 0) { | |
473 | warnx("Invalid binary package, doesn't start with +CONTENTS"); | 473 | warnx("Invalid binary package, doesn't start with +CONTENTS"); | |
474 | archive_read_finish(a); | 474 | archive_read_finish(a); | |
475 | return NULL; | 475 | return NULL; | |
476 | } | 476 | } | |
477 | if (archive_entry_size(entry) > SSIZE_MAX - 1) { | 477 | if (archive_entry_size(entry) > SSIZE_MAX - 1) { | |
478 | warnx("+CONTENTS too large to process"); | 478 | warnx("+CONTENTS too large to process"); | |
479 | archive_read_finish(a); | 479 | archive_read_finish(a); | |
480 | return NULL; | 480 | return NULL; | |
481 | } | 481 | } | |
482 | 482 | |||
483 | len = archive_entry_size(entry); | 483 | len = archive_entry_size(entry); | |
484 | buf = xmalloc(len + 1); | 484 | buf = xmalloc(len + 1); | |
485 | 485 | |||
486 | if (archive_read_data(a, buf, len) != len) { | 486 | if (archive_read_data(a, buf, len) != len) { | |
487 | warnx("Short read when extracing +CONTENTS"); | 487 | warnx("Short read when extracing +CONTENTS"); | |
488 | free(buf); | 488 | free(buf); | |
489 | archive_read_finish(a); | 489 | archive_read_finish(a); | |
490 | return NULL; | 490 | return NULL; | |
491 | } | 491 | } | |
492 | buf[len] = '\0'; | 492 | buf[len] = '\0'; | |
493 | 493 | |||
494 | archive_read_finish(a); | 494 | archive_read_finish(a); | |
495 | 495 | |||
496 | parse_plist(&plist, buf); | 496 | parse_plist(&plist, buf); | |
497 | free(buf); | 497 | free(buf); | |
498 | p = find_plist(&plist, PLIST_NAME); | 498 | p = find_plist(&plist, PLIST_NAME); | |
499 | if (p != NULL) { | 499 | if (p != NULL) { | |
500 | buf = xstrdup(p->name); | 500 | buf = xstrdup(p->name); | |
501 | } else { | 501 | } else { | |
502 | warnx("Invalid PLIST: missing @name"); | 502 | warnx("Invalid PLIST: missing @name"); | |
503 | buf = NULL; | 503 | buf = NULL; | |
504 | } | 504 | } | |
505 | free_plist(&plist); | 505 | free_plist(&plist); | |
506 | 506 | |||
507 | if (lseek(fd, 0, SEEK_SET) != 0) { | 507 | if (lseek(fd, 0, SEEK_SET) != 0) { | |
508 | warn("Cannot seek in archive"); | 508 | warn("Cannot seek in archive"); | |
509 | free(buf); | 509 | free(buf); | |
510 | return NULL; | 510 | return NULL; | |
511 | } | 511 | } | |
512 | 512 | |||
513 | return buf; | 513 | return buf; | |
514 | } | 514 | } | |
515 | 515 | |||
516 | static const char hash_template[] = | 516 | static const char hash_template[] = | |
517 | "pkgsrc signature\n" | 517 | "pkgsrc signature\n" | |
518 | "\n" | 518 | "\n" | |
519 | "version: 1\n" | 519 | "version: 1\n" | |
520 | "pkgname: %s\n" | 520 | "pkgname: %s\n" | |
521 | "algorithm: SHA512\n" | 521 | "algorithm: SHA512\n" | |
522 | "block size: 65536\n" | 522 | "block size: 65536\n" | |
523 | "file size: %lld\n" | 523 | "file size: %lld\n" | |
524 | "\n"; | 524 | "\n"; | |
525 | 525 | |||
526 | static const char hash_trailer[] = "end pkgsrc signature\n"; | 526 | static const char hash_trailer[] = "end pkgsrc signature\n"; | |
527 | 527 | |||
528 | #ifdef HAVE_SSL | 528 | #ifdef HAVE_SSL | |
529 | void | 529 | void | |
530 | pkg_sign_x509(const char *name, const char *output, const char *key_file, const char *cert_file) | 530 | pkg_sign_x509(const char *name, const char *output, const char *key_file, const char *cert_file) | |
531 | { | 531 | { | |
532 | struct archive *pkg; | 532 | struct archive *pkg; | |
533 | struct archive_entry *entry, *hash_entry, *sign_entry; | 533 | struct archive_entry *entry, *hash_entry, *sign_entry; | |
534 | int fd; | 534 | int fd; | |
535 | struct stat sb; | 535 | struct stat sb; | |
536 | char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; | 536 | char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; | |
537 | unsigned char block[65536]; | 537 | unsigned char block[65536]; | |
538 | off_t i, size; | 538 | off_t i, size; | |
539 | size_t block_len, signature_len; | 539 | size_t block_len, signature_len; | |
540 | 540 | |||
541 | if ((fd = open(name, O_RDONLY)) == -1) | 541 | if ((fd = open(name, O_RDONLY)) == -1) | |
542 | err(EXIT_FAILURE, "Cannot open binary package %s", name); | 542 | err(EXIT_FAILURE, "Cannot open binary package %s", name); | |
543 | if (fstat(fd, &sb) == -1) | 543 | if (fstat(fd, &sb) == -1) | |
544 | err(EXIT_FAILURE, "Cannot stat %s", name); | 544 | err(EXIT_FAILURE, "Cannot stat %s", name); | |
545 | 545 | |||
546 | entry = archive_entry_new(); | 546 | entry = archive_entry_new(); | |
547 | archive_entry_copy_stat(entry, &sb); | 547 | archive_entry_copy_stat(entry, &sb); | |
548 | 548 | |||
549 | pkgname = extract_pkgname(fd); | 549 | pkgname = extract_pkgname(fd); | |
550 | hash_file = xasprintf(hash_template, pkgname, | 550 | hash_file = xasprintf(hash_template, pkgname, | |
551 | (long long)archive_entry_size(entry)); | 551 | (long long)archive_entry_size(entry)); | |
552 | free(pkgname); | 552 | free(pkgname); | |
553 | 553 | |||
554 | for (i = 0; i < archive_entry_size(entry); i += block_len) { | 554 | for (i = 0; i < archive_entry_size(entry); i += block_len) { | |
555 | if (i + sizeof(block) < archive_entry_size(entry)) | 555 | if (i + sizeof(block) < archive_entry_size(entry)) | |
556 | block_len = sizeof(block); | 556 | block_len = sizeof(block); | |
557 | else | 557 | else | |
558 | block_len = archive_entry_size(entry) % sizeof(block); | 558 | block_len = archive_entry_size(entry) % sizeof(block); | |
559 | if (read(fd, block, block_len) != block_len) | 559 | if (read(fd, block, block_len) != block_len) | |
560 | err(2, "short read"); | 560 | err(2, "short read"); | |
561 | hash_block(block, block_len, hash); | 561 | hash_block(block, block_len, hash); | |
562 | tmp = xasprintf("%s%s\n", hash_file, hash); | 562 | tmp = xasprintf("%s%s\n", hash_file, hash); | |
563 | free(hash_file); | 563 | free(hash_file); | |
564 | hash_file = tmp; | 564 | hash_file = tmp; | |
565 | } | 565 | } | |
566 | tmp = xasprintf("%s%s", hash_file, hash_trailer); | 566 | tmp = xasprintf("%s%s", hash_file, hash_trailer); | |
567 | free(hash_file); | 567 | free(hash_file); | |
568 | hash_file = tmp; | 568 | hash_file = tmp; | |
569 | 569 | |||
570 | if (easy_pkcs7_sign(hash_file, strlen(hash_file), &signature_file, | 570 | if (easy_pkcs7_sign(hash_file, strlen(hash_file), &signature_file, | |
571 | &signature_len, key_file, cert_file)) | 571 | &signature_len, key_file, cert_file)) | |
572 | err(EXIT_FAILURE, "Cannot sign hash file"); | 572 | err(EXIT_FAILURE, "Cannot sign hash file"); | |
573 | 573 | |||
574 | lseek(fd, 0, SEEK_SET); | 574 | lseek(fd, 0, SEEK_SET); | |
575 | 575 | |||
576 | sign_entry = archive_entry_clone(entry); | 576 | sign_entry = archive_entry_clone(entry); | |
577 | hash_entry = archive_entry_clone(entry); | 577 | hash_entry = archive_entry_clone(entry); | |
578 | pkgname = strrchr(name, '/'); | 578 | pkgname = strrchr(name, '/'); | |
579 | archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); | 579 | archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); | |
580 | archive_entry_set_pathname(hash_entry, HASH_FNAME); | 580 | archive_entry_set_pathname(hash_entry, HASH_FNAME); | |
581 | archive_entry_set_pathname(sign_entry, SIGNATURE_FNAME); | 581 | archive_entry_set_pathname(sign_entry, SIGNATURE_FNAME); | |
582 | archive_entry_set_size(hash_entry, strlen(hash_file)); | 582 | archive_entry_set_size(hash_entry, strlen(hash_file)); | |
583 | archive_entry_set_size(sign_entry, signature_len); | 583 | archive_entry_set_size(sign_entry, signature_len); | |
584 | 584 | |||
585 | pkg = archive_write_new(); | 585 | pkg = archive_write_new(); | |
586 | archive_write_set_compression_none(pkg); | 586 | archive_write_set_compression_none(pkg); | |
587 | archive_write_set_format_ar_bsd(pkg); | 587 | archive_write_set_format_ar_bsd(pkg); | |
588 | archive_write_open_filename(pkg, output); | 588 | archive_write_open_filename(pkg, output); | |
589 | 589 | |||
590 | archive_write_header(pkg, hash_entry); | 590 | archive_write_header(pkg, hash_entry); | |
591 | archive_write_data(pkg, hash_file, strlen(hash_file)); | 591 | archive_write_data(pkg, hash_file, strlen(hash_file)); | |
592 | archive_write_finish_entry(pkg); | 592 | archive_write_finish_entry(pkg); | |
593 | archive_entry_free(hash_entry); | 593 | archive_entry_free(hash_entry); | |
594 | 594 | |||
595 | archive_write_header(pkg, sign_entry); | 595 | archive_write_header(pkg, sign_entry); | |
596 | archive_write_data(pkg, signature_file, signature_len); | 596 | archive_write_data(pkg, signature_file, signature_len); | |
597 | archive_write_finish_entry(pkg); | 597 | archive_write_finish_entry(pkg); | |
598 | archive_entry_free(sign_entry); | 598 | archive_entry_free(sign_entry); | |
599 | 599 | |||
600 | size = archive_entry_size(entry); | 600 | size = archive_entry_size(entry); | |
601 | archive_write_header(pkg, entry); | 601 | archive_write_header(pkg, entry); | |
602 | 602 | |||
603 | for (i = 0; i < size; i += block_len) { | 603 | for (i = 0; i < size; i += block_len) { | |
604 | if (i + sizeof(block) < size) | 604 | if (i + sizeof(block) < size) | |
605 | block_len = sizeof(block); | 605 | block_len = sizeof(block); | |
606 | else | 606 | else | |
607 | block_len = size % sizeof(block); | 607 | block_len = size % sizeof(block); | |
608 | if (read(fd, block, block_len) != block_len) | 608 | if (read(fd, block, block_len) != block_len) | |
609 | err(2, "short read"); | 609 | err(2, "short read"); | |
610 | archive_write_data(pkg, block, block_len); | 610 | archive_write_data(pkg, block, block_len); | |
611 | } | 611 | } | |
612 | archive_write_finish_entry(pkg); | 612 | archive_write_finish_entry(pkg); | |
613 | archive_entry_free(entry); | 613 | archive_entry_free(entry); | |
614 | 614 | |||
615 | archive_write_finish(pkg); | 615 | archive_write_finish(pkg); | |
616 | 616 | |||
617 | close(fd); | |||
618 | ||||
617 | exit(0); | 619 | exit(0); | |
618 | } | 620 | } | |
619 | #endif | 621 | #endif | |
620 | 622 | |||
621 | void | 623 | void | |
622 | pkg_sign_gpg(const char *name, const char *output) | 624 | pkg_sign_gpg(const char *name, const char *output) | |
623 | { | 625 | { | |
624 | struct archive *pkg; | 626 | struct archive *pkg; | |
625 | struct archive_entry *entry, *hash_entry, *sign_entry; | 627 | struct archive_entry *entry, *hash_entry, *sign_entry; | |
626 | int fd; | 628 | int fd; | |
627 | struct stat sb; | 629 | struct stat sb; | |
628 | char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; | 630 | char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; | |
629 | unsigned char block[65536]; | 631 | unsigned char block[65536]; | |
630 | off_t i, size; | 632 | off_t i, size; | |
631 | size_t block_len, signature_len; | 633 | size_t block_len, signature_len; | |
632 | 634 | |||
633 | if ((fd = open(name, O_RDONLY)) == -1) | 635 | if ((fd = open(name, O_RDONLY)) == -1) | |
634 | err(EXIT_FAILURE, "Cannot open binary package %s", name); | 636 | err(EXIT_FAILURE, "Cannot open binary package %s", name); | |
635 | if (fstat(fd, &sb) == -1) | 637 | if (fstat(fd, &sb) == -1) | |
636 | err(EXIT_FAILURE, "Cannot stat %s", name); | 638 | err(EXIT_FAILURE, "Cannot stat %s", name); | |
637 | 639 | |||
638 | entry = archive_entry_new(); | 640 | entry = archive_entry_new(); | |
639 | archive_entry_copy_stat(entry, &sb); | 641 | archive_entry_copy_stat(entry, &sb); | |
640 | 642 | |||
641 | pkgname = extract_pkgname(fd); | 643 | pkgname = extract_pkgname(fd); | |
642 | hash_file = xasprintf(hash_template, pkgname, | 644 | hash_file = xasprintf(hash_template, pkgname, | |
643 | (long long)archive_entry_size(entry)); | 645 | (long long)archive_entry_size(entry)); | |
644 | free(pkgname); | 646 | free(pkgname); | |
645 | 647 | |||
646 | for (i = 0; i < archive_entry_size(entry); i += block_len) { | 648 | for (i = 0; i < archive_entry_size(entry); i += block_len) { | |
647 | if (i + sizeof(block) < archive_entry_size(entry)) | 649 | if (i + sizeof(block) < archive_entry_size(entry)) | |
648 | block_len = sizeof(block); | 650 | block_len = sizeof(block); | |
649 | else | 651 | else | |
650 | block_len = archive_entry_size(entry) % sizeof(block); | 652 | block_len = archive_entry_size(entry) % sizeof(block); | |
651 | if (read(fd, block, block_len) != block_len) | 653 | if (read(fd, block, block_len) != block_len) | |
652 | err(2, "short read"); | 654 | err(2, "short read"); | |
653 | hash_block(block, block_len, hash); | 655 | hash_block(block, block_len, hash); | |
654 | tmp = xasprintf("%s%s\n", hash_file, hash); | 656 | tmp = xasprintf("%s%s\n", hash_file, hash); | |
655 | free(hash_file); | 657 | free(hash_file); | |
656 | hash_file = tmp; | 658 | hash_file = tmp; | |
657 | } | 659 | } | |
658 | tmp = xasprintf("%s%s", hash_file, hash_trailer); | 660 | tmp = xasprintf("%s%s", hash_file, hash_trailer); | |
659 | free(hash_file); | 661 | free(hash_file); | |
660 | hash_file = tmp; | 662 | hash_file = tmp; | |
661 | 663 | |||
662 | if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file, | 664 | if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file, | |
663 | &signature_len, gpg_keyring_sign, gpg_sign_as)) | 665 | &signature_len, gpg_keyring_sign, gpg_sign_as)) | |
664 | err(EXIT_FAILURE, "Cannot sign hash file"); | 666 | err(EXIT_FAILURE, "Cannot sign hash file"); | |
665 | 667 | |||
666 | lseek(fd, 0, SEEK_SET); | 668 | lseek(fd, 0, SEEK_SET); | |
667 | 669 | |||
668 | sign_entry = archive_entry_clone(entry); | 670 | sign_entry = archive_entry_clone(entry); | |
669 | hash_entry = archive_entry_clone(entry); | 671 | hash_entry = archive_entry_clone(entry); | |
670 | pkgname = strrchr(name, '/'); | 672 | pkgname = strrchr(name, '/'); | |
671 | archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); | 673 | archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); | |
672 | archive_entry_set_pathname(hash_entry, HASH_FNAME); | 674 | archive_entry_set_pathname(hash_entry, HASH_FNAME); | |
673 | archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME); | 675 | archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME); | |
674 | archive_entry_set_size(hash_entry, strlen(hash_file)); | 676 | archive_entry_set_size(hash_entry, strlen(hash_file)); | |
675 | archive_entry_set_size(sign_entry, signature_len); | 677 | archive_entry_set_size(sign_entry, signature_len); | |
676 | 678 | |||
677 | pkg = archive_write_new(); | 679 | pkg = archive_write_new(); | |
678 | archive_write_set_compression_none(pkg); | 680 | archive_write_set_compression_none(pkg); | |
679 | archive_write_set_format_ar_bsd(pkg); | 681 | archive_write_set_format_ar_bsd(pkg); | |
680 | archive_write_open_filename(pkg, output); | 682 | archive_write_open_filename(pkg, output); | |
681 | 683 | |||
682 | archive_write_header(pkg, hash_entry); | 684 | archive_write_header(pkg, hash_entry); | |
683 | archive_write_data(pkg, hash_file, strlen(hash_file)); | 685 | archive_write_data(pkg, hash_file, strlen(hash_file)); | |
684 | archive_write_finish_entry(pkg); | 686 | archive_write_finish_entry(pkg); | |
685 | archive_entry_free(hash_entry); | 687 | archive_entry_free(hash_entry); | |
686 | 688 | |||
687 | archive_write_header(pkg, sign_entry); | 689 | archive_write_header(pkg, sign_entry); | |
688 | archive_write_data(pkg, signature_file, signature_len); | 690 | archive_write_data(pkg, signature_file, signature_len); | |
689 | archive_write_finish_entry(pkg); | 691 | archive_write_finish_entry(pkg); | |
690 | archive_entry_free(sign_entry); | 692 | archive_entry_free(sign_entry); | |
691 | 693 | |||
692 | size = archive_entry_size(entry); | 694 | size = archive_entry_size(entry); | |
693 | archive_write_header(pkg, entry); | 695 | archive_write_header(pkg, entry); | |
694 | 696 | |||
695 | for (i = 0; i < size; i += block_len) { | 697 | for (i = 0; i < size; i += block_len) { | |
696 | if (i + sizeof(block) < size) | 698 | if (i + sizeof(block) < size) | |
697 | block_len = sizeof(block); | 699 | block_len = sizeof(block); | |
698 | else | 700 | else | |
699 | block_len = size % sizeof(block); | 701 | block_len = size % sizeof(block); | |
700 | if (read(fd, block, block_len) != block_len) | 702 | if (read(fd, block, block_len) != block_len) | |
701 | err(2, "short read"); | 703 | err(2, "short read"); | |
702 | archive_write_data(pkg, block, block_len); | 704 | archive_write_data(pkg, block, block_len); | |
703 | } | 705 | } | |
704 | archive_write_finish_entry(pkg); | 706 | archive_write_finish_entry(pkg); | |
705 | archive_entry_free(entry); | 707 | archive_entry_free(entry); | |
706 | 708 | |||
707 | archive_write_finish(pkg); | 709 | archive_write_finish(pkg); | |
708 | 710 | |||
711 | close(fd); | |||
712 | ||||
709 | exit(0); | 713 | exit(0); | |
710 | } | 714 | } |
@@ -1,32 +1,32 @@ | @@ -1,32 +1,32 @@ | |||
1 | /* $NetBSD: version.h,v 1.115 2009/02/28 16:03:56 joerg Exp $ */ | 1 | /* $NetBSD: version.h,v 1.116 2009/03/02 14:59:14 joerg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2001 Thomas Klausner. All rights reserved. | 4 | * Copyright (c) 2001 Thomas Klausner. All rights reserved. | |
5 | * | 5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | 8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | 9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | 10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | 12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | 13 | * documentation and/or other materials provided with the distribution. | |
14 | * | 14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 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 | 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 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 | 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 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 | 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. | 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | */ | 25 | */ | |
26 | 26 | |||
27 | #ifndef _INST_LIB_VERSION_H_ | 27 | #ifndef _INST_LIB_VERSION_H_ | |
28 | #define _INST_LIB_VERSION_H_ | 28 | #define _INST_LIB_VERSION_H_ | |
29 | 29 | |||
30 | #define PKGTOOLS_VERSION "20090228" | 30 | #define PKGTOOLS_VERSION "20090301" | |
31 | 31 | |||
32 | #endif /* _INST_LIB_VERSION_H_ */ | 32 | #endif /* _INST_LIB_VERSION_H_ */ |
@@ -1,588 +1,590 @@ | @@ -1,588 +1,590 @@ | |||
1 | /* $NetBSD: vulnerabilities-file.c,v 1.4 2009/02/02 12:35:01 joerg Exp $ */ | 1 | /* $NetBSD: vulnerabilities-file.c,v 1.5 2009/03/02 14:59:14 joerg Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | 4 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * | 10 | * | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | 14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | 15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | 16 | * distribution. | |
17 | * | 17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
22 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 22 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
28 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #if HAVE_CONFIG_H | 32 | #if HAVE_CONFIG_H | |
33 | #include "config.h" | 33 | #include "config.h" | |
34 | #endif | 34 | #endif | |
35 | 35 | |||
36 | #include <nbcompat.h> | 36 | #include <nbcompat.h> | |
37 | 37 | |||
38 | #if HAVE_SYS_CDEFS_H | 38 | #if HAVE_SYS_CDEFS_H | |
39 | #include <sys/cdefs.h> | 39 | #include <sys/cdefs.h> | |
40 | #endif | 40 | #endif | |
41 | __RCSID("$NetBSD: vulnerabilities-file.c,v 1.4 2009/02/02 12:35:01 joerg Exp $"); | 41 | __RCSID("$NetBSD: vulnerabilities-file.c,v 1.5 2009/03/02 14:59:14 joerg Exp $"); | |
42 | 42 | |||
43 | #if HAVE_SYS_STAT_H | 43 | #if HAVE_SYS_STAT_H | |
44 | #include <sys/stat.h> | 44 | #include <sys/stat.h> | |
45 | #endif | 45 | #endif | |
46 | #if HAVE_SYS_WAIT_H | 46 | #if HAVE_SYS_WAIT_H | |
47 | #include <sys/wait.h> | 47 | #include <sys/wait.h> | |
48 | #endif | 48 | #endif | |
49 | #include <ctype.h> | 49 | #include <ctype.h> | |
50 | #if HAVE_ERR_H | 50 | #if HAVE_ERR_H | |
51 | #include <err.h> | 51 | #include <err.h> | |
52 | #endif | 52 | #endif | |
53 | #include <errno.h> | 53 | #include <errno.h> | |
54 | #include <fcntl.h> | 54 | #include <fcntl.h> | |
55 | #include <limits.h> | 55 | #include <limits.h> | |
56 | #include <stdlib.h> | 56 | #include <stdlib.h> | |
57 | #include <string.h> | 57 | #include <string.h> | |
58 | #ifndef NETBSD | 58 | #ifndef NETBSD | |
59 | #include <nbcompat/sha1.h> | 59 | #include <nbcompat/sha1.h> | |
60 | #include <nbcompat/sha2.h> | 60 | #include <nbcompat/sha2.h> | |
61 | #else | 61 | #else | |
62 | #include <sha1.h> | 62 | #include <sha1.h> | |
63 | #include <sha2.h> | 63 | #include <sha2.h> | |
64 | #endif | 64 | #endif | |
65 | #include <unistd.h> | 65 | #include <unistd.h> | |
66 | 66 | |||
67 | #include "lib.h" | 67 | #include "lib.h" | |
68 | 68 | |||
69 | static const char pgp_msg_start[] = "-----BEGIN PGP SIGNED MESSAGE-----\n"; | 69 | static const char pgp_msg_start[] = "-----BEGIN PGP SIGNED MESSAGE-----\n"; | |
70 | static const char pgp_msg_end[] = "-----BEGIN PGP SIGNATURE-----\n"; | 70 | static const char pgp_msg_end[] = "-----BEGIN PGP SIGNATURE-----\n"; | |
71 | static const char pkcs7_begin[] = "-----BEGIN PKCS7-----\n"; | 71 | static const char pkcs7_begin[] = "-----BEGIN PKCS7-----\n"; | |
72 | static const char pkcs7_end[] = "-----END PKCS7-----\n"; | 72 | static const char pkcs7_end[] = "-----END PKCS7-----\n"; | |
73 | 73 | |||
74 | static void | 74 | static void | |
75 | verify_signature_pkcs7(const char *input) | 75 | verify_signature_pkcs7(const char *input) | |
76 | { | 76 | { | |
77 | #ifdef HAVE_SSL | 77 | #ifdef HAVE_SSL | |
78 | const char *begin_pkgvul, *end_pkgvul, *begin_sig, *end_sig; | 78 | const char *begin_pkgvul, *end_pkgvul, *begin_sig, *end_sig; | |
79 | 79 | |||
80 | if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { | 80 | if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { | |
81 | begin_pkgvul = input + strlen(pgp_msg_start); | 81 | begin_pkgvul = input + strlen(pgp_msg_start); | |
82 | if ((end_pkgvul = strstr(begin_pkgvul, pgp_msg_end)) == NULL) | 82 | if ((end_pkgvul = strstr(begin_pkgvul, pgp_msg_end)) == NULL) | |
83 | errx(EXIT_FAILURE, "Invalid PGP signature"); | 83 | errx(EXIT_FAILURE, "Invalid PGP signature"); | |
84 | if ((begin_sig = strstr(end_pkgvul, pkcs7_begin)) == NULL) | 84 | if ((begin_sig = strstr(end_pkgvul, pkcs7_begin)) == NULL) | |
85 | errx(EXIT_FAILURE, "No PKCS7 signature"); | 85 | errx(EXIT_FAILURE, "No PKCS7 signature"); | |
86 | } else { | 86 | } else { | |
87 | begin_pkgvul = input; | 87 | begin_pkgvul = input; | |
88 | if ((begin_sig = strstr(begin_pkgvul, pkcs7_begin)) == NULL) | 88 | if ((begin_sig = strstr(begin_pkgvul, pkcs7_begin)) == NULL) | |
89 | errx(EXIT_FAILURE, "No PKCS7 signature"); | 89 | errx(EXIT_FAILURE, "No PKCS7 signature"); | |
90 | end_pkgvul = begin_sig; | 90 | end_pkgvul = begin_sig; | |
91 | } | 91 | } | |
92 | if ((end_sig = strstr(begin_sig, pkcs7_end)) == NULL) | 92 | if ((end_sig = strstr(begin_sig, pkcs7_end)) == NULL) | |
93 | errx(EXIT_FAILURE, "Invalid PKCS7 signature"); | 93 | errx(EXIT_FAILURE, "Invalid PKCS7 signature"); | |
94 | end_sig += strlen(pkcs7_end); | 94 | end_sig += strlen(pkcs7_end); | |
95 | 95 | |||
96 | if (easy_pkcs7_verify(begin_pkgvul, end_pkgvul - begin_pkgvul, | 96 | if (easy_pkcs7_verify(begin_pkgvul, end_pkgvul - begin_pkgvul, | |
97 | begin_sig, end_sig - begin_sig, certs_pkg_vulnerabilities, 0)) | 97 | begin_sig, end_sig - begin_sig, certs_pkg_vulnerabilities, 0)) | |
98 | errx(EXIT_FAILURE, "Unable to verify PKCS7 signature"); | 98 | errx(EXIT_FAILURE, "Unable to verify PKCS7 signature"); | |
99 | #else | 99 | #else | |
100 | errx(EXIT_FAILURE, "OpenSSL support is not compiled in"); | 100 | errx(EXIT_FAILURE, "OpenSSL support is not compiled in"); | |
101 | #endif | 101 | #endif | |
102 | } | 102 | } | |
103 | 103 | |||
104 | static void | 104 | static void | |
105 | verify_signature(const char *input, size_t input_len) | 105 | verify_signature(const char *input, size_t input_len) | |
106 | { | 106 | { | |
107 | if (gpg_cmd == NULL && certs_pkg_vulnerabilities == NULL) | 107 | if (gpg_cmd == NULL && certs_pkg_vulnerabilities == NULL) | |
108 | errx(EXIT_FAILURE, | 108 | errx(EXIT_FAILURE, | |
109 | "At least GPG or CERTIFICATE_ANCHOR_PKGVULN " | 109 | "At least GPG or CERTIFICATE_ANCHOR_PKGVULN " | |
110 | "must be configured"); | 110 | "must be configured"); | |
111 | if (gpg_cmd != NULL) | 111 | if (gpg_cmd != NULL) | |
112 | inline_gpg_verify(input, input_len, gpg_keyring_pkgvuln); | 112 | inline_gpg_verify(input, input_len, gpg_keyring_pkgvuln); | |
113 | if (certs_pkg_vulnerabilities != NULL) | 113 | if (certs_pkg_vulnerabilities != NULL) | |
114 | verify_signature_pkcs7(input); | 114 | verify_signature_pkcs7(input); | |
115 | } | 115 | } | |
116 | 116 | |||
117 | static void * | 117 | static void * | |
118 | sha512_hash_init(void) | 118 | sha512_hash_init(void) | |
119 | { | 119 | { | |
120 | static SHA512_CTX hash_ctx; | 120 | static SHA512_CTX hash_ctx; | |
121 | 121 | |||
122 | SHA512_Init(&hash_ctx); | 122 | SHA512_Init(&hash_ctx); | |
123 | return &hash_ctx; | 123 | return &hash_ctx; | |
124 | } | 124 | } | |
125 | 125 | |||
126 | static void | 126 | static void | |
127 | sha512_hash_update(void *ctx, const void *data, size_t len) | 127 | sha512_hash_update(void *ctx, const void *data, size_t len) | |
128 | { | 128 | { | |
129 | SHA512_CTX *hash_ctx = ctx; | 129 | SHA512_CTX *hash_ctx = ctx; | |
130 | 130 | |||
131 | SHA512_Update(hash_ctx, data, len); | 131 | SHA512_Update(hash_ctx, data, len); | |
132 | } | 132 | } | |
133 | 133 | |||
134 | static const char * | 134 | static const char * | |
135 | sha512_hash_finish(void *ctx) | 135 | sha512_hash_finish(void *ctx) | |
136 | { | 136 | { | |
137 | static char hash[SHA512_DIGEST_STRING_LENGTH]; | 137 | static char hash[SHA512_DIGEST_STRING_LENGTH]; | |
138 | unsigned char digest[SHA512_DIGEST_LENGTH]; | 138 | unsigned char digest[SHA512_DIGEST_LENGTH]; | |
139 | SHA512_CTX *hash_ctx = ctx; | 139 | SHA512_CTX *hash_ctx = ctx; | |
140 | int i; | 140 | int i; | |
141 | 141 | |||
142 | SHA512_Final(digest, hash_ctx); | 142 | SHA512_Final(digest, hash_ctx); | |
143 | for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) { | 143 | for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) { | |
144 | unsigned char c; | 144 | unsigned char c; | |
145 | 145 | |||
146 | c = digest[i] / 16; | 146 | c = digest[i] / 16; | |
147 | if (c < 10) | 147 | if (c < 10) | |
148 | hash[2 * i] = '0' + c; | 148 | hash[2 * i] = '0' + c; | |
149 | else | 149 | else | |
150 | hash[2 * i] = 'a' - 10 + c; | 150 | hash[2 * i] = 'a' - 10 + c; | |
151 | 151 | |||
152 | c = digest[i] % 16; | 152 | c = digest[i] % 16; | |
153 | if (c < 10) | 153 | if (c < 10) | |
154 | hash[2 * i + 1] = '0' + c; | 154 | hash[2 * i + 1] = '0' + c; | |
155 | else | 155 | else | |
156 | hash[2 * i + 1] = 'a' - 10 + c; | 156 | hash[2 * i + 1] = 'a' - 10 + c; | |
157 | } | 157 | } | |
158 | hash[2 * i] = '\0'; | 158 | hash[2 * i] = '\0'; | |
159 | 159 | |||
160 | return hash; | 160 | return hash; | |
161 | } | 161 | } | |
162 | 162 | |||
163 | static void * | 163 | static void * | |
164 | sha1_hash_init(void) | 164 | sha1_hash_init(void) | |
165 | { | 165 | { | |
166 | static SHA1_CTX hash_ctx; | 166 | static SHA1_CTX hash_ctx; | |
167 | 167 | |||
168 | SHA1Init(&hash_ctx); | 168 | SHA1Init(&hash_ctx); | |
169 | return &hash_ctx; | 169 | return &hash_ctx; | |
170 | } | 170 | } | |
171 | 171 | |||
172 | static void | 172 | static void | |
173 | sha1_hash_update(void *ctx, const void *data, size_t len) | 173 | sha1_hash_update(void *ctx, const void *data, size_t len) | |
174 | { | 174 | { | |
175 | SHA1_CTX *hash_ctx = ctx; | 175 | SHA1_CTX *hash_ctx = ctx; | |
176 | 176 | |||
177 | SHA1Update(hash_ctx, data, len); | 177 | SHA1Update(hash_ctx, data, len); | |
178 | } | 178 | } | |
179 | 179 | |||
180 | static const char * | 180 | static const char * | |
181 | sha1_hash_finish(void *ctx) | 181 | sha1_hash_finish(void *ctx) | |
182 | { | 182 | { | |
183 | static char hash[SHA1_DIGEST_STRING_LENGTH]; | 183 | static char hash[SHA1_DIGEST_STRING_LENGTH]; | |
184 | SHA1_CTX *hash_ctx = ctx; | 184 | SHA1_CTX *hash_ctx = ctx; | |
185 | 185 | |||
186 | SHA1End(hash_ctx, hash); | 186 | SHA1End(hash_ctx, hash); | |
187 | 187 | |||
188 | return hash; | 188 | return hash; | |
189 | } | 189 | } | |
190 | 190 | |||
191 | static const struct hash_algorithm { | 191 | static const struct hash_algorithm { | |
192 | const char *name; | 192 | const char *name; | |
193 | size_t name_len; | 193 | size_t name_len; | |
194 | void * (*init)(void); | 194 | void * (*init)(void); | |
195 | void (*update)(void *, const void *, size_t); | 195 | void (*update)(void *, const void *, size_t); | |
196 | const char * (* finish)(void *); | 196 | const char * (* finish)(void *); | |
197 | } hash_algorithms[] = { | 197 | } hash_algorithms[] = { | |
198 | { "SHA512", 6, sha512_hash_init, sha512_hash_update, | 198 | { "SHA512", 6, sha512_hash_init, sha512_hash_update, | |
199 | sha512_hash_finish }, | 199 | sha512_hash_finish }, | |
200 | { "SHA1", 4, sha1_hash_init, sha1_hash_update, | 200 | { "SHA1", 4, sha1_hash_init, sha1_hash_update, | |
201 | sha1_hash_finish }, | 201 | sha1_hash_finish }, | |
202 | { NULL, 0, NULL, NULL, NULL } | 202 | { NULL, 0, NULL, NULL, NULL } | |
203 | }; | 203 | }; | |
204 | 204 | |||
205 | static void | 205 | static void | |
206 | verify_hash(const char *input, const char *hash_line) | 206 | verify_hash(const char *input, const char *hash_line) | |
207 | { | 207 | { | |
208 | const struct hash_algorithm *hash; | 208 | const struct hash_algorithm *hash; | |
209 | void *ctx; | 209 | void *ctx; | |
210 | const char *last_start, *next, *hash_value; | 210 | const char *last_start, *next, *hash_value; | |
211 | int in_pgp_msg; | 211 | int in_pgp_msg; | |
212 | 212 | |||
213 | for (hash = hash_algorithms; hash->name != NULL; ++hash) { | 213 | for (hash = hash_algorithms; hash->name != NULL; ++hash) { | |
214 | if (strncmp(hash_line, hash->name, hash->name_len)) | 214 | if (strncmp(hash_line, hash->name, hash->name_len)) | |
215 | continue; | 215 | continue; | |
216 | if (isspace((unsigned char)hash_line[hash->name_len])) | 216 | if (isspace((unsigned char)hash_line[hash->name_len])) | |
217 | break; | 217 | break; | |
218 | } | 218 | } | |
219 | if (hash->name == NULL) { | 219 | if (hash->name == NULL) { | |
220 | const char *end_name; | 220 | const char *end_name; | |
221 | for (end_name = hash_line; *end_name != '\0'; ++end_name) { | 221 | for (end_name = hash_line; *end_name != '\0'; ++end_name) { | |
222 | if (!isalnum((unsigned char)*end_name)) | 222 | if (!isalnum((unsigned char)*end_name)) | |
223 | break; | 223 | break; | |
224 | } | 224 | } | |
225 | warnx("Unsupported hash algorithm: %.*s", | 225 | warnx("Unsupported hash algorithm: %.*s", | |
226 | (int)(end_name - hash_line), hash_line); | 226 | (int)(end_name - hash_line), hash_line); | |
227 | return; | 227 | return; | |
228 | } | 228 | } | |
229 | 229 | |||
230 | hash_line += hash->name_len; | 230 | hash_line += hash->name_len; | |
231 | if (!isspace((unsigned char)*hash_line)) | 231 | if (!isspace((unsigned char)*hash_line)) | |
232 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | 232 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | |
233 | while (isspace((unsigned char)*hash_line) && *hash_line != '\n') | 233 | while (isspace((unsigned char)*hash_line) && *hash_line != '\n') | |
234 | ++hash_line; | 234 | ++hash_line; | |
235 | 235 | |||
236 | if (*hash_line == '\n') | 236 | if (*hash_line == '\n') | |
237 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | 237 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | |
238 | 238 | |||
239 | ctx = (*hash->init)(); | 239 | ctx = (*hash->init)(); | |
240 | if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { | 240 | if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { | |
241 | input += strlen(pgp_msg_start); | 241 | input += strlen(pgp_msg_start); | |
242 | in_pgp_msg = 1; | 242 | in_pgp_msg = 1; | |
243 | } else { | 243 | } else { | |
244 | in_pgp_msg = 0; | 244 | in_pgp_msg = 0; | |
245 | } | 245 | } | |
246 | for (last_start = input; *input != '\0'; input = next) { | 246 | for (last_start = input; *input != '\0'; input = next) { | |
247 | if ((next = strchr(input, '\n')) == NULL) | 247 | if ((next = strchr(input, '\n')) == NULL) | |
248 | errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); | 248 | errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); | |
249 | ++next; | 249 | ++next; | |
250 | if (in_pgp_msg && strncmp(input, pgp_msg_end, strlen(pgp_msg_end)) == 0) | 250 | if (in_pgp_msg && strncmp(input, pgp_msg_end, strlen(pgp_msg_end)) == 0) | |
251 | break; | 251 | break; | |
252 | if (!in_pgp_msg && strncmp(input, pkcs7_begin, strlen(pkcs7_begin)) == 0) | 252 | if (!in_pgp_msg && strncmp(input, pkcs7_begin, strlen(pkcs7_begin)) == 0) | |
253 | break; | 253 | break; | |
254 | if (*input == '\n' || | 254 | if (*input == '\n' || | |
255 | strncmp(input, "Hash:", 5) == 0 || | 255 | strncmp(input, "Hash:", 5) == 0 || | |
256 | strncmp(input, "# $NetBSD", 9) == 0 || | 256 | strncmp(input, "# $NetBSD", 9) == 0 || | |
257 | strncmp(input, "#CHECKSUM", 9) == 0) { | 257 | strncmp(input, "#CHECKSUM", 9) == 0) { | |
258 | (*hash->update)(ctx, last_start, input - last_start); | 258 | (*hash->update)(ctx, last_start, input - last_start); | |
259 | last_start = next; | 259 | last_start = next; | |
260 | } | 260 | } | |
261 | } | 261 | } | |
262 | (*hash->update)(ctx, last_start, input - last_start); | 262 | (*hash->update)(ctx, last_start, input - last_start); | |
263 | hash_value = (*hash->finish)(ctx); | 263 | hash_value = (*hash->finish)(ctx); | |
264 | if (strncmp(hash_line, hash_value, strlen(hash_value))) | 264 | if (strncmp(hash_line, hash_value, strlen(hash_value))) | |
265 | errx(EXIT_FAILURE, "%s hash doesn't match", hash->name); | 265 | errx(EXIT_FAILURE, "%s hash doesn't match", hash->name); | |
266 | hash_line += strlen(hash_value); | 266 | hash_line += strlen(hash_value); | |
267 | 267 | |||
268 | while (isspace((unsigned char)*hash_line) && *hash_line != '\n') | 268 | while (isspace((unsigned char)*hash_line) && *hash_line != '\n') | |
269 | ++hash_line; | 269 | ++hash_line; | |
270 | 270 | |||
271 | if (!isspace((unsigned char)*hash_line)) | 271 | if (!isspace((unsigned char)*hash_line)) | |
272 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | 272 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | |
273 | } | 273 | } | |
274 | 274 | |||
275 | static void | 275 | static void | |
276 | add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *line) | 276 | add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *line) | |
277 | { | 277 | { | |
278 | size_t len_pattern, len_class, len_url; | 278 | size_t len_pattern, len_class, len_url; | |
279 | const char *start_pattern, *start_class, *start_url; | 279 | const char *start_pattern, *start_class, *start_url; | |
280 | 280 | |||
281 | start_pattern = line; | 281 | start_pattern = line; | |
282 | 282 | |||
283 | start_class = line; | 283 | start_class = line; | |
284 | while (*start_class != '\0' && !isspace((unsigned char)*start_class)) | 284 | while (*start_class != '\0' && !isspace((unsigned char)*start_class)) | |
285 | ++start_class; | 285 | ++start_class; | |
286 | len_pattern = start_class - line; | 286 | len_pattern = start_class - line; | |
287 | 287 | |||
288 | while (*start_class != '\n' && isspace((unsigned char)*start_class)) | 288 | while (*start_class != '\n' && isspace((unsigned char)*start_class)) | |
289 | ++start_class; | 289 | ++start_class; | |
290 | 290 | |||
291 | if (*start_class == '0' || *start_class == '\n') | 291 | if (*start_class == '0' || *start_class == '\n') | |
292 | errx(EXIT_FAILURE, "Input error: missing classification"); | 292 | errx(EXIT_FAILURE, "Input error: missing classification"); | |
293 | 293 | |||
294 | start_url = start_class; | 294 | start_url = start_class; | |
295 | while (*start_url != '\0' && !isspace((unsigned char)*start_url)) | 295 | while (*start_url != '\0' && !isspace((unsigned char)*start_url)) | |
296 | ++start_url; | 296 | ++start_url; | |
297 | len_class = start_url - start_class; | 297 | len_class = start_url - start_class; | |
298 | 298 | |||
299 | while (*start_url != '\n' && isspace((unsigned char)*start_url)) | 299 | while (*start_url != '\n' && isspace((unsigned char)*start_url)) | |
300 | ++start_url; | 300 | ++start_url; | |
301 | 301 | |||
302 | if (*start_url == '0' || *start_url == '\n') | 302 | if (*start_url == '0' || *start_url == '\n') | |
303 | errx(EXIT_FAILURE, "Input error: missing URL"); | 303 | errx(EXIT_FAILURE, "Input error: missing URL"); | |
304 | 304 | |||
305 | line = start_url; | 305 | line = start_url; | |
306 | while (*line != '\0' && !isspace((unsigned char)*line)) | 306 | while (*line != '\0' && !isspace((unsigned char)*line)) | |
307 | ++line; | 307 | ++line; | |
308 | len_url = line - start_url; | 308 | len_url = line - start_url; | |
309 | 309 | |||
310 | if (pv->entries == *allocated) { | 310 | if (pv->entries == *allocated) { | |
311 | if (*allocated == 0) | 311 | if (*allocated == 0) | |
312 | *allocated = 16; | 312 | *allocated = 16; | |
313 | else if (*allocated <= SSIZE_MAX / 2) | 313 | else if (*allocated <= SSIZE_MAX / 2) | |
314 | *allocated *= 2; | 314 | *allocated *= 2; | |
315 | else | 315 | else | |
316 | errx(EXIT_FAILURE, "Too many vulnerabilities"); | 316 | errx(EXIT_FAILURE, "Too many vulnerabilities"); | |
317 | pv->vulnerability = xrealloc(pv->vulnerability, | 317 | pv->vulnerability = xrealloc(pv->vulnerability, | |
318 | sizeof(char *) * *allocated); | 318 | sizeof(char *) * *allocated); | |
319 | pv->classification = xrealloc(pv->classification, | 319 | pv->classification = xrealloc(pv->classification, | |
320 | sizeof(char *) * *allocated); | 320 | sizeof(char *) * *allocated); | |
321 | pv->advisory = xrealloc(pv->advisory, | 321 | pv->advisory = xrealloc(pv->advisory, | |
322 | sizeof(char *) * *allocated); | 322 | sizeof(char *) * *allocated); | |
323 | } | 323 | } | |
324 | 324 | |||
325 | pv->vulnerability[pv->entries] = xmalloc(len_pattern + 1); | 325 | pv->vulnerability[pv->entries] = xmalloc(len_pattern + 1); | |
326 | memcpy(pv->vulnerability[pv->entries], start_pattern, len_pattern); | 326 | memcpy(pv->vulnerability[pv->entries], start_pattern, len_pattern); | |
327 | pv->vulnerability[pv->entries][len_pattern] = '\0'; | 327 | pv->vulnerability[pv->entries][len_pattern] = '\0'; | |
328 | pv->classification[pv->entries] = xmalloc(len_class + 1); | 328 | pv->classification[pv->entries] = xmalloc(len_class + 1); | |
329 | memcpy(pv->classification[pv->entries], start_class, len_class); | 329 | memcpy(pv->classification[pv->entries], start_class, len_class); | |
330 | pv->classification[pv->entries][len_class] = '\0'; | 330 | pv->classification[pv->entries][len_class] = '\0'; | |
331 | pv->advisory[pv->entries] = xmalloc(len_url + 1); | 331 | pv->advisory[pv->entries] = xmalloc(len_url + 1); | |
332 | memcpy(pv->advisory[pv->entries], start_url, len_url); | 332 | memcpy(pv->advisory[pv->entries], start_url, len_url); | |
333 | pv->advisory[pv->entries][len_url] = '\0'; | 333 | pv->advisory[pv->entries][len_url] = '\0'; | |
334 | 334 | |||
335 | ++pv->entries; | 335 | ++pv->entries; | |
336 | } | 336 | } | |
337 | 337 | |||
338 | struct pkg_vulnerabilities * | 338 | struct pkg_vulnerabilities * | |
339 | read_pkg_vulnerabilities(const char *path, int ignore_missing, int check_sum) | 339 | read_pkg_vulnerabilities(const char *path, int ignore_missing, int check_sum) | |
340 | { | 340 | { | |
341 | struct pkg_vulnerabilities *pv; | 341 | struct pkg_vulnerabilities *pv; | |
342 | struct stat st; | 342 | struct stat st; | |
343 | int fd; | 343 | int fd; | |
344 | char *input, *decompressed_input; | 344 | char *input, *decompressed_input; | |
345 | size_t input_len, decompressed_len; | 345 | size_t input_len, decompressed_len; | |
346 | ssize_t bytes_read; | 346 | ssize_t bytes_read; | |
347 | 347 | |||
348 | if ((fd = open(path, O_RDONLY)) == -1) { | 348 | if ((fd = open(path, O_RDONLY)) == -1) { | |
349 | if (errno == ENOENT && ignore_missing) | 349 | if (errno == ENOENT && ignore_missing) | |
350 | return NULL; | 350 | return NULL; | |
351 | err(EXIT_FAILURE, "Cannot open %s", path); | 351 | err(EXIT_FAILURE, "Cannot open %s", path); | |
352 | } | 352 | } | |
353 | 353 | |||
354 | if (fstat(fd, &st) == -1) | 354 | if (fstat(fd, &st) == -1) | |
355 | err(EXIT_FAILURE, "Cannot stat %s", path); | 355 | err(EXIT_FAILURE, "Cannot stat %s", path); | |
356 | 356 | |||
357 | if ((st.st_mode & S_IFMT) != S_IFREG) | 357 | if ((st.st_mode & S_IFMT) != S_IFREG) | |
358 | errx(EXIT_FAILURE, "Input is not regular file"); | 358 | errx(EXIT_FAILURE, "Input is not regular file"); | |
359 | if (st.st_size > SSIZE_MAX - 1) | 359 | if (st.st_size > SSIZE_MAX - 1) | |
360 | errx(EXIT_FAILURE, "Input too large"); | 360 | errx(EXIT_FAILURE, "Input too large"); | |
361 | 361 | |||
362 | input_len = (size_t)st.st_size; | 362 | input_len = (size_t)st.st_size; | |
363 | if (input_len < 4) | 363 | if (input_len < 4) | |
364 | err(EXIT_FAILURE, "Input too short for a pkg_vulnerability file"); | 364 | err(EXIT_FAILURE, "Input too short for a pkg_vulnerability file"); | |
365 | input = xmalloc(input_len + 1); | 365 | input = xmalloc(input_len + 1); | |
366 | if ((bytes_read = read(fd, input, input_len)) == -1) | 366 | if ((bytes_read = read(fd, input, input_len)) == -1) | |
367 | err(1, "Failed to read input"); | 367 | err(1, "Failed to read input"); | |
368 | if (bytes_read != st.st_size) | 368 | if (bytes_read != st.st_size) | |
369 | errx(1, "Unexpected short read"); | 369 | errx(1, "Unexpected short read"); | |
370 | 370 | |||
371 | close(fd); | |||
372 | ||||
371 | if (decompress_buffer(input, input_len, &decompressed_input, | 373 | if (decompress_buffer(input, input_len, &decompressed_input, | |
372 | &decompressed_len)) { | 374 | &decompressed_len)) { | |
373 | free(input); | 375 | free(input); | |
374 | input = decompressed_input; | 376 | input = decompressed_input; | |
375 | input_len = decompressed_len; | 377 | input_len = decompressed_len; | |
376 | } | 378 | } | |
377 | pv = parse_pkg_vulnerabilities(input, input_len, check_sum); | 379 | pv = parse_pkg_vulnerabilities(input, input_len, check_sum); | |
378 | free(input); | 380 | free(input); | |
379 | 381 | |||
380 | return pv; | 382 | return pv; | |
381 | } | 383 | } | |
382 | 384 | |||
383 | struct pkg_vulnerabilities * | 385 | struct pkg_vulnerabilities * | |
384 | parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum) | 386 | parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum) | |
385 | { | 387 | { | |
386 | struct pkg_vulnerabilities *pv; | 388 | struct pkg_vulnerabilities *pv; | |
387 | long version; | 389 | long version; | |
388 | char *end; | 390 | char *end; | |
389 | const char *iter, *next; | 391 | const char *iter, *next; | |
390 | size_t allocated_vulns; | 392 | size_t allocated_vulns; | |
391 | int in_pgp_msg; | 393 | int in_pgp_msg; | |
392 | 394 | |||
393 | pv = xmalloc(sizeof(*pv)); | 395 | pv = xmalloc(sizeof(*pv)); | |
394 | 396 | |||
395 | allocated_vulns = pv->entries = 0; | 397 | allocated_vulns = pv->entries = 0; | |
396 | pv->vulnerability = NULL; | 398 | pv->vulnerability = NULL; | |
397 | pv->classification = NULL; | 399 | pv->classification = NULL; | |
398 | pv->advisory = NULL; | 400 | pv->advisory = NULL; | |
399 | 401 | |||
400 | if (strlen(input) != input_len) | 402 | if (strlen(input) != input_len) | |
401 | errx(1, "Invalid input (NUL character found)"); | 403 | errx(1, "Invalid input (NUL character found)"); | |
402 | 404 | |||
403 | if (check_sum) | 405 | if (check_sum) | |
404 | verify_signature(input, input_len); | 406 | verify_signature(input, input_len); | |
405 | 407 | |||
406 | if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { | 408 | if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { | |
407 | iter = input + strlen(pgp_msg_start); | 409 | iter = input + strlen(pgp_msg_start); | |
408 | in_pgp_msg = 1; | 410 | in_pgp_msg = 1; | |
409 | } else { | 411 | } else { | |
410 | iter = input; | 412 | iter = input; | |
411 | in_pgp_msg = 0; | 413 | in_pgp_msg = 0; | |
412 | } | 414 | } | |
413 | 415 | |||
414 | for (; *iter; iter = next) { | 416 | for (; *iter; iter = next) { | |
415 | if ((next = strchr(iter, '\n')) == NULL) | 417 | if ((next = strchr(iter, '\n')) == NULL) | |
416 | errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); | 418 | errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); | |
417 | ++next; | 419 | ++next; | |
418 | if (*iter == '\0' || *iter == '\n') | 420 | if (*iter == '\0' || *iter == '\n') | |
419 | continue; | 421 | continue; | |
420 | if (strncmp(iter, "Hash:", 5) == 0) | 422 | if (strncmp(iter, "Hash:", 5) == 0) | |
421 | continue; | 423 | continue; | |
422 | if (strncmp(iter, "# $NetBSD", 9) == 0) | 424 | if (strncmp(iter, "# $NetBSD", 9) == 0) | |
423 | continue; | 425 | continue; | |
424 | if (*iter == '#' && isspace((unsigned char)iter[1])) { | 426 | if (*iter == '#' && isspace((unsigned char)iter[1])) { | |
425 | for (++iter; iter != next; ++iter) { | 427 | for (++iter; iter != next; ++iter) { | |
426 | if (!isspace((unsigned char)*iter)) | 428 | if (!isspace((unsigned char)*iter)) | |
427 | errx(EXIT_FAILURE, "Invalid header"); | 429 | errx(EXIT_FAILURE, "Invalid header"); | |
428 | } | 430 | } | |
429 | continue; | 431 | continue; | |
430 | } | 432 | } | |
431 | 433 | |||
432 | if (strncmp(iter, "#FORMAT", 7) != 0) | 434 | if (strncmp(iter, "#FORMAT", 7) != 0) | |
433 | errx(EXIT_FAILURE, "Input header is malformed"); | 435 | errx(EXIT_FAILURE, "Input header is malformed"); | |
434 | 436 | |||
435 | iter += 7; | 437 | iter += 7; | |
436 | if (!isspace((unsigned char)*iter)) | 438 | if (!isspace((unsigned char)*iter)) | |
437 | errx(EXIT_FAILURE, "Invalid #FORMAT"); | 439 | errx(EXIT_FAILURE, "Invalid #FORMAT"); | |
438 | ++iter; | 440 | ++iter; | |
439 | version = strtol(iter, &end, 10); | 441 | version = strtol(iter, &end, 10); | |
440 | if (iter == end || version != 1 || *end != '.') | 442 | if (iter == end || version != 1 || *end != '.') | |
441 | errx(EXIT_FAILURE, "Input #FORMAT"); | 443 | errx(EXIT_FAILURE, "Input #FORMAT"); | |
442 | iter = end + 1; | 444 | iter = end + 1; | |
443 | version = strtol(iter, &end, 10); | 445 | version = strtol(iter, &end, 10); | |
444 | if (iter == end || version != 1 || *end != '.') | 446 | if (iter == end || version != 1 || *end != '.') | |
445 | errx(EXIT_FAILURE, "Input #FORMAT"); | 447 | errx(EXIT_FAILURE, "Input #FORMAT"); | |
446 | iter = end + 1; | 448 | iter = end + 1; | |
447 | version = strtol(iter, &end, 10); | 449 | version = strtol(iter, &end, 10); | |
448 | if (iter == end || version != 0) | 450 | if (iter == end || version != 0) | |
449 | errx(EXIT_FAILURE, "Input #FORMAT"); | 451 | errx(EXIT_FAILURE, "Input #FORMAT"); | |
450 | for (iter = end; iter != next; ++iter) { | 452 | for (iter = end; iter != next; ++iter) { | |
451 | if (!isspace((unsigned char)*iter)) | 453 | if (!isspace((unsigned char)*iter)) | |
452 | errx(EXIT_FAILURE, "Input #FORMAT"); | 454 | errx(EXIT_FAILURE, "Input #FORMAT"); | |
453 | } | 455 | } | |
454 | break; | 456 | break; | |
455 | } | 457 | } | |
456 | if (*iter == '\0') | 458 | if (*iter == '\0') | |
457 | errx(EXIT_FAILURE, "Missing #CHECKSUM or content"); | 459 | errx(EXIT_FAILURE, "Missing #CHECKSUM or content"); | |
458 | 460 | |||
459 | for (iter = next; *iter; iter = next) { | 461 | for (iter = next; *iter; iter = next) { | |
460 | if ((next = strchr(iter, '\n')) == NULL) | 462 | if ((next = strchr(iter, '\n')) == NULL) | |
461 | errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); | 463 | errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); | |
462 | ++next; | 464 | ++next; | |
463 | if (*iter == '\0' || *iter == '\n') | 465 | if (*iter == '\0' || *iter == '\n') | |
464 | continue; | 466 | continue; | |
465 | if (in_pgp_msg && strncmp(iter, pgp_msg_end, strlen(pgp_msg_end)) == 0) | 467 | if (in_pgp_msg && strncmp(iter, pgp_msg_end, strlen(pgp_msg_end)) == 0) | |
466 | break; | 468 | break; | |
467 | if (!in_pgp_msg && strncmp(iter, pkcs7_begin, strlen(pkcs7_begin)) == 0) | 469 | if (!in_pgp_msg && strncmp(iter, pkcs7_begin, strlen(pkcs7_begin)) == 0) | |
468 | break; | 470 | break; | |
469 | if (*iter == '#' && | 471 | if (*iter == '#' && | |
470 | (iter[1] == '\0' || iter[1] == '\n' || isspace((unsigned char)iter[1]))) | 472 | (iter[1] == '\0' || iter[1] == '\n' || isspace((unsigned char)iter[1]))) | |
471 | continue; | 473 | continue; | |
472 | if (strncmp(iter, "#CHECKSUM", 9) == 0) { | 474 | if (strncmp(iter, "#CHECKSUM", 9) == 0) { | |
473 | iter += 9; | 475 | iter += 9; | |
474 | if (!isspace((unsigned char)*iter)) | 476 | if (!isspace((unsigned char)*iter)) | |
475 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | 477 | errx(EXIT_FAILURE, "Invalid #CHECKSUM"); | |
476 | while (isspace((unsigned char)*iter)) | 478 | while (isspace((unsigned char)*iter)) | |
477 | ++iter; | 479 | ++iter; | |
478 | verify_hash(input, iter); | 480 | verify_hash(input, iter); | |
479 | continue; | 481 | continue; | |
480 | } | 482 | } | |
481 | if (*iter == '#') { | 483 | if (*iter == '#') { | |
482 | /* | 484 | /* | |
483 | * This should really be an error, | 485 | * This should really be an error, | |
484 | * but it is still used. | 486 | * but it is still used. | |
485 | */ | 487 | */ | |
486 | /* errx(EXIT_FAILURE, "Invalid data line starting with #"); */ | 488 | /* errx(EXIT_FAILURE, "Invalid data line starting with #"); */ | |
487 | continue; | 489 | continue; | |
488 | } | 490 | } | |
489 | add_vulnerability(pv, &allocated_vulns, iter); | 491 | add_vulnerability(pv, &allocated_vulns, iter); | |
490 | } | 492 | } | |
491 | 493 | |||
492 | if (pv->entries != allocated_vulns) { | 494 | if (pv->entries != allocated_vulns) { | |
493 | pv->vulnerability = xrealloc(pv->vulnerability, | 495 | pv->vulnerability = xrealloc(pv->vulnerability, | |
494 | sizeof(char *) * pv->entries); | 496 | sizeof(char *) * pv->entries); | |
495 | pv->classification = xrealloc(pv->classification, | 497 | pv->classification = xrealloc(pv->classification, | |
496 | sizeof(char *) * pv->entries); | 498 | sizeof(char *) * pv->entries); | |
497 | pv->advisory = xrealloc(pv->advisory, | 499 | pv->advisory = xrealloc(pv->advisory, | |
498 | sizeof(char *) * pv->entries); | 500 | sizeof(char *) * pv->entries); | |
499 | } | 501 | } | |
500 | 502 | |||
501 | return pv; | 503 | return pv; | |
502 | } | 504 | } | |
503 | 505 | |||
504 | void | 506 | void | |
505 | free_pkg_vulnerabilities(struct pkg_vulnerabilities *pv) | 507 | free_pkg_vulnerabilities(struct pkg_vulnerabilities *pv) | |
506 | { | 508 | { | |
507 | size_t i; | 509 | size_t i; | |
508 | 510 | |||
509 | for (i = 0; i < pv->entries; ++i) { | 511 | for (i = 0; i < pv->entries; ++i) { | |
510 | free(pv->vulnerability[i]); | 512 | free(pv->vulnerability[i]); | |
511 | free(pv->classification[i]); | 513 | free(pv->classification[i]); | |
512 | free(pv->advisory[i]); | 514 | free(pv->advisory[i]); | |
513 | } | 515 | } | |
514 | free(pv->vulnerability); | 516 | free(pv->vulnerability); | |
515 | free(pv->classification); | 517 | free(pv->classification); | |
516 | free(pv->advisory); | 518 | free(pv->advisory); | |
517 | free(pv); | 519 | free(pv); | |
518 | } | 520 | } | |
519 | 521 | |||
520 | static int | 522 | static int | |
521 | check_ignored_entry(struct pkg_vulnerabilities *pv, size_t i) | 523 | check_ignored_entry(struct pkg_vulnerabilities *pv, size_t i) | |
522 | { | 524 | { | |
523 | const char *iter, *next; | 525 | const char *iter, *next; | |
524 | size_t entry_len, url_len; | 526 | size_t entry_len, url_len; | |
525 | 527 | |||
526 | if (ignore_advisories == NULL) | 528 | if (ignore_advisories == NULL) | |
527 | return 0; | 529 | return 0; | |
528 | 530 | |||
529 | url_len = strlen(pv->advisory[i]); | 531 | url_len = strlen(pv->advisory[i]); | |
530 | 532 | |||
531 | for (iter = ignore_advisories; *iter; iter = next) { | 533 | for (iter = ignore_advisories; *iter; iter = next) { | |
532 | if ((next = strchr(iter, '\n')) == NULL) { | 534 | if ((next = strchr(iter, '\n')) == NULL) { | |
533 | entry_len = strlen(iter); | 535 | entry_len = strlen(iter); | |
534 | next = iter + entry_len; | 536 | next = iter + entry_len; | |
535 | } else { | 537 | } else { | |
536 | entry_len = next - iter; | 538 | entry_len = next - iter; | |
537 | ++next; | 539 | ++next; | |
538 | } | 540 | } | |
539 | if (url_len != entry_len) | 541 | if (url_len != entry_len) | |
540 | continue; | 542 | continue; | |
541 | if (strncmp(pv->advisory[i], iter, entry_len) == 0) | 543 | if (strncmp(pv->advisory[i], iter, entry_len) == 0) | |
542 | return 1; | 544 | return 1; | |
543 | } | 545 | } | |
544 | return 0; | 546 | return 0; | |
545 | } | 547 | } | |
546 | 548 | |||
547 | int | 549 | int | |
548 | audit_package(struct pkg_vulnerabilities *pv, const char *pkgname, | 550 | audit_package(struct pkg_vulnerabilities *pv, const char *pkgname, | |
549 | const char *limit_vul_types, int check_eol, int output_type) | 551 | const char *limit_vul_types, int check_eol, int output_type) | |
550 | { | 552 | { | |
551 | FILE *output = output_type == 1 ? stdout : stderr; | 553 | FILE *output = output_type == 1 ? stdout : stderr; | |
552 | size_t i; | 554 | size_t i; | |
553 | int retval; | 555 | int retval; | |
554 | 556 | |||
555 | retval = 0; | 557 | retval = 0; | |
556 | 558 | |||
557 | for (i = 0; i < pv->entries; ++i) { | 559 | for (i = 0; i < pv->entries; ++i) { | |
558 | if (check_ignored_entry(pv, i)) | 560 | if (check_ignored_entry(pv, i)) | |
559 | continue; | 561 | continue; | |
560 | if (limit_vul_types != NULL && | 562 | if (limit_vul_types != NULL && | |
561 | strcmp(limit_vul_types, pv->classification[i])) | 563 | strcmp(limit_vul_types, pv->classification[i])) | |
562 | continue; | 564 | continue; | |
563 | if (!pkg_match(pv->vulnerability[i], pkgname)) | 565 | if (!pkg_match(pv->vulnerability[i], pkgname)) | |
564 | continue; | 566 | continue; | |
565 | if (strcmp("eol", pv->classification[i]) == 0) { | 567 | if (strcmp("eol", pv->classification[i]) == 0) { | |
566 | if (!check_eol) | 568 | if (!check_eol) | |
567 | continue; | 569 | continue; | |
568 | if (output_type == 0) { | 570 | if (output_type == 0) { | |
569 | puts(pkgname); | 571 | puts(pkgname); | |
570 | continue; | 572 | continue; | |
571 | } | 573 | } | |
572 | fprintf(output, | 574 | fprintf(output, | |
573 | "Package %s has reached end-of-life (eol), " | 575 | "Package %s has reached end-of-life (eol), " | |
574 | "see %s/eol-packages\n", pkgname, | 576 | "see %s/eol-packages\n", pkgname, | |
575 | tnf_vulnerability_base); | 577 | tnf_vulnerability_base); | |
576 | continue; | 578 | continue; | |
577 | } | 579 | } | |
578 | retval = 1; | 580 | retval = 1; | |
579 | if (output_type == 0) { | 581 | if (output_type == 0) { | |
580 | puts(pkgname); | 582 | puts(pkgname); | |
581 | } else { | 583 | } else { | |
582 | fprintf(output, | 584 | fprintf(output, | |
583 | "Package %s has a %s vulnerability, see %s\n", | 585 | "Package %s has a %s vulnerability, see %s\n", | |
584 | pkgname, pv->classification[i], pv->advisory[i]); | 586 | pkgname, pv->classification[i], pv->advisory[i]); | |
585 | } | 587 | } | |
586 | } | 588 | } | |
587 | return retval; | 589 | return retval; | |
588 | } | 590 | } |