[Open-scap] [PATCH 1/1] Add the dpkginfo probe to query information on Debian packages

Pierre Chifflier chifflier at edenwall.com
Mon Feb 22 21:22:53 UTC 2010


Implement the dpkginfo probe, mostly inspired from the rpminfo probe.
The apt-pkg library is available only in C++, so the configure script
now checks for the C++ compiler.

Signed-off-by: Pierre Chifflier <chifflier at edenwall.com>
---
 configure.ac                                   |   14 ++
 src/OVAL/oval_probe.c                          |    2 +-
 src/OVAL/probes/Makefile.am                    |    9 ++
 src/OVAL/probes/unix/linux/dpkginfo-helper.cxx |  130 +++++++++++++++++
 src/OVAL/probes/unix/linux/dpkginfo-helper.h   |   34 +++++
 src/OVAL/probes/unix/linux/dpkginfo.c          |  182 ++++++++++++++++++++++++
 6 files changed, 370 insertions(+), 1 deletions(-)
 create mode 100644 src/OVAL/probes/unix/linux/dpkginfo-helper.cxx
 create mode 100644 src/OVAL/probes/unix/linux/dpkginfo-helper.h
 create mode 100644 src/OVAL/probes/unix/linux/dpkginfo.c

diff --git a/configure.ac b/configure.ac
index 36bc38b..3a7a0ef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,7 @@ AM_PATH_PYTHON
 # Checks for programs.
 AC_PROG_CC
 AM_PROG_CC_C_O
+AC_PROG_CXX
 AC_PROG_INSTALL
 AC_PROG_LN_S
 AC_PROG_MAKE_SET
@@ -170,6 +171,15 @@ AC_SEARCH_LIBS(
 ;;
 esac
 
+AC_CHECK_LIB(
+  [apt-pkg],
+  [pkgVersion],
+  [deb_cflags=""
+   deb_libs="-lapt-pkg"
+   have_libapt_pkg=yes
+  ]
+)
+
 #
 # threads
 #
@@ -252,6 +262,9 @@ AC_SUBST(pcre_libs)
 AC_SUBST(rpm_cflags)
 AC_SUBST(rpm_libs)
 
+AC_SUBST(deb_cflags)
+AC_SUBST(deb_libs)
+
 AC_SUBST(libnl_cflags)
 AC_SUBST(libnl_libs)
 
@@ -419,6 +432,7 @@ AM_CONDITIONAL([WANT_PROBES_UNIX], test "$probes_unix" = yes)
 AM_CONDITIONAL([WANT_PROBES_LINUX], test "$probes_linux" = yes)
 AM_CONDITIONAL([ENABLE_PROBE_RPMINFO], test "$have_librpm" = yes)
 AM_CONDITIONAL([ENABLE_PROBE_RPMINFO44], test "$have_librpm44" = yes)
+AM_CONDITIONAL([ENABLE_PROBE_DPKGINFO], test "$have_libapt_pkg" = yes)
 AM_CONDITIONAL([WANT_BINDINGS], test "$bindings" = yes)
 
 AC_CONFIG_FILES([Makefile
diff --git a/src/OVAL/oval_probe.c b/src/OVAL/oval_probe.c
index be5cf6f..01bffe6 100644
--- a/src/OVAL/oval_probe.c
+++ b/src/OVAL/oval_probe.c
@@ -37,7 +37,7 @@ static const oval_pdsc_t __ovalp_ltable[] = {
 	/*  7007 */ {OVAL_INDEPENDENT_TEXT_FILE_CONTENT,    "textfilecontent",   NULL},
 	/*  7010 */ {OVAL_INDEPENDENT_XML_FILE_CONTENT,     "xmlfilecontent",    "probe_xmlfilecontent"},
 	/*  7999 */ {OVAL_INDEPENDENT_SYSCHAR_SUBTYPE,      "system_info",       "probe_system_info"},
-//      /*  9001 */ { OVAL_LINUX_DPKG_INFO,                  "dpkginfo",          "probe_dpkginfo"          },
+	/*  9001 */ { OVAL_LINUX_DPKG_INFO,                  "dpkginfo",          "probe_dpkginfo"          },
 	/*  9003 */ {OVAL_LINUX_RPM_INFO,                   "rpminfo",           "probe_rpminfo"},
 //      /*  9004 */ { OVAL_LINUX_SLACKWARE_PKG_INFO_TEST,    "slackwarepkginfo",  "probe_slackwarepkginfo"  },
 	/* 13001 */ {OVAL_UNIX_FILE,                        "file",              "probe_file"},
diff --git a/src/OVAL/probes/Makefile.am b/src/OVAL/probes/Makefile.am
index 4b888e6..d6918e9 100644
--- a/src/OVAL/probes/Makefile.am
+++ b/src/OVAL/probes/Makefile.am
@@ -55,7 +55,16 @@ pkglibexec_PROGRAMS += probe_rpminfo
 probe_rpminfo_SOURCES= unix/linux/rpminfo.c
 probe_rpminfo_CFLAGS= @rpm_cflags@
 probe_rpminfo_LDFLAGS= @rpm_libs@
+endif
 
+if ENABLE_PROBE_DPKGINFO
+pkglibexec_PROGRAMS += probe_dpkginfo
+probe_dpkginfo_SOURCES= unix/linux/dpkginfo.c \
+	unix/linux/dpkginfo-helper.cxx \
+	unix/linux/dpkginfo-helper.h
+probe_dpkginfo_CFLAGS= @deb_cflags@
+probe_dpkginfo_CXXFLAGS= @deb_cflags@
+probe_dpkginfo_LDFLAGS= @deb_libs@
 endif
 endif
 endif
diff --git a/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx b/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx
new file mode 100644
index 0000000..0ed544e
--- /dev/null
+++ b/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx
@@ -0,0 +1,130 @@
+#ifndef __STUB_PROBE
+/*
+ * Author: Pierre Chifflier <chifflier at edenwall.com>
+ */
+
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include <stdlib.h>
+
+#include <apt-pkg/init.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/mmap.h>
+#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/pkgrecords.h>
+
+#include "dpkginfo-helper.h"
+
+using namespace std;
+
+static int _init_done = 0;
+static pkgCache *cgCache = NULL;
+
+static int opencache (void) {
+        if (pkgInitConfig (*_config) == false) return 0;
+        if (pkgInitSystem (*_config, _system) == false) return 0;
+
+        FileFd *fd = new FileFd (_config->FindFile ("Dir::Cache::pkgcache"),
+                        FileFd::ReadOnly);
+
+        MMap *map = new MMap (*fd, MMap::Public|MMap::ReadOnly);
+        if (_error->PendingError () == true) {
+                _error->DumpErrors ();
+                return 0;
+        }
+
+        cgCache = new pkgCache (map);
+        if (0 == cgCache) return 0;
+        if (_error->PendingError () == true) {
+                _error->DumpErrors ();
+                return 0;
+        }
+
+        return 1;
+}
+
+struct dpkginfo_reply_t * dpkginfo_get_by_name(const char *name, int *err)
+{
+        pkgCache &cache = *cgCache;
+        pkgRecords Recs (cache);
+        struct dpkginfo_reply_t *reply = NULL;
+
+        // Locate the package
+        pkgCache::PkgIterator Pkg = cache.FindPkg(name);
+        if (Pkg.end() == true) {
+                /* not found, clear error flag */
+                if (err) *err = 0;
+                return NULL;
+        }
+
+        pkgCache::VerIterator V1 = Pkg.CurrentVer();
+        if (V1.end() == true) {
+                /* not installed, clear error flag */
+                /* FIXME this should be different that not found */
+                if (err) *err = 0;
+                return NULL;
+        }
+        pkgRecords::Parser &P = Recs.Lookup(V1.FileList());
+
+        /* split epoch, version and release */
+        string evr = V1.VerStr();
+        string epoch, version, release;
+        string::size_type version_start = 0, version_stop;
+        string::size_type pos;
+
+        pos = evr.find_first_of(":");
+        if (pos != string::npos) {
+                epoch = evr.substr(0, pos);
+                version_start = pos+1;
+        }
+
+        pos = evr.find_first_of("-");
+        if (pos != string::npos) {
+                version = evr.substr(version_start, pos-version_start);
+                version_stop = pos+1;
+                release = evr.substr(version_stop, evr.length()-version_stop);
+        } else { /* no release number, probably a native package */
+                version = evr.substr(version_start, evr.length()-version_start);
+                release = "";
+        }
+
+        reply = new(struct dpkginfo_reply_t);
+        memset(reply, 0, sizeof(struct dpkginfo_reply_t));
+        reply->name = strdup(Pkg.Name());
+        reply->arch = strdup(V1.Arch());
+        reply->epoch = strdup(epoch.c_str());
+        reply->release = strdup(release.c_str());
+        reply->version = strdup(version.c_str());
+        reply->evr = strdup(evr.c_str());
+
+        return reply;
+}
+
+void * dpkginfo_free_reply(struct dpkginfo_reply_t *reply)
+{
+        if (reply) {
+                free(reply->name);
+                delete reply;
+        }
+}
+
+int dpkginfo_init()
+{
+        if (_init_done == 0)
+                if (opencache() != 1) {
+                        return -1;
+                }
+
+        return 0;
+}
+
+int dpkginfo_fini()
+{
+        delete cgCache;
+        cgCache = NULL;
+
+        return 0;
+}
+
+#endif /* __STUB_PROBE */
diff --git a/src/OVAL/probes/unix/linux/dpkginfo-helper.h b/src/OVAL/probes/unix/linux/dpkginfo-helper.h
new file mode 100644
index 0000000..98a90e7
--- /dev/null
+++ b/src/OVAL/probes/unix/linux/dpkginfo-helper.h
@@ -0,0 +1,34 @@
+#ifndef __STUB_PROBE
+#ifndef __DPKGINFO_HELPER__
+#define __DPKGINFO_HELPER__
+
+/*
+ * Author: Pierre Chifflier <chifflier at edenwall.com>
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dpkginfo_reply_t {
+        char *name;
+        char *arch;
+        char *epoch;
+        char *release;
+        char *version;
+        char *evr;
+};
+
+int dpkginfo_init();
+int dpkginfo_fini();
+
+struct dpkginfo_reply_t * dpkginfo_get_by_name(const char *name, int *err);
+
+void * dpkginfo_free_reply(struct dpkginfo_reply_t *reply);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DPKGINFO_HELPER__ */
+#endif /* __STUB_PROBE */
diff --git a/src/OVAL/probes/unix/linux/dpkginfo.c b/src/OVAL/probes/unix/linux/dpkginfo.c
new file mode 100644
index 0000000..e4619c6
--- /dev/null
+++ b/src/OVAL/probes/unix/linux/dpkginfo.c
@@ -0,0 +1,182 @@
+#ifndef __STUB_PROBE
+/*
+ * dpkginfo probe:
+ *
+ *  dpkginfo_object(string name)
+ *
+ *  dpkginfo_state(string name,
+ *                string arch,
+ *                string epoch,
+ *                string release,
+ *                string version,
+ *                string evr,
+ *                string signature_keyid)
+ */
+/*
+ * Author: Pierre Chifflier <chifflier at edenwall.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+/* SEAP */
+#include <seap.h>
+#include <probe-api.h>
+#include <alloc.h>
+
+
+#include "dpkginfo-helper.h"
+
+
+struct dpkginfo_global {
+        pthread_mutex_t mutex;
+};
+
+static struct dpkginfo_global g_dpkg;
+
+
+void *probe_init(void)
+{
+        pthread_mutex_init (&(g_dpkg.mutex), NULL);
+        dpkginfo_init();
+
+        return ((void *)&g_dpkg);
+}
+
+void probe_fini (void *ptr)
+{
+        struct dpkginfo_global *d = (struct dpkginfo_global *)ptr;
+
+        pthread_mutex_destroy (&(d->mutex));
+        dpkginfo_fini();
+
+        return;
+}
+
+SEXP_t *probe_main (SEXP_t *object, int *err, void *arg)
+{
+        SEXP_t *probe_out, *val, *item_sexp, *r0;
+        char *request_st = NULL;
+        struct dpkginfo_reply_t *dpkginfo_reply = NULL;
+        int errflag;
+
+        val = probe_obj_getentval (object, "name", 1);
+
+        if (val == NULL) {
+                _D("%s: no value\n", "name");
+                *err = PROBE_ENOVAL;
+                return (NULL);
+        }
+
+        request_st = SEXP_string_cstr (val);
+        SEXP_free (val);
+
+        if (request_st == NULL) {
+                switch (errno) {
+                case EINVAL:
+                        _D("%s: invalid value type\n", "name");
+                        *err = PROBE_EINVAL;
+                        break;
+                case EFAULT:
+                        _D("%s: element not found\n", "name");
+                        *err = PROBE_ENOELM;
+                        break;
+                }
+
+                return (NULL);
+        }
+
+        probe_out = SEXP_list_new (NULL);
+
+        /* get info from debian apt cache */
+        pthread_mutex_lock (&(g_dpkg.mutex));
+        dpkginfo_reply = dpkginfo_get_by_name(request_st, &errflag);
+        pthread_mutex_unlock (&(g_dpkg.mutex));
+
+        if (dpkginfo_reply == NULL) {
+                switch (errflag) {
+                        case 0: /* Not found */
+                                _D("Package \"%s\" not found.\n", request_st);
+
+                                item_sexp = probe_item_creat ("dpkginfo_item", NULL,
+                                                "name", NULL,
+                                                r0 = SEXP_string_newf(request_st),
+                                                NULL);
+
+                                probe_item_setstatus (item_sexp, OVAL_STATUS_DOESNOTEXIST);
+                                probe_itement_setstatus (item_sexp, "name", 1, OVAL_STATUS_DOESNOTEXIST);
+
+                                SEXP_list_add (probe_out, item_sexp);
+                                SEXP_free (item_sexp);
+                                SEXP_free (r0);
+
+                                break;
+                        case -1: /* Error */
+                                _D("get_dpkginfo failed\n");
+
+                                item_sexp = probe_item_creat ("dpkginfo_item", NULL,
+                                                "name", NULL,
+                                                r0 = SEXP_string_newf(request_st),
+                                                NULL);
+
+                                probe_item_setstatus (item_sexp, OVAL_STATUS_ERROR);
+
+                                SEXP_list_add (probe_out, item_sexp);
+                                SEXP_free (item_sexp);
+                                SEXP_free (r0);
+
+                                break;
+                }
+        } else { /* Ok */
+                SEXP_t *r1, *r2, *r3, *r4, *r5;
+                int i;
+                int num_items = 1; /* FIXME */
+
+                for (i = 0; i < num_items; ++i) {
+                        item_sexp = probe_item_creat ("dpkginfo_item", NULL,
+
+                                        "name", NULL,
+                                        r0 = SEXP_string_newf (dpkginfo_reply->name),
+
+                                        "arch", NULL,
+                                        r1 = SEXP_string_newf (dpkginfo_reply->arch),
+
+                                        "epoch", NULL,
+                                        r2 = SEXP_string_newf (dpkginfo_reply->epoch),
+
+                                        "release", NULL,
+                                        r3 = SEXP_string_newf (dpkginfo_reply->release),
+
+                                        "version", NULL,
+                                        r4 = SEXP_string_newf (dpkginfo_reply->version),
+
+                                        "evr", NULL,
+                                        r5 = SEXP_string_newf (dpkginfo_reply->evr),
+
+                                        NULL, NULL,
+                                        NULL,
+
+                                        NULL);
+
+                        SEXP_list_add (probe_out, item_sexp);
+                        SEXP_free (item_sexp);
+                        /* FIXME: this is... stupid */
+                        SEXP_free (r0);
+                        SEXP_free (r1);
+                        SEXP_free (r2);
+                        SEXP_free (r3);
+                        SEXP_free (r4);
+                        SEXP_free (r5);
+
+                        dpkginfo_free_reply(dpkginfo_reply);
+                }
+        }
+
+        *err = 0;
+        return (probe_out);
+}
+
+#endif
+
-- 
1.7.0




More information about the Open-scap-list mailing list