1224090Sdougb/*
2254402Serwin * Copyright (C) 2009, 2012  Internet Systems Consortium, Inc. ("ISC")
3224090Sdougb *
4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any
5224090Sdougb * purpose with or without fee is hereby granted, provided that the above
6224090Sdougb * copyright notice and this permission notice appear in all copies.
7224090Sdougb *
8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10224090Sdougb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14224090Sdougb * PERFORMANCE OF THIS SOFTWARE.
15224090Sdougb */
16224090Sdougb
17234010Sdougb/* $Id: dnsconf.c,v 1.3 2009/09/02 23:48:02 tbox Exp $ */
18224090Sdougb
19224090Sdougb/*! \file */
20224090Sdougb
21224090Sdougb#include <config.h>
22224090Sdougb
23224090Sdougb#include <string.h>
24224090Sdougb
25224090Sdougb#include <isc/base64.h>
26224090Sdougb#include <isc/buffer.h>
27224090Sdougb#include <isc/file.h>
28224090Sdougb#include <isc/mem.h>
29224090Sdougb#include <isc/util.h>
30224090Sdougb
31224090Sdougb#include <isccfg/dnsconf.h>
32224090Sdougb
33224090Sdougb#include <dns/fixedname.h>
34224090Sdougb#include <dns/name.h>
35224090Sdougb#include <dns/rdata.h>
36224090Sdougb#include <dns/rdatastruct.h>
37224090Sdougb
38224090Sdougb#include <irs/dnsconf.h>
39224090Sdougb
40224090Sdougb#define IRS_DNSCONF_MAGIC		ISC_MAGIC('D', 'c', 'f', 'g')
41224090Sdougb#define IRS_DNSCONF_VALID(c)		ISC_MAGIC_VALID(c, IRS_DNSCONF_MAGIC)
42224090Sdougb
43224090Sdougb/*!
44224090Sdougb * configuration data structure
45224090Sdougb */
46224090Sdougb
47224090Sdougbstruct irs_dnsconf {
48224090Sdougb	unsigned int magic;
49224090Sdougb	isc_mem_t *mctx;
50224090Sdougb	irs_dnsconf_dnskeylist_t trusted_keylist;
51224090Sdougb};
52224090Sdougb
53224090Sdougbstatic isc_result_t
54224090Sdougbconfigure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj,
55224090Sdougb		     dns_rdataclass_t rdclass)
56224090Sdougb{
57224090Sdougb	isc_mem_t *mctx = conf->mctx;
58224090Sdougb	const cfg_obj_t *keys = NULL;
59224090Sdougb	const cfg_obj_t *key, *keylist;
60224090Sdougb	dns_fixedname_t fkeyname;
61224090Sdougb	dns_name_t *keyname_base, *keyname;
62224090Sdougb	const cfg_listelt_t *element, *element2;
63224090Sdougb	isc_result_t result;
64224090Sdougb	isc_uint32_t flags, proto, alg;
65224090Sdougb	const char *keystr, *keynamestr;
66224090Sdougb	unsigned char keydata[4096];
67224090Sdougb	isc_buffer_t keydatabuf_base, *keydatabuf;
68224090Sdougb	dns_rdata_dnskey_t keystruct;
69224090Sdougb	unsigned char rrdata[4096];
70224090Sdougb	isc_buffer_t rrdatabuf;
71224090Sdougb	isc_region_t r;
72224090Sdougb	isc_buffer_t namebuf;
73224090Sdougb	irs_dnsconf_dnskey_t *keyent;
74224090Sdougb
75224090Sdougb	cfg_map_get(cfgobj, "trusted-keys", &keys);
76224090Sdougb	if (keys == NULL)
77224090Sdougb		return (ISC_R_SUCCESS);
78224090Sdougb
79224090Sdougb	for (element = cfg_list_first(keys);
80224090Sdougb	     element != NULL;
81224090Sdougb	     element = cfg_list_next(element)) {
82224090Sdougb		keylist = cfg_listelt_value(element);
83224090Sdougb		for (element2 = cfg_list_first(keylist);
84224090Sdougb		     element2 != NULL;
85224090Sdougb		     element2 = cfg_list_next(element2))
86224090Sdougb		{
87224090Sdougb			keydatabuf = NULL;
88224090Sdougb			keyname = NULL;
89224090Sdougb
90224090Sdougb			key = cfg_listelt_value(element2);
91224090Sdougb
92224090Sdougb			flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
93224090Sdougb			proto = cfg_obj_asuint32(cfg_tuple_get(key,
94224090Sdougb							       "protocol"));
95224090Sdougb			alg = cfg_obj_asuint32(cfg_tuple_get(key,
96224090Sdougb							     "algorithm"));
97224090Sdougb			keynamestr = cfg_obj_asstring(cfg_tuple_get(key,
98224090Sdougb								    "name"));
99224090Sdougb
100224090Sdougb			keystruct.common.rdclass = rdclass;
101224090Sdougb			keystruct.common.rdtype = dns_rdatatype_dnskey;
102224090Sdougb			keystruct.mctx = NULL;
103224090Sdougb			ISC_LINK_INIT(&keystruct.common, link);
104224090Sdougb
105224090Sdougb			if (flags > 0xffff)
106224090Sdougb				return (ISC_R_RANGE);
107224090Sdougb			if (proto > 0xff)
108224090Sdougb				return (ISC_R_RANGE);
109224090Sdougb			if (alg > 0xff)
110224090Sdougb				return (ISC_R_RANGE);
111224090Sdougb			keystruct.flags = (isc_uint16_t)flags;
112224090Sdougb			keystruct.protocol = (isc_uint8_t)proto;
113224090Sdougb			keystruct.algorithm = (isc_uint8_t)alg;
114224090Sdougb
115224090Sdougb			isc_buffer_init(&keydatabuf_base, keydata,
116224090Sdougb					sizeof(keydata));
117224090Sdougb			isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
118224090Sdougb
119224090Sdougb			/* Configure key value */
120224090Sdougb			keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
121224090Sdougb			result = isc_base64_decodestring(keystr,
122224090Sdougb							 &keydatabuf_base);
123224090Sdougb			if (result != ISC_R_SUCCESS)
124224090Sdougb				return (result);
125224090Sdougb			isc_buffer_usedregion(&keydatabuf_base, &r);
126224090Sdougb			keystruct.datalen = r.length;
127224090Sdougb			keystruct.data = r.base;
128224090Sdougb
129224090Sdougb			result = dns_rdata_fromstruct(NULL,
130224090Sdougb						      keystruct.common.rdclass,
131224090Sdougb						      keystruct.common.rdtype,
132224090Sdougb						      &keystruct, &rrdatabuf);
133224090Sdougb			if (result != ISC_R_SUCCESS)
134224090Sdougb				return (result);
135224090Sdougb			isc_buffer_usedregion(&rrdatabuf, &r);
136224090Sdougb			result = isc_buffer_allocate(mctx, &keydatabuf,
137224090Sdougb						     r.length);
138224090Sdougb			if (result != ISC_R_SUCCESS)
139224090Sdougb				return (result);
140224090Sdougb			result = isc_buffer_copyregion(keydatabuf, &r);
141224090Sdougb			if (result != ISC_R_SUCCESS)
142224090Sdougb				goto cleanup;
143224090Sdougb
144224090Sdougb			/* Configure key name */
145224090Sdougb			dns_fixedname_init(&fkeyname);
146224090Sdougb			keyname_base = dns_fixedname_name(&fkeyname);
147254402Serwin			isc_buffer_constinit(&namebuf, keynamestr,
148254402Serwin					     strlen(keynamestr));
149224090Sdougb			isc_buffer_add(&namebuf, strlen(keynamestr));
150224090Sdougb			result = dns_name_fromtext(keyname_base, &namebuf,
151224090Sdougb						   dns_rootname, 0, NULL);
152224090Sdougb			if (result != ISC_R_SUCCESS)
153224090Sdougb				return (result);
154224090Sdougb			keyname = isc_mem_get(mctx, sizeof(*keyname));
155224090Sdougb			if (keyname == NULL) {
156224090Sdougb				result = ISC_R_NOMEMORY;
157224090Sdougb				goto cleanup;
158224090Sdougb			}
159224090Sdougb			dns_name_init(keyname, NULL);
160224090Sdougb			result = dns_name_dup(keyname_base, mctx, keyname);
161224090Sdougb			if (result != ISC_R_SUCCESS)
162224090Sdougb				goto cleanup;
163224090Sdougb
164224090Sdougb			/* Add the key data to the list */
165224090Sdougb			keyent = isc_mem_get(mctx, sizeof(*keyent));
166224090Sdougb			if (keyent == NULL) {
167224090Sdougb				dns_name_free(keyname, mctx);
168224090Sdougb				result = ISC_R_NOMEMORY;
169224090Sdougb				goto cleanup;
170224090Sdougb			}
171224090Sdougb			keyent->keyname = keyname;
172224090Sdougb			keyent->keydatabuf = keydatabuf;
173224090Sdougb
174224090Sdougb			ISC_LIST_APPEND(conf->trusted_keylist, keyent, link);
175224090Sdougb		}
176224090Sdougb	}
177224090Sdougb
178224090Sdougb	return (ISC_R_SUCCESS);
179224090Sdougb
180224090Sdougb cleanup:
181224090Sdougb	if (keydatabuf != NULL)
182224090Sdougb		isc_buffer_free(&keydatabuf);
183224090Sdougb	if (keyname != NULL)
184224090Sdougb		isc_mem_put(mctx, keyname, sizeof(*keyname));
185224090Sdougb
186224090Sdougb	return (result);
187224090Sdougb}
188224090Sdougb
189224090Sdougbisc_result_t
190224090Sdougbirs_dnsconf_load(isc_mem_t *mctx, const char *filename, irs_dnsconf_t **confp)
191224090Sdougb{
192224090Sdougb	irs_dnsconf_t *conf;
193224090Sdougb	cfg_parser_t *parser = NULL;
194224090Sdougb	cfg_obj_t *cfgobj = NULL;
195224090Sdougb	isc_result_t result = ISC_R_SUCCESS;
196224090Sdougb
197224090Sdougb	REQUIRE(confp != NULL && *confp == NULL);
198224090Sdougb
199224090Sdougb	conf = isc_mem_get(mctx, sizeof(*conf));
200224090Sdougb	if (conf == NULL)
201224090Sdougb		return (ISC_R_NOMEMORY);
202224090Sdougb
203224090Sdougb	conf->mctx = mctx;
204224090Sdougb	ISC_LIST_INIT(conf->trusted_keylist);
205224090Sdougb
206224090Sdougb	/*
207224090Sdougb	 * If the specified file does not exist, we'll simply with an empty
208224090Sdougb	 * configuration.
209224090Sdougb	 */
210224090Sdougb	if (!isc_file_exists(filename))
211224090Sdougb		goto cleanup;
212224090Sdougb
213224090Sdougb	result = cfg_parser_create(mctx, NULL, &parser);
214224090Sdougb	if (result != ISC_R_SUCCESS)
215224090Sdougb		goto cleanup;
216224090Sdougb
217224090Sdougb	result = cfg_parse_file(parser, filename, &cfg_type_dnsconf,
218224090Sdougb				&cfgobj);
219224090Sdougb	if (result != ISC_R_SUCCESS)
220224090Sdougb		goto cleanup;
221224090Sdougb
222224090Sdougb	result = configure_dnsseckeys(conf, cfgobj, dns_rdataclass_in);
223224090Sdougb
224224090Sdougb cleanup:
225224090Sdougb	if (parser != NULL) {
226224090Sdougb		if (cfgobj != NULL)
227224090Sdougb			cfg_obj_destroy(parser, &cfgobj);
228224090Sdougb		cfg_parser_destroy(&parser);
229224090Sdougb	}
230224090Sdougb
231224090Sdougb	conf->magic = IRS_DNSCONF_MAGIC;
232224090Sdougb
233224090Sdougb	if (result == ISC_R_SUCCESS)
234224090Sdougb		*confp = conf;
235224090Sdougb	else
236224090Sdougb		irs_dnsconf_destroy(&conf);
237224090Sdougb
238224090Sdougb	return (result);
239224090Sdougb}
240224090Sdougb
241224090Sdougbvoid
242224090Sdougbirs_dnsconf_destroy(irs_dnsconf_t **confp) {
243224090Sdougb	irs_dnsconf_t *conf;
244224090Sdougb	irs_dnsconf_dnskey_t *keyent;
245224090Sdougb
246224090Sdougb	REQUIRE(confp != NULL);
247224090Sdougb	conf = *confp;
248224090Sdougb	REQUIRE(IRS_DNSCONF_VALID(conf));
249224090Sdougb
250224090Sdougb	while ((keyent = ISC_LIST_HEAD(conf->trusted_keylist)) != NULL) {
251224090Sdougb		ISC_LIST_UNLINK(conf->trusted_keylist, keyent, link);
252224090Sdougb
253224090Sdougb		isc_buffer_free(&keyent->keydatabuf);
254224090Sdougb		dns_name_free(keyent->keyname, conf->mctx);
255224090Sdougb		isc_mem_put(conf->mctx, keyent->keyname, sizeof(dns_name_t));
256224090Sdougb		isc_mem_put(conf->mctx, keyent, sizeof(*keyent));
257224090Sdougb	}
258224090Sdougb
259224090Sdougb	isc_mem_put(conf->mctx, conf, sizeof(*conf));
260224090Sdougb
261224090Sdougb	*confp = NULL;
262224090Sdougb}
263224090Sdougb
264224090Sdougbirs_dnsconf_dnskeylist_t *
265224090Sdougbirs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf) {
266224090Sdougb	REQUIRE(IRS_DNSCONF_VALID(conf));
267224090Sdougb
268224090Sdougb	return (&conf->trusted_keylist);
269224090Sdougb}
270