summaryrefslogtreecommitdiff
path: root/tools/virt-pki-query-dn.c
blob: 2d7849feb710e09475f9a2dec91001a2430c3b2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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;
}