xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/irs/dnsconf.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: dnsconf.c,v 1.1 2024/02/18 20:57:47 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0.  If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <inttypes.h>
19 #include <string.h>
20 
21 #include <isc/base64.h>
22 #include <isc/buffer.h>
23 #include <isc/file.h>
24 #include <isc/mem.h>
25 #include <isc/util.h>
26 
27 #include <dns/fixedname.h>
28 #include <dns/name.h>
29 #include <dns/rdata.h>
30 #include <dns/rdatastruct.h>
31 
32 #include <isccfg/dnsconf.h>
33 
34 #include <irs/dnsconf.h>
35 
36 #define IRS_DNSCONF_MAGIC    ISC_MAGIC('D', 'c', 'f', 'g')
37 #define IRS_DNSCONF_VALID(c) ISC_MAGIC_VALID(c, IRS_DNSCONF_MAGIC)
38 
39 /*!
40  * configuration data structure
41  */
42 
43 struct irs_dnsconf {
44 	unsigned int magic;
45 	isc_mem_t *mctx;
46 	irs_dnsconf_dnskeylist_t trusted_keylist;
47 };
48 
49 static isc_result_t
configure_key(isc_mem_t * mctx,const cfg_obj_t * key,irs_dnsconf_t * conf,dns_rdataclass_t rdclass)50 configure_key(isc_mem_t *mctx, const cfg_obj_t *key, irs_dnsconf_t *conf,
51 	      dns_rdataclass_t rdclass) {
52 	isc_result_t result;
53 	uint32_t flags, proto, alg;
54 	dns_fixedname_t fkeyname;
55 	dns_name_t *keyname_base = NULL, *keyname = NULL;
56 	const char *keystr = NULL, *keynamestr = NULL;
57 	unsigned char keydata[4096];
58 	isc_buffer_t keydatabuf_base, *keydatabuf = NULL;
59 	dns_rdata_dnskey_t keystruct;
60 	unsigned char rrdata[4096];
61 	isc_buffer_t rrdatabuf;
62 	isc_region_t r;
63 	isc_buffer_t namebuf;
64 	irs_dnsconf_dnskey_t *keyent = NULL;
65 
66 	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
67 	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
68 	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
69 	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
70 
71 	keystruct.common.rdclass = rdclass;
72 	keystruct.common.rdtype = dns_rdatatype_dnskey;
73 	keystruct.mctx = NULL;
74 	ISC_LINK_INIT(&keystruct.common, link);
75 
76 	if (flags > 0xffff) {
77 		return (ISC_R_RANGE);
78 	}
79 	if (proto > 0xff) {
80 		return (ISC_R_RANGE);
81 	}
82 	if (alg > 0xff) {
83 		return (ISC_R_RANGE);
84 	}
85 	keystruct.flags = (uint16_t)flags;
86 	keystruct.protocol = (uint8_t)proto;
87 	keystruct.algorithm = (uint8_t)alg;
88 
89 	isc_buffer_init(&keydatabuf_base, keydata, sizeof(keydata));
90 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
91 
92 	/* Configure key value */
93 	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
94 	result = isc_base64_decodestring(keystr, &keydatabuf_base);
95 	if (result != ISC_R_SUCCESS) {
96 		return (result);
97 	}
98 	isc_buffer_usedregion(&keydatabuf_base, &r);
99 	keystruct.datalen = r.length;
100 	keystruct.data = r.base;
101 
102 	result = dns_rdata_fromstruct(NULL, keystruct.common.rdclass,
103 				      keystruct.common.rdtype, &keystruct,
104 				      &rrdatabuf);
105 	if (result != ISC_R_SUCCESS) {
106 		return (result);
107 	}
108 	isc_buffer_usedregion(&rrdatabuf, &r);
109 	isc_buffer_allocate(mctx, &keydatabuf, r.length);
110 	result = isc_buffer_copyregion(keydatabuf, &r);
111 	if (result != ISC_R_SUCCESS) {
112 		goto cleanup;
113 	}
114 
115 	/* Configure key name */
116 	keyname_base = dns_fixedname_initname(&fkeyname);
117 	isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
118 	isc_buffer_add(&namebuf, strlen(keynamestr));
119 	result = dns_name_fromtext(keyname_base, &namebuf, dns_rootname, 0,
120 				   NULL);
121 	if (result != ISC_R_SUCCESS) {
122 		return (result);
123 	}
124 	keyname = isc_mem_get(mctx, sizeof(*keyname));
125 	dns_name_init(keyname, NULL);
126 	dns_name_dup(keyname_base, mctx, keyname);
127 
128 	/* Add the key data to the list */
129 	keyent = isc_mem_get(mctx, sizeof(*keyent));
130 	keyent->keyname = keyname;
131 	keyent->keydatabuf = keydatabuf;
132 
133 	ISC_LIST_APPEND(conf->trusted_keylist, keyent, link);
134 
135 cleanup:
136 	if (keydatabuf != NULL) {
137 		isc_buffer_free(&keydatabuf);
138 	}
139 	if (keyname != NULL) {
140 		isc_mem_put(mctx, keyname, sizeof(*keyname));
141 	}
142 
143 	return (result);
144 }
145 
146 static isc_result_t
configure_keygroup(irs_dnsconf_t * conf,const cfg_obj_t * keys,dns_rdataclass_t rdclass)147 configure_keygroup(irs_dnsconf_t *conf, const cfg_obj_t *keys,
148 		   dns_rdataclass_t rdclass) {
149 	isc_result_t result;
150 	const cfg_obj_t *key, *keylist;
151 	const cfg_listelt_t *element, *element2;
152 	isc_mem_t *mctx = conf->mctx;
153 
154 	for (element = cfg_list_first(keys); element != NULL;
155 	     element = cfg_list_next(element))
156 	{
157 		keylist = cfg_listelt_value(element);
158 		for (element2 = cfg_list_first(keylist); element2 != NULL;
159 		     element2 = cfg_list_next(element2))
160 		{
161 			key = cfg_listelt_value(element2);
162 			result = configure_key(mctx, key, conf, rdclass);
163 			if (result != ISC_R_SUCCESS) {
164 				return (result);
165 			}
166 		}
167 	}
168 
169 	return (ISC_R_SUCCESS);
170 }
171 
172 static isc_result_t
configure_dnsseckeys(irs_dnsconf_t * conf,cfg_obj_t * cfgobj,dns_rdataclass_t rdclass)173 configure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj,
174 		     dns_rdataclass_t rdclass) {
175 	isc_result_t result;
176 	const cfg_obj_t *keys = NULL;
177 
178 	cfg_map_get(cfgobj, "trusted-keys", &keys);
179 	if (keys == NULL) {
180 		return (ISC_R_SUCCESS);
181 	}
182 
183 	result = configure_keygroup(conf, keys, rdclass);
184 	if (result != ISC_R_SUCCESS) {
185 		return (result);
186 	}
187 
188 	keys = NULL;
189 	cfg_map_get(cfgobj, "trust-anchors", &keys);
190 	if (keys == NULL) {
191 		return (ISC_R_SUCCESS);
192 	}
193 
194 	result = configure_keygroup(conf, keys, rdclass);
195 	if (result != ISC_R_SUCCESS) {
196 		return (result);
197 	}
198 
199 	keys = NULL;
200 	cfg_map_get(cfgobj, "managed-keys", &keys);
201 	if (keys == NULL) {
202 		return (ISC_R_SUCCESS);
203 	}
204 
205 	result = configure_keygroup(conf, keys, rdclass);
206 	if (result != ISC_R_SUCCESS) {
207 		return (result);
208 	}
209 
210 	return (ISC_R_SUCCESS);
211 }
212 
213 isc_result_t
irs_dnsconf_load(isc_mem_t * mctx,const char * filename,irs_dnsconf_t ** confp)214 irs_dnsconf_load(isc_mem_t *mctx, const char *filename, irs_dnsconf_t **confp) {
215 	irs_dnsconf_t *conf;
216 	cfg_parser_t *parser = NULL;
217 	cfg_obj_t *cfgobj = NULL;
218 	isc_result_t result = ISC_R_SUCCESS;
219 
220 	REQUIRE(confp != NULL && *confp == NULL);
221 
222 	conf = isc_mem_get(mctx, sizeof(*conf));
223 
224 	conf->mctx = mctx;
225 	ISC_LIST_INIT(conf->trusted_keylist);
226 
227 	/*
228 	 * If the specified file does not exist, we'll simply with an empty
229 	 * configuration.
230 	 */
231 	if (!isc_file_exists(filename)) {
232 		goto cleanup;
233 	}
234 
235 	result = cfg_parser_create(mctx, NULL, &parser);
236 	if (result != ISC_R_SUCCESS) {
237 		goto cleanup;
238 	}
239 
240 	result = cfg_parse_file(parser, filename, &cfg_type_dnsconf, &cfgobj);
241 	if (result != ISC_R_SUCCESS) {
242 		goto cleanup;
243 	}
244 
245 	result = configure_dnsseckeys(conf, cfgobj, dns_rdataclass_in);
246 
247 cleanup:
248 	if (parser != NULL) {
249 		if (cfgobj != NULL) {
250 			cfg_obj_destroy(parser, &cfgobj);
251 		}
252 		cfg_parser_destroy(&parser);
253 	}
254 
255 	conf->magic = IRS_DNSCONF_MAGIC;
256 
257 	if (result == ISC_R_SUCCESS) {
258 		*confp = conf;
259 	} else {
260 		irs_dnsconf_destroy(&conf);
261 	}
262 
263 	return (result);
264 }
265 
266 void
irs_dnsconf_destroy(irs_dnsconf_t ** confp)267 irs_dnsconf_destroy(irs_dnsconf_t **confp) {
268 	irs_dnsconf_t *conf;
269 	irs_dnsconf_dnskey_t *keyent;
270 
271 	REQUIRE(confp != NULL);
272 	conf = *confp;
273 	*confp = NULL;
274 	REQUIRE(IRS_DNSCONF_VALID(conf));
275 
276 	while ((keyent = ISC_LIST_HEAD(conf->trusted_keylist)) != NULL) {
277 		ISC_LIST_UNLINK(conf->trusted_keylist, keyent, link);
278 
279 		isc_buffer_free(&keyent->keydatabuf);
280 		dns_name_free(keyent->keyname, conf->mctx);
281 		isc_mem_put(conf->mctx, keyent->keyname, sizeof(dns_name_t));
282 		isc_mem_put(conf->mctx, keyent, sizeof(*keyent));
283 	}
284 
285 	isc_mem_put(conf->mctx, conf, sizeof(*conf));
286 }
287 
288 irs_dnsconf_dnskeylist_t *
irs_dnsconf_gettrustedkeys(irs_dnsconf_t * conf)289 irs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf) {
290 	REQUIRE(IRS_DNSCONF_VALID(conf));
291 
292 	return (&conf->trusted_keylist);
293 }
294