1*a824f5a1SJean-Baptiste Boric /* $NetBSD: audit.c,v 1.1.1.9 2011/02/18 22:32:28 aymeric Exp $ */
2*a824f5a1SJean-Baptiste Boric
3*a824f5a1SJean-Baptiste Boric #if HAVE_CONFIG_H
4*a824f5a1SJean-Baptiste Boric #include "config.h"
5*a824f5a1SJean-Baptiste Boric #endif
6*a824f5a1SJean-Baptiste Boric #include <nbcompat.h>
7*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_CDEFS_H
8*a824f5a1SJean-Baptiste Boric #include <sys/cdefs.h>
9*a824f5a1SJean-Baptiste Boric #endif
10*a824f5a1SJean-Baptiste Boric __RCSID("$NetBSD: audit.c,v 1.1.1.9 2011/02/18 22:32:28 aymeric Exp $");
11*a824f5a1SJean-Baptiste Boric
12*a824f5a1SJean-Baptiste Boric /*-
13*a824f5a1SJean-Baptiste Boric * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
14*a824f5a1SJean-Baptiste Boric * All rights reserved.
15*a824f5a1SJean-Baptiste Boric *
16*a824f5a1SJean-Baptiste Boric * Redistribution and use in source and binary forms, with or without
17*a824f5a1SJean-Baptiste Boric * modification, are permitted provided that the following conditions
18*a824f5a1SJean-Baptiste Boric * are met:
19*a824f5a1SJean-Baptiste Boric *
20*a824f5a1SJean-Baptiste Boric * 1. Redistributions of source code must retain the above copyright
21*a824f5a1SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer.
22*a824f5a1SJean-Baptiste Boric * 2. Redistributions in binary form must reproduce the above copyright
23*a824f5a1SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer in
24*a824f5a1SJean-Baptiste Boric * the documentation and/or other materials provided with the
25*a824f5a1SJean-Baptiste Boric * distribution.
26*a824f5a1SJean-Baptiste Boric *
27*a824f5a1SJean-Baptiste Boric * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28*a824f5a1SJean-Baptiste Boric * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29*a824f5a1SJean-Baptiste Boric * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30*a824f5a1SJean-Baptiste Boric * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31*a824f5a1SJean-Baptiste Boric * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32*a824f5a1SJean-Baptiste Boric * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
33*a824f5a1SJean-Baptiste Boric * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34*a824f5a1SJean-Baptiste Boric * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
35*a824f5a1SJean-Baptiste Boric * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36*a824f5a1SJean-Baptiste Boric * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37*a824f5a1SJean-Baptiste Boric * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38*a824f5a1SJean-Baptiste Boric * SUCH DAMAGE.
39*a824f5a1SJean-Baptiste Boric */
40*a824f5a1SJean-Baptiste Boric
41*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_TYPES_H
42*a824f5a1SJean-Baptiste Boric #include <sys/types.h>
43*a824f5a1SJean-Baptiste Boric #endif
44*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_STAT_H
45*a824f5a1SJean-Baptiste Boric #include <sys/stat.h>
46*a824f5a1SJean-Baptiste Boric #endif
47*a824f5a1SJean-Baptiste Boric #if HAVE_ERR_H
48*a824f5a1SJean-Baptiste Boric #include <err.h>
49*a824f5a1SJean-Baptiste Boric #endif
50*a824f5a1SJean-Baptiste Boric #if HAVE_ERRNO_H
51*a824f5a1SJean-Baptiste Boric #include <errno.h>
52*a824f5a1SJean-Baptiste Boric #endif
53*a824f5a1SJean-Baptiste Boric #if HAVE_FCNTL_H
54*a824f5a1SJean-Baptiste Boric #include <fcntl.h>
55*a824f5a1SJean-Baptiste Boric #endif
56*a824f5a1SJean-Baptiste Boric #if HAVE_SIGNAL_H
57*a824f5a1SJean-Baptiste Boric #include <signal.h>
58*a824f5a1SJean-Baptiste Boric #endif
59*a824f5a1SJean-Baptiste Boric #if HAVE_STDIO_H
60*a824f5a1SJean-Baptiste Boric #include <stdio.h>
61*a824f5a1SJean-Baptiste Boric #endif
62*a824f5a1SJean-Baptiste Boric #if HAVE_STRING_H
63*a824f5a1SJean-Baptiste Boric #include <string.h>
64*a824f5a1SJean-Baptiste Boric #endif
65*a824f5a1SJean-Baptiste Boric #ifdef NETBSD
66*a824f5a1SJean-Baptiste Boric #include <unistd.h>
67*a824f5a1SJean-Baptiste Boric #else
68*a824f5a1SJean-Baptiste Boric #include <nbcompat/unistd.h>
69*a824f5a1SJean-Baptiste Boric #endif
70*a824f5a1SJean-Baptiste Boric
71*a824f5a1SJean-Baptiste Boric #include <fetch.h>
72*a824f5a1SJean-Baptiste Boric
73*a824f5a1SJean-Baptiste Boric #include "admin.h"
74*a824f5a1SJean-Baptiste Boric #include "lib.h"
75*a824f5a1SJean-Baptiste Boric
76*a824f5a1SJean-Baptiste Boric static int check_signature = 0;
77*a824f5a1SJean-Baptiste Boric static const char *limit_vul_types = NULL;
78*a824f5a1SJean-Baptiste Boric static int update_pkg_vuln = 0;
79*a824f5a1SJean-Baptiste Boric
80*a824f5a1SJean-Baptiste Boric static struct pkg_vulnerabilities *pv;
81*a824f5a1SJean-Baptiste Boric
82*a824f5a1SJean-Baptiste Boric static const char audit_options[] = "est:";
83*a824f5a1SJean-Baptiste Boric
84*a824f5a1SJean-Baptiste Boric static void
parse_options(int argc,char ** argv,const char * options)85*a824f5a1SJean-Baptiste Boric parse_options(int argc, char **argv, const char *options)
86*a824f5a1SJean-Baptiste Boric {
87*a824f5a1SJean-Baptiste Boric int ch;
88*a824f5a1SJean-Baptiste Boric
89*a824f5a1SJean-Baptiste Boric optreset = 1;
90*a824f5a1SJean-Baptiste Boric /*
91*a824f5a1SJean-Baptiste Boric * optind == 0 is interpreted as partial reset request
92*a824f5a1SJean-Baptiste Boric * by GNU getopt, so compensate against this and cleanup
93*a824f5a1SJean-Baptiste Boric * at the end.
94*a824f5a1SJean-Baptiste Boric */
95*a824f5a1SJean-Baptiste Boric optind = 1;
96*a824f5a1SJean-Baptiste Boric ++argc;
97*a824f5a1SJean-Baptiste Boric --argv;
98*a824f5a1SJean-Baptiste Boric
99*a824f5a1SJean-Baptiste Boric while ((ch = getopt(argc, argv, options)) != -1) {
100*a824f5a1SJean-Baptiste Boric switch (ch) {
101*a824f5a1SJean-Baptiste Boric case 'e':
102*a824f5a1SJean-Baptiste Boric check_eol = "yes";
103*a824f5a1SJean-Baptiste Boric break;
104*a824f5a1SJean-Baptiste Boric case 's':
105*a824f5a1SJean-Baptiste Boric check_signature = 1;
106*a824f5a1SJean-Baptiste Boric break;
107*a824f5a1SJean-Baptiste Boric case 't':
108*a824f5a1SJean-Baptiste Boric limit_vul_types = optarg;
109*a824f5a1SJean-Baptiste Boric break;
110*a824f5a1SJean-Baptiste Boric case 'u':
111*a824f5a1SJean-Baptiste Boric update_pkg_vuln = 1;
112*a824f5a1SJean-Baptiste Boric break;
113*a824f5a1SJean-Baptiste Boric default:
114*a824f5a1SJean-Baptiste Boric usage();
115*a824f5a1SJean-Baptiste Boric /* NOTREACHED */
116*a824f5a1SJean-Baptiste Boric }
117*a824f5a1SJean-Baptiste Boric }
118*a824f5a1SJean-Baptiste Boric
119*a824f5a1SJean-Baptiste Boric --optind; /* See above comment. */
120*a824f5a1SJean-Baptiste Boric }
121*a824f5a1SJean-Baptiste Boric
122*a824f5a1SJean-Baptiste Boric static int
check_exact_pkg(const char * pkg)123*a824f5a1SJean-Baptiste Boric check_exact_pkg(const char *pkg)
124*a824f5a1SJean-Baptiste Boric {
125*a824f5a1SJean-Baptiste Boric return audit_package(pv, pkg, limit_vul_types, quiet ? 0 : 1);
126*a824f5a1SJean-Baptiste Boric }
127*a824f5a1SJean-Baptiste Boric
128*a824f5a1SJean-Baptiste Boric static int
check_batch_exact_pkgs(const char * fname)129*a824f5a1SJean-Baptiste Boric check_batch_exact_pkgs(const char *fname)
130*a824f5a1SJean-Baptiste Boric {
131*a824f5a1SJean-Baptiste Boric FILE *f;
132*a824f5a1SJean-Baptiste Boric char buf[4096], *line, *eol;
133*a824f5a1SJean-Baptiste Boric int ret;
134*a824f5a1SJean-Baptiste Boric
135*a824f5a1SJean-Baptiste Boric ret = 0;
136*a824f5a1SJean-Baptiste Boric if (strcmp(fname, "-") == 0)
137*a824f5a1SJean-Baptiste Boric f = stdin;
138*a824f5a1SJean-Baptiste Boric else {
139*a824f5a1SJean-Baptiste Boric f = fopen(fname, "r");
140*a824f5a1SJean-Baptiste Boric if (f == NULL)
141*a824f5a1SJean-Baptiste Boric err(EXIT_FAILURE, "Failed to open input file %s",
142*a824f5a1SJean-Baptiste Boric fname);
143*a824f5a1SJean-Baptiste Boric }
144*a824f5a1SJean-Baptiste Boric while ((line = fgets(buf, sizeof(buf), f)) != NULL) {
145*a824f5a1SJean-Baptiste Boric eol = line + strlen(line);
146*a824f5a1SJean-Baptiste Boric if (eol == line)
147*a824f5a1SJean-Baptiste Boric continue;
148*a824f5a1SJean-Baptiste Boric --eol;
149*a824f5a1SJean-Baptiste Boric if (*eol == '\n') {
150*a824f5a1SJean-Baptiste Boric if (eol == line)
151*a824f5a1SJean-Baptiste Boric continue;
152*a824f5a1SJean-Baptiste Boric *eol = '\0';
153*a824f5a1SJean-Baptiste Boric }
154*a824f5a1SJean-Baptiste Boric ret |= check_exact_pkg(line);
155*a824f5a1SJean-Baptiste Boric }
156*a824f5a1SJean-Baptiste Boric if (f != stdin)
157*a824f5a1SJean-Baptiste Boric fclose(f);
158*a824f5a1SJean-Baptiste Boric
159*a824f5a1SJean-Baptiste Boric return ret;
160*a824f5a1SJean-Baptiste Boric }
161*a824f5a1SJean-Baptiste Boric
162*a824f5a1SJean-Baptiste Boric static int
check_one_installed_pkg(const char * pkg,void * cookie)163*a824f5a1SJean-Baptiste Boric check_one_installed_pkg(const char *pkg, void *cookie)
164*a824f5a1SJean-Baptiste Boric {
165*a824f5a1SJean-Baptiste Boric int *ret = cookie;
166*a824f5a1SJean-Baptiste Boric
167*a824f5a1SJean-Baptiste Boric *ret |= check_exact_pkg(pkg);
168*a824f5a1SJean-Baptiste Boric return 0;
169*a824f5a1SJean-Baptiste Boric }
170*a824f5a1SJean-Baptiste Boric
171*a824f5a1SJean-Baptiste Boric static int
check_installed_pattern(const char * pattern)172*a824f5a1SJean-Baptiste Boric check_installed_pattern(const char *pattern)
173*a824f5a1SJean-Baptiste Boric {
174*a824f5a1SJean-Baptiste Boric int ret = 0;
175*a824f5a1SJean-Baptiste Boric
176*a824f5a1SJean-Baptiste Boric match_installed_pkgs(pattern, check_one_installed_pkg, &ret);
177*a824f5a1SJean-Baptiste Boric
178*a824f5a1SJean-Baptiste Boric return ret;
179*a824f5a1SJean-Baptiste Boric }
180*a824f5a1SJean-Baptiste Boric
181*a824f5a1SJean-Baptiste Boric static void
check_and_read_pkg_vulnerabilities(void)182*a824f5a1SJean-Baptiste Boric check_and_read_pkg_vulnerabilities(void)
183*a824f5a1SJean-Baptiste Boric {
184*a824f5a1SJean-Baptiste Boric struct stat st;
185*a824f5a1SJean-Baptiste Boric time_t now;
186*a824f5a1SJean-Baptiste Boric
187*a824f5a1SJean-Baptiste Boric if (pkg_vulnerabilities_file == NULL)
188*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "PKG_VULNERABILITIES is not set");
189*a824f5a1SJean-Baptiste Boric
190*a824f5a1SJean-Baptiste Boric if (verbose >= 1) {
191*a824f5a1SJean-Baptiste Boric if (stat(pkg_vulnerabilities_file, &st) == -1) {
192*a824f5a1SJean-Baptiste Boric if (errno == ENOENT)
193*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE,
194*a824f5a1SJean-Baptiste Boric "pkg-vulnerabilities not found, run %s -d",
195*a824f5a1SJean-Baptiste Boric getprogname());
196*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "pkg-vulnerabilities not readable");
197*a824f5a1SJean-Baptiste Boric }
198*a824f5a1SJean-Baptiste Boric now = time(NULL);
199*a824f5a1SJean-Baptiste Boric now -= st.st_mtime;
200*a824f5a1SJean-Baptiste Boric if (now < 0)
201*a824f5a1SJean-Baptiste Boric warnx("pkg-vulnerabilities is from the future");
202*a824f5a1SJean-Baptiste Boric else if (now > 86400 * 7)
203*a824f5a1SJean-Baptiste Boric warnx("pkg-vulnerabilities is out of date (%ld days old)",
204*a824f5a1SJean-Baptiste Boric (long)(now / 86400));
205*a824f5a1SJean-Baptiste Boric else if (verbose >= 2)
206*a824f5a1SJean-Baptiste Boric warnx("pkg-vulnerabilities is %ld day%s old",
207*a824f5a1SJean-Baptiste Boric (long)(now / 86400), now / 86400 == 1 ? "" : "s");
208*a824f5a1SJean-Baptiste Boric }
209*a824f5a1SJean-Baptiste Boric
210*a824f5a1SJean-Baptiste Boric pv = read_pkg_vulnerabilities_file(pkg_vulnerabilities_file, 0, check_signature);
211*a824f5a1SJean-Baptiste Boric }
212*a824f5a1SJean-Baptiste Boric
213*a824f5a1SJean-Baptiste Boric void
audit_pkgdb(int argc,char ** argv)214*a824f5a1SJean-Baptiste Boric audit_pkgdb(int argc, char **argv)
215*a824f5a1SJean-Baptiste Boric {
216*a824f5a1SJean-Baptiste Boric int rv;
217*a824f5a1SJean-Baptiste Boric
218*a824f5a1SJean-Baptiste Boric parse_options(argc, argv, audit_options);
219*a824f5a1SJean-Baptiste Boric argv += optind;
220*a824f5a1SJean-Baptiste Boric
221*a824f5a1SJean-Baptiste Boric check_and_read_pkg_vulnerabilities();
222*a824f5a1SJean-Baptiste Boric
223*a824f5a1SJean-Baptiste Boric rv = 0;
224*a824f5a1SJean-Baptiste Boric if (*argv == NULL)
225*a824f5a1SJean-Baptiste Boric rv |= check_installed_pattern("*");
226*a824f5a1SJean-Baptiste Boric else {
227*a824f5a1SJean-Baptiste Boric for (; *argv != NULL; ++argv)
228*a824f5a1SJean-Baptiste Boric rv |= check_installed_pattern(*argv);
229*a824f5a1SJean-Baptiste Boric }
230*a824f5a1SJean-Baptiste Boric free_pkg_vulnerabilities(pv);
231*a824f5a1SJean-Baptiste Boric
232*a824f5a1SJean-Baptiste Boric if (rv == 0 && verbose >= 1)
233*a824f5a1SJean-Baptiste Boric fputs("No vulnerabilities found\n", stderr);
234*a824f5a1SJean-Baptiste Boric exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
235*a824f5a1SJean-Baptiste Boric }
236*a824f5a1SJean-Baptiste Boric
237*a824f5a1SJean-Baptiste Boric void
audit_pkg(int argc,char ** argv)238*a824f5a1SJean-Baptiste Boric audit_pkg(int argc, char **argv)
239*a824f5a1SJean-Baptiste Boric {
240*a824f5a1SJean-Baptiste Boric int rv;
241*a824f5a1SJean-Baptiste Boric
242*a824f5a1SJean-Baptiste Boric parse_options(argc, argv, audit_options);
243*a824f5a1SJean-Baptiste Boric argv += optind;
244*a824f5a1SJean-Baptiste Boric
245*a824f5a1SJean-Baptiste Boric check_and_read_pkg_vulnerabilities();
246*a824f5a1SJean-Baptiste Boric rv = 0;
247*a824f5a1SJean-Baptiste Boric for (; *argv != NULL; ++argv)
248*a824f5a1SJean-Baptiste Boric rv |= check_exact_pkg(*argv);
249*a824f5a1SJean-Baptiste Boric
250*a824f5a1SJean-Baptiste Boric free_pkg_vulnerabilities(pv);
251*a824f5a1SJean-Baptiste Boric
252*a824f5a1SJean-Baptiste Boric if (rv == 0 && verbose >= 1)
253*a824f5a1SJean-Baptiste Boric fputs("No vulnerabilities found\n", stderr);
254*a824f5a1SJean-Baptiste Boric exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
255*a824f5a1SJean-Baptiste Boric }
256*a824f5a1SJean-Baptiste Boric
257*a824f5a1SJean-Baptiste Boric void
audit_batch(int argc,char ** argv)258*a824f5a1SJean-Baptiste Boric audit_batch(int argc, char **argv)
259*a824f5a1SJean-Baptiste Boric {
260*a824f5a1SJean-Baptiste Boric int rv;
261*a824f5a1SJean-Baptiste Boric
262*a824f5a1SJean-Baptiste Boric parse_options(argc, argv, audit_options);
263*a824f5a1SJean-Baptiste Boric argv += optind;
264*a824f5a1SJean-Baptiste Boric
265*a824f5a1SJean-Baptiste Boric check_and_read_pkg_vulnerabilities();
266*a824f5a1SJean-Baptiste Boric rv = 0;
267*a824f5a1SJean-Baptiste Boric for (; *argv != NULL; ++argv)
268*a824f5a1SJean-Baptiste Boric rv |= check_batch_exact_pkgs(*argv);
269*a824f5a1SJean-Baptiste Boric free_pkg_vulnerabilities(pv);
270*a824f5a1SJean-Baptiste Boric
271*a824f5a1SJean-Baptiste Boric if (rv == 0 && verbose >= 1)
272*a824f5a1SJean-Baptiste Boric fputs("No vulnerabilities found\n", stderr);
273*a824f5a1SJean-Baptiste Boric exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
274*a824f5a1SJean-Baptiste Boric }
275*a824f5a1SJean-Baptiste Boric
276*a824f5a1SJean-Baptiste Boric void
check_pkg_vulnerabilities(int argc,char ** argv)277*a824f5a1SJean-Baptiste Boric check_pkg_vulnerabilities(int argc, char **argv)
278*a824f5a1SJean-Baptiste Boric {
279*a824f5a1SJean-Baptiste Boric parse_options(argc, argv, "s");
280*a824f5a1SJean-Baptiste Boric if (argc != optind + 1)
281*a824f5a1SJean-Baptiste Boric usage();
282*a824f5a1SJean-Baptiste Boric
283*a824f5a1SJean-Baptiste Boric pv = read_pkg_vulnerabilities_file(argv[optind], 0, check_signature);
284*a824f5a1SJean-Baptiste Boric free_pkg_vulnerabilities(pv);
285*a824f5a1SJean-Baptiste Boric }
286*a824f5a1SJean-Baptiste Boric
287*a824f5a1SJean-Baptiste Boric void
fetch_pkg_vulnerabilities(int argc,char ** argv)288*a824f5a1SJean-Baptiste Boric fetch_pkg_vulnerabilities(int argc, char **argv)
289*a824f5a1SJean-Baptiste Boric {
290*a824f5a1SJean-Baptiste Boric struct pkg_vulnerabilities *pv_check;
291*a824f5a1SJean-Baptiste Boric char *buf;
292*a824f5a1SJean-Baptiste Boric size_t buf_len, buf_fetched;
293*a824f5a1SJean-Baptiste Boric ssize_t cur_fetched;
294*a824f5a1SJean-Baptiste Boric struct url *url;
295*a824f5a1SJean-Baptiste Boric struct url_stat st;
296*a824f5a1SJean-Baptiste Boric fetchIO *f;
297*a824f5a1SJean-Baptiste Boric int fd;
298*a824f5a1SJean-Baptiste Boric struct stat sb;
299*a824f5a1SJean-Baptiste Boric char my_flags[20];
300*a824f5a1SJean-Baptiste Boric const char *flags;
301*a824f5a1SJean-Baptiste Boric
302*a824f5a1SJean-Baptiste Boric parse_options(argc, argv, "su");
303*a824f5a1SJean-Baptiste Boric if (argc != optind)
304*a824f5a1SJean-Baptiste Boric usage();
305*a824f5a1SJean-Baptiste Boric
306*a824f5a1SJean-Baptiste Boric if (verbose >= 2)
307*a824f5a1SJean-Baptiste Boric fprintf(stderr, "Fetching %s\n", pkg_vulnerabilities_url);
308*a824f5a1SJean-Baptiste Boric
309*a824f5a1SJean-Baptiste Boric url = fetchParseURL(pkg_vulnerabilities_url);
310*a824f5a1SJean-Baptiste Boric if (url == NULL)
311*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE,
312*a824f5a1SJean-Baptiste Boric "Could not parse location of pkg_vulnerabilities: %s",
313*a824f5a1SJean-Baptiste Boric fetchLastErrString);
314*a824f5a1SJean-Baptiste Boric
315*a824f5a1SJean-Baptiste Boric flags = fetch_flags;
316*a824f5a1SJean-Baptiste Boric if (update_pkg_vuln) {
317*a824f5a1SJean-Baptiste Boric fd = open(pkg_vulnerabilities_file, O_RDONLY);
318*a824f5a1SJean-Baptiste Boric if (fd != -1 && fstat(fd, &sb) != -1) {
319*a824f5a1SJean-Baptiste Boric url->last_modified = sb.st_mtime;
320*a824f5a1SJean-Baptiste Boric snprintf(my_flags, sizeof(my_flags), "%si",
321*a824f5a1SJean-Baptiste Boric fetch_flags);
322*a824f5a1SJean-Baptiste Boric flags = my_flags;
323*a824f5a1SJean-Baptiste Boric } else
324*a824f5a1SJean-Baptiste Boric update_pkg_vuln = 0;
325*a824f5a1SJean-Baptiste Boric if (fd != -1)
326*a824f5a1SJean-Baptiste Boric close(fd);
327*a824f5a1SJean-Baptiste Boric }
328*a824f5a1SJean-Baptiste Boric
329*a824f5a1SJean-Baptiste Boric f = fetchXGet(url, &st, flags);
330*a824f5a1SJean-Baptiste Boric if (f == NULL && update_pkg_vuln &&
331*a824f5a1SJean-Baptiste Boric fetchLastErrCode == FETCH_UNCHANGED) {
332*a824f5a1SJean-Baptiste Boric if (verbose >= 1)
333*a824f5a1SJean-Baptiste Boric fprintf(stderr, "%s is not newer\n",
334*a824f5a1SJean-Baptiste Boric pkg_vulnerabilities_url);
335*a824f5a1SJean-Baptiste Boric exit(EXIT_SUCCESS);
336*a824f5a1SJean-Baptiste Boric }
337*a824f5a1SJean-Baptiste Boric
338*a824f5a1SJean-Baptiste Boric if (f == NULL)
339*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "Could not fetch vulnerability file: %s",
340*a824f5a1SJean-Baptiste Boric fetchLastErrString);
341*a824f5a1SJean-Baptiste Boric
342*a824f5a1SJean-Baptiste Boric if (st.size > SSIZE_MAX - 1)
343*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "pkg-vulnerabilities is too large");
344*a824f5a1SJean-Baptiste Boric
345*a824f5a1SJean-Baptiste Boric buf_len = st.size;
346*a824f5a1SJean-Baptiste Boric buf = xmalloc(buf_len + 1);
347*a824f5a1SJean-Baptiste Boric buf_fetched = 0;
348*a824f5a1SJean-Baptiste Boric
349*a824f5a1SJean-Baptiste Boric while (buf_fetched < buf_len) {
350*a824f5a1SJean-Baptiste Boric cur_fetched = fetchIO_read(f, buf + buf_fetched,
351*a824f5a1SJean-Baptiste Boric buf_len - buf_fetched);
352*a824f5a1SJean-Baptiste Boric if (cur_fetched == 0)
353*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE,
354*a824f5a1SJean-Baptiste Boric "Truncated pkg-vulnerabilities received");
355*a824f5a1SJean-Baptiste Boric else if (cur_fetched == -1)
356*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE,
357*a824f5a1SJean-Baptiste Boric "IO error while fetching pkg-vulnerabilities: %s",
358*a824f5a1SJean-Baptiste Boric fetchLastErrString);
359*a824f5a1SJean-Baptiste Boric buf_fetched += cur_fetched;
360*a824f5a1SJean-Baptiste Boric }
361*a824f5a1SJean-Baptiste Boric
362*a824f5a1SJean-Baptiste Boric buf[buf_len] = '\0';
363*a824f5a1SJean-Baptiste Boric
364*a824f5a1SJean-Baptiste Boric pv_check = read_pkg_vulnerabilities_memory(buf, buf_len, check_signature);
365*a824f5a1SJean-Baptiste Boric free_pkg_vulnerabilities(pv_check);
366*a824f5a1SJean-Baptiste Boric
367*a824f5a1SJean-Baptiste Boric fd = open(pkg_vulnerabilities_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
368*a824f5a1SJean-Baptiste Boric if (fd == -1)
369*a824f5a1SJean-Baptiste Boric err(EXIT_FAILURE, "Cannot create pkg-vulnerability file %s",
370*a824f5a1SJean-Baptiste Boric pkg_vulnerabilities_file);
371*a824f5a1SJean-Baptiste Boric
372*a824f5a1SJean-Baptiste Boric if (write(fd, buf, buf_len) != (ssize_t)buf_len)
373*a824f5a1SJean-Baptiste Boric err(EXIT_FAILURE, "Cannot write pkg-vulnerability file");
374*a824f5a1SJean-Baptiste Boric if (close(fd) == -1)
375*a824f5a1SJean-Baptiste Boric err(EXIT_FAILURE, "Cannot close pkg-vulnerability file after write");
376*a824f5a1SJean-Baptiste Boric
377*a824f5a1SJean-Baptiste Boric free(buf);
378*a824f5a1SJean-Baptiste Boric
379*a824f5a1SJean-Baptiste Boric exit(EXIT_SUCCESS);
380*a824f5a1SJean-Baptiste Boric }
381*a824f5a1SJean-Baptiste Boric
382*a824f5a1SJean-Baptiste Boric static int
check_pkg_history_pattern(const char * pkg,const char * pattern)383*a824f5a1SJean-Baptiste Boric check_pkg_history_pattern(const char *pkg, const char *pattern)
384*a824f5a1SJean-Baptiste Boric {
385*a824f5a1SJean-Baptiste Boric const char *delim, *end_base;
386*a824f5a1SJean-Baptiste Boric
387*a824f5a1SJean-Baptiste Boric if (strpbrk(pattern, "*[") != NULL) {
388*a824f5a1SJean-Baptiste Boric end_base = NULL;
389*a824f5a1SJean-Baptiste Boric for (delim = pattern;
390*a824f5a1SJean-Baptiste Boric *delim != '\0' && *delim != '['; delim++) {
391*a824f5a1SJean-Baptiste Boric if (*delim == '-')
392*a824f5a1SJean-Baptiste Boric end_base = delim;
393*a824f5a1SJean-Baptiste Boric }
394*a824f5a1SJean-Baptiste Boric
395*a824f5a1SJean-Baptiste Boric if (end_base == NULL)
396*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "Missing - in wildcard pattern %s",
397*a824f5a1SJean-Baptiste Boric pattern);
398*a824f5a1SJean-Baptiste Boric if ((delim = strchr(pattern, '>')) != NULL ||
399*a824f5a1SJean-Baptiste Boric (delim = strchr(pattern, '<')) != NULL)
400*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE,
401*a824f5a1SJean-Baptiste Boric "Mixed relational and wildcard patterns in %s",
402*a824f5a1SJean-Baptiste Boric pattern);
403*a824f5a1SJean-Baptiste Boric } else if ((delim = strchr(pattern, '>')) != NULL) {
404*a824f5a1SJean-Baptiste Boric end_base = delim;
405*a824f5a1SJean-Baptiste Boric if ((delim = strchr(pattern, '<')) != NULL && delim < end_base)
406*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "Inverted operators in %s",
407*a824f5a1SJean-Baptiste Boric pattern);
408*a824f5a1SJean-Baptiste Boric } else if ((delim = strchr(pattern, '<')) != NULL) {
409*a824f5a1SJean-Baptiste Boric end_base = delim;
410*a824f5a1SJean-Baptiste Boric } else if ((end_base = strrchr(pattern, '-')) == NULL) {
411*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "Missing - in absolute pattern %s",
412*a824f5a1SJean-Baptiste Boric pattern);
413*a824f5a1SJean-Baptiste Boric }
414*a824f5a1SJean-Baptiste Boric
415*a824f5a1SJean-Baptiste Boric if (strncmp(pkg, pattern, end_base - pattern) != 0)
416*a824f5a1SJean-Baptiste Boric return 0;
417*a824f5a1SJean-Baptiste Boric if (pkg[end_base - pattern] != '\0')
418*a824f5a1SJean-Baptiste Boric return 0;
419*a824f5a1SJean-Baptiste Boric
420*a824f5a1SJean-Baptiste Boric return 1;
421*a824f5a1SJean-Baptiste Boric }
422*a824f5a1SJean-Baptiste Boric
423*a824f5a1SJean-Baptiste Boric static int
check_pkg_history1(const char * pkg,const char * pattern)424*a824f5a1SJean-Baptiste Boric check_pkg_history1(const char *pkg, const char *pattern)
425*a824f5a1SJean-Baptiste Boric {
426*a824f5a1SJean-Baptiste Boric const char *open_brace, *close_brace, *inner_brace, *suffix, *iter;
427*a824f5a1SJean-Baptiste Boric size_t prefix_len, suffix_len, middle_len;
428*a824f5a1SJean-Baptiste Boric char *expanded_pkg;
429*a824f5a1SJean-Baptiste Boric
430*a824f5a1SJean-Baptiste Boric open_brace = strchr(pattern, '{');
431*a824f5a1SJean-Baptiste Boric if (open_brace == NULL) {
432*a824f5a1SJean-Baptiste Boric if ((close_brace = strchr(pattern, '}')) != NULL)
433*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "Unbalanced {} in pattern %s",
434*a824f5a1SJean-Baptiste Boric pattern);
435*a824f5a1SJean-Baptiste Boric return check_pkg_history_pattern(pkg, pattern);
436*a824f5a1SJean-Baptiste Boric }
437*a824f5a1SJean-Baptiste Boric close_brace = strchr(open_brace, '}');
438*a824f5a1SJean-Baptiste Boric if (strchr(pattern, '}') != close_brace)
439*a824f5a1SJean-Baptiste Boric errx(EXIT_FAILURE, "Unbalanced {} in pattern %s",
440*a824f5a1SJean-Baptiste Boric pattern);
441*a824f5a1SJean-Baptiste Boric
442*a824f5a1SJean-Baptiste Boric while ((inner_brace = strchr(open_brace + 1, '{')) != NULL) {
443*a824f5a1SJean-Baptiste Boric if (inner_brace >= close_brace)
444*a824f5a1SJean-Baptiste Boric break;
445*a824f5a1SJean-Baptiste Boric open_brace = inner_brace;
446*a824f5a1SJean-Baptiste Boric }
447*a824f5a1SJean-Baptiste Boric
448*a824f5a1SJean-Baptiste Boric expanded_pkg = xmalloc(strlen(pattern)); /* {} are going away... */
449*a824f5a1SJean-Baptiste Boric
450*a824f5a1SJean-Baptiste Boric prefix_len = open_brace - pattern;
451*a824f5a1SJean-Baptiste Boric suffix = close_brace + 1;
452*a824f5a1SJean-Baptiste Boric suffix_len = strlen(suffix) + 1;
453*a824f5a1SJean-Baptiste Boric memcpy(expanded_pkg, pattern, prefix_len);
454*a824f5a1SJean-Baptiste Boric
455*a824f5a1SJean-Baptiste Boric ++open_brace;
456*a824f5a1SJean-Baptiste Boric
457*a824f5a1SJean-Baptiste Boric do {
458*a824f5a1SJean-Baptiste Boric iter = strchr(open_brace, ',');
459*a824f5a1SJean-Baptiste Boric if (iter == NULL || iter > close_brace)
460*a824f5a1SJean-Baptiste Boric iter = close_brace;
461*a824f5a1SJean-Baptiste Boric
462*a824f5a1SJean-Baptiste Boric middle_len = iter - open_brace;
463*a824f5a1SJean-Baptiste Boric memcpy(expanded_pkg + prefix_len, open_brace, middle_len);
464*a824f5a1SJean-Baptiste Boric memcpy(expanded_pkg + prefix_len + middle_len, suffix,
465*a824f5a1SJean-Baptiste Boric suffix_len);
466*a824f5a1SJean-Baptiste Boric if (check_pkg_history1(pkg, expanded_pkg)) {
467*a824f5a1SJean-Baptiste Boric free(expanded_pkg);
468*a824f5a1SJean-Baptiste Boric return 1;
469*a824f5a1SJean-Baptiste Boric }
470*a824f5a1SJean-Baptiste Boric open_brace = iter + 1;
471*a824f5a1SJean-Baptiste Boric } while (iter < close_brace);
472*a824f5a1SJean-Baptiste Boric
473*a824f5a1SJean-Baptiste Boric free(expanded_pkg);
474*a824f5a1SJean-Baptiste Boric return 0;
475*a824f5a1SJean-Baptiste Boric }
476*a824f5a1SJean-Baptiste Boric
477*a824f5a1SJean-Baptiste Boric static void
check_pkg_history(const char * pkg)478*a824f5a1SJean-Baptiste Boric check_pkg_history(const char *pkg)
479*a824f5a1SJean-Baptiste Boric {
480*a824f5a1SJean-Baptiste Boric size_t i;
481*a824f5a1SJean-Baptiste Boric
482*a824f5a1SJean-Baptiste Boric for (i = 0; i < pv->entries; ++i) {
483*a824f5a1SJean-Baptiste Boric if (!quick_pkg_match(pv->vulnerability[i], pkg))
484*a824f5a1SJean-Baptiste Boric continue;
485*a824f5a1SJean-Baptiste Boric if (strcmp("eol", pv->classification[i]) == 0)
486*a824f5a1SJean-Baptiste Boric continue;
487*a824f5a1SJean-Baptiste Boric if (check_pkg_history1(pkg, pv->vulnerability[i]) == 0)
488*a824f5a1SJean-Baptiste Boric continue;
489*a824f5a1SJean-Baptiste Boric
490*a824f5a1SJean-Baptiste Boric printf("%s %s %s\n", pv->vulnerability[i],
491*a824f5a1SJean-Baptiste Boric pv->classification[i], pv->advisory[i]);
492*a824f5a1SJean-Baptiste Boric }
493*a824f5a1SJean-Baptiste Boric }
494*a824f5a1SJean-Baptiste Boric
495*a824f5a1SJean-Baptiste Boric void
audit_history(int argc,char ** argv)496*a824f5a1SJean-Baptiste Boric audit_history(int argc, char **argv)
497*a824f5a1SJean-Baptiste Boric {
498*a824f5a1SJean-Baptiste Boric parse_options(argc, argv, "st:");
499*a824f5a1SJean-Baptiste Boric argv += optind;
500*a824f5a1SJean-Baptiste Boric
501*a824f5a1SJean-Baptiste Boric check_and_read_pkg_vulnerabilities();
502*a824f5a1SJean-Baptiste Boric for (; *argv != NULL; ++argv)
503*a824f5a1SJean-Baptiste Boric check_pkg_history(*argv);
504*a824f5a1SJean-Baptiste Boric
505*a824f5a1SJean-Baptiste Boric free_pkg_vulnerabilities(pv);
506*a824f5a1SJean-Baptiste Boric exit(EXIT_SUCCESS);
507*a824f5a1SJean-Baptiste Boric }
508