xref: /minix3/external/bsd/pkg_install/dist/lib/vulnerabilities-file.c (revision 7ecc6a9247125543940025b38b2e27c7ab19b121)
1 /*	$NetBSD: vulnerabilities-file.c,v 1.1.1.5 2010/06/26 00:14:33 joerg Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
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
29  * SUCH DAMAGE.
30  */
31 
32 #if HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <nbcompat.h>
37 
38 #if HAVE_SYS_CDEFS_H
39 #include <sys/cdefs.h>
40 #endif
41 __RCSID("$NetBSD: vulnerabilities-file.c,v 1.1.1.5 2010/06/26 00:14:33 joerg Exp $");
42 
43 #if HAVE_SYS_STAT_H
44 #include <sys/stat.h>
45 #endif
46 #if HAVE_SYS_WAIT_H
47 #include <sys/wait.h>
48 #endif
49 #ifndef BOOTSTRAP
50 #include <archive.h>
51 #endif
52 #include <ctype.h>
53 #if HAVE_ERR_H
54 #include <err.h>
55 #endif
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <limits.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #ifndef NETBSD
62 #include <nbcompat/sha1.h>
63 #include <nbcompat/sha2.h>
64 #else
65 #include <sha1.h>
66 #include <sha2.h>
67 #endif
68 #include <unistd.h>
69 
70 #include "lib.h"
71 
72 static struct pkg_vulnerabilities *read_pkg_vulnerabilities_archive(struct archive *, int);
73 static struct pkg_vulnerabilities *parse_pkg_vuln(const char *, size_t, int);
74 
75 static const char pgp_msg_start[] = "-----BEGIN PGP SIGNED MESSAGE-----\n";
76 static const char pgp_msg_end[] = "-----BEGIN PGP SIGNATURE-----\n";
77 static const char pkcs7_begin[] = "-----BEGIN PKCS7-----\n";
78 static const char pkcs7_end[] = "-----END PKCS7-----\n";
79 
80 static void
81 verify_signature_pkcs7(const char *input)
82 {
83 #ifdef HAVE_SSL
84 	const char *begin_pkgvul, *end_pkgvul, *begin_sig, *end_sig;
85 
86 	if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
87 		begin_pkgvul = input + strlen(pgp_msg_start);
88 		if ((end_pkgvul = strstr(begin_pkgvul, pgp_msg_end)) == NULL)
89 			errx(EXIT_FAILURE, "Invalid PGP signature");
90 		if ((begin_sig = strstr(end_pkgvul, pkcs7_begin)) == NULL)
91 			errx(EXIT_FAILURE, "No PKCS7 signature");
92 	} else {
93 		begin_pkgvul = input;
94 		if ((begin_sig = strstr(begin_pkgvul, pkcs7_begin)) == NULL)
95 			errx(EXIT_FAILURE, "No PKCS7 signature");
96 		end_pkgvul = begin_sig;
97 	}
98 	if ((end_sig = strstr(begin_sig, pkcs7_end)) == NULL)
99 		errx(EXIT_FAILURE, "Invalid PKCS7 signature");
100 	end_sig += strlen(pkcs7_end);
101 
102 	if (easy_pkcs7_verify(begin_pkgvul, end_pkgvul - begin_pkgvul,
103 	    begin_sig, end_sig - begin_sig, certs_pkg_vulnerabilities, 0))
104 		errx(EXIT_FAILURE, "Unable to verify PKCS7 signature");
105 #else
106 	errx(EXIT_FAILURE, "OpenSSL support is not compiled in");
107 #endif
108 }
109 
110 static void
111 verify_signature(const char *input, size_t input_len)
112 {
113 	if (gpg_cmd == NULL && certs_pkg_vulnerabilities == NULL)
114 		errx(EXIT_FAILURE,
115 		    "At least GPG or CERTIFICATE_ANCHOR_PKGVULN "
116 		    "must be configured");
117 	if (gpg_cmd != NULL)
118 		inline_gpg_verify(input, input_len, gpg_keyring_pkgvuln);
119 	if (certs_pkg_vulnerabilities != NULL)
120 		verify_signature_pkcs7(input);
121 }
122 
123 static void *
124 sha512_hash_init(void)
125 {
126 	static SHA512_CTX hash_ctx;
127 
128 	SHA512_Init(&hash_ctx);
129 	return &hash_ctx;
130 }
131 
132 static void
133 sha512_hash_update(void *ctx, const void *data, size_t len)
134 {
135 	SHA512_CTX *hash_ctx = ctx;
136 
137 	SHA512_Update(hash_ctx, data, len);
138 }
139 
140 static const char *
141 sha512_hash_finish(void *ctx)
142 {
143 	static char hash[SHA512_DIGEST_STRING_LENGTH];
144 	unsigned char digest[SHA512_DIGEST_LENGTH];
145 	SHA512_CTX *hash_ctx = ctx;
146 	int i;
147 
148 	SHA512_Final(digest, hash_ctx);
149 	for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
150 		unsigned char c;
151 
152 		c = digest[i] / 16;
153 		if (c < 10)
154 			hash[2 * i] = '0' + c;
155 		else
156 			hash[2 * i] = 'a' - 10 + c;
157 
158 		c = digest[i] % 16;
159 		if (c < 10)
160 			hash[2 * i + 1] = '0' + c;
161 		else
162 			hash[2 * i + 1] = 'a' - 10 + c;
163 	}
164 	hash[2 * i] = '\0';
165 
166 	return hash;
167 }
168 
169 static void *
170 sha1_hash_init(void)
171 {
172 	static SHA1_CTX hash_ctx;
173 
174 	SHA1Init(&hash_ctx);
175 	return &hash_ctx;
176 }
177 
178 static void
179 sha1_hash_update(void *ctx, const void *data, size_t len)
180 {
181 	SHA1_CTX *hash_ctx = ctx;
182 
183 	SHA1Update(hash_ctx, data, len);
184 }
185 
186 static const char *
187 sha1_hash_finish(void *ctx)
188 {
189 	static char hash[SHA1_DIGEST_STRING_LENGTH];
190 	SHA1_CTX *hash_ctx = ctx;
191 
192 	SHA1End(hash_ctx, hash);
193 
194 	return hash;
195 }
196 
197 static const struct hash_algorithm {
198 	const char *name;
199 	size_t name_len;
200 	void * (*init)(void);
201 	void (*update)(void *, const void *, size_t);
202 	const char * (* finish)(void *);
203 } hash_algorithms[] = {
204 	{ "SHA512", 6, sha512_hash_init, sha512_hash_update,
205 	  sha512_hash_finish },
206 	{ "SHA1", 4, sha1_hash_init, sha1_hash_update,
207 	  sha1_hash_finish },
208 	{ NULL, 0, NULL, NULL, NULL }
209 };
210 
211 static void
212 verify_hash(const char *input, const char *hash_line)
213 {
214 	const struct hash_algorithm *hash;
215 	void *ctx;
216 	const char *last_start, *next, *hash_value;
217 	int in_pgp_msg;
218 
219 	for (hash = hash_algorithms; hash->name != NULL; ++hash) {
220 		if (strncmp(hash_line, hash->name, hash->name_len))
221 			continue;
222 		if (isspace((unsigned char)hash_line[hash->name_len]))
223 			break;
224 	}
225 	if (hash->name == NULL) {
226 		const char *end_name;
227 		for (end_name = hash_line; *end_name != '\0'; ++end_name) {
228 			if (!isalnum((unsigned char)*end_name))
229 				break;
230 		}
231 		warnx("Unsupported hash algorithm: %.*s",
232 		    (int)(end_name - hash_line), hash_line);
233 		return;
234 	}
235 
236 	hash_line += hash->name_len;
237 	if (!isspace((unsigned char)*hash_line))
238 		errx(EXIT_FAILURE, "Invalid #CHECKSUM");
239 	while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
240 		++hash_line;
241 
242 	if (*hash_line == '\n')
243 		errx(EXIT_FAILURE, "Invalid #CHECKSUM");
244 
245 	ctx = (*hash->init)();
246 	if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
247 		input += strlen(pgp_msg_start);
248 		in_pgp_msg = 1;
249 	} else {
250 		in_pgp_msg = 0;
251 	}
252 	for (last_start = input; *input != '\0'; input = next) {
253 		if ((next = strchr(input, '\n')) == NULL)
254 			errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
255 		++next;
256 		if (in_pgp_msg && strncmp(input, pgp_msg_end, strlen(pgp_msg_end)) == 0)
257 			break;
258 		if (!in_pgp_msg && strncmp(input, pkcs7_begin, strlen(pkcs7_begin)) == 0)
259 			break;
260 		if (*input == '\n' ||
261 		    strncmp(input, "Hash:", 5) == 0 ||
262 		    strncmp(input, "# $NetBSD", 9) == 0 ||
263 		    strncmp(input, "#CHECKSUM", 9) == 0) {
264 			(*hash->update)(ctx, last_start, input - last_start);
265 			last_start = next;
266 		}
267 	}
268 	(*hash->update)(ctx, last_start, input - last_start);
269 	hash_value = (*hash->finish)(ctx);
270 	if (strncmp(hash_line, hash_value, strlen(hash_value)))
271 		errx(EXIT_FAILURE, "%s hash doesn't match", hash->name);
272 	hash_line += strlen(hash_value);
273 
274 	while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
275 		++hash_line;
276 
277 	if (!isspace((unsigned char)*hash_line))
278 		errx(EXIT_FAILURE, "Invalid #CHECKSUM");
279 }
280 
281 static void
282 add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *line)
283 {
284 	size_t len_pattern, len_class, len_url;
285 	const char *start_pattern, *start_class, *start_url;
286 
287 	start_pattern = line;
288 
289 	start_class = line;
290 	while (*start_class != '\0' && !isspace((unsigned char)*start_class))
291 		++start_class;
292 	len_pattern = start_class - line;
293 
294 	while (*start_class != '\n' && isspace((unsigned char)*start_class))
295 		++start_class;
296 
297 	if (*start_class == '0' || *start_class == '\n')
298 		errx(EXIT_FAILURE, "Input error: missing classification");
299 
300 	start_url = start_class;
301 	while (*start_url != '\0' && !isspace((unsigned char)*start_url))
302 		++start_url;
303 	len_class = start_url - start_class;
304 
305 	while (*start_url != '\n' && isspace((unsigned char)*start_url))
306 		++start_url;
307 
308 	if (*start_url == '0' || *start_url == '\n')
309 		errx(EXIT_FAILURE, "Input error: missing URL");
310 
311 	line = start_url;
312 	while (*line != '\0' && !isspace((unsigned char)*line))
313 		++line;
314 	len_url = line - start_url;
315 
316 	if (pv->entries == *allocated) {
317 		if (*allocated == 0)
318 			*allocated = 16;
319 		else if (*allocated <= SSIZE_MAX / 2)
320 			*allocated *= 2;
321 		else
322 			errx(EXIT_FAILURE, "Too many vulnerabilities");
323 		pv->vulnerability = xrealloc(pv->vulnerability,
324 		    sizeof(char *) * *allocated);
325 		pv->classification = xrealloc(pv->classification,
326 		    sizeof(char *) * *allocated);
327 		pv->advisory = xrealloc(pv->advisory,
328 		    sizeof(char *) * *allocated);
329 	}
330 
331 	pv->vulnerability[pv->entries] = xmalloc(len_pattern + 1);
332 	memcpy(pv->vulnerability[pv->entries], start_pattern, len_pattern);
333 	pv->vulnerability[pv->entries][len_pattern] = '\0';
334 	pv->classification[pv->entries] = xmalloc(len_class + 1);
335 	memcpy(pv->classification[pv->entries], start_class, len_class);
336 	pv->classification[pv->entries][len_class] = '\0';
337 	pv->advisory[pv->entries] = xmalloc(len_url + 1);
338 	memcpy(pv->advisory[pv->entries], start_url, len_url);
339 	pv->advisory[pv->entries][len_url] = '\0';
340 
341 	++pv->entries;
342 }
343 
344 struct pkg_vulnerabilities *
345 read_pkg_vulnerabilities_memory(void *buf, size_t len, int check_sum)
346 {
347 #ifdef BOOTSTRAP
348 	errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap");
349 #else
350 	struct archive *a;
351 	struct pkg_vulnerabilities *pv;
352 
353 	if ((a = archive_read_new()) == NULL)
354 		errx(EXIT_FAILURE, "memory allocation failed");
355 
356 	if (archive_read_support_compression_all(a) != ARCHIVE_OK ||
357 	    archive_read_support_format_raw(a) != ARCHIVE_OK ||
358 	    archive_read_open_memory(a, buf, len) != ARCHIVE_OK)
359 		errx(EXIT_FAILURE, "Cannot open pkg_vulnerabilies buffer: %s",
360 		    archive_error_string(a));
361 
362 	pv = read_pkg_vulnerabilities_archive(a, check_sum);
363 
364 	return pv;
365 #endif
366 }
367 
368 struct pkg_vulnerabilities *
369 read_pkg_vulnerabilities_file(const char *path, int ignore_missing, int check_sum)
370 {
371 #ifdef BOOTSTRAP
372 	errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap");
373 #else
374 	struct archive *a;
375 	struct pkg_vulnerabilities *pv;
376 	int fd;
377 
378 	if ((fd = open(path, O_RDONLY)) == -1) {
379 		if (errno == ENOENT && ignore_missing)
380 			return NULL;
381 		err(EXIT_FAILURE, "Cannot open %s", path);
382 	}
383 
384 	if ((a = archive_read_new()) == NULL)
385 		errx(EXIT_FAILURE, "memory allocation failed");
386 
387 	if (archive_read_support_compression_all(a) != ARCHIVE_OK ||
388 	    archive_read_support_format_raw(a) != ARCHIVE_OK ||
389 	    archive_read_open_fd(a, fd, 65536) != ARCHIVE_OK)
390 		errx(EXIT_FAILURE, "Cannot open ``%s'': %s", path,
391 		    archive_error_string(a));
392 
393 	pv = read_pkg_vulnerabilities_archive(a, check_sum);
394 	close(fd);
395 
396 	return pv;
397 #endif
398 }
399 
400 #ifndef BOOTSTRAP
401 static struct pkg_vulnerabilities *
402 read_pkg_vulnerabilities_archive(struct archive *a, int check_sum)
403 {
404 	struct archive_entry *ae;
405 	struct pkg_vulnerabilities *pv;
406 	char *buf;
407 	size_t buf_len, off;
408 	ssize_t r;
409 
410 	if (archive_read_next_header(a, &ae) != ARCHIVE_OK)
411 		errx(EXIT_FAILURE, "Cannot read pkg_vulnerabilities: %s",
412 		    archive_error_string(a));
413 
414 	off = 0;
415 	buf_len = 65536;
416 	buf = xmalloc(buf_len + 1);
417 
418 	for (;;) {
419 		r = archive_read_data(a, buf + off, buf_len - off);
420 		if (r <= 0)
421 			break;
422 		off += r;
423 		if (off == buf_len) {
424 			buf_len *= 2;
425 			if (buf_len < off)
426 				errx(EXIT_FAILURE, "pkg_vulnerabilties too large");
427 			buf = xrealloc(buf, buf_len + 1);
428 		}
429 	}
430 
431 	if (r != ARCHIVE_OK)
432 		errx(EXIT_FAILURE, "Cannot read pkg_vulnerabilities: %s",
433 		    archive_error_string(a));
434 
435 	archive_read_close(a);
436 
437 	buf[off] = '\0';
438 	pv = parse_pkg_vuln(buf, off, check_sum);
439 	free(buf);
440 	return pv;
441 }
442 
443 static struct pkg_vulnerabilities *
444 parse_pkg_vuln(const char *input, size_t input_len, int check_sum)
445 {
446 	struct pkg_vulnerabilities *pv;
447 	long version;
448 	char *end;
449 	const char *iter, *next;
450 	size_t allocated_vulns;
451 	int in_pgp_msg;
452 
453 #if defined(__minix)
454 	next = NULL; /* LSC: Fix -Os compilation: -Werror=maybe-uninitialized */
455 #endif /* defined(__minix) */
456 	pv = xmalloc(sizeof(*pv));
457 
458 	allocated_vulns = pv->entries = 0;
459 	pv->vulnerability = NULL;
460 	pv->classification = NULL;
461 	pv->advisory = NULL;
462 
463 	if (strlen(input) != input_len)
464 		errx(1, "Invalid input (NUL character found)");
465 
466 	if (check_sum)
467 		verify_signature(input, input_len);
468 
469 	if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
470 		iter = input + strlen(pgp_msg_start);
471 		in_pgp_msg = 1;
472 	} else {
473 		iter = input;
474 		in_pgp_msg = 0;
475 	}
476 
477 	for (; *iter; iter = next) {
478 		if ((next = strchr(iter, '\n')) == NULL)
479 			errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
480 		++next;
481 		if (*iter == '\0' || *iter == '\n')
482 			continue;
483 		if (strncmp(iter, "Hash:", 5) == 0)
484 			continue;
485 		if (strncmp(iter, "# $NetBSD", 9) == 0)
486 			continue;
487 		if (*iter == '#' && isspace((unsigned char)iter[1])) {
488 			for (++iter; iter != next; ++iter) {
489 				if (!isspace((unsigned char)*iter))
490 					errx(EXIT_FAILURE, "Invalid header");
491 			}
492 			continue;
493 		}
494 
495 		if (strncmp(iter, "#FORMAT", 7) != 0)
496 			errx(EXIT_FAILURE, "Input header is malformed");
497 
498 		iter += 7;
499 		if (!isspace((unsigned char)*iter))
500 			errx(EXIT_FAILURE, "Invalid #FORMAT");
501 		++iter;
502 		version = strtol(iter, &end, 10);
503 		if (iter == end || version != 1 || *end != '.')
504 			errx(EXIT_FAILURE, "Input #FORMAT");
505 		iter = end + 1;
506 		version = strtol(iter, &end, 10);
507 		if (iter == end || version != 1 || *end != '.')
508 			errx(EXIT_FAILURE, "Input #FORMAT");
509 		iter = end + 1;
510 		version = strtol(iter, &end, 10);
511 		if (iter == end || version != 0)
512 			errx(EXIT_FAILURE, "Input #FORMAT");
513 		for (iter = end; iter != next; ++iter) {
514 			if (!isspace((unsigned char)*iter))
515 				errx(EXIT_FAILURE, "Input #FORMAT");
516 		}
517 		break;
518 	}
519 	if (*iter == '\0')
520 		errx(EXIT_FAILURE, "Missing #CHECKSUM or content");
521 
522 	for (iter = next; *iter; iter = next) {
523 		if ((next = strchr(iter, '\n')) == NULL)
524 			errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
525 		++next;
526 		if (*iter == '\0' || *iter == '\n')
527 			continue;
528 		if (in_pgp_msg && strncmp(iter, pgp_msg_end, strlen(pgp_msg_end)) == 0)
529 			break;
530 		if (!in_pgp_msg && strncmp(iter, pkcs7_begin, strlen(pkcs7_begin)) == 0)
531 			break;
532 		if (*iter == '#' &&
533 		    (iter[1] == '\0' || iter[1] == '\n' || isspace((unsigned char)iter[1])))
534 			continue;
535 		if (strncmp(iter, "#CHECKSUM", 9) == 0) {
536 			iter += 9;
537 			if (!isspace((unsigned char)*iter))
538 				errx(EXIT_FAILURE, "Invalid #CHECKSUM");
539 			while (isspace((unsigned char)*iter))
540 				++iter;
541 			verify_hash(input, iter);
542 			continue;
543 		}
544 		if (*iter == '#') {
545 			/*
546 			 * This should really be an error,
547 			 * but it is still used.
548 			 */
549 			/* errx(EXIT_FAILURE, "Invalid data line starting with #"); */
550 			continue;
551 		}
552 		add_vulnerability(pv, &allocated_vulns, iter);
553 	}
554 
555 	if (pv->entries != allocated_vulns) {
556 		pv->vulnerability = xrealloc(pv->vulnerability,
557 		    sizeof(char *) * pv->entries);
558 		pv->classification = xrealloc(pv->classification,
559 		    sizeof(char *) * pv->entries);
560 		pv->advisory = xrealloc(pv->advisory,
561 		    sizeof(char *) * pv->entries);
562 	}
563 
564 	return pv;
565 }
566 #endif
567 
568 void
569 free_pkg_vulnerabilities(struct pkg_vulnerabilities *pv)
570 {
571 	size_t i;
572 
573 	for (i = 0; i < pv->entries; ++i) {
574 		free(pv->vulnerability[i]);
575 		free(pv->classification[i]);
576 		free(pv->advisory[i]);
577 	}
578 	free(pv->vulnerability);
579 	free(pv->classification);
580 	free(pv->advisory);
581 	free(pv);
582 }
583 
584 static int
585 check_ignored_entry(struct pkg_vulnerabilities *pv, size_t i)
586 {
587 	const char *iter, *next;
588 	size_t entry_len, url_len;
589 
590 	if (ignore_advisories == NULL)
591 		return 0;
592 
593 	url_len = strlen(pv->advisory[i]);
594 
595 	for (iter = ignore_advisories; *iter; iter = next) {
596 		if ((next = strchr(iter, '\n')) == NULL) {
597 			entry_len = strlen(iter);
598 			next = iter + entry_len;
599 		} else {
600 			entry_len = next - iter;
601 			++next;
602 		}
603 		if (url_len != entry_len)
604 			continue;
605 		if (strncmp(pv->advisory[i], iter, entry_len) == 0)
606 			return 1;
607 	}
608 	return 0;
609 }
610 
611 int
612 audit_package(struct pkg_vulnerabilities *pv, const char *pkgname,
613     const char *limit_vul_types, int output_type)
614 {
615 	FILE *output = output_type == 1 ? stdout : stderr;
616 	size_t i;
617 	int retval, do_eol;
618 
619 	retval = 0;
620 
621 	do_eol = (strcasecmp(check_eol, "yes") == 0);
622 
623 	for (i = 0; i < pv->entries; ++i) {
624 		if (check_ignored_entry(pv, i))
625 			continue;
626 		if (limit_vul_types != NULL &&
627 		    strcmp(limit_vul_types, pv->classification[i]))
628 			continue;
629 		if (!pkg_match(pv->vulnerability[i], pkgname))
630 			continue;
631 		if (strcmp("eol", pv->classification[i]) == 0) {
632 			if (!do_eol)
633 				continue;
634 			retval = 1;
635 			if (output_type == 0) {
636 				puts(pkgname);
637 				continue;
638 			}
639 			fprintf(output,
640 			    "Package %s has reached end-of-life (eol), "
641 			    "see %s/eol-packages\n", pkgname,
642 			    tnf_vulnerability_base);
643 			continue;
644 		}
645 		retval = 1;
646 		if (output_type == 0) {
647 			puts(pkgname);
648 		} else {
649 			fprintf(output,
650 			    "Package %s has a %s vulnerability, see %s\n",
651 			    pkgname, pv->classification[i], pv->advisory[i]);
652 		}
653 	}
654 	return retval;
655 }
656