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

Daniel P. Berrangé berrange at redhat.com
Thu Nov 11 15:38:24 UTC 2021


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 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>

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 :|




More information about the libvir-list mailing list