1 /*        $NetBSD: vulnerabilities-file.c,v 1.5 2021/04/10 19:49:59 nia 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.5 2021/04/10 19:49:59 nia 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 #ifndef BOOTSTRAP
81 static struct archive *
prepare_raw_file(void)82 prepare_raw_file(void)
83 {
84           struct archive *a = archive_read_new();
85           if (a == NULL)
86                     errx(EXIT_FAILURE, "memory allocation failed");
87 
88           archive_read_support_filter_gzip(a);
89           archive_read_support_filter_bzip2(a);
90           archive_read_support_filter_xz(a);
91           archive_read_support_format_raw(a);
92           return a;
93 }
94 #endif
95 
96 static void
verify_signature_pkcs7(const char * input)97 verify_signature_pkcs7(const char *input)
98 {
99 #ifdef HAVE_SSL
100           const char *begin_pkgvul, *end_pkgvul, *begin_sig, *end_sig;
101 
102           if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
103                     begin_pkgvul = input + strlen(pgp_msg_start);
104                     if ((end_pkgvul = strstr(begin_pkgvul, pgp_msg_end)) == NULL)
105                               errx(EXIT_FAILURE, "Invalid PGP signature");
106                     if ((begin_sig = strstr(end_pkgvul, pkcs7_begin)) == NULL)
107                               errx(EXIT_FAILURE, "No PKCS7 signature");
108           } else {
109                     begin_pkgvul = input;
110                     if ((begin_sig = strstr(begin_pkgvul, pkcs7_begin)) == NULL)
111                               errx(EXIT_FAILURE, "No PKCS7 signature");
112                     end_pkgvul = begin_sig;
113           }
114           if ((end_sig = strstr(begin_sig, pkcs7_end)) == NULL)
115                     errx(EXIT_FAILURE, "Invalid PKCS7 signature");
116           end_sig += strlen(pkcs7_end);
117 
118           if (easy_pkcs7_verify(begin_pkgvul, end_pkgvul - begin_pkgvul,
119               begin_sig, end_sig - begin_sig, certs_pkg_vulnerabilities, 0))
120                     errx(EXIT_FAILURE, "Unable to verify PKCS7 signature");
121 #else
122           errx(EXIT_FAILURE, "OpenSSL support is not compiled in");
123 #endif
124 }
125 
126 static void
verify_signature(const char * input,size_t input_len)127 verify_signature(const char *input, size_t input_len)
128 {
129           gpg_verify(input, input_len, gpg_keyring_pkgvuln, NULL, 0);
130           if (certs_pkg_vulnerabilities != NULL)
131                     verify_signature_pkcs7(input);
132 }
133 
134 static void *
sha512_hash_init(void)135 sha512_hash_init(void)
136 {
137           static SHA512_CTX hash_ctx;
138 
139           SHA512_Init(&hash_ctx);
140           return &hash_ctx;
141 }
142 
143 static void
sha512_hash_update(void * ctx,const void * data,size_t len)144 sha512_hash_update(void *ctx, const void *data, size_t len)
145 {
146           SHA512_CTX *hash_ctx = ctx;
147 
148           SHA512_Update(hash_ctx, data, len);
149 }
150 
151 static const char *
sha512_hash_finish(void * ctx)152 sha512_hash_finish(void *ctx)
153 {
154           static char hash[SHA512_DIGEST_STRING_LENGTH];
155           unsigned char digest[SHA512_DIGEST_LENGTH];
156           SHA512_CTX *hash_ctx = ctx;
157           int i;
158 
159           SHA512_Final(digest, hash_ctx);
160           for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
161                     unsigned char c;
162 
163                     c = digest[i] / 16;
164                     if (c < 10)
165                               hash[2 * i] = '0' + c;
166                     else
167                               hash[2 * i] = 'a' - 10 + c;
168 
169                     c = digest[i] % 16;
170                     if (c < 10)
171                               hash[2 * i + 1] = '0' + c;
172                     else
173                               hash[2 * i + 1] = 'a' - 10 + c;
174           }
175           hash[2 * i] = '\0';
176 
177           return hash;
178 }
179 
180 static void *
sha1_hash_init(void)181 sha1_hash_init(void)
182 {
183           static SHA1_CTX hash_ctx;
184 
185           SHA1Init(&hash_ctx);
186           return &hash_ctx;
187 }
188 
189 static void
sha1_hash_update(void * ctx,const void * data,size_t len)190 sha1_hash_update(void *ctx, const void *data, size_t len)
191 {
192           SHA1_CTX *hash_ctx = ctx;
193 
194           SHA1Update(hash_ctx, data, len);
195 }
196 
197 static const char *
sha1_hash_finish(void * ctx)198 sha1_hash_finish(void *ctx)
199 {
200           static char hash[SHA1_DIGEST_STRING_LENGTH];
201           SHA1_CTX *hash_ctx = ctx;
202 
203           SHA1End(hash_ctx, hash);
204 
205           return hash;
206 }
207 
208 static const struct hash_algorithm {
209           const char *name;
210           size_t name_len;
211           void * (*init)(void);
212           void (*update)(void *, const void *, size_t);
213           const char * (* finish)(void *);
214 } hash_algorithms[] = {
215           { "SHA512", 6, sha512_hash_init, sha512_hash_update,
216             sha512_hash_finish },
217           { "SHA1", 4, sha1_hash_init, sha1_hash_update,
218             sha1_hash_finish },
219           { NULL, 0, NULL, NULL, NULL }
220 };
221 
222 static void
verify_hash(const char * input,const char * hash_line)223 verify_hash(const char *input, const char *hash_line)
224 {
225           const struct hash_algorithm *hash;
226           void *ctx;
227           const char *last_start, *next, *hash_value;
228           int in_pgp_msg;
229 
230           for (hash = hash_algorithms; hash->name != NULL; ++hash) {
231                     if (strncmp(hash_line, hash->name, hash->name_len))
232                               continue;
233                     if (isspace((unsigned char)hash_line[hash->name_len]))
234                               break;
235           }
236           if (hash->name == NULL) {
237                     const char *end_name;
238                     for (end_name = hash_line; *end_name != '\0'; ++end_name) {
239                               if (!isalnum((unsigned char)*end_name))
240                                         break;
241                     }
242                     warnx("Unsupported hash algorithm: %.*s",
243                         (int)(end_name - hash_line), hash_line);
244                     return;
245           }
246 
247           hash_line += hash->name_len;
248           if (!isspace((unsigned char)*hash_line))
249                     errx(EXIT_FAILURE, "Invalid #CHECKSUM");
250           while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
251                     ++hash_line;
252 
253           if (*hash_line == '\n')
254                     errx(EXIT_FAILURE, "Invalid #CHECKSUM");
255 
256           ctx = (*hash->init)();
257           if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
258                     input += strlen(pgp_msg_start);
259                     in_pgp_msg = 1;
260           } else {
261                     in_pgp_msg = 0;
262           }
263           for (last_start = input; *input != '\0'; input = next) {
264                     if ((next = strchr(input, '\n')) == NULL)
265                               errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
266                     ++next;
267                     if (in_pgp_msg && strncmp(input, pgp_msg_end, strlen(pgp_msg_end)) == 0)
268                               break;
269                     if (!in_pgp_msg && strncmp(input, pkcs7_begin, strlen(pkcs7_begin)) == 0)
270                               break;
271                     if (*input == '\n' ||
272                         strncmp(input, "Hash:", 5) == 0 ||
273                         strncmp(input, "# $NetBSD", 9) == 0 ||
274                         strncmp(input, "#CHECKSUM", 9) == 0) {
275                               (*hash->update)(ctx, last_start, input - last_start);
276                               last_start = next;
277                     }
278           }
279           (*hash->update)(ctx, last_start, input - last_start);
280           hash_value = (*hash->finish)(ctx);
281           if (strncmp(hash_line, hash_value, strlen(hash_value)))
282                     errx(EXIT_FAILURE, "%s hash doesn't match", hash->name);
283           hash_line += strlen(hash_value);
284 
285           while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
286                     ++hash_line;
287 
288           if (!isspace((unsigned char)*hash_line))
289                     errx(EXIT_FAILURE, "Invalid #CHECKSUM");
290 }
291 
292 static void
add_vulnerability(struct pkg_vulnerabilities * pv,size_t * allocated,const char * line)293 add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *line)
294 {
295           size_t len_pattern, len_class, len_url;
296           const char *start_pattern, *start_class, *start_url;
297 
298           start_pattern = line;
299 
300           start_class = line;
301           while (*start_class != '\0' && !isspace((unsigned char)*start_class))
302                     ++start_class;
303           len_pattern = start_class - line;
304 
305           while (*start_class != '\n' && isspace((unsigned char)*start_class))
306                     ++start_class;
307 
308           if (*start_class == '0' || *start_class == '\n')
309                     errx(EXIT_FAILURE, "Input error: missing classification");
310 
311           start_url = start_class;
312           while (*start_url != '\0' && !isspace((unsigned char)*start_url))
313                     ++start_url;
314           len_class = start_url - start_class;
315 
316           while (*start_url != '\n' && isspace((unsigned char)*start_url))
317                     ++start_url;
318 
319           if (*start_url == '0' || *start_url == '\n')
320                     errx(EXIT_FAILURE, "Input error: missing URL");
321 
322           line = start_url;
323           while (*line != '\0' && !isspace((unsigned char)*line))
324                     ++line;
325           len_url = line - start_url;
326 
327           if (pv->entries == *allocated) {
328                     if (*allocated == 0)
329                               *allocated = 16;
330                     else if (*allocated <= SSIZE_MAX / 2)
331                               *allocated *= 2;
332                     else
333                               errx(EXIT_FAILURE, "Too many vulnerabilities");
334                     pv->vulnerability = xrealloc(pv->vulnerability,
335                         sizeof(char *) * *allocated);
336                     pv->classification = xrealloc(pv->classification,
337                         sizeof(char *) * *allocated);
338                     pv->advisory = xrealloc(pv->advisory,
339                         sizeof(char *) * *allocated);
340           }
341 
342           pv->vulnerability[pv->entries] = xmalloc(len_pattern + 1);
343           memcpy(pv->vulnerability[pv->entries], start_pattern, len_pattern);
344           pv->vulnerability[pv->entries][len_pattern] = '\0';
345           pv->classification[pv->entries] = xmalloc(len_class + 1);
346           memcpy(pv->classification[pv->entries], start_class, len_class);
347           pv->classification[pv->entries][len_class] = '\0';
348           pv->advisory[pv->entries] = xmalloc(len_url + 1);
349           memcpy(pv->advisory[pv->entries], start_url, len_url);
350           pv->advisory[pv->entries][len_url] = '\0';
351 
352           ++pv->entries;
353 }
354 
355 struct pkg_vulnerabilities *
read_pkg_vulnerabilities_memory(void * buf,size_t len,int check_sum)356 read_pkg_vulnerabilities_memory(void *buf, size_t len, int check_sum)
357 {
358 #ifdef BOOTSTRAP
359           errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap");
360 #else
361           struct archive *a;
362           struct pkg_vulnerabilities *pv;
363 
364           a = prepare_raw_file();
365           if (archive_read_open_memory(a, buf, len) != ARCHIVE_OK)
366                     errx(EXIT_FAILURE, "Cannot open pkg_vulnerabilies buffer: %s",
367                         archive_error_string(a));
368 
369           pv = read_pkg_vulnerabilities_archive(a, check_sum);
370 
371           return pv;
372 #endif
373 }
374 
375 struct pkg_vulnerabilities *
read_pkg_vulnerabilities_file(const char * path,int ignore_missing,int check_sum)376 read_pkg_vulnerabilities_file(const char *path, int ignore_missing, int check_sum)
377 {
378 #ifdef BOOTSTRAP
379           errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap");
380 #else
381           struct archive *a;
382           struct pkg_vulnerabilities *pv;
383           int fd;
384 
385           if ((fd = open(path, O_RDONLY)) == -1) {
386                     if (errno == ENOENT && ignore_missing)
387                               return NULL;
388                     err(EXIT_FAILURE, "Cannot open %s", path);
389           }
390 
391           a = prepare_raw_file();
392           if (archive_read_open_fd(a, fd, 65536) != ARCHIVE_OK)
393                     errx(EXIT_FAILURE, "Cannot open ``%s'': %s", path,
394                         archive_error_string(a));
395 
396           pv = read_pkg_vulnerabilities_archive(a, check_sum);
397           close(fd);
398 
399           return pv;
400 #endif
401 }
402 
403 #ifndef BOOTSTRAP
404 static struct pkg_vulnerabilities *
read_pkg_vulnerabilities_archive(struct archive * a,int check_sum)405 read_pkg_vulnerabilities_archive(struct archive *a, int check_sum)
406 {
407           struct archive_entry *ae;
408           struct pkg_vulnerabilities *pv;
409           char *buf;
410           size_t buf_len, off;
411           ssize_t r;
412 
413           if (archive_read_next_header(a, &ae) != ARCHIVE_OK)
414                     errx(EXIT_FAILURE, "Cannot read pkg_vulnerabilities: %s",
415                         archive_error_string(a));
416 
417           off = 0;
418           buf_len = 65536;
419           buf = xmalloc(buf_len + 1);
420 
421           for (;;) {
422                     r = archive_read_data(a, buf + off, buf_len - off);
423                     if (r <= 0)
424                               break;
425                     off += r;
426                     if (off == buf_len) {
427                               buf_len *= 2;
428                               if (buf_len < off)
429                                         errx(EXIT_FAILURE, "pkg_vulnerabilties too large");
430                               buf = xrealloc(buf, buf_len + 1);
431                     }
432           }
433 
434           if (r != ARCHIVE_OK)
435                     errx(EXIT_FAILURE, "Cannot read pkg_vulnerabilities: %s",
436                         archive_error_string(a));
437 
438           archive_read_close(a);
439 
440           buf[off] = '\0';
441           pv = parse_pkg_vuln(buf, off, check_sum);
442           free(buf);
443           return pv;
444 }
445 
446 static struct pkg_vulnerabilities *
parse_pkg_vuln(const char * input,size_t input_len,int check_sum)447 parse_pkg_vuln(const char *input, size_t input_len, int check_sum)
448 {
449           struct pkg_vulnerabilities *pv;
450           long version;
451           char *end;
452           const char *iter, *next;
453           size_t allocated_vulns;
454           int in_pgp_msg;
455 
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
free_pkg_vulnerabilities(struct pkg_vulnerabilities * pv)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
check_ignored_entry(struct pkg_vulnerabilities * pv,size_t i)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
audit_package(struct pkg_vulnerabilities * pv,const char * pkgname,const char * limit_vul_types,int include_ignored,int output_type)612 audit_package(struct pkg_vulnerabilities *pv, const char *pkgname,
613     const char *limit_vul_types, int include_ignored, int output_type)
614 {
615           FILE *output = output_type == 1 ? stdout : stderr;
616           size_t i;
617           int retval, do_eol, ignored;
618 
619           retval = 0;
620 
621           do_eol = (strcasecmp(check_eol, "yes") == 0);
622 
623           for (i = 0; i < pv->entries; ++i) {
624                     ignored = check_ignored_entry(pv, i);
625                     if (ignored && !include_ignored)
626                               continue;
627                     if (limit_vul_types != NULL &&
628                         strcmp(limit_vul_types, pv->classification[i]))
629                               continue;
630                     if (!pkg_match(pv->vulnerability[i], pkgname))
631                               continue;
632                     if (strcmp("eol", pv->classification[i]) == 0) {
633                               if (!do_eol)
634                                         continue;
635                               retval = 1;
636                               if (output_type == 0) {
637                                         puts(pkgname);
638                                         continue;
639                               }
640                               fprintf(output,
641                                   "Package %s has reached end-of-life (eol), "
642                                   "see %s/eol-packages\n", pkgname,
643                                   tnf_vulnerability_base);
644                               continue;
645                     }
646                     retval = 1;
647                     if (output_type == 0) {
648                               fprintf(stdout, "%s%s\n",
649                                         pkgname, ignored ? " (ignored)" : "");
650                     } else {
651                               fprintf(output,
652                                   "Package %s has a%s %s vulnerability, see %s\n",
653                                   pkgname, ignored ? "n ignored" : "",
654                                   pv->classification[i], pv->advisory[i]);
655                     }
656           }
657           return retval;
658 }
659