On Thu, Nov 11, 2021 at 04:06:42PM +0100, Martin Kletzander wrote: > 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@xxxxxxxxxx> > --- > 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@tools/virt-host-validate-qemu.c > @SRCDIR@tools/virt-host-validate.c > @SRCDIR@tools/virt-login-shell-helper.c > +@SRCDIR@tools/virt-pki-query-dn.c > @SRCDIR@tools/vsh-table.c > @SRCDIR@tools/vsh.c > @SRCDIR@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> This is not a standard C library API. Doesn't exist on Mingw at least AFAICT. > +#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); IMHO better to just use g_printerr() and return EXIT_FAILURE so the control flow isn't disguised, and the API is portable. > + > + 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 > Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|