File: configutl.c

package info (click to toggle)
openssl 3.6.0-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 148,104 kB
  • sloc: ansic: 612,658; perl: 248,939; asm: 6,332; sh: 1,755; pascal: 997; python: 648; makefile: 551; lisp: 35; ruby: 16; cpp: 10; sed: 6
file content (202 lines) | stat: -rw-r--r-- 5,955 bytes parent folder | download
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
 * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/safestack.h>

#include "apps.h"
#include "progs.h"

/**
 * Print the given value escaped for the OpenSSL configuration file format.
 */
static void print_escaped_value(BIO *out, const char *value)
{
    const char *p;

    for (p = value; *p != '\0'; p++) {
        switch (*p) {
        case '"':
        case '\'':
        case '#':
        case '\\':
        case '$':
            BIO_printf(out, "\\");
            BIO_write(out, p, 1);
            break;
        case '\n':
            BIO_printf(out, "%s", "\\n");
            break;
        case '\r':
            BIO_printf(out, "%s", "\\r");
            break;
        case '\b':
            BIO_printf(out, "%s", "\\b");
            break;
        case '\t':
            BIO_printf(out, "%s", "\\t");
            break;
        case ' ':
            if (p == value || p[1] == '\0') {
                /*
                 * Quote spaces if they are the first or last char of the
                 * value. We could quote the entire string (and it would
                 * certainly produce nicer output), but in quoted strings
                 * the escape sequences for \n, \r, \t, and \b do not work.
                 * To make sure we're producing correct results we'd thus
                 * have to selectively not use those in quoted strings and
                 * close and re-open the quotes if they appear, which is
                 * more trouble than adding the quotes just around the
                 * first and last leading and trailing space.
                 */
                BIO_printf(out, "%s", "\" \"");
                break;
            }
            /* FALLTHROUGH */
        default:
            BIO_write(out, p, 1);
            break;
        }
    }
}

/**
 * Print all values in the configuration section identified by section_name
 */
static void print_section(BIO *out, const CONF *cnf, OPENSSL_CSTRING section_name)
{
    STACK_OF(CONF_VALUE) *values = NCONF_get_section(cnf, section_name);
    int idx;

    for (idx = 0; idx < sk_CONF_VALUE_num(values); idx++) {
        CONF_VALUE *value = sk_CONF_VALUE_value(values, idx);

        BIO_printf(out, "%s = ", value->name);
        print_escaped_value(out, value->value);
        BIO_printf(out, "\n");
    }
}

typedef enum OPTION_choice {
    OPT_COMMON,
    OPT_OUT,
    OPT_NOHEADER,
    OPT_CONFIG
} OPTION_CHOICE;

const OPTIONS configutl_options[] = {
    OPT_SECTION("General"),
    {"help", OPT_HELP, '-', "Display this summary"},
    {"config", OPT_CONFIG, 's', "Config file to deal with (the default one if omitted)"},
    OPT_SECTION("Output"),
    {"out", OPT_OUT, '>', "Output to filename rather than stdout"},
    {"noheader", OPT_NOHEADER, '-', "Don't print the information about original config"},
    {NULL}
};

/**
 * Parse the passed OpenSSL configuration file (or the default one/specified in the
 * OPENSSL_CONF environment variable) and write it back in
 * a canonical format with all includes and variables expanded.
 */
int configutl_main(int argc, char *argv[])
{
    int ret = 1;
    char *prog, *configfile = NULL;
    OPTION_CHOICE o;
    CONF *cnf = NULL;
    long eline = 0;
    int default_section_idx, idx;
    int no_header = 0;
    STACK_OF(OPENSSL_CSTRING) *sections = NULL;
    BIO *out = NULL;
    const char *outfile = NULL;

    prog = opt_init(argc, argv, configutl_options);
    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_HELP:
            opt_help(configutl_options);
            ret = 0;
            goto end;
            break;
        case OPT_NOHEADER:
            no_header = 1;
            break;
        case OPT_CONFIG:
            /*
             * In case multiple OPT_CONFIG options are passed, we need to free
             * the previous one before assigning the new one.
             */
            OPENSSL_free(configfile);
            configfile = OPENSSL_strdup(opt_arg());
            break;
        case OPT_OUT:
            outfile = opt_arg();
            break;
        case OPT_ERR:
        /*
         * default needed for OPT_EOF which might never happen.
         */
        default:
            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
            goto end;
        }
    }

    out = bio_open_default(outfile, 'w', FORMAT_TEXT);
    if (out == NULL)
        goto end;

    if (configfile == NULL)
        configfile = CONF_get1_default_config_file();

    if (configfile == NULL)
        goto end;

    if ((cnf = NCONF_new(NULL)) == NULL)
        goto end;

    if (NCONF_load(cnf, configfile, &eline) == 0) {
        BIO_printf(bio_err, "Error on line %ld of configuration file\n", eline + 1);
        goto end;
    }

    if ((sections = NCONF_get_section_names(cnf)) == NULL)
        goto end;

    if (no_header == 0)
        BIO_printf(out, "# This configuration file was linearized and expanded from %s\n",
                   configfile);

    default_section_idx = sk_OPENSSL_CSTRING_find(sections, "default");
    if (default_section_idx != -1)
        print_section(out, cnf, "default");

    for (idx = 0; idx < sk_OPENSSL_CSTRING_num(sections); idx++) {
        OPENSSL_CSTRING section_name = sk_OPENSSL_CSTRING_value(sections, idx);

        if (idx == default_section_idx)
            continue;

        BIO_printf(out, "\n[%s]\n", section_name);
        print_section(out, cnf, section_name);
    }

    ret = 0;

end:
    ERR_print_errors(bio_err);
    BIO_free(out);
    OPENSSL_free(configfile);
    NCONF_free(cnf);
    sk_OPENSSL_CSTRING_free(sections);
    return ret;
}