[PATCH 2/6] tools: Add virt-pki-query-dn binary

Martin Kletzander mkletzan at redhat.com
Thu Nov 11 15:06:42 UTC 2021


With this program we do not have to depend on the output of `certtool -i`, which
changed the order of the fields at some point and the newest version is
incompatible with what libvirt expects in tls_allowed_dn_list configuration
option.

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 libvirt.spec.in           |   1 +
 po/POTFILES.in            |   1 +
 tools/meson.build         |  26 ++++++++
 tools/virt-pki-query-dn.c | 137 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+)
 create mode 100644 tools/virt-pki-query-dn.c

diff --git a/libvirt.spec.in b/libvirt.spec.in
index 4ecb28114ce8..5f1773ef93f2 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1983,6 +1983,7 @@ exit 0
 %{_mandir}/man1/virt-pki-validate.1*
 %{_bindir}/virsh
 %{_bindir}/virt-xml-validate
+%{_bindir}/virt-pki-query-dn
 %{_bindir}/virt-pki-validate
 
 %{_datadir}/bash-completion/completions/virsh
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8a726f624e38..bf0a3b352979 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -376,6 +376,7 @@
 @SRCDIR at tools/virt-host-validate-qemu.c
 @SRCDIR at tools/virt-host-validate.c
 @SRCDIR at tools/virt-login-shell-helper.c
+ at SRCDIR@tools/virt-pki-query-dn.c
 @SRCDIR at tools/vsh-table.c
 @SRCDIR at tools/vsh.c
 @SRCDIR at tools/vsh.h
diff --git a/tools/meson.build b/tools/meson.build
index bf0eab8b6bf2..9fc07ef32bb3 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -257,6 +257,32 @@ configure_file(
   install_mode: 'rwxrwxr-x',
 )
 
+executable(
+  'virt-pki-query-dn',
+  [
+    'virt-pki-query-dn.c',
+  ],
+  dependencies: [
+    glib_dep,
+    gnutls_dep,
+  ],
+  include_directories: [
+    src_inc_dir,
+    top_inc_dir,
+    util_inc_dir,
+  ],
+  link_args: (
+    libvirt_relro
+    + libvirt_no_indirect
+    + libvirt_no_undefined
+  ),
+  link_with: [
+    libvirt_lib
+  ],
+  install: true,
+  install_dir: bindir,
+)
+
 if conf.has('WITH_SANLOCK')
   configure_file(
     input: 'virt-sanlock-cleanup.in',
diff --git a/tools/virt-pki-query-dn.c b/tools/virt-pki-query-dn.c
new file mode 100644
index 000000000000..0706256d0016
--- /dev/null
+++ b/tools/virt-pki-query-dn.c
@@ -0,0 +1,137 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+#include "internal.h"
+
+#include <err.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "virgettext.h"
+
+
+static void
+glib_auto_cleanup_gnutls_x509_crt_t(gnutls_x509_crt_t *pointer)
+{
+    gnutls_x509_crt_deinit(*pointer);
+}
+
+
+static void
+print_usage(const char *progname,
+            FILE *out)
+{
+  fprintf(out,
+          _("Usage:\n"
+            "  %s FILE\n"
+            "  %s { -v | -h }\n"
+            "\n"
+            "Extract Distinguished Name from a PEM certificate.\n"
+            "The output is meant to be used in the tls_allowed_dn_list\n"
+            "configuration option in the libvirtd.conf file.\n"
+            "\n"
+            "  FILE            certificate file to extract the DN from\n"
+            "\n"
+            "options:\n"
+            "  -h | --help     display this help and exit\n"
+            "  -v | --version  output version information and exit\n"),
+          progname, progname);
+}
+
+
+int
+main(int argc,
+     char **argv)
+{
+    const char *progname = NULL;
+    const char *filename = NULL;
+    size_t dnamesize = 256;
+    size_t bufsize = 0;
+    g_autofree char *dname = g_new0(char, dnamesize);
+    g_autofree char *buf = NULL;
+    g_auto(gnutls_x509_crt_t) crt = {0};
+    gnutls_datum_t crt_data = {0};
+    g_autoptr(GError) error = NULL;
+    int arg = 0;
+    int rv = 0;
+
+    struct option opt[] = {
+        {"help", no_argument, NULL, 'h'},
+        {"version", optional_argument, NULL, 'v'},
+        {NULL, 0, NULL, 0}
+    };
+
+    if (virGettextInitialize() < 0)
+        return EXIT_FAILURE;
+
+    if (!(progname = strrchr(argv[0], '/')))
+        progname = argv[0];
+    else
+        progname++;
+
+    while ((arg = getopt_long(argc, argv, "hv", opt, NULL)) != -1) {
+        switch (arg) {
+        case 'v':
+            printf("%s\n", PACKAGE_VERSION);
+            return EXIT_SUCCESS;
+        case 'h':
+            print_usage(progname, stdout);
+            return EXIT_SUCCESS;
+        default:
+            print_usage(progname, stderr);
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (optind != argc - 1) {
+        print_usage(progname, stderr);
+        return EXIT_FAILURE;
+    }
+
+    filename = argv[optind];
+
+    g_file_get_contents(filename, &buf, &bufsize, &error);
+    if (error)
+        errx(EXIT_FAILURE, "%s", error->message);
+
+    if (bufsize > UINT_MAX)
+        errx(EXIT_FAILURE, _("File '%s' is too large"), filename);
+
+    crt_data.data = (unsigned char *)buf;
+    crt_data.size = bufsize;
+
+    rv = gnutls_x509_crt_init(&crt);
+    if (rv < 0) {
+        err(EXIT_FAILURE,
+            _("Unable to initialize certificate: %s"),
+            gnutls_strerror(rv));
+    }
+
+    rv = gnutls_x509_crt_import(crt, &crt_data, GNUTLS_X509_FMT_PEM);
+    if (rv < 0) {
+        err(EXIT_FAILURE,
+            _("Unable to load certificate, make sure it is in PEM format: %s"),
+            gnutls_strerror(rv));
+    }
+
+    rv = gnutls_x509_crt_get_dn(crt, dname, &dnamesize);
+    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+        dname = g_realloc(dname, dnamesize);
+        rv = gnutls_x509_crt_get_dn(crt, dname, &dnamesize);
+    }
+    if (rv != 0) {
+        err(EXIT_FAILURE,
+            _("Failed to get distinguished name: %s"),
+            gnutls_strerror(rv));
+    }
+
+    printf("%s\n", dname);
+
+    return EXIT_SUCCESS;
+}
-- 
2.33.1




More information about the libvir-list mailing list