Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 5 Oct 2008 23:03:17 +0400
From:      Eygene Ryabinkin <rea-fbsd@codelabs.ru>
To:        Miroslav Lachman <000.fbsd@quip.cz>
Cc:        freebsd-hackers@freebsd.org, Roman Kurakin <rik@inse.ru>, freebsd-ports@freebsd.org, bug-followup@freebsd.org
Subject:   Re: ports/126853: ports-mgmt/portaudit: speed up audit of installed packages
Message-ID:  <xIGBGzzNkgJfXK2hY3ABIqS4mko@Nv45r0f9gWT8HCu35qu0Xm2Zg98>
In-Reply-To: <4bESZpNwE3z/DdlE2fwK/BXzQSo@2MQ0uKCiT7mdMUuLeUzs8Nv3ToQ>
References:  <WGReTVL6CLts/44OKi4qLEsAGHs@jm/Q2DKg1djxmpGNf45V%2BWpjPIE> <48DE5CC0.9000708@localhost.inse.ru> <o/JeKQBFxyWYOEj%2BysAVRhQK6g8@iXA9ZWPrtc2I2BMzBXoToMd7YdQ> <48DF6735.4030906@quip.cz> <4bESZpNwE3z/DdlE2fwK/BXzQSo@2MQ0uKCiT7mdMUuLeUzs8Nv3ToQ>

next in thread | previous in thread | raw e-mail | index | archive | help

--aPdhxNJGSeOG9wFI
Content-Type: multipart/mixed; boundary="X3gaHHMYHkYqP6yf"
Content-Disposition: inline


--X3gaHHMYHkYqP6yf
Content-Type: text/plain; charset=koi8-r
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Miroslav, good day.

Sun, Sep 28, 2008 at 04:14:24PM +0400, Eygene Ryabinkin wrote:
> > If I read nightly security e-mail with for example 4 vulnerable=20
> > packages, then I need to log in to server and manualy try, if newer=20
> > (fixed) packages are available. It seems not so hard to check output of=
=20
> > `pkg_version -vIL =3D` and compare both versions (installed and availab=
le)=20
> > with portaudit in some shellscript, I didn't start to write it yet ;).
>=20
> I think it won't be very hard: I'll try to see how to extend portaudit
> with such functionality -- it would be very handy, in my opinion.

OK, I extended portaudit with this -- flag '-n' will do it.  Currently
this option requires network access, but I think that it is perfectly
fits into the security check -- it downloads auditfile anyway.

I had greatly reworked the old part of patch and I have series of
4 patches that implement both my pkg_audit stuff and the '-n' stuff.
I am also attaching the mega-patch, it can be applied to the current
port sources to give the port version that includes both mentioned
enchancements.  If you have no pkg_audit -- this isn't a problem:
portaudit fill fall back to the awk script.

I had also changed the output format for pkg_audit, so I am attaching
another version of the second patch for the pkg_install bundle.

I had briefly tested my modifications -- they work for now, but I will
continue testing.  Any bug reports or thoughts about these patches are
more that welcome.

> Hadn't you have a chance to test my patch?

Miroslav, still: had you tested the pkg_audit thingy?
--=20
Eygene
 _                ___       _.--.   #
 \`.|\..----...-'`   `-._.-'_.-'`   #  Remember that it is hard
 /  ' `         ,       __.--'      #  to read the on-line manual  =20
 )/' _/     \   `-_,   /            #  while single-stepping the kernel.
 `-'" `"\_  ,_.-;_.-\_ ',  fsc/as   #
     _.-'_./   {_.'   ; /           #    -- FreeBSD Developers handbook=20
    {_.-``-'         {_/            #

--X3gaHHMYHkYqP6yf
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment; filename="0002-New-utility-pkg_audit.patch"
Content-Transfer-Encoding: quoted-printable

=46rom 88a3659c2d941e27de698fe05e4852a9f418f16e Mon Sep 17 00:00:00 2001
=46rom: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Tue, 26 Aug 2008 15:08:46 +0400
Subject: [PATCH] New utility: pkg_audit

It is mainly a helper for portupgrade to avoid awk scripting and
numerous calls for pkg_info.  This utility speeds up portaudit by a
factor of 10 on a system with 521 installed ports and the auditfile that
contains 3213 entries:
-----
$ ls -d /var/db/pkg/*  | wc -l
     521

$ tar xOf /var/db/portaudit/auditfile.tbz auditfile | sed -e'/^#/d' | wc -l
    3213

$ time ./portaudit
Affected package: ruby-1.8.6.111_4,1
Type of problem: ruby -- DNS spoofing vulnerability.
Reference: <http://www.FreeBSD.org/ports/portaudit/959d384d-6b59-11dd-9d79-=
001fc61c2a55.html>

Affected package: ruby-1.8.6.111_4,1
Type of problem: ruby -- DoS vulnerability in WEBrick.
Reference: <http://www.FreeBSD.org/ports/portaudit/f7ba20aa-6b5a-11dd-9d79-=
001fc61c2a55.html>

Affected package: ruby-1.8.6.111_4,1
Type of problem: ruby -- multiple vulnerabilities in safe level.
Reference: <http://www.FreeBSD.org/ports/portaudit/c329712a-6b5b-11dd-9d79-=
001fc61c2a55.html>

3 problem(s) in your installed packages found.

You are advised to update or deinstall the affected package(s) immediately.

real    0m0.107s
user    0m0.116s
sys     0m0.012s

$ time portaudit
Affected package: ruby-1.8.6.111_4,1
Type of problem: ruby -- multiple vulnerabilities in safe level.
Reference: <http://www.FreeBSD.org/ports/portaudit/c329712a-6b5b-11dd-9d79-=
001fc61c2a55.html>

Affected package: ruby-1.8.6.111_4,1
Type of problem: ruby -- DoS vulnerability in WEBrick.
Reference: <http://www.FreeBSD.org/ports/portaudit/f7ba20aa-6b5a-11dd-9d79-=
001fc61c2a55.html>

Affected package: ruby-1.8.6.111_4,1
Type of problem: ruby -- DNS spoofing vulnerability.
Reference: <http://www.FreeBSD.org/ports/portaudit/959d384d-6b59-11dd-9d79-=
001fc61c2a55.html>

3 problem(s) in your installed packages found.

You are advised to update or deinstall the affected package(s) immediately.

real    0m1.583s
user    0m0.560s
sys     0m1.057s
-----

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 Makefile          |    2 +-
 audit/Makefile    |   14 +++
 audit/audit.h     |   43 +++++++++
 audit/main.c      |  166 ++++++++++++++++++++++++++++++++++
 audit/parse.c     |  259 +++++++++++++++++++++++++++++++++++++++++++++++++=
++++
 audit/pkg_audit.1 |   63 +++++++++++++
 6 files changed, 546 insertions(+), 1 deletions(-)
 create mode 100644 audit/Makefile
 create mode 100644 audit/audit.h
 create mode 100644 audit/main.c
 create mode 100644 audit/parse.c
 create mode 100644 audit/pkg_audit.1

diff --git a/Makefile b/Makefile
index fefbd08..abc1e65 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
=20
 .include <bsd.own.mk>
=20
-SUBDIR=3D	lib add create delete info updating version
+SUBDIR=3D	lib add create delete info updating version audit
=20
 .include <bsd.subdir.mk>
=20
diff --git a/audit/Makefile b/audit/Makefile
new file mode 100644
index 0000000..2ece5f8
--- /dev/null
+++ b/audit/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+PROG=3D	pkg_audit
+SRCS=3D	main.c parse.c
+
+CFLAGS+=3D -I${.CURDIR}/../lib
+
+WARNS?=3D	6
+WFORMAT?=3D	1
+
+DPADD=3D	${LIBINSTALL} ${LIBFETCH} ${LIBMD}
+LDADD=3D	${LIBINSTALL} -lfetch -lmd
+
+.include <bsd.prog.mk>
diff --git a/audit/audit.h b/audit/audit.h
new file mode 100644
index 0000000..1f0a369
--- /dev/null
+++ b/audit/audit.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Eygene Ryabinkin
+ * 26 August 2008
+ *
+ * Parsing module for pkg_audit, header file.
+ *
+ */
+
+#ifndef __AUDIT_H__
+#define __AUDIT_H__
+
+#include <sys/queue.h>
+
+SLIST_HEAD(audit_contents, audit_entry);
+
+struct audit_entry {
+	char	*pkgglob;	/* Package name glob */
+	char	*url;		/* URL of advisory */
+	char	*descr;		/* Description of vulnerability */
+	size_t	pfx_size;	/* Metacharacter-less glob part size */
+	SLIST_ENTRY(audit_entry) entries;
+};
+
+
+/* Function prototypes */
+int
+parse_auditfile(FILE *_fp, struct audit_contents *_head);
+
+
+#endif /* defined(__AUDIT_H__) */
diff --git a/audit/main.c b/audit/main.c
new file mode 100644
index 0000000..6ad18a9
--- /dev/null
+++ b/audit/main.c
@@ -0,0 +1,166 @@
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Eygene Ryabinkin
+ * 26 August 2008
+ *
+ * This is the audit module -- fast helper for the portaudit script.
+ *
+ * It is filter-like utility: it reads the audit file from the
+ * standard input, intersects the vulnerable port list with the
+ * packages installed in the system and outputs the entries for
+ * the vulnerable ports that are present in the system to the
+ * standard output.
+ *
+ * The installed package can be listed multiple times, since it
+ * can be vulnerable to more than one bug at a time.  But the
+ * whole output entries will be unique -- package name and
+ * vulnerability details should produce unique entry.
+ *
+ * One more field is prepended to the list of the input fields --
+ * the name of the matched port.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef PROFILING
+#include <sys/time.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <getopt.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "lib.h"
+#include "audit.h"
+
+static inline void
+audit_package(const char *_pkgname, struct audit_contents *_head,
+    struct match_session *_msess, FILE *_fp);
+
+int
+main(int argc, char *argv[])
+{
+	char freebsd[sizeof("FreeBSD-XXYYZZXXYYZZ")];
+	unsigned long reldate;
+	size_t reldate_size =3D sizeof(reldate);
+	int mib[2];
+
+	FILE *in =3D stdin, *out =3D stdout;
+	struct match_session *msess;
+	struct audit_entry *item;
+#ifdef PROFILING
+	struct timeval t1, t2;
+	double dt;
+#endif
+
+	/* Make compiler happy */
+	if (argv[argc] =3D=3D NULL) {};
+
+	struct audit_contents head =3D
+	    SLIST_HEAD_INITIALIZER(head);
+
+	mib[0] =3D CTL_KERN;
+	mib[1] =3D KERN_OSRELDATE;
+	if (sysctl(mib, 2, (void *)&reldate, &reldate_size, NULL, 0) !=3D 0)
+		errx(1, "Unable to get kern.osreldate");
+	snprintf(freebsd, sizeof(freebsd), "%s-%lu", "FreeBSD", reldate);
+=09
+	SLIST_INIT(&head);
+#ifdef PROFILING
+	gettimeofday(&t1, NULL);
+#endif
+	if (parse_auditfile(in, &head) !=3D 0) {
+		errx(1, "Failed to parse audit entries");
+	}
+#ifdef PROFILING
+	gettimeofday(&t2, NULL);
+	dt =3D t2.tv_sec - t1.tv_sec + 1e-6 * (t2.tv_usec - t1.tv_usec);
+	fprintf(stderr, "parse_auditfile(): %.6lf sec\n", dt);
+#endif
+
+	msess =3D match_begin(MATCH_GLOB);
+	if (msess =3D=3D NULL)
+		return 1;
+=09
+#ifdef PROFILING
+	gettimeofday(&t1, NULL);
+#endif
+
+	/* Special check: FreeBSD itself */
+	SLIST_FOREACH (item, &head, entries) {
+		if (strncmp(item->pkgglob,
+		    "FreeBSD", sizeof("FreeBSD") - 1) =3D=3D 0 &&
+		    pattern_match(MATCH_GLOB, item->pkgglob, freebsd)) {
+			fprintf(out, "%s|%s|%s\n",
+			    freebsd, item->url, item->descr);
+		}
+	}
+
+	/* Installed packages */
+	while (match_next_package(msess))
+		audit_package(match_get_pkgname(msess), &head, msess, out);
+
+#ifdef PROFILING
+	gettimeofday(&t2, NULL);
+	dt =3D t2.tv_sec - t1.tv_sec + 1e-6 * (t2.tv_usec - t1.tv_usec);
+	fprintf(stderr, "match loop: %.6lf sec\n", dt);
+#endif
+
+	match_end(msess);
+
+	SLIST_FOREACH (item, &head, entries) {
+		free((void *)item->pkgglob);
+		free((void *)item);
+	}
+
+	return 0;
+}
+
+void
+cleanup(int sig)
+{
+	sig =3D 0;
+	return;
+}
+
+/*
+ * Loops over audit file contents and checks each entry in turn.
+ *
+ * The great speedup is to test the package prefix at the first
+ * place and only if it matches perform full match -- match_matches
+ * uses slow matching routines without precompilation and other
+ * tricks.  For hundreds of installed ports and a couple of thousands
+ * audit entries this slows things down very well.
+ */
+static inline void
+audit_package(const char *pkgname, struct audit_contents *head,
+    struct match_session *msess, FILE *fp)
+{
+	struct audit_entry *item;
+
+	SLIST_FOREACH (item, head, entries) {
+		if (strncmp(pkgname, item->pkgglob,
+		    item->pfx_size) =3D=3D 0 &&
+		    match_matches(msess, item->pkgglob)) {
+			fprintf(fp, "%s|%s|%s|%s\n",
+			    pkgname,
+			    item->pkgglob, item->url, item->descr);
+		}
+	}
+}
diff --git a/audit/parse.c b/audit/parse.c
new file mode 100644
index 0000000..fb33f7c
--- /dev/null
+++ b/audit/parse.c
@@ -0,0 +1,259 @@
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Eygene Ryabinkin
+ * 26 August 2008
+ *
+ * Parsing module for pkg_audit.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <getopt.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "lib.h"
+#include "audit.h"
+
+/* Simple exponentially-growing buffer. */
+
+struct dyn_buffer {
+	char *buf;
+	size_t size;
+};
+
+/* Prototypes */
+static int
+parse_audit_entry(struct dyn_buffer *_b, struct audit_entry *_e);
+
+static int
+read_line(FILE *_fp, struct dyn_buffer *_b);
+
+static struct dyn_buffer *
+buf_init(size_t _size);
+static void
+buf_destroy(struct dyn_buffer *_b);
+static int
+buf_grow(struct dyn_buffer *_b);
+
+/*
+ * Parses audit file to the linked list of single entries.
+ *
+ * Return values:
+ * 0 -- file was successfully parsed;
+ * 1 -- parsing or read error occured;
+ * -1 -- bad arguments, memory allocation problems, etc.
+ */
+int
+parse_auditfile(FILE *fp, struct audit_contents *head)
+{
+	struct audit_entry *e;
+	struct dyn_buffer *b;
+	int errcode;
+
+	b =3D buf_init(256);
+	if (b =3D=3D NULL)
+		return 1;
+
+	while ((errcode =3D read_line(fp, b)) =3D=3D 0) {
+		if (b->buf[0] =3D=3D '#')
+			continue;
+		e =3D (struct audit_entry *)malloc(sizeof(*e));
+		if (e =3D=3D NULL) {
+			buf_destroy(b);
+			return -1;
+		}
+		bzero((void *)e, sizeof(*e));
+		if ((errcode =3D parse_audit_entry(b, e)) !=3D 0) {
+			buf_destroy(b);
+			return errcode;
+		}
+		SLIST_INSERT_HEAD(head, e, entries);
+	}
+
+	buf_destroy(b);
+
+	if (errcode !=3D 1)
+		return 1;
+	else
+		return 0;
+}
+
+/*
+ * Helpers for audit file parsing routine.
+ */
+
+static struct dyn_buffer *
+buf_init(size_t size)
+{
+	struct dyn_buffer *b;
+
+	if (size <=3D 0)
+		return NULL;
+
+	b =3D (struct dyn_buffer *)malloc(sizeof(*b));
+	if (b =3D=3D NULL)
+		return NULL;
+
+	bzero((void *)b, sizeof(*b));
+	b->size =3D size;
+	b->buf =3D (char *)malloc(b->size * sizeof(b->buf[0]));
+	if (b->buf =3D=3D NULL) {
+		free((void *)b);
+		return NULL;
+	}
+
+	bzero((void *)b->buf, b->size);
+	return b;
+}
+
+static void
+buf_destroy(struct dyn_buffer *b)
+{
+	if (b =3D=3D NULL)
+		return;
+=09
+	if (b->buf !=3D NULL)
+		free((void *)b->buf);
+	free((void *)b);
+	return;
+}
+
+static int
+buf_grow(struct dyn_buffer *b)
+{
+	char *newbuf;
+
+	if (b =3D=3D NULL || b->buf =3D=3D NULL || b->size <=3D 0)
+		return -1;
+
+	newbuf =3D (char *)malloc(2 * b->size * sizeof(newbuf));
+	if (newbuf =3D=3D NULL)
+		return 1;
+
+	bzero(newbuf, 2 * b->size);
+	bcopy((void *)b->buf, (void *)newbuf, b->size);
+	b->buf =3D newbuf;
+	b->size *=3D 2;
+
+	return 0;
+}
+
+/*
+ * fgets()-like function that reads the whole input line
+ * Returns 0 on the successful read, 1 for the end-of-file
+ * condition, -1 for any error.
+ *
+ * Terminating '\n' is removed from the line.
+ */
+static int
+read_line(FILE *fp, struct dyn_buffer *b)
+{
+	size_t offset =3D 0, len =3D 0;
+
+	if (fp =3D=3D NULL || b =3D=3D NULL)
+		return -1;
+
+	if (feof(fp))
+		return 1;
+
+	/* We need at least two-character buffer */
+	if (b->size =3D=3D 1 && buf_grow(b) !=3D 0)
+		return -1;
+
+	b->buf[b->size - 1] =3D '\0';
+	offset =3D 0;
+	while (fgets(b->buf + offset, b->size - offset, fp) !=3D NULL) {
+		len =3D strlen(b->buf);
+		/*
+		 * Read zero characters or buffer even shrinked?
+		 * Strange, let's indicate error.
+		 */
+		if (len <=3D offset)
+			return -1;
+		if (b->buf[len - 1] =3D=3D '\n') {
+			b->buf[len - 1] =3D '\0';
+			return 0;
+		}
+
+		offset =3D len;
+		if (buf_grow(b) !=3D 0)
+			return -1;
+
+		/* Should not happen, but who knows */
+		if (offset >=3D b->size)
+			return -1;
+	}
+
+	if (feof(fp)) {
+		/*
+		 * If we read no characters, if means that we were
+		 * at the EOF, but it was detected only by fgets(),
+		 * not the first feof().
+		 */
+		if (len =3D=3D 0)
+			return 1;
+		else
+			return 0;
+	} else {
+		return -1;
+	}
+}
+
+/*
+ * Parses single audit line and places it to the structure.
+ * Calculates length of the package name suffix that is free
+ * from metacharacters -- it is used for the quick matches
+ * against port name.
+ */
+static int
+parse_audit_entry(struct dyn_buffer *b, struct audit_entry *e)
+{
+	size_t len;
+	char *string =3D NULL, *d1 =3D NULL, *d2 =3D NULL;
+	static const char globset[] =3D "{*?><=3D!";
+
+	/*
+	 * At least 5 characters:
+	 * two delimiters and three non-empty fields.
+	 */
+	len =3D strlen(b->buf);
+	if (len < 5)
+		return 1;
+
+	/* Locate delimiters. */
+	d1 =3D strchr(b->buf, '|');
+	if (d1 =3D=3D NULL)
+		return 1;
+	d2 =3D strchr(d1 + 1, '|');
+	if (d2 =3D=3D NULL)
+		return 1;
+
+	string =3D (char *)malloc((len + 1) * sizeof(string[0]));
+	if (string =3D=3D NULL)
+		return -1;
+
+	bcopy((void *)b->buf, (void *)string, (len + 1) * sizeof(string[0]));
+	string[d1 - b->buf] =3D '\0';
+	string[d2 - b->buf] =3D '\0';
+	e->pkgglob =3D string;
+	e->url =3D string + (d1 - b->buf) + 1;
+	e->descr =3D string + (d2 - b->buf) + 1;
+	e->pfx_size =3D strcspn(e->pkgglob, globset);
+
+	return 0;
+}
diff --git a/audit/pkg_audit.1 b/audit/pkg_audit.1
new file mode 100644
index 0000000..cd4abbc
--- /dev/null
+++ b/audit/pkg_audit.1
@@ -0,0 +1,63 @@
+.\"
+.\" FreeBSD install - a package for the installation and maintenance
+.\" of non-core utilities.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" Eygene Ryabinkin
+.\"
+.\"
+.\"     @(#)pkg_audit.1
+.\" $FreeBSD$
+.\"
+.Dd Aug 26, 2008
+.Dt PKG_AUDIT 1
+.Os
+.Sh NAME
+.Nm pkg_audit
+.Nd lists vulnerable ports installed in the system
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+command is used to extract vulnerability information from the audit
+file and list vulnerable packages that are present in the system.
+It is main purpose to help
+.Xr portaudit 1
+utility to avoid time-consuming scripting.
+.Nm
+reads vulnerability information from the standard input and writes
+the list of vulnerable ports to the standard output.
+Format of the output lines is the same as for the audit file, but
+package matching globs are substituted with the actual package names.
+.Sh TECHNICAL DETAILS
+First the audit file is parsed to the internal representation
+(currently it is linked list).
+Then we are traversing installed packages database and trying to
+match the package name against each audit entry.
+The crucial step for the speeding up the process is to first
+match the package prefix that has no CSH-like metacharacters
+and perform full comparison only if match is found.
+One more name is tested prior to the installed packages: it is
+.Qo FreeBSD-`sysctl -n kern.osreldate` Qc ,
+the version of
+.Fx
+the current system is running.
+.Sh SEE ALSO
+.Xr portaudit 1 ,
+.Xr pkg_add 1 ,
+.Xr pkg_create 1 ,
+.Xr pkg_delete 1 ,
+.Xr pkg_version 1 .
+.Sh AUTHORS
+.An Eygene Ryabinkin Aq rea-fbsd@codelabs.ru
+.Sh BUGS
+Sure to be some.
--=20
1.6.0.2


--X3gaHHMYHkYqP6yf
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment;
	filename="0001-Avoid-usage-of-global-variables-N-in-the-print_affe.patch"
Content-Transfer-Encoding: quoted-printable

=46rom b5fc2033e39aecd8b65f3bda45bf71572b72262a Mon Sep 17 00:00:00 2001
=46rom: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Sun, 5 Oct 2008 18:04:10 +0400
Subject: [PATCH 1/4] Avoid usage of global variables $N in the print_affect=
ed

I will need this functionality in the next commits: some invocations of
print_affected will be called with shifted variables $N.  But this is
good anyway: globals are always been bad and now functions are looking
more sanely -- one does not need to guess the meaning of $1, $2 and $3.

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 files/portaudit-cmd.sh |   68 ++++++++++++++++++++++++--------------------=
---
 1 files changed, 35 insertions(+), 33 deletions(-)

diff --git a/files/portaudit-cmd.sh b/files/portaudit-cmd.sh
index c0eb67b..4583c9c 100755
--- a/files/portaudit-cmd.sh
+++ b/files/portaudit-cmd.sh
@@ -140,7 +140,8 @@ audit_installed()
 		$1 ~ /^FreeBSD[<=3D>!]/ {
 			if (fixedre && $2 ~ fixedre) next
 			if (!system("'"$pkg_version"' -T \"FreeBSD-'"$osversion"'\" \"" $1 "\""=
)) {
-				print_affected("FreeBSD-'"$osversion"'", \
+				print_affected("FreeBSD-'"$osversion"'",=20
+					$1, $2, $3, \
 					"To disable this check add the uuid to \`portaudit_fixed'"'"' in %%PR=
EFIX%%/etc/portaudit.conf")
 			}
 			next
@@ -152,7 +153,7 @@ audit_installed()
 			cmd=3D"'"$pkg_info"' -E \"" $1 "\""
 			while((cmd | getline pkg) > 0) {
 				vul++
-				print_affected(pkg, "")
+				print_affected(pkg, $1, $2, $3, "")
 			}
 			close(cmd)
 		}
@@ -207,7 +208,7 @@ audit_file()
 				if ($2 !~ /'"$opt_restrict"'/)
 					continue
 				vul++
-				print_affected(pkg, "")
+				print_affected(pkg, $1, $2, $3, "")
 			}
 			close(cmd)
 		}
@@ -244,7 +245,8 @@ audit_args()
 				' | $pkg_version -T "$1" -`; then
 				VULCNT=3D$(($VULCNT+1))
 				echo "$VLIST" | awk -F\| "$PRINTAFFECTED_AWK"'
-					{ print_affected("'"$1"'", "") }
+					{ print_affected("'"$1"'",
+					    $1, $2, $3, "") }
 				'
 			fi
 			;;
@@ -277,7 +279,7 @@ audit_cwd()
 			{ print }
 		' | $pkg_version -T "$PKGNAME" -`; then
 		echo "$VLIST" | awk -F\| "$PRINTAFFECTED_AWK"'
-			{ print_affected("'"$PKGNAME"'", "") }
+			{ print_affected("'"$PKGNAME"'", $1, $2, $3, "") }
 		'
 		return 1
 	fi
@@ -425,38 +427,38 @@ prerequisites_checked=3Dfalse
=20
 if $opt_quiet; then
 	PRINTAFFECTED_AWK=3D'
-		function print_affected(apkg, note) {
-			print apkg
-		}
-		'
+function print_affected(apkg, glob, refs, descr, note) {
+	print apkg
+}
+'
 elif $opt_verbose; then
 	PRINTAFFECTED_AWK=3D'
-		function print_affected(apkg, note) {
-			split(apkg, thepkg)
-			print "Affected package: " thepkg[1] " (matched by " $1 ")"
-			print "Type of problem: " $3 "."
-			split($2, ref, / /)
-			for (r in ref)
-				print "Reference: <" ref[r] ">"
-			if (note)
-				print "Note: " note
-			print ""
-		}
-		'
+function print_affected(apkg, glob, refs, descr, note) {
+	split(apkg, thepkg)
+	print "Affected package: " thepkg[1] " (matched by " glob ")"
+	print "Type of problem: " descr "."
+	split(refs, ref, / /)
+	for (r in ref)
+		print "Reference: <" ref[r] ">"
+	if (note)
+		print "Note: " note
+	print ""
+}
+'
 else
 	PRINTAFFECTED_AWK=3D'
-		function print_affected(apkg, note) {
-			split(apkg, thepkg)
-			print "Affected package: " thepkg[1]
-			print "Type of problem: " $3 "."
-			split($2, ref, / /)
-			for (r in ref)
-				print "Reference: <" ref[r] ">"
-			if (note)
-				print "Note: " note
-			print ""
-		}
-		'
+function print_affected(apkg, glob, refs, descr, note) {
+	split(apkg, thepkg)
+	print "Affected package: " thepkg[1]
+	print "Type of problem: " descr "."
+	split(refs, ref, / /)
+	for (r in ref)
+		print "Reference: <" ref[r] ">"
+	if (note)
+		print "Note: " note
+	print ""
+}
+'
 fi
=20
 if $opt_audit; then
--=20
1.6.0.2


--X3gaHHMYHkYqP6yf
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment;
	filename="0002-Separate-vulnerable-ports-search-from-the-formatter.patch"
Content-Transfer-Encoding: quoted-printable

=46rom b595cf7da5b81489b5e21d85df4dd8e79f3a0b1f Mon Sep 17 00:00:00 2001
=46rom: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Sun, 5 Oct 2008 18:56:13 +0400
Subject: [PATCH 2/4] Separate vulnerable ports search from the formatter ro=
utine

I am planning to insert some other filters between the code that outputs
the vulnerable port entries and the code that formats the messages about
vulnerabilities that had been found.  Such a split provides a big
flexibility: one can insert more filters that will transform entries and
one can substitute search routine for something else (I am planning to
substitute it with the binary utility written in a compiled language).

This was done only for the routine that checks the installed ports,
because it is my primary target for now.  May be later I will split
other auditing functions in the same way.

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 files/portaudit-cmd.sh |  101 ++++++++++++++++++++++++++++++--------------=
----
 1 files changed, 63 insertions(+), 38 deletions(-)

diff --git a/files/portaudit-cmd.sh b/files/portaudit-cmd.sh
index 4583c9c..5fc0d1d 100755
--- a/files/portaudit-cmd.sh
+++ b/files/portaudit-cmd.sh
@@ -125,50 +125,75 @@ portaudit_prerequisites()
 	return 0
 }
=20
+#
+# Helper for audit_installed that actually finds vulnerable packages.
+#
+# It processes the auditfile entries (that are read from the stdin)
+# in the form "glob|refs|desc" and outputs entries in the form
+# "pkgname|glob|refs|desc", where "pkgname" is the matched package name.
+#
+findvuln_installed()
+{
+	local fixedre=3D`echo -n $portaudit_fixed | tr -c '[:alnum:]- \t\n' 'x' |=
 tr -s ' \t\n' '|'`
+	local installedre=3D`$pkg_info -aE | sed -e 's/-[^-]*$//g' | paste -s -d =
'|' -`
+	local osversion=3D`sysctl -n kern.osreldate`
+
+	awk -F\| \
+	    -v fixedre=3D"$fixedre" -v installedre=3D"$installedre" \
+	    -v pkg_version=3D"$pkg_version" -v pkg_info=3D"$pkg_info" \
+	    -v osversion=3D"$osversion" -v opt_restrict=3D"$opt_restrict" \
+	    '
+/^(#|\$)/ { next }
+opt_restrict && $2 !~ opt_restrict { next }
+$1 ~ /^FreeBSD[<=3D>!]/ {
+	if (fixedre && $2 ~ fixedre) next
+	if (!system(pkg_version " -T \"FreeBSD-" osversion "\" \"" $1 "\"")) {
+		printf("FreeBSD-%s|%s\n", osversion, $0);
+	}
+	next
+}
+$1 ~ /^[^{}*?]*[<=3D>!]/ {
+	if ($1 !~ "^(" installedre ")[<=3D>!]") next;
+}
+{
+	cmd=3Dpkg_info " -E \"" $1 "\""
+	while((cmd | getline pkg) > 0) {
+		printf("%s|%s\n", pkg, $0);
+	}
+	close(cmd)
+}
+'
+}
+
 audit_installed()
 {
 	local rc=3D0
 	local osversion=3D`sysctl -n kern.osreldate`
=20
-	fixedre=3D`echo -n $portaudit_fixed | tr -c '[:alnum:]- \t\n' 'x' | tr -s=
 ' \t\n' '|'`
-	installedre=3D`$pkg_info -aE | sed -e 's/-[^-]*$//g' | paste -s -d '|' -`
-
-	extract_auditfile | awk -F\| "$PRINTAFFECTED_AWK"'
-		BEGIN { vul=3D0; fixedre=3D"'"$fixedre"'" }
-		/^(#|\$)/ { next }
-		$2 !~ /'"$opt_restrict"'/ { next }
-		$1 ~ /^FreeBSD[<=3D>!]/ {
-			if (fixedre && $2 ~ fixedre) next
-			if (!system("'"$pkg_version"' -T \"FreeBSD-'"$osversion"'\" \"" $1 "\""=
)) {
-				print_affected("FreeBSD-'"$osversion"'",=20
-					$1, $2, $3, \
-					"To disable this check add the uuid to \`portaudit_fixed'"'"' in %%PR=
EFIX%%/etc/portaudit.conf")
-			}
-			next
-		}
-		$1 ~ /^[^{}*?]*[<=3D>!]/ {
-			if ($1 !~ "^('"$installedre"')[<=3D>!]") next;
-		}
-		{
-			cmd=3D"'"$pkg_info"' -E \"" $1 "\""
-			while((cmd | getline pkg) > 0) {
-				vul++
-				print_affected(pkg, $1, $2, $3, "")
-			}
-			close(cmd)
-		}
-		END {
-			if ("'$opt_quiet'" =3D=3D "false") {
-				print vul " problem(s) in your installed packages found."
-			}
-			if (vul > 0) {
-				if ("'$opt_quiet'" =3D=3D "false") {
-					print "\nYou are advised to update or deinstall" \
-						" the affected package(s) immediately."
-				}
-				exit(1)
-			}
+	extract_auditfile | findvuln_installed | \
+	awk -F\| "$PRINTAFFECTED_AWK"'
+BEGIN { vul=3D0; }
+$1 ~ /^FreeBSD-/ {
+	print_affected($1, $2, $3, $4, \
+		"To disable this check add the uuid to \`portaudit_fixed'"'"' in %%PREFI=
X%%/etc/portaudit.conf")
+	next
+}
+{
+	print_affected($1, $2, $3, $4, "");
+	vul++;
+}
+END {
+	if ("'$opt_quiet'" =3D=3D "false") {
+		print vul " problem(s) in your installed packages found."
+	}
+	if (vul > 0) {
+		if ("'$opt_quiet'" =3D=3D "false") {
+			print "\nYou are advised to update or deinstall" \
+				" the affected package(s) immediately."
 		}
+		exit(1)
+	}
+}
 	' || rc=3D$?
=20
 	return $rc
--=20
1.6.0.2


--X3gaHHMYHkYqP6yf
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment;
	filename="0003-Use-pkg_audit-utility-if-it-is-available.patch"
Content-Transfer-Encoding: quoted-printable

=46rom 100bf18057bb16f21f0058e31279b9c3730e097d Mon Sep 17 00:00:00 2001
=46rom: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Sun, 5 Oct 2008 19:20:34 +0400
Subject: [PATCH 3/4] Use pkg_audit utility if it is available

Pkg_audit provides a good speed-up to the search of vulnerable packages
within installed ones.  It can be unavailable, so its usage is
conditionalized.

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 files/portaudit-cmd.sh |   15 +++++++++++++++
 files/portaudit.conf   |    4 ++++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/files/portaudit-cmd.sh b/files/portaudit-cmd.sh
index 5fc0d1d..32c121d 100755
--- a/files/portaudit-cmd.sh
+++ b/files/portaudit-cmd.sh
@@ -43,6 +43,8 @@ portaudit_confs()
=20
 	: ${portaudit_fixed=3D""}
=20
+	: ${portaudit_pkg_audit=3D"/usr/sbin/pkg_audit"}
+
 	if [ -r %%PREFIX%%/etc/portaudit.conf ]; then
 		. %%PREFIX%%/etc/portaudit.conf
 	fi
@@ -135,6 +137,19 @@ portaudit_prerequisites()
 findvuln_installed()
 {
 	local fixedre=3D`echo -n $portaudit_fixed | tr -c '[:alnum:]- \t\n' 'x' |=
 tr -s ' \t\n' '|'`
+
+	if [ -x "${portaudit_pkg_audit}" ]; then
+		"${portaudit_pkg_audit}" | awk -F \| \
+		    -v fixedre=3D"$fixedre" -v opt_restrict=3D"$opt_restrict" \
+		    '
+opt_restrict && $3 !~ opt_restrict { next }
+$2 ~ /^FreeBSD[<=3D>!]/ && fixedre && $3 ~ fixedre { next }
+{ print }
+'
+
+		return
+	fi
+
 	local installedre=3D`$pkg_info -aE | sed -e 's/-[^-]*$//g' | paste -s -d =
'|' -`
 	local osversion=3D`sysctl -n kern.osreldate`
=20
diff --git a/files/portaudit.conf b/files/portaudit.conf
index 4eb08d7..9ea2c4a 100644
--- a/files/portaudit.conf
+++ b/files/portaudit.conf
@@ -17,3 +17,7 @@
=20
 # this vulnerability has been fixed in your FreeBSD version
 #portaudit_fixed=3D"d2102505-f03d-11d8-81b0-000347a4fa7d"
+
+# this command will be used to find the vulnerable packages
+# instead of awk(1) script.
+# portaudit_pkg_audit=3D"/usr/sbin/pkg_audit"
--=20
1.6.0.2


--X3gaHHMYHkYqP6yf
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment;
	filename="0004-Implement-checking-for-a-new-package-versions.patch"
Content-Transfer-Encoding: quoted-printable

=46rom f4ef2c5c03ea9543ecdfc68a62b26449b8d492ed Mon Sep 17 00:00:00 2001
=46rom: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Sun, 5 Oct 2008 22:27:53 +0400
Subject: [PATCH 4/4] Implement checking for a new package versions

Flag '-n' tells portaudit to check if updated packages are available.
It is currently done only for the 'all installed packages' mode, i.e.
when '-a' flag is given.

To do this, one additional utility, portaudit-checknew, is introduced.
It downloads the ports INDEX file for the current FreeBSD version and
checks if new versions of packages are available.  This utility is
spawned at the late stage when vulnerable packages are already
determined and thus only they are checked.  So the number of input items
shouldn't be very large and portaudit-checknew is a plain shell script.

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 Makefile                    |    4 +-
 files/portaudit-checknew.sh |  159 +++++++++++++++++++++++++++++++++++++++=
++++
 files/portaudit-cmd.sh      |   67 +++++++++++++++---
 files/portaudit.1           |    4 +-
 pkg-plist                   |    1 +
 5 files changed, 222 insertions(+), 13 deletions(-)
 create mode 100755 files/portaudit-checknew.sh

diff --git a/Makefile b/Makefile
index 885dc27..6083235 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,8 @@ SED_SCRIPT=3D	-e 's|%%PREFIX%%|${PREFIX}|g' \
 		-e "s|%%BZIP2_CMD%%|${BZIP2_CMD}|g" \
=20
 do-build:
-.for f in portaudit-cmd.sh portaudit.sh portaudit.1 portaudit.conf
+.for f in portaudit-cmd.sh portaudit-checknew.sh portaudit.sh \
+    portaudit.1 portaudit.conf
 	@${SED} ${SED_SCRIPT} ${FILESDIR}/${f} >${WRKDIR}/${f}
 .endfor
=20
@@ -54,6 +55,7 @@ pre-install:
=20
 do-install:
 	@${INSTALL_SCRIPT} ${WRKDIR}/portaudit-cmd.sh ${PREFIX}/sbin/portaudit
+	@${INSTALL_SCRIPT} ${WRKDIR}/portaudit-checknew.sh ${PREFIX}/sbin/portaud=
it-checknew
 	@${INSTALL_DATA} ${WRKDIR}/portaudit.conf ${PREFIX}/etc/portaudit.conf.sa=
mple
 	@${INSTALL_MAN} ${WRKDIR}/portaudit.1 ${MAN1PREFIX}/man/man1
 	@${MKDIR} ${PERIODICDIR}/security
diff --git a/files/portaudit-checknew.sh b/files/portaudit-checknew.sh
new file mode 100755
index 0000000..6bc7dfe
--- /dev/null
+++ b/files/portaudit-checknew.sh
@@ -0,0 +1,159 @@
+#!/bin/sh
+# $FreeBSD$
+#
+# Script to check if newer port versions then the ones installed
+# in the system are available.  Uses downloaded ports index from
+# the master site.
+#
+# Utility acts as a filter: reads input strings, processes them
+# and outputs the result to the standard output.  Each input string
+# is treated as the collection of '|'-separated fields.  First field
+# should be the package name with version, other fields can have
+# any contents -- they won't be touched.
+#
+# One more field can be added -- the newest port version, if it can
+# be deduced.  This field will be added to the end fieldset.
+#
+# For any error the utility will just output the unmodified input
+# contents.
+#
+# Eygene Ryabinkin, rea-fbsd@codelabs.ru.  September 2008.
+
+BASEURL=3Dhttp://www.freebsd.org/ports/INDEX-
+PKGBASE=3D/var/db/pkg
+
+# Obtains FreeBSD major version number from uname output.
+freebsd_major () {
+	uname -r | cut -f1 -d- | cut -f1 -d.
+}
+
+# Returns the OS version for the INDEX file.  It is just a wrapper
+# for the freebsd_major routine that applies the fixups for the
+# known unsupported versions.
+index_version () {
+	local major
+
+	major=3D`freebsd_major`
+	case "$major" in
+	1|2|3|4)
+		major=3D5
+		;;
+	esac
+	echo "$major"
+}
+
+# Guesses (installed) port origin.
+# Arguments:
+# - port name with version specification.
+# - name of file wit
+guess_origin () {
+	local contents origin
+
+	if [ -z "$1" ]; then
+		echo "guess_origin(): called without arguments" >&2
+		exit 255
+	fi
+	if [ -z "$2" ]; then
+		echo "guess_origin(): called without second argument" >&2
+		exit 255
+	fi
+
+	contents=3D"$PKGBASE"/"$1"/"+CONTENTS"
+	if [ -s "$contents" ]; then
+		origin=3D`grep '^@comment ORIGIN:' "$contents" | \
+		    sed -e's/^@comment ORIGIN://'`
+		if [ -n "$origin" ]; then
+			echo "$origin"
+			return
+		fi
+	fi
+	# Not yet implemented: loop over INDEX file and try to get
+	# the origin from the matched ports description.
+}
+
+# Fetches bzipped port index file and outputs it to the stdout
+# Arguments:
+# - URL to get file from.
+#
+# Uses 'opt_cachedir' (if it is not empty) as the name of the directory
+# to place the downloaded file to.  Download is made in the mirror mode,
+# so if file's timestamps and size are checked and no download takes
+# place if the remote file has the same characteristics.
+fetch_index () {
+	if [ -z "$1" ]; then
+		echo "fetch_index(): called without arguments" >&2
+		exit 255
+	fi
+
+	if [ -z "$opt_cachedir" -o ! -d "$opt_cachedir" ]; then
+		fetch -qpo - "$1"
+		return
+	fi
+
+	local outfile=3D"$opt_cachedir"/`basename "$1"`
+	fetch -mpo "$outfile" "$1" && cat "$outfile"
+}
+
+TMPINDEX=3D`mktemp -q -t versionaudit-INDEX`
+if [ -z "$TMPINDEX" ]; then
+	echo "Unable to create temporary file for ports index." >&2
+	cat
+	exit 1
+fi
+
+trap "rm -f \"$TMPINDEX\"" 0 1 2 3 15
+
+opt_cachedir=3D
+
+while getopts c: opt; do
+	case "$opt" in
+	c)
+		opt_cachedir=3D"$OPTARG"
+		;;
+	?)
+		echo "Usage: $0 [-c cachedir]"
+		exit 2
+		;;
+	esac
+done
+
+url=3D"$BASEURL"`index_version`.bz2
+fetch_index "$url" | bunzip2 -c > "$TMPINDEX"
+if ! [ -s "$TMPINDEX" ]; then
+	echo "Unable to download port index from $url" >&2
+	cat
+	exit 1
+fi
+
+IFS=3D'|'
+while read portspec rest; do
+	portname=3D`echo "$portspec" | sed -e's/-[^-]*$//'`
+	origin=3D`guess_origin "$portspec" "$TMPINDEX"`
+	if [ -z "$origin" ]; then
+		echo "Unable to get port origin for '$portspec'." >&2
+		continue
+	fi
+	# The while cycle is hackish: we make "$?" non-zero if no
+	# matches were found and it is set to zero if match was
+	# found.  All exit paths from the cycle should set "$?"
+	# properly.
+	#
+	# Another way to proceed is to make subroutine that will
+	# either print something or not, because we can't pass
+	# variables outside the while loop -- it is done in the
+	# separate process.
+	grep "^$portname-" "$TMPINDEX" | while read nportspec ndir nrest
+	do
+		nportname=3D`echo "$nportspec" | sed -e's/-[^-]*$//'`
+		norigin=3D`echo "$ndir" | sed -e's|^/[^/]*/[^/]*/||'`
+		if [ "$nportname" =3D "$portname" -a \
+		     "$norigin" =3D "$origin" ]; then
+			echo "$portspec|$rest|$nportspec"
+			true
+			break
+		fi
+		false
+	done || echo "$portspec|$rest"
+done
+
+exit 0
diff --git a/files/portaudit-cmd.sh b/files/portaudit-cmd.sh
index 32c121d..0ddd3d3 100755
--- a/files/portaudit-cmd.sh
+++ b/files/portaudit-cmd.sh
@@ -127,6 +127,15 @@ portaudit_prerequisites()
 	return 0
 }
=20
+checknew()
+{
+	if [ -n "$opt_checknew" ]; then
+		portaudit-checknew -c "${portaudit_dir}"
+	else
+		cat
+	fi
+}
+
 #
 # Helper for audit_installed that actually finds vulnerable packages.
 #
@@ -185,16 +194,16 @@ audit_installed()
 	local rc=3D0
 	local osversion=3D`sysctl -n kern.osreldate`
=20
-	extract_auditfile | findvuln_installed | \
-	awk -F\| "$PRINTAFFECTED_AWK"'
+	extract_auditfile | findvuln_installed | checknew | \
+	awk -F\| -v pkg_version=3D"$pkg_version" "$PRINTAFFECTED_AWK"'
 BEGIN { vul=3D0; }
 $1 ~ /^FreeBSD-/ {
-	print_affected($1, $2, $3, $4, \
+	print_affected($1, $2, $3, $4, "", \
 		"To disable this check add the uuid to \`portaudit_fixed'"'"' in %%PREFI=
X%%/etc/portaudit.conf")
 	next
 }
 {
-	print_affected($1, $2, $3, $4, "");
+	print_affected($1, $2, $3, $4, $5, "");
 	vul++;
 }
 END {
@@ -248,7 +257,7 @@ audit_file()
 				if ($2 !~ /'"$opt_restrict"'/)
 					continue
 				vul++
-				print_affected(pkg, $1, $2, $3, "")
+				print_affected(pkg, $1, $2, $3, "", "")
 			}
 			close(cmd)
 		}
@@ -286,7 +295,7 @@ audit_args()
 				VULCNT=3D$(($VULCNT+1))
 				echo "$VLIST" | awk -F\| "$PRINTAFFECTED_AWK"'
 					{ print_affected("'"$1"'",
-					    $1, $2, $3, "") }
+					    $1, $2, $3, "", "") }
 				'
 			fi
 			;;
@@ -319,7 +328,7 @@ audit_cwd()
 			{ print }
 		' | $pkg_version -T "$PKGNAME" -`; then
 		echo "$VLIST" | awk -F\| "$PRINTAFFECTED_AWK"'
-			{ print_affected("'"$PKGNAME"'", $1, $2, $3, "") }
+			{ print_affected("'"$PKGNAME"'", $1, $2, $3, "", "") }
 		'
 		return 1
 	fi
@@ -389,12 +398,13 @@ opt_restrict=3D
 opt_verbose=3Dfalse
 opt_version=3Dfalse
 opt_expiry=3D
+opt_checknew=3D
=20
 if [ $# -eq 0 ] ; then
 	opt_audit=3Dtrue
 fi
=20
-while getopts aCdf:Fqr:vVX: opt; do
+while getopts aCdf:Fnqr:vVX: opt; do
 	case "$opt" in
 	a)
 		opt_audit=3Dtrue;;
@@ -406,6 +416,8 @@ while getopts aCdf:Fqr:vVX: opt; do
 		opt_file=3D"$OPTARG";;
 	F)
 		opt_fetch=3Dtrue;;
+	n)
+		opt_checknew=3Dtrue;;
 	q)
 		opt_quiet=3Dtrue;;
 	r)
@@ -465,15 +477,42 @@ fi
=20
 prerequisites_checked=3Dfalse
=20
+# This awk code demands 'pkg_version' variable to be set
+# if 'newver' variable is non-empty.
+NEWVERS_AWK=3D'
+
+nparts=3Dsplit(thepkg[1], verarr, /-/)
+gtglob=3Dverarr[1]
+for (i=3D2; i<nparts; i++)
+	gtglob=3Dgtglob "-" verarr[i]
+gtglob=3Dgtglob ">" verarr[i]
+
+updated=3D""
+avail=3D0
+if (system(pkg_version " -T \"" newver "\" '\''" gtglob "'\''") =3D=3D 0) {
+	updated=3D"available, " newver
+	avail=3D1
+} else {
+	updated=3D"not available"
+}
+if (avail !=3D 0) {
+	if (system(pkg_version " -T \"" newver "\" '\''" glob "'\''") =3D=3D 0)
+		updated=3Dupdated ", still vulnerable"
+	else
+		updated=3Dupdated ", not vulnerable"
+}
+print "Updated package: " updated
+'
+
 if $opt_quiet; then
 	PRINTAFFECTED_AWK=3D'
-function print_affected(apkg, glob, refs, descr, note) {
+function print_affected(apkg, glob, refs, descr, newver, note) {
 	print apkg
 }
 '
 elif $opt_verbose; then
 	PRINTAFFECTED_AWK=3D'
-function print_affected(apkg, glob, refs, descr, note) {
+function print_affected(apkg, glob, refs, descr, newver, note) {
 	split(apkg, thepkg)
 	print "Affected package: " thepkg[1] " (matched by " glob ")"
 	print "Type of problem: " descr "."
@@ -482,12 +521,15 @@ function print_affected(apkg, glob, refs, descr, note=
) {
 		print "Reference: <" ref[r] ">"
 	if (note)
 		print "Note: " note
+	if (newver) {
+'"$NEWVERS_AWK"'
+	}
 	print ""
 }
 '
 else
 	PRINTAFFECTED_AWK=3D'
-function print_affected(apkg, glob, refs, descr, note) {
+function print_affected(apkg, glob, refs, descr, newver, note) {
 	split(apkg, thepkg)
 	print "Affected package: " thepkg[1]
 	print "Type of problem: " descr "."
@@ -496,6 +538,9 @@ function print_affected(apkg, glob, refs, descr, note) {
 		print "Reference: <" ref[r] ">"
 	if (note)
 		print "Note: " note
+	if (newver) {
+'"$NEWVERS_AWK"'
+	}
 	print ""
 }
 '
diff --git a/files/portaudit.1 b/files/portaudit.1
index c982b41..5cb0ec2 100644
--- a/files/portaudit.1
+++ b/files/portaudit.1
@@ -42,7 +42,7 @@
 .Sh SYNOPSIS
 .
 .Nm
-.Op Fl aCdFqvV
+.Op Fl aCdFnqvV
 .Op Fl X Ar days
 .Op Fl f Ar file
 .Op Fl r Ar eregex
@@ -85,6 +85,8 @@ Print the creation date of the database.
 Fetch the current database from the
 .Fx
 servers.
+.It Fl n
+Check if new versions of vulnerable ports are present.
 .It Fl q
 Quiet mode.
 .It Fl V
diff --git a/pkg-plist b/pkg-plist
index 8edf7bb..3c9f775 100644
--- a/pkg-plist
+++ b/pkg-plist
@@ -1,4 +1,5 @@
 sbin/portaudit
+sbin/portaudit-checknew
 etc/portaudit.conf.sample
 %%PERIODICDIR%%/security/410.portaudit
 @dirrmtry %%PERIODICDIR%%/security
--=20
1.6.0.2


--X3gaHHMYHkYqP6yf
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment;
	filename="portaudit-megapatch_pkg_audit-and-checknew.diff"
Content-Transfer-Encoding: quoted-printable

This is the megapatch that adds both pkg_audit support and the ability
to check if new versions of vulnerable ports are present.

diff --git a/Makefile b/Makefile
index 885dc27..6083235 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,8 @@ SED_SCRIPT=3D	-e 's|%%PREFIX%%|${PREFIX}|g' \
 		-e "s|%%BZIP2_CMD%%|${BZIP2_CMD}|g" \
=20
 do-build:
-.for f in portaudit-cmd.sh portaudit.sh portaudit.1 portaudit.conf
+.for f in portaudit-cmd.sh portaudit-checknew.sh portaudit.sh \
+    portaudit.1 portaudit.conf
 	@${SED} ${SED_SCRIPT} ${FILESDIR}/${f} >${WRKDIR}/${f}
 .endfor
=20
@@ -54,6 +55,7 @@ pre-install:
=20
 do-install:
 	@${INSTALL_SCRIPT} ${WRKDIR}/portaudit-cmd.sh ${PREFIX}/sbin/portaudit
+	@${INSTALL_SCRIPT} ${WRKDIR}/portaudit-checknew.sh ${PREFIX}/sbin/portaud=
it-checknew
 	@${INSTALL_DATA} ${WRKDIR}/portaudit.conf ${PREFIX}/etc/portaudit.conf.sa=
mple
 	@${INSTALL_MAN} ${WRKDIR}/portaudit.1 ${MAN1PREFIX}/man/man1
 	@${MKDIR} ${PERIODICDIR}/security
diff --git a/files/portaudit-checknew.sh b/files/portaudit-checknew.sh
new file mode 100755
index 0000000..6bc7dfe
--- /dev/null
+++ b/files/portaudit-checknew.sh
@@ -0,0 +1,159 @@
+#!/bin/sh
+# $FreeBSD$
+#
+# Script to check if newer port versions then the ones installed
+# in the system are available.  Uses downloaded ports index from
+# the master site.
+#
+# Utility acts as a filter: reads input strings, processes them
+# and outputs the result to the standard output.  Each input string
+# is treated as the collection of '|'-separated fields.  First field
+# should be the package name with version, other fields can have
+# any contents -- they won't be touched.
+#
+# One more field can be added -- the newest port version, if it can
+# be deduced.  This field will be added to the end fieldset.
+#
+# For any error the utility will just output the unmodified input
+# contents.
+#
+# Eygene Ryabinkin, rea-fbsd@codelabs.ru.  September 2008.
+
+BASEURL=3Dhttp://www.freebsd.org/ports/INDEX-
+PKGBASE=3D/var/db/pkg
+
+# Obtains FreeBSD major version number from uname output.
+freebsd_major () {
+	uname -r | cut -f1 -d- | cut -f1 -d.
+}
+
+# Returns the OS version for the INDEX file.  It is just a wrapper
+# for the freebsd_major routine that applies the fixups for the
+# known unsupported versions.
+index_version () {
+	local major
+
+	major=3D`freebsd_major`
+	case "$major" in
+	1|2|3|4)
+		major=3D5
+		;;
+	esac
+	echo "$major"
+}
+
+# Guesses (installed) port origin.
+# Arguments:
+# - port name with version specification.
+# - name of file wit
+guess_origin () {
+	local contents origin
+
+	if [ -z "$1" ]; then
+		echo "guess_origin(): called without arguments" >&2
+		exit 255
+	fi
+	if [ -z "$2" ]; then
+		echo "guess_origin(): called without second argument" >&2
+		exit 255
+	fi
+
+	contents=3D"$PKGBASE"/"$1"/"+CONTENTS"
+	if [ -s "$contents" ]; then
+		origin=3D`grep '^@comment ORIGIN:' "$contents" | \
+		    sed -e's/^@comment ORIGIN://'`
+		if [ -n "$origin" ]; then
+			echo "$origin"
+			return
+		fi
+	fi
+	# Not yet implemented: loop over INDEX file and try to get
+	# the origin from the matched ports description.
+}
+
+# Fetches bzipped port index file and outputs it to the stdout
+# Arguments:
+# - URL to get file from.
+#
+# Uses 'opt_cachedir' (if it is not empty) as the name of the directory
+# to place the downloaded file to.  Download is made in the mirror mode,
+# so if file's timestamps and size are checked and no download takes
+# place if the remote file has the same characteristics.
+fetch_index () {
+	if [ -z "$1" ]; then
+		echo "fetch_index(): called without arguments" >&2
+		exit 255
+	fi
+
+	if [ -z "$opt_cachedir" -o ! -d "$opt_cachedir" ]; then
+		fetch -qpo - "$1"
+		return
+	fi
+
+	local outfile=3D"$opt_cachedir"/`basename "$1"`
+	fetch -mpo "$outfile" "$1" && cat "$outfile"
+}
+
+TMPINDEX=3D`mktemp -q -t versionaudit-INDEX`
+if [ -z "$TMPINDEX" ]; then
+	echo "Unable to create temporary file for ports index." >&2
+	cat
+	exit 1
+fi
+
+trap "rm -f \"$TMPINDEX\"" 0 1 2 3 15
+
+opt_cachedir=3D
+
+while getopts c: opt; do
+	case "$opt" in
+	c)
+		opt_cachedir=3D"$OPTARG"
+		;;
+	?)
+		echo "Usage: $0 [-c cachedir]"
+		exit 2
+		;;
+	esac
+done
+
+url=3D"$BASEURL"`index_version`.bz2
+fetch_index "$url" | bunzip2 -c > "$TMPINDEX"
+if ! [ -s "$TMPINDEX" ]; then
+	echo "Unable to download port index from $url" >&2
+	cat
+	exit 1
+fi
+
+IFS=3D'|'
+while read portspec rest; do
+	portname=3D`echo "$portspec" | sed -e's/-[^-]*$//'`
+	origin=3D`guess_origin "$portspec" "$TMPINDEX"`
+	if [ -z "$origin" ]; then
+		echo "Unable to get port origin for '$portspec'." >&2
+		continue
+	fi
+	# The while cycle is hackish: we make "$?" non-zero if no
+	# matches were found and it is set to zero if match was
+	# found.  All exit paths from the cycle should set "$?"
+	# properly.
+	#
+	# Another way to proceed is to make subroutine that will
+	# either print something or not, because we can't pass
+	# variables outside the while loop -- it is done in the
+	# separate process.
+	grep "^$portname-" "$TMPINDEX" | while read nportspec ndir nrest
+	do
+		nportname=3D`echo "$nportspec" | sed -e's/-[^-]*$//'`
+		norigin=3D`echo "$ndir" | sed -e's|^/[^/]*/[^/]*/||'`
+		if [ "$nportname" =3D "$portname" -a \
+		     "$norigin" =3D "$origin" ]; then
+			echo "$portspec|$rest|$nportspec"
+			true
+			break
+		fi
+		false
+	done || echo "$portspec|$rest"
+done
+
+exit 0
diff --git a/files/portaudit-cmd.sh b/files/portaudit-cmd.sh
index c0eb67b..0ddd3d3 100755
--- a/files/portaudit-cmd.sh
+++ b/files/portaudit-cmd.sh
@@ -43,6 +43,8 @@ portaudit_confs()
=20
 	: ${portaudit_fixed=3D""}
=20
+	: ${portaudit_pkg_audit=3D"/usr/sbin/pkg_audit"}
+
 	if [ -r %%PREFIX%%/etc/portaudit.conf ]; then
 		. %%PREFIX%%/etc/portaudit.conf
 	fi
@@ -125,49 +127,97 @@ portaudit_prerequisites()
 	return 0
 }
=20
+checknew()
+{
+	if [ -n "$opt_checknew" ]; then
+		portaudit-checknew -c "${portaudit_dir}"
+	else
+		cat
+	fi
+}
+
+#
+# Helper for audit_installed that actually finds vulnerable packages.
+#
+# It processes the auditfile entries (that are read from the stdin)
+# in the form "glob|refs|desc" and outputs entries in the form
+# "pkgname|glob|refs|desc", where "pkgname" is the matched package name.
+#
+findvuln_installed()
+{
+	local fixedre=3D`echo -n $portaudit_fixed | tr -c '[:alnum:]- \t\n' 'x' |=
 tr -s ' \t\n' '|'`
+
+	if [ -x "${portaudit_pkg_audit}" ]; then
+		"${portaudit_pkg_audit}" | awk -F \| \
+		    -v fixedre=3D"$fixedre" -v opt_restrict=3D"$opt_restrict" \
+		    '
+opt_restrict && $3 !~ opt_restrict { next }
+$2 ~ /^FreeBSD[<=3D>!]/ && fixedre && $3 ~ fixedre { next }
+{ print }
+'
+
+		return
+	fi
+
+	local installedre=3D`$pkg_info -aE | sed -e 's/-[^-]*$//g' | paste -s -d =
'|' -`
+	local osversion=3D`sysctl -n kern.osreldate`
+
+	awk -F\| \
+	    -v fixedre=3D"$fixedre" -v installedre=3D"$installedre" \
+	    -v pkg_version=3D"$pkg_version" -v pkg_info=3D"$pkg_info" \
+	    -v osversion=3D"$osversion" -v opt_restrict=3D"$opt_restrict" \
+	    '
+/^(#|\$)/ { next }
+opt_restrict && $2 !~ opt_restrict { next }
+$1 ~ /^FreeBSD[<=3D>!]/ {
+	if (fixedre && $2 ~ fixedre) next
+	if (!system(pkg_version " -T \"FreeBSD-" osversion "\" \"" $1 "\"")) {
+		printf("FreeBSD-%s|%s\n", osversion, $0);
+	}
+	next
+}
+$1 ~ /^[^{}*?]*[<=3D>!]/ {
+	if ($1 !~ "^(" installedre ")[<=3D>!]") next;
+}
+{
+	cmd=3Dpkg_info " -E \"" $1 "\""
+	while((cmd | getline pkg) > 0) {
+		printf("%s|%s\n", pkg, $0);
+	}
+	close(cmd)
+}
+'
+}
+
 audit_installed()
 {
 	local rc=3D0
 	local osversion=3D`sysctl -n kern.osreldate`
=20
-	fixedre=3D`echo -n $portaudit_fixed | tr -c '[:alnum:]- \t\n' 'x' | tr -s=
 ' \t\n' '|'`
-	installedre=3D`$pkg_info -aE | sed -e 's/-[^-]*$//g' | paste -s -d '|' -`
-
-	extract_auditfile | awk -F\| "$PRINTAFFECTED_AWK"'
-		BEGIN { vul=3D0; fixedre=3D"'"$fixedre"'" }
-		/^(#|\$)/ { next }
-		$2 !~ /'"$opt_restrict"'/ { next }
-		$1 ~ /^FreeBSD[<=3D>!]/ {
-			if (fixedre && $2 ~ fixedre) next
-			if (!system("'"$pkg_version"' -T \"FreeBSD-'"$osversion"'\" \"" $1 "\""=
)) {
-				print_affected("FreeBSD-'"$osversion"'", \
-					"To disable this check add the uuid to \`portaudit_fixed'"'"' in %%PR=
EFIX%%/etc/portaudit.conf")
-			}
-			next
-		}
-		$1 ~ /^[^{}*?]*[<=3D>!]/ {
-			if ($1 !~ "^('"$installedre"')[<=3D>!]") next;
-		}
-		{
-			cmd=3D"'"$pkg_info"' -E \"" $1 "\""
-			while((cmd | getline pkg) > 0) {
-				vul++
-				print_affected(pkg, "")
-			}
-			close(cmd)
-		}
-		END {
-			if ("'$opt_quiet'" =3D=3D "false") {
-				print vul " problem(s) in your installed packages found."
-			}
-			if (vul > 0) {
-				if ("'$opt_quiet'" =3D=3D "false") {
-					print "\nYou are advised to update or deinstall" \
-						" the affected package(s) immediately."
-				}
-				exit(1)
-			}
+	extract_auditfile | findvuln_installed | checknew | \
+	awk -F\| -v pkg_version=3D"$pkg_version" "$PRINTAFFECTED_AWK"'
+BEGIN { vul=3D0; }
+$1 ~ /^FreeBSD-/ {
+	print_affected($1, $2, $3, $4, "", \
+		"To disable this check add the uuid to \`portaudit_fixed'"'"' in %%PREFI=
X%%/etc/portaudit.conf")
+	next
+}
+{
+	print_affected($1, $2, $3, $4, $5, "");
+	vul++;
+}
+END {
+	if ("'$opt_quiet'" =3D=3D "false") {
+		print vul " problem(s) in your installed packages found."
+	}
+	if (vul > 0) {
+		if ("'$opt_quiet'" =3D=3D "false") {
+			print "\nYou are advised to update or deinstall" \
+				" the affected package(s) immediately."
 		}
+		exit(1)
+	}
+}
 	' || rc=3D$?
=20
 	return $rc
@@ -207,7 +257,7 @@ audit_file()
 				if ($2 !~ /'"$opt_restrict"'/)
 					continue
 				vul++
-				print_affected(pkg, "")
+				print_affected(pkg, $1, $2, $3, "", "")
 			}
 			close(cmd)
 		}
@@ -244,7 +294,8 @@ audit_args()
 				' | $pkg_version -T "$1" -`; then
 				VULCNT=3D$(($VULCNT+1))
 				echo "$VLIST" | awk -F\| "$PRINTAFFECTED_AWK"'
-					{ print_affected("'"$1"'", "") }
+					{ print_affected("'"$1"'",
+					    $1, $2, $3, "", "") }
 				'
 			fi
 			;;
@@ -277,7 +328,7 @@ audit_cwd()
 			{ print }
 		' | $pkg_version -T "$PKGNAME" -`; then
 		echo "$VLIST" | awk -F\| "$PRINTAFFECTED_AWK"'
-			{ print_affected("'"$PKGNAME"'", "") }
+			{ print_affected("'"$PKGNAME"'", $1, $2, $3, "", "") }
 		'
 		return 1
 	fi
@@ -347,12 +398,13 @@ opt_restrict=3D
 opt_verbose=3Dfalse
 opt_version=3Dfalse
 opt_expiry=3D
+opt_checknew=3D
=20
 if [ $# -eq 0 ] ; then
 	opt_audit=3Dtrue
 fi
=20
-while getopts aCdf:Fqr:vVX: opt; do
+while getopts aCdf:Fnqr:vVX: opt; do
 	case "$opt" in
 	a)
 		opt_audit=3Dtrue;;
@@ -364,6 +416,8 @@ while getopts aCdf:Fqr:vVX: opt; do
 		opt_file=3D"$OPTARG";;
 	F)
 		opt_fetch=3Dtrue;;
+	n)
+		opt_checknew=3Dtrue;;
 	q)
 		opt_quiet=3Dtrue;;
 	r)
@@ -423,40 +477,73 @@ fi
=20
 prerequisites_checked=3Dfalse
=20
+# This awk code demands 'pkg_version' variable to be set
+# if 'newver' variable is non-empty.
+NEWVERS_AWK=3D'
+
+nparts=3Dsplit(thepkg[1], verarr, /-/)
+gtglob=3Dverarr[1]
+for (i=3D2; i<nparts; i++)
+	gtglob=3Dgtglob "-" verarr[i]
+gtglob=3Dgtglob ">" verarr[i]
+
+updated=3D""
+avail=3D0
+if (system(pkg_version " -T \"" newver "\" '\''" gtglob "'\''") =3D=3D 0) {
+	updated=3D"available, " newver
+	avail=3D1
+} else {
+	updated=3D"not available"
+}
+if (avail !=3D 0) {
+	if (system(pkg_version " -T \"" newver "\" '\''" glob "'\''") =3D=3D 0)
+		updated=3Dupdated ", still vulnerable"
+	else
+		updated=3Dupdated ", not vulnerable"
+}
+print "Updated package: " updated
+'
+
 if $opt_quiet; then
 	PRINTAFFECTED_AWK=3D'
-		function print_affected(apkg, note) {
-			print apkg
-		}
-		'
+function print_affected(apkg, glob, refs, descr, newver, note) {
+	print apkg
+}
+'
 elif $opt_verbose; then
 	PRINTAFFECTED_AWK=3D'
-		function print_affected(apkg, note) {
-			split(apkg, thepkg)
-			print "Affected package: " thepkg[1] " (matched by " $1 ")"
-			print "Type of problem: " $3 "."
-			split($2, ref, / /)
-			for (r in ref)
-				print "Reference: <" ref[r] ">"
-			if (note)
-				print "Note: " note
-			print ""
-		}
-		'
+function print_affected(apkg, glob, refs, descr, newver, note) {
+	split(apkg, thepkg)
+	print "Affected package: " thepkg[1] " (matched by " glob ")"
+	print "Type of problem: " descr "."
+	split(refs, ref, / /)
+	for (r in ref)
+		print "Reference: <" ref[r] ">"
+	if (note)
+		print "Note: " note
+	if (newver) {
+'"$NEWVERS_AWK"'
+	}
+	print ""
+}
+'
 else
 	PRINTAFFECTED_AWK=3D'
-		function print_affected(apkg, note) {
-			split(apkg, thepkg)
-			print "Affected package: " thepkg[1]
-			print "Type of problem: " $3 "."
-			split($2, ref, / /)
-			for (r in ref)
-				print "Reference: <" ref[r] ">"
-			if (note)
-				print "Note: " note
-			print ""
-		}
-		'
+function print_affected(apkg, glob, refs, descr, newver, note) {
+	split(apkg, thepkg)
+	print "Affected package: " thepkg[1]
+	print "Type of problem: " descr "."
+	split(refs, ref, / /)
+	for (r in ref)
+		print "Reference: <" ref[r] ">"
+	if (note)
+		print "Note: " note
+	if (newver) {
+'"$NEWVERS_AWK"'
+	}
+	print ""
+}
+'
 fi
=20
 if $opt_audit; then
diff --git a/files/portaudit.1 b/files/portaudit.1
index c982b41..5cb0ec2 100644
--- a/files/portaudit.1
+++ b/files/portaudit.1
@@ -42,7 +42,7 @@
 .Sh SYNOPSIS
 .
 .Nm
-.Op Fl aCdFqvV
+.Op Fl aCdFnqvV
 .Op Fl X Ar days
 .Op Fl f Ar file
 .Op Fl r Ar eregex
@@ -85,6 +85,8 @@ Print the creation date of the database.
 Fetch the current database from the
 .Fx
 servers.
+.It Fl n
+Check if new versions of vulnerable ports are present.
 .It Fl q
 Quiet mode.
 .It Fl V
diff --git a/files/portaudit.conf b/files/portaudit.conf
index 4eb08d7..9ea2c4a 100644
--- a/files/portaudit.conf
+++ b/files/portaudit.conf
@@ -17,3 +17,7 @@
=20
 # this vulnerability has been fixed in your FreeBSD version
 #portaudit_fixed=3D"d2102505-f03d-11d8-81b0-000347a4fa7d"
+
+# this command will be used to find the vulnerable packages
+# instead of awk(1) script.
+# portaudit_pkg_audit=3D"/usr/sbin/pkg_audit"
diff --git a/pkg-plist b/pkg-plist
index 8edf7bb..3c9f775 100644
--- a/pkg-plist
+++ b/pkg-plist
@@ -1,4 +1,5 @@
 sbin/portaudit
+sbin/portaudit-checknew
 etc/portaudit.conf.sample
 %%PERIODICDIR%%/security/410.portaudit
 @dirrmtry %%PERIODICDIR%%/security

--X3gaHHMYHkYqP6yf--

--aPdhxNJGSeOG9wFI
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (FreeBSD)

iEYEARECAAYFAkjpD3QACgkQthUKNsbL7YhR0gCcDLqUN4PF6QqCWua2KuIza2OD
hfEAn11non2XPdY+r4zIsFYIPC0x4vs1
=kJcQ
-----END PGP SIGNATURE-----

--aPdhxNJGSeOG9wFI--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?xIGBGzzNkgJfXK2hY3ABIqS4mko>