1/* $OpenBSD: conf_lib.c,v 1.17 2024/04/09 13:56:30 beck Exp $ */
2/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
3 * project 2000.
4 */
5/* ====================================================================
6 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 *    software must display the following acknowledgment:
22 *    "This product includes software developed by the OpenSSL Project
23 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 *    endorse or promote products derived from this software without
27 *    prior written permission. For written permission, please contact
28 *    licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 *    nor may "OpenSSL" appear in their names without prior written
32 *    permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 *    acknowledgment:
36 *    "This product includes software developed by the OpenSSL Project
37 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 * This product includes cryptographic software written by Eric Young
54 * (eay@cryptsoft.com).  This product includes software written by Tim
55 * Hudson (tjh@cryptsoft.com).
56 *
57 */
58
59#include <stdio.h>
60#include <openssl/crypto.h>
61#include <openssl/err.h>
62#include <openssl/conf.h>
63#include <openssl/conf_api.h>
64#include <openssl/lhash.h>
65
66static CONF_METHOD *default_CONF_method = NULL;
67
68/* Init a 'CONF' structure from an old LHASH */
69
70void
71CONF_set_nconf(CONF *conf, LHASH_OF(CONF_VALUE) *hash)
72{
73	if (default_CONF_method == NULL)
74		default_CONF_method = NCONF_default();
75	default_CONF_method->init(conf);
76	conf->data = hash;
77}
78LCRYPTO_ALIAS(CONF_set_nconf);
79
80/* The following section contains the "CONF classic" functions,
81   rewritten in terms of the new CONF interface. */
82
83int
84CONF_set_default_method(CONF_METHOD *meth)
85{
86	default_CONF_method = meth;
87	return 1;
88}
89LCRYPTO_ALIAS(CONF_set_default_method);
90
91LHASH_OF(CONF_VALUE) *
92CONF_load(LHASH_OF(CONF_VALUE) *conf, const char *file, long *eline)
93{
94	LHASH_OF(CONF_VALUE) *ltmp;
95	BIO *in = NULL;
96
97	in = BIO_new_file(file, "rb");
98	if (in == NULL) {
99		CONFerror(ERR_R_SYS_LIB);
100		return NULL;
101	}
102
103	ltmp = CONF_load_bio(conf, in, eline);
104	BIO_free(in);
105
106	return ltmp;
107}
108LCRYPTO_ALIAS(CONF_load);
109
110LHASH_OF(CONF_VALUE) *
111CONF_load_fp(LHASH_OF(CONF_VALUE) *conf, FILE *fp, long *eline)
112{
113	BIO *btmp;
114	LHASH_OF(CONF_VALUE) *ltmp;
115
116	if (!(btmp = BIO_new_fp(fp, BIO_NOCLOSE))) {
117		CONFerror(ERR_R_BUF_LIB);
118		return NULL;
119	}
120	ltmp = CONF_load_bio(conf, btmp, eline);
121	BIO_free(btmp);
122	return ltmp;
123}
124LCRYPTO_ALIAS(CONF_load_fp);
125
126LHASH_OF(CONF_VALUE) *
127CONF_load_bio(LHASH_OF(CONF_VALUE) *conf, BIO *bp, long *eline)
128{
129	CONF ctmp;
130	int ret;
131
132	CONF_set_nconf(&ctmp, conf);
133
134	ret = NCONF_load_bio(&ctmp, bp, eline);
135	if (ret)
136		return ctmp.data;
137	return NULL;
138}
139LCRYPTO_ALIAS(CONF_load_bio);
140
141STACK_OF(CONF_VALUE) *
142CONF_get_section(LHASH_OF(CONF_VALUE) *conf, const char *section)
143{
144	if (conf == NULL) {
145		return NULL;
146	} else {
147		CONF ctmp;
148		CONF_set_nconf(&ctmp, conf);
149		return NCONF_get_section(&ctmp, section);
150	}
151}
152LCRYPTO_ALIAS(CONF_get_section);
153
154char *
155CONF_get_string(LHASH_OF(CONF_VALUE) *conf, const char *group,
156    const char *name)
157{
158	if (conf == NULL) {
159		return NCONF_get_string(NULL, group, name);
160	} else {
161		CONF ctmp;
162		CONF_set_nconf(&ctmp, conf);
163		return NCONF_get_string(&ctmp, group, name);
164	}
165}
166LCRYPTO_ALIAS(CONF_get_string);
167
168long
169CONF_get_number(LHASH_OF(CONF_VALUE) *conf, const char *group,
170    const char *name)
171{
172	int status;
173	long result = 0;
174
175	if (conf == NULL) {
176		status = NCONF_get_number_e(NULL, group, name, &result);
177	} else {
178		CONF ctmp;
179		CONF_set_nconf(&ctmp, conf);
180		status = NCONF_get_number_e(&ctmp, group, name, &result);
181	}
182
183	if (status == 0) {
184		/* This function does not believe in errors... */
185		ERR_clear_error();
186	}
187	return result;
188}
189LCRYPTO_ALIAS(CONF_get_number);
190
191void
192CONF_free(LHASH_OF(CONF_VALUE) *conf)
193{
194	CONF ctmp;
195
196	CONF_set_nconf(&ctmp, conf);
197	NCONF_free_data(&ctmp);
198}
199LCRYPTO_ALIAS(CONF_free);
200
201int
202CONF_dump_fp(LHASH_OF(CONF_VALUE) *conf, FILE *out)
203{
204	BIO *btmp;
205	int ret;
206
207	if (!(btmp = BIO_new_fp(out, BIO_NOCLOSE))) {
208		CONFerror(ERR_R_BUF_LIB);
209		return 0;
210	}
211	ret = CONF_dump_bio(conf, btmp);
212	BIO_free(btmp);
213	return ret;
214}
215LCRYPTO_ALIAS(CONF_dump_fp);
216
217int
218CONF_dump_bio(LHASH_OF(CONF_VALUE) *conf, BIO *out)
219{
220	CONF ctmp;
221
222	CONF_set_nconf(&ctmp, conf);
223	return NCONF_dump_bio(&ctmp, out);
224}
225LCRYPTO_ALIAS(CONF_dump_bio);
226
227/* The following section contains the "New CONF" functions.  They are
228   completely centralised around a new CONF structure that may contain
229   basically anything, but at least a method pointer and a table of data.
230   These functions are also written in terms of the bridge functions used
231   by the "CONF classic" functions, for consistency.  */
232
233CONF *
234NCONF_new(CONF_METHOD *meth)
235{
236	CONF *ret;
237
238	if (meth == NULL)
239		meth = NCONF_default();
240
241	ret = meth->create(meth);
242	if (ret == NULL) {
243		CONFerror(ERR_R_MALLOC_FAILURE);
244		return (NULL);
245	}
246
247	return ret;
248}
249LCRYPTO_ALIAS(NCONF_new);
250
251void
252NCONF_free(CONF *conf)
253{
254	if (conf == NULL)
255		return;
256	conf->meth->destroy(conf);
257}
258LCRYPTO_ALIAS(NCONF_free);
259
260void
261NCONF_free_data(CONF *conf)
262{
263	if (conf == NULL)
264		return;
265	conf->meth->destroy_data(conf);
266}
267LCRYPTO_ALIAS(NCONF_free_data);
268
269int
270NCONF_load(CONF *conf, const char *file, long *eline)
271{
272	if (conf == NULL) {
273		CONFerror(CONF_R_NO_CONF);
274		return 0;
275	}
276
277	return conf->meth->load(conf, file, eline);
278}
279LCRYPTO_ALIAS(NCONF_load);
280
281int
282NCONF_load_fp(CONF *conf, FILE *fp, long *eline)
283{
284	BIO *btmp;
285	int ret;
286
287	if (!(btmp = BIO_new_fp(fp, BIO_NOCLOSE))) {
288		CONFerror(ERR_R_BUF_LIB);
289		return 0;
290	}
291	ret = NCONF_load_bio(conf, btmp, eline);
292	BIO_free(btmp);
293	return ret;
294}
295LCRYPTO_ALIAS(NCONF_load_fp);
296
297int
298NCONF_load_bio(CONF *conf, BIO *bp, long *eline)
299{
300	if (conf == NULL) {
301		CONFerror(CONF_R_NO_CONF);
302		return 0;
303	}
304
305	return conf->meth->load_bio(conf, bp, eline);
306}
307LCRYPTO_ALIAS(NCONF_load_bio);
308
309STACK_OF(CONF_VALUE) *
310NCONF_get_section(const CONF *conf, const char *section)
311{
312	if (conf == NULL) {
313		CONFerror(CONF_R_NO_CONF);
314		return NULL;
315	}
316
317	if (section == NULL) {
318		CONFerror(CONF_R_NO_SECTION);
319		return NULL;
320	}
321
322	return _CONF_get_section_values(conf, section);
323}
324LCRYPTO_ALIAS(NCONF_get_section);
325
326char *
327NCONF_get_string(const CONF *conf, const char *group, const char *name)
328{
329	char *s = _CONF_get_string(conf, group, name);
330
331        /* Since we may get a value from an environment variable even
332           if conf is NULL, let's check the value first */
333	if (s)
334		return s;
335
336	if (conf == NULL) {
337		CONFerror(CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE);
338		return NULL;
339	}
340	CONFerror(CONF_R_NO_VALUE);
341	ERR_asprintf_error_data("group=%s name=%s",
342	    group ? group : "", name);
343	return NULL;
344}
345LCRYPTO_ALIAS(NCONF_get_string);
346
347int
348NCONF_get_number_e(const CONF *conf, const char *group, const char *name,
349    long *result)
350{
351	char *str;
352
353	if (result == NULL) {
354		CONFerror(ERR_R_PASSED_NULL_PARAMETER);
355		return 0;
356	}
357
358	str = NCONF_get_string(conf, group, name);
359
360	if (str == NULL)
361		return 0;
362
363	for (*result = 0; conf->meth->is_number(conf, *str); ) {
364		*result = (*result) * 10 + conf->meth->to_int(conf, *str);
365		str++;
366	}
367
368	return 1;
369}
370LCRYPTO_ALIAS(NCONF_get_number_e);
371
372int
373NCONF_dump_fp(const CONF *conf, FILE *out)
374{
375	BIO *btmp;
376	int ret;
377	if (!(btmp = BIO_new_fp(out, BIO_NOCLOSE))) {
378		CONFerror(ERR_R_BUF_LIB);
379		return 0;
380	}
381	ret = NCONF_dump_bio(conf, btmp);
382	BIO_free(btmp);
383	return ret;
384}
385LCRYPTO_ALIAS(NCONF_dump_fp);
386
387int
388NCONF_dump_bio(const CONF *conf, BIO *out)
389{
390	if (conf == NULL) {
391		CONFerror(CONF_R_NO_CONF);
392		return 0;
393	}
394
395	return conf->meth->dump(conf, out);
396}
397LCRYPTO_ALIAS(NCONF_dump_bio);
398