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(a)redhat.com>
---
libvirt.spec.in | 1 +
po/POTFILES.in | 1 +
tools/meson.build | 27 ++++++++
tools/virt-pki-query-dn.c | 140 ++++++++++++++++++++++++++++++++++++++
4 files changed, 169 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(a)tools/virt-host-validate-qemu.c
@SRCDIR(a)tools/virt-host-validate.c
@SRCDIR(a)tools/virt-login-shell-helper.c
+@SRCDIR(a)tools/virt-pki-query-dn.c
@SRCDIR(a)tools/vsh-table.c
@SRCDIR(a)tools/vsh.c
@SRCDIR(a)tools/vsh.h
diff --git a/tools/meson.build b/tools/meson.build
index bf0eab8b6bf2..3fba313e5f49 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -257,6 +257,33 @@ configure_file(
install_mode: 'rwxrwxr-x',
)
+executable(
+ 'virt-pki-query-dn',
+ [
+ 'virt-pki-query-dn.c',
+ ],
+ dependencies: [
+ glib_dep,
+ gnutls_dep,
+ ],
+ include_directories: [
+ libvirt_inc,
+ 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..ee3783c1b279
--- /dev/null
+++ b/tools/virt-pki-query-dn.c
@@ -0,0 +1,140 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+#include "internal.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) {
+ g_printerr("%s: %s\n", progname, error->message);
+ return EXIT_FAILURE;
+ }
+
+ if (bufsize > UINT_MAX) {
+ g_printerr(_("%s: File '%s' is too large\n"), progname,
filename);
+ return EXIT_FAILURE;
+ }
+
+ crt_data.data = (unsigned char *)buf;
+ crt_data.size = bufsize;
+
+ rv = gnutls_x509_crt_init(&crt);
+ if (rv < 0) {
+ g_printerr(_("Unable to initialize certificate: %s\n"),
+ gnutls_strerror(rv));
+ return EXIT_FAILURE;
+ }
+
+ rv = gnutls_x509_crt_import(crt, &crt_data, GNUTLS_X509_FMT_PEM);
+ if (rv < 0) {
+ g_printerr(_("Unable to load certificate, make sure it is in PEM format:
%s\n"),
+ gnutls_strerror(rv));
+ return EXIT_FAILURE;
+ }
+
+ 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) {
+ g_printerr(_("Failed to get distinguished name: %s\n"),
+ gnutls_strerror(rv));
+ return EXIT_FAILURE;
+ }
+
+ printf("%s\n", dname);
+
+ return EXIT_SUCCESS;
+}
--
2.33.1