1/* 2 * Copyright (C) 2009, 2012 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id: dnsconf.c,v 1.3 2009/09/02 23:48:02 tbox Exp $ */ 18 19/*! \file */ 20 21#include <config.h> 22 23#include <string.h> 24 25#include <isc/base64.h> 26#include <isc/buffer.h> 27#include <isc/file.h> 28#include <isc/mem.h> 29#include <isc/util.h> 30 31#include <isccfg/dnsconf.h> 32 33#include <dns/fixedname.h> 34#include <dns/name.h> 35#include <dns/rdata.h> 36#include <dns/rdatastruct.h> 37 38#include <irs/dnsconf.h> 39 40#define IRS_DNSCONF_MAGIC ISC_MAGIC('D', 'c', 'f', 'g') 41#define IRS_DNSCONF_VALID(c) ISC_MAGIC_VALID(c, IRS_DNSCONF_MAGIC) 42 43/*! 44 * configuration data structure 45 */ 46 47struct irs_dnsconf { 48 unsigned int magic; 49 isc_mem_t *mctx; 50 irs_dnsconf_dnskeylist_t trusted_keylist; 51}; 52 53static isc_result_t 54configure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj, 55 dns_rdataclass_t rdclass) 56{ 57 isc_mem_t *mctx = conf->mctx; 58 const cfg_obj_t *keys = NULL; 59 const cfg_obj_t *key, *keylist; 60 dns_fixedname_t fkeyname; 61 dns_name_t *keyname_base, *keyname; 62 const cfg_listelt_t *element, *element2; 63 isc_result_t result; 64 isc_uint32_t flags, proto, alg; 65 const char *keystr, *keynamestr; 66 unsigned char keydata[4096]; 67 isc_buffer_t keydatabuf_base, *keydatabuf; 68 dns_rdata_dnskey_t keystruct; 69 unsigned char rrdata[4096]; 70 isc_buffer_t rrdatabuf; 71 isc_region_t r; 72 isc_buffer_t namebuf; 73 irs_dnsconf_dnskey_t *keyent; 74 75 cfg_map_get(cfgobj, "trusted-keys", &keys); 76 if (keys == NULL) 77 return (ISC_R_SUCCESS); 78 79 for (element = cfg_list_first(keys); 80 element != NULL; 81 element = cfg_list_next(element)) { 82 keylist = cfg_listelt_value(element); 83 for (element2 = cfg_list_first(keylist); 84 element2 != NULL; 85 element2 = cfg_list_next(element2)) 86 { 87 keydatabuf = NULL; 88 keyname = NULL; 89 90 key = cfg_listelt_value(element2); 91 92 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); 93 proto = cfg_obj_asuint32(cfg_tuple_get(key, 94 "protocol")); 95 alg = cfg_obj_asuint32(cfg_tuple_get(key, 96 "algorithm")); 97 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, 98 "name")); 99 100 keystruct.common.rdclass = rdclass; 101 keystruct.common.rdtype = dns_rdatatype_dnskey; 102 keystruct.mctx = NULL; 103 ISC_LINK_INIT(&keystruct.common, link); 104 105 if (flags > 0xffff) 106 return (ISC_R_RANGE); 107 if (proto > 0xff) 108 return (ISC_R_RANGE); 109 if (alg > 0xff) 110 return (ISC_R_RANGE); 111 keystruct.flags = (isc_uint16_t)flags; 112 keystruct.protocol = (isc_uint8_t)proto; 113 keystruct.algorithm = (isc_uint8_t)alg; 114 115 isc_buffer_init(&keydatabuf_base, keydata, 116 sizeof(keydata)); 117 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 118 119 /* Configure key value */ 120 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); 121 result = isc_base64_decodestring(keystr, 122 &keydatabuf_base); 123 if (result != ISC_R_SUCCESS) 124 return (result); 125 isc_buffer_usedregion(&keydatabuf_base, &r); 126 keystruct.datalen = r.length; 127 keystruct.data = r.base; 128 129 result = dns_rdata_fromstruct(NULL, 130 keystruct.common.rdclass, 131 keystruct.common.rdtype, 132 &keystruct, &rrdatabuf); 133 if (result != ISC_R_SUCCESS) 134 return (result); 135 isc_buffer_usedregion(&rrdatabuf, &r); 136 result = isc_buffer_allocate(mctx, &keydatabuf, 137 r.length); 138 if (result != ISC_R_SUCCESS) 139 return (result); 140 result = isc_buffer_copyregion(keydatabuf, &r); 141 if (result != ISC_R_SUCCESS) 142 goto cleanup; 143 144 /* Configure key name */ 145 dns_fixedname_init(&fkeyname); 146 keyname_base = dns_fixedname_name(&fkeyname); 147 isc_buffer_constinit(&namebuf, keynamestr, 148 strlen(keynamestr)); 149 isc_buffer_add(&namebuf, strlen(keynamestr)); 150 result = dns_name_fromtext(keyname_base, &namebuf, 151 dns_rootname, 0, NULL); 152 if (result != ISC_R_SUCCESS) 153 return (result); 154 keyname = isc_mem_get(mctx, sizeof(*keyname)); 155 if (keyname == NULL) { 156 result = ISC_R_NOMEMORY; 157 goto cleanup; 158 } 159 dns_name_init(keyname, NULL); 160 result = dns_name_dup(keyname_base, mctx, keyname); 161 if (result != ISC_R_SUCCESS) 162 goto cleanup; 163 164 /* Add the key data to the list */ 165 keyent = isc_mem_get(mctx, sizeof(*keyent)); 166 if (keyent == NULL) { 167 dns_name_free(keyname, mctx); 168 result = ISC_R_NOMEMORY; 169 goto cleanup; 170 } 171 keyent->keyname = keyname; 172 keyent->keydatabuf = keydatabuf; 173 174 ISC_LIST_APPEND(conf->trusted_keylist, keyent, link); 175 } 176 } 177 178 return (ISC_R_SUCCESS); 179 180 cleanup: 181 if (keydatabuf != NULL) 182 isc_buffer_free(&keydatabuf); 183 if (keyname != NULL) 184 isc_mem_put(mctx, keyname, sizeof(*keyname)); 185 186 return (result); 187} 188 189isc_result_t 190irs_dnsconf_load(isc_mem_t *mctx, const char *filename, irs_dnsconf_t **confp) 191{ 192 irs_dnsconf_t *conf; 193 cfg_parser_t *parser = NULL; 194 cfg_obj_t *cfgobj = NULL; 195 isc_result_t result = ISC_R_SUCCESS; 196 197 REQUIRE(confp != NULL && *confp == NULL); 198 199 conf = isc_mem_get(mctx, sizeof(*conf)); 200 if (conf == NULL) 201 return (ISC_R_NOMEMORY); 202 203 conf->mctx = mctx; 204 ISC_LIST_INIT(conf->trusted_keylist); 205 206 /* 207 * If the specified file does not exist, we'll simply with an empty 208 * configuration. 209 */ 210 if (!isc_file_exists(filename)) 211 goto cleanup; 212 213 result = cfg_parser_create(mctx, NULL, &parser); 214 if (result != ISC_R_SUCCESS) 215 goto cleanup; 216 217 result = cfg_parse_file(parser, filename, &cfg_type_dnsconf, 218 &cfgobj); 219 if (result != ISC_R_SUCCESS) 220 goto cleanup; 221 222 result = configure_dnsseckeys(conf, cfgobj, dns_rdataclass_in); 223 224 cleanup: 225 if (parser != NULL) { 226 if (cfgobj != NULL) 227 cfg_obj_destroy(parser, &cfgobj); 228 cfg_parser_destroy(&parser); 229 } 230 231 conf->magic = IRS_DNSCONF_MAGIC; 232 233 if (result == ISC_R_SUCCESS) 234 *confp = conf; 235 else 236 irs_dnsconf_destroy(&conf); 237 238 return (result); 239} 240 241void 242irs_dnsconf_destroy(irs_dnsconf_t **confp) { 243 irs_dnsconf_t *conf; 244 irs_dnsconf_dnskey_t *keyent; 245 246 REQUIRE(confp != NULL); 247 conf = *confp; 248 REQUIRE(IRS_DNSCONF_VALID(conf)); 249 250 while ((keyent = ISC_LIST_HEAD(conf->trusted_keylist)) != NULL) { 251 ISC_LIST_UNLINK(conf->trusted_keylist, keyent, link); 252 253 isc_buffer_free(&keyent->keydatabuf); 254 dns_name_free(keyent->keyname, conf->mctx); 255 isc_mem_put(conf->mctx, keyent->keyname, sizeof(dns_name_t)); 256 isc_mem_put(conf->mctx, keyent, sizeof(*keyent)); 257 } 258 259 isc_mem_put(conf->mctx, conf, sizeof(*conf)); 260 261 *confp = NULL; 262} 263 264irs_dnsconf_dnskeylist_t * 265irs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf) { 266 REQUIRE(IRS_DNSCONF_VALID(conf)); 267 268 return (&conf->trusted_keylist); 269} 270