libvirt/tools/virt-pki-query-dn.c
Martin Kletzander 9715043544 tools: Add virt-pki-query-dn binary
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@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
2021-11-12 12:37:29 +01:00

141 lines
3.5 KiB
C

/*
* 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;
}