static isc_result_t add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl, dns_namelist_t *namelist) { isc_result_t result; isc_region_t r, newr; dns_rdata_t *newrdata = NULL; dns_name_t *newname = NULL; dns_rdatalist_t *newlist = NULL; dns_rdataset_t *newset = NULL; isc_buffer_t *tmprdatabuf = NULL; RETERR(dns_message_gettemprdata(msg, &newrdata)); dns_rdata_toregion(rdata, &r); RETERR(isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length)); isc_buffer_availableregion(tmprdatabuf, &newr); memcpy(newr.base, r.base, r.length); dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr); dns_message_takebuffer(msg, &tmprdatabuf); RETERR(dns_message_gettempname(msg, &newname)); dns_name_init(newname, NULL); RETERR(dns_name_dup(name, msg->mctx, newname)); RETERR(dns_message_gettemprdatalist(msg, &newlist)); newlist->rdclass = newrdata->rdclass; newlist->type = newrdata->type; newlist->covers = 0; newlist->ttl = ttl; ISC_LIST_INIT(newlist->rdata); ISC_LIST_APPEND(newlist->rdata, newrdata, link); RETERR(dns_message_gettemprdataset(msg, &newset)); dns_rdataset_init(newset); RETERR(dns_rdatalist_tordataset(newlist, newset)); ISC_LIST_INIT(newname->list); ISC_LIST_APPEND(newname->list, newset, link); ISC_LIST_APPEND(*namelist, newname, link); return (ISC_R_SUCCESS); failure: if (newrdata != NULL) { if (ISC_LINK_LINKED(newrdata, link)) ISC_LIST_UNLINK(newlist->rdata, newrdata, link); dns_message_puttemprdata(msg, &newrdata); } if (newname != NULL) dns_message_puttempname(msg, &newname); if (newset != NULL) { dns_rdataset_disassociate(newset); dns_message_puttemprdataset(msg, &newset); } if (newlist != NULL) dns_message_puttemprdatalist(msg, &newlist); return (result); }
isc_result_t dns_peer_setkeybycharp(dns_peer_t *peer, const char *keyval) { isc_buffer_t b; dns_fixedname_t fname; dns_name_t *name; isc_result_t result; dns_fixedname_init(&fname); isc_buffer_constinit(&b, keyval, strlen(keyval)); isc_buffer_add(&b, strlen(keyval)); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) return (result); name = isc_mem_get(peer->mem, sizeof(dns_name_t)); if (name == NULL) return (ISC_R_NOMEMORY); dns_name_init(name, NULL); result = dns_name_dup(dns_fixedname_name(&fname), peer->mem, name); if (result != ISC_R_SUCCESS) { isc_mem_put(peer->mem, name, sizeof(dns_name_t)); return (result); } result = dns_peer_setkey(peer, &name); if (result != ISC_R_SUCCESS) isc_mem_put(peer->mem, name, sizeof(dns_name_t)); return (result); }
static isc_result_t build_event(dns_lookup_t *lookup) { dns_name_t *name = NULL; dns_rdataset_t *rdataset = NULL; dns_rdataset_t *sigrdataset = NULL; isc_result_t result; name = isc_mem_get(lookup->mctx, sizeof(dns_name_t)); if (name == NULL) { result = ISC_R_NOMEMORY; goto fail; } dns_name_init(name, NULL); result = dns_name_dup(dns_fixedname_name(&lookup->name), lookup->mctx, name); if (result != ISC_R_SUCCESS) goto fail; if (dns_rdataset_isassociated(&lookup->rdataset)) { rdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t)); if (rdataset == NULL) { result = ISC_R_NOMEMORY; goto fail; } dns_rdataset_init(rdataset); dns_rdataset_clone(&lookup->rdataset, rdataset); } if (dns_rdataset_isassociated(&lookup->sigrdataset)) { sigrdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t)); if (sigrdataset == NULL) { result = ISC_R_NOMEMORY; goto fail; } dns_rdataset_init(sigrdataset); dns_rdataset_clone(&lookup->sigrdataset, sigrdataset); } lookup->event->name = name; lookup->event->rdataset = rdataset; lookup->event->sigrdataset = sigrdataset; return (ISC_R_SUCCESS); fail: if (name != NULL) { if (dns_name_dynamic(name)) dns_name_free(name, lookup->mctx); isc_mem_put(lookup->mctx, name, sizeof(dns_name_t)); } if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); isc_mem_put(lookup->mctx, rdataset, sizeof(dns_rdataset_t)); } return (result); }
/*% * Allocates a key structure and fills in some of the fields. */ static dst_key_t * get_key_struct(dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, unsigned int bits, dns_rdataclass_t rdclass, dns_ttl_t ttl, isc_mem_t *mctx) { dst_key_t *key; isc_result_t result; int i; key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); if (key == NULL) return (NULL); memset(key, 0, sizeof(dst_key_t)); key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); if (key->key_name == NULL) { isc_mem_put(mctx, key, sizeof(dst_key_t)); return (NULL); } dns_name_init(key->key_name, NULL); result = dns_name_dup(name, mctx, key->key_name); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); isc_mem_put(mctx, key, sizeof(dst_key_t)); return (NULL); } result = isc_refcount_init(&key->refs, 1); if (result != ISC_R_SUCCESS) { dns_name_free(key->key_name, mctx); isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); isc_mem_put(mctx, key, sizeof(dst_key_t)); return (NULL); } isc_mem_attach(mctx, &key->mctx); key->key_alg = alg; key->key_flags = flags; key->key_proto = protocol; key->keydata.generic = NULL; key->key_size = bits; key->key_class = rdclass; key->key_ttl = ttl; key->func = dst_t_func[alg]; key->fmt_major = 0; key->fmt_minor = 0; for (i = 0; i < (DST_MAX_TIMES + 1); i++) { key->times[i] = 0; key->timeset[i] = ISC_FALSE; } key->inactive = ISC_FALSE; key->magic = KEY_MAGIC; return (key); }
static isc_result_t findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, dns_dbnode_t **nodep) { dns_ecdb_t *ecdb = (dns_ecdb_t *)db; isc_mem_t *mctx; dns_ecdbnode_t *node; isc_result_t result; REQUIRE(VALID_ECDB(ecdb)); REQUIRE(nodep != NULL && *nodep == NULL); UNUSED(name); if (create != ISC_TRUE) { /* an 'ephemeral' node is never reused. */ return (ISC_R_NOTFOUND); } mctx = ecdb->common.mctx; node = isc_mem_get(mctx, sizeof(*node)); if (node == NULL) return (ISC_R_NOMEMORY); result = isc_mutex_init(&node->lock); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() failed: %s", isc_result_totext(result)); isc_mem_put(mctx, node, sizeof(*node)); return (ISC_R_UNEXPECTED); } dns_name_init(&node->name, NULL); result = dns_name_dup(name, mctx, &node->name); if (result != ISC_R_SUCCESS) { DESTROYLOCK(&node->lock); isc_mem_put(mctx, node, sizeof(*node)); return (result); } node->ecdb= ecdb; node->references = 1; ISC_LIST_INIT(node->rdatasets); ISC_LINK_INIT(node, link); LOCK(&ecdb->lock); ISC_LIST_APPEND(ecdb->nodes, node, link); UNLOCK(&ecdb->lock); node->magic = ECDBNODE_MAGIC; *nodep = node; return (ISC_R_SUCCESS); }
static void lookup(const char *target) { dns_name_t name; unsigned char namedata[256]; client_t *client; isc_buffer_t t, namebuf; isc_result_t result; unsigned int options; INSIST(target != NULL); client = new_client(); isc_buffer_init(&t, target, strlen(target)); isc_buffer_add(&t, strlen(target)); isc_buffer_init(&namebuf, namedata, sizeof(namedata)); dns_name_init(&name, NULL); result = dns_name_fromtext(&name, &t, dns_rootname, ISC_FALSE, &namebuf); check_result(result, "dns_name_fromtext %s", target); result = dns_name_dup(&name, mctx, &client->name); check_result(result, "dns_name_dup %s", target); options = 0; options |= DNS_ADBFIND_INET; options |= DNS_ADBFIND_INET6; options |= DNS_ADBFIND_WANTEVENT; options |= DNS_ADBFIND_HINTOK; options |= DNS_ADBFIND_GLUEOK; result = dns_adb_createfind(adb, t2, lookup_callback, client, &client->name, dns_rootname, options, now, NULL, view->dstport, &client->find); #if 0 check_result(result, "dns_adb_createfind()"); #endif dns_adb_dumpfind(client->find, stderr); if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { client->target = target; ISC_LIST_APPEND(clients, client, link); } else { printf("NAME %s: err4 %s, err6 %s\n", target, isc_result_totext(client->find->result_v4), isc_result_totext(client->find->result_v6)); dns_adb_destroyfind(&client->find); free_client(&client); } }
isc_result_t ns_lwsearchlist_append(ns_lwsearchlist_t *list, dns_name_t *name) { dns_name_t *newname; isc_result_t result; REQUIRE(VALID_LWSEARCHLIST(list)); REQUIRE(name != NULL); newname = isc_mem_get(list->mctx, sizeof(dns_name_t)); if (newname == NULL) return (ISC_R_NOMEMORY); dns_name_init(newname, NULL); result = dns_name_dup(name, list->mctx, newname); if (result != ISC_R_SUCCESS) { isc_mem_put(list->mctx, newname, sizeof(dns_name_t)); return (result); } ISC_LINK_INIT(newname, link); ISC_LIST_APPEND(list->names, newname, link); return (ISC_R_SUCCESS); }
static isc_result_t convert_keyname(cfg_obj_t *keyobj, isc_mem_t *mctx, dns_name_t *dnsname) { isc_result_t result; isc_buffer_t buf; dns_fixedname_t fixname; unsigned int keylen; const char *txtname = cfg_obj_asstring(keyobj); keylen = strlen(txtname); isc_buffer_init(&buf, txtname, keylen); isc_buffer_add(&buf, keylen); dns_fixedname_init(&fixname); result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf, dns_rootname, ISC_FALSE, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(keyobj, dns_lctx, ISC_LOG_WARNING, "key name '%s' is not a valid domain name", txtname); return (result); } return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname)); }
/*% * Allocates a key structure and fills in some of the fields. */ static dst_key_t * get_key_struct(dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, unsigned int bits, dns_rdataclass_t rdclass, isc_mem_t *mctx) { dst_key_t *key; isc_result_t result; key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); if (key == NULL) return (NULL); memset(key, 0, sizeof(dst_key_t)); key->magic = KEY_MAGIC; key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); if (key->key_name == NULL) { isc_mem_put(mctx, key, sizeof(dst_key_t)); return (NULL); } dns_name_init(key->key_name, NULL); result = dns_name_dup(name, mctx, key->key_name); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); isc_mem_put(mctx, key, sizeof(dst_key_t)); return (NULL); } key->key_alg = alg; key->key_flags = flags; key->key_proto = protocol; key->mctx = mctx; key->opaque = NULL; key->key_size = bits; key->key_class = rdclass; key->func = dst_t_func[alg]; return (key); }
isc_result_t dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant, dns_name_t *identity, unsigned int matchtype, dns_name_t *name, unsigned int ntypes, dns_rdatatype_t *types) { dns_ssurule_t *rule; isc_mem_t *mctx; isc_result_t result; REQUIRE(VALID_SSUTABLE(table)); REQUIRE(dns_name_isabsolute(identity)); REQUIRE(dns_name_isabsolute(name)); REQUIRE(matchtype <= DNS_SSUMATCHTYPE_MAX); if (matchtype == DNS_SSUMATCHTYPE_WILDCARD) REQUIRE(dns_name_iswildcard(name)); if (ntypes > 0) REQUIRE(types != NULL); mctx = table->mctx; rule = isc_mem_get(mctx, sizeof(dns_ssurule_t)); if (rule == NULL) return (ISC_R_NOMEMORY); rule->identity = NULL; rule->name = NULL; rule->types = NULL; rule->grant = grant; rule->identity = isc_mem_get(mctx, sizeof(dns_name_t)); if (rule->identity == NULL) { result = ISC_R_NOMEMORY; goto failure; } dns_name_init(rule->identity, NULL); result = dns_name_dup(identity, mctx, rule->identity); if (result != ISC_R_SUCCESS) goto failure; rule->name = isc_mem_get(mctx, sizeof(dns_name_t)); if (rule->name == NULL) { result = ISC_R_NOMEMORY; goto failure; } dns_name_init(rule->name, NULL); result = dns_name_dup(name, mctx, rule->name); if (result != ISC_R_SUCCESS) goto failure; rule->matchtype = matchtype; rule->ntypes = ntypes; if (ntypes > 0) { rule->types = isc_mem_get(mctx, ntypes * sizeof(dns_rdatatype_t)); if (rule->types == NULL) { result = ISC_R_NOMEMORY; goto failure; } memmove(rule->types, types, ntypes * sizeof(dns_rdatatype_t)); } else rule->types = NULL; rule->magic = SSURULEMAGIC; ISC_LIST_INITANDAPPEND(table->rules, rule, link); return (ISC_R_SUCCESS); failure: if (rule->identity != NULL) { if (dns_name_dynamic(rule->identity)) dns_name_free(rule->identity, mctx); isc_mem_put(mctx, rule->identity, sizeof(dns_name_t)); } if (rule->name != NULL) { if (dns_name_dynamic(rule->name)) dns_name_free(rule->name, mctx); isc_mem_put(mctx, rule->name, sizeof(dns_name_t)); } if (rule->types != NULL) isc_mem_put(mctx, rule->types, ntypes * sizeof(dns_rdatatype_t)); isc_mem_put(mctx, rule, sizeof(dns_ssurule_t)); return (result); }
isc_result_t ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp) { isc_result_t result; dns_tkeyctx_t *tctx = NULL; const char *s; isc_uint32_t n; dns_fixedname_t fname; dns_name_t *name; isc_buffer_t b; const cfg_obj_t *obj; int type; result = dns_tkeyctx_create(mctx, ectx, &tctx); if (result != ISC_R_SUCCESS) return (result); obj = NULL; result = cfg_map_get(options, "tkey-dhkey", &obj); if (result == ISC_R_SUCCESS) { s = cfg_obj_asstring(cfg_tuple_get(obj, "name")); n = cfg_obj_asuint32(cfg_tuple_get(obj, "keyid")); isc_buffer_constinit(&b, s, strlen(s)); isc_buffer_add(&b, strlen(s)); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); type = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_KEY; RETERR(dst_key_fromfile(name, (dns_keytag_t) n, DNS_KEYALG_DH, type, NULL, mctx, &tctx->dhkey)); } obj = NULL; result = cfg_map_get(options, "tkey-domain", &obj); if (result == ISC_R_SUCCESS) { s = cfg_obj_asstring(obj); isc_buffer_constinit(&b, s, strlen(s)); isc_buffer_add(&b, strlen(s)); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); tctx->domain = isc_mem_get(mctx, sizeof(dns_name_t)); if (tctx->domain == NULL) { result = ISC_R_NOMEMORY; goto failure; } dns_name_init(tctx->domain, NULL); RETERR(dns_name_dup(name, mctx, tctx->domain)); } obj = NULL; result = cfg_map_get(options, "tkey-gssapi-credential", &obj); if (result == ISC_R_SUCCESS) { s = cfg_obj_asstring(obj); isc_buffer_constinit(&b, s, strlen(s)); isc_buffer_add(&b, strlen(s)); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); RETERR(dst_gssapi_acquirecred(name, ISC_FALSE, &tctx->gsscred)); } obj = NULL; result = cfg_map_get(options, "tkey-gssapi-keytab", &obj); if (result == ISC_R_SUCCESS) { s = cfg_obj_asstring(obj); tctx->gssapi_keytab = isc_mem_strdup(mctx, s); if (tctx->gssapi_keytab == NULL) { result = ISC_R_NOMEMORY; goto failure; } } *tctxp = tctx; return (ISC_R_SUCCESS); failure: dns_tkeyctx_destroy(&tctx); return (result); }
isc_result_t dns_tsig_sign(dns_message_t *msg) { dns_tsigkey_t *key; dns_rdata_any_tsig_t tsig, querytsig; unsigned char data[128]; isc_buffer_t databuf, sigbuf; isc_buffer_t *dynbuf; dns_name_t *owner; dns_rdata_t *rdata = NULL; dns_rdatalist_t *datalist; dns_rdataset_t *dataset; isc_region_t r; isc_stdtime_t now; isc_mem_t *mctx; dst_context_t *ctx = NULL; isc_result_t ret; unsigned char badtimedata[BADTIMELEN]; unsigned int sigsize = 0; isc_boolean_t response = is_response(msg); REQUIRE(msg != NULL); REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg))); /* * If this is a response, there should be a query tsig. */ if (response && msg->querytsig == NULL) return (DNS_R_EXPECTEDTSIG); dynbuf = NULL; mctx = msg->mctx; key = dns_message_gettsigkey(msg); tsig.mctx = mctx; tsig.common.rdclass = dns_rdataclass_any; tsig.common.rdtype = dns_rdatatype_tsig; ISC_LINK_INIT(&tsig.common, link); dns_name_init(&tsig.algorithm, NULL); dns_name_clone(key->algorithm, &tsig.algorithm); isc_stdtime_get(&now); tsig.timesigned = now + msg->timeadjust; tsig.fudge = DNS_TSIG_FUDGE; tsig.originalid = msg->id; isc_buffer_init(&databuf, data, sizeof(data)); if (response) tsig.error = msg->querytsigstatus; else tsig.error = dns_rcode_noerror; if (tsig.error != dns_tsigerror_badtime) { tsig.otherlen = 0; tsig.other = NULL; } else { isc_buffer_t otherbuf; tsig.otherlen = BADTIMELEN; tsig.other = badtimedata; isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen); isc_buffer_putuint48(&otherbuf, tsig.timesigned); } if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf; isc_uint16_t digestbits; ret = dst_context_create3(key->key, mctx, DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx); if (ret != ISC_R_SUCCESS) return (ret); /* * If this is a response, digest the query signature. */ if (response) { dns_rdata_t querytsigrdata = DNS_RDATA_INIT; ret = dns_rdataset_first(msg->querytsig); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_rdataset_current(msg->querytsig, &querytsigrdata); ret = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_putuint16(&databuf, querytsig.siglen); if (isc_buffer_availablelength(&databuf) < querytsig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_context; } isc_buffer_putmem(&databuf, querytsig.signature, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } #if defined(__clang__) && \ ( __clang_major__ < 3 || \ (__clang_major__ == 3 && __clang_minor__ < 2) || \ (__clang_major__ == 4 && __clang_minor__ < 2)) /* false positive: http://llvm.org/bugs/show_bug.cgi?id=14461 */ else memset(&querytsig, 0, sizeof(querytsig)); #endif /* * Digest the header. */ isc_buffer_init(&headerbuf, header, sizeof(header)); dns_message_renderheader(msg, &headerbuf); isc_buffer_usedregion(&headerbuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the remainder of the message. */ isc_buffer_usedregion(msg->buffer, &r); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the name, class, ttl, alg. */ dns_name_toregion(&key->name, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, dns_rdataclass_any); isc_buffer_putuint32(&databuf, 0); /* ttl */ isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_name_toregion(&tsig.algorithm, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } /* Digest the timesigned and fudge */ isc_buffer_clear(&databuf); if (tsig.error == dns_tsigerror_badtime) { INSIST(response); tsig.timesigned = querytsig.timesigned; } isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the error and other data length. */ isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, tsig.error); isc_buffer_putuint16(&databuf, tsig.otherlen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest other data. */ if (tsig.otherlen > 0) { r.length = tsig.otherlen; r.base = tsig.other; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } } ret = dst_key_sigsize(key->key, &sigsize); if (ret != ISC_R_SUCCESS) goto cleanup_context; tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize); if (tsig.signature == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_context; } isc_buffer_init(&sigbuf, tsig.signature, sigsize); ret = dst_context_sign(ctx, &sigbuf); if (ret != ISC_R_SUCCESS) goto cleanup_signature; dst_context_destroy(&ctx); digestbits = dst_key_getbits(key->key); if (digestbits != 0) { unsigned int bytes = (digestbits + 1) / 8; if (response && bytes < querytsig.siglen) bytes = querytsig.siglen; if (bytes > isc_buffer_usedlength(&sigbuf)) bytes = isc_buffer_usedlength(&sigbuf); tsig.siglen = bytes; } else tsig.siglen = isc_buffer_usedlength(&sigbuf); } else { tsig.siglen = 0; tsig.signature = NULL; } ret = dns_message_gettemprdata(msg, &rdata); if (ret != ISC_R_SUCCESS) goto cleanup_signature; ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512); if (ret != ISC_R_SUCCESS) goto cleanup_rdata; ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &tsig, dynbuf); if (ret != ISC_R_SUCCESS) goto cleanup_dynbuf; dns_message_takebuffer(msg, &dynbuf); if (tsig.signature != NULL) { isc_mem_put(mctx, tsig.signature, sigsize); tsig.signature = NULL; } owner = NULL; ret = dns_message_gettempname(msg, &owner); if (ret != ISC_R_SUCCESS) goto cleanup_rdata; dns_name_init(owner, NULL); ret = dns_name_dup(&key->name, msg->mctx, owner); if (ret != ISC_R_SUCCESS) goto cleanup_owner; datalist = NULL; ret = dns_message_gettemprdatalist(msg, &datalist); if (ret != ISC_R_SUCCESS) goto cleanup_owner; dataset = NULL; ret = dns_message_gettemprdataset(msg, &dataset); if (ret != ISC_R_SUCCESS) goto cleanup_rdatalist; datalist->rdclass = dns_rdataclass_any; datalist->type = dns_rdatatype_tsig; datalist->covers = 0; datalist->ttl = 0; ISC_LIST_INIT(datalist->rdata); ISC_LIST_APPEND(datalist->rdata, rdata, link); RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS); msg->tsig = dataset; msg->tsigname = owner; /* Windows does not like the tsig name being compressed. */ msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; return (ISC_R_SUCCESS); cleanup_rdatalist: dns_message_puttemprdatalist(msg, &datalist); cleanup_owner: dns_message_puttempname(msg, &owner); goto cleanup_rdata; cleanup_dynbuf: isc_buffer_free(&dynbuf); cleanup_rdata: dns_message_puttemprdata(msg, &rdata); cleanup_signature: if (tsig.signature != NULL) isc_mem_put(mctx, tsig.signature, sigsize); cleanup_context: if (ctx != NULL) dst_context_destroy(&ctx); return (ret); }
isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { dns_tsigkey_t *tkey; isc_result_t ret; unsigned int refs = 0; REQUIRE(key == NULL || *key == NULL); REQUIRE(name != NULL); REQUIRE(algorithm != NULL); REQUIRE(mctx != NULL); REQUIRE(key != NULL || ring != NULL); tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t)); if (tkey == NULL) return (ISC_R_NOMEMORY); dns_name_init(&tkey->name, NULL); ret = dns_name_dup(name, mctx, &tkey->name); if (ret != ISC_R_SUCCESS) goto cleanup_key; (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { tkey->algorithm = DNS_TSIG_HMACMD5_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA1_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA224_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA224) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA256_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA256) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA384_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA384) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA512_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA512) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else { if (dstkey != NULL) { ret = DNS_R_BADALG; goto cleanup_name; } tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->algorithm == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_name; } dns_name_init(tkey->algorithm, NULL); ret = dns_name_dup(algorithm, mctx, tkey->algorithm); if (ret != ISC_R_SUCCESS) goto cleanup_algorithm; (void)dns_name_downcase(tkey->algorithm, tkey->algorithm, NULL); } if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->creator == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_algorithm; } dns_name_init(tkey->creator, NULL); ret = dns_name_dup(creator, mctx, tkey->creator); if (ret != ISC_R_SUCCESS) { isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); goto cleanup_algorithm; } } else tkey->creator = NULL; tkey->key = NULL; if (dstkey != NULL) dst_key_attach(dstkey, &tkey->key); tkey->ring = ring; if (key != NULL) refs = 1; if (ring != NULL) refs++; ret = isc_refcount_init(&tkey->refs, refs); if (ret != ISC_R_SUCCESS) goto cleanup_creator; tkey->generated = generated; tkey->inception = inception; tkey->expire = expire; tkey->mctx = NULL; isc_mem_attach(mctx, &tkey->mctx); ISC_LINK_INIT(tkey, link); tkey->magic = TSIG_MAGIC; if (ring != NULL) { ret = keyring_add(ring, name, tkey); if (ret != ISC_R_SUCCESS) goto cleanup_refs; } /* * Ignore this if it's a GSS key, since the key size is meaningless. */ if (dstkey != NULL && dst_key_size(dstkey) < 64 && !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, ISC_LOG_INFO, "the key '%s' is too short to be secure", namestr); } if (key != NULL) *key = tkey; return (ISC_R_SUCCESS); cleanup_refs: tkey->magic = 0; while (refs-- > 0) isc_refcount_decrement(&tkey->refs, NULL); isc_refcount_destroy(&tkey->refs); cleanup_creator: if (tkey->key != NULL) dst_key_free(&tkey->key); if (tkey->creator != NULL) { dns_name_free(tkey->creator, mctx); isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); } cleanup_algorithm: if (algname_is_allocated(tkey->algorithm)) { if (dns_name_dynamic(tkey->algorithm)) dns_name_free(tkey->algorithm, mctx); isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t)); } cleanup_name: dns_name_free(&tkey->name, mctx); cleanup_key: isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t)); return (ret); }
isc_result_t dns_tsig_sign(dns_message_t *msg) { dns_tsigkey_t *key; dns_rdata_any_tsig_t tsig, querytsig; unsigned char data[128]; isc_buffer_t databuf, sigbuf; isc_buffer_t *dynbuf; dns_name_t *owner; dns_rdata_t *rdata; dns_rdatalist_t *datalist; dns_rdataset_t *dataset; isc_region_t r; isc_stdtime_t now; isc_mem_t *mctx; dst_context_t *ctx = NULL; isc_result_t ret; unsigned char badtimedata[BADTIMELEN]; unsigned int sigsize = 0; REQUIRE(msg != NULL); REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg))); /* * If this is a response, there should be a query tsig. */ if (is_response(msg) && msg->querytsig == NULL) return (DNS_R_EXPECTEDTSIG); dynbuf = NULL; mctx = msg->mctx; key = dns_message_gettsigkey(msg); tsig.mctx = mctx; tsig.common.rdclass = dns_rdataclass_any; tsig.common.rdtype = dns_rdatatype_tsig; ISC_LINK_INIT(&tsig.common, link); dns_name_init(&tsig.algorithm, NULL); dns_name_clone(key->algorithm, &tsig.algorithm); isc_stdtime_get(&now); tsig.timesigned = now + msg->timeadjust; tsig.fudge = DNS_TSIG_FUDGE; tsig.originalid = msg->id; isc_buffer_init(&databuf, data, sizeof(data)); if (is_response(msg)) tsig.error = msg->querytsigstatus; else tsig.error = dns_rcode_noerror; if (tsig.error != dns_tsigerror_badtime) { tsig.otherlen = 0; tsig.other = NULL; } else { isc_buffer_t otherbuf; tsig.otherlen = BADTIMELEN; tsig.other = badtimedata; isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen); buffer_putuint48(&otherbuf, tsig.timesigned); } if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf; ret = dst_context_create(key->key, mctx, &ctx); if (ret != ISC_R_SUCCESS) return (ret); /* * If this is a response, digest the query signature. */ if (is_response(msg)) { dns_rdata_t querytsigrdata = DNS_RDATA_INIT; ret = dns_rdataset_first(msg->querytsig); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_rdataset_current(msg->querytsig, &querytsigrdata); ret = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_putuint16(&databuf, querytsig.siglen); if (isc_buffer_availablelength(&databuf) < querytsig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_context; } isc_buffer_putmem(&databuf, querytsig.signature, querytsig.siglen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } /* * Digest the header. */ isc_buffer_init(&headerbuf, header, sizeof(header)); dns_message_renderheader(msg, &headerbuf); isc_buffer_usedregion(&headerbuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the remainder of the message. */ isc_buffer_usedregion(msg->buffer, &r); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the name, class, ttl, alg. */ dns_name_toregion(&key->name, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, dns_rdataclass_any); isc_buffer_putuint32(&databuf, 0); /* ttl */ isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; dns_name_toregion(&tsig.algorithm, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } /* Digest the timesigned and fudge */ isc_buffer_clear(&databuf); if (tsig.error == dns_tsigerror_badtime) tsig.timesigned = querytsig.timesigned; buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; if (msg->tcp_continuation == 0) { /* * Digest the error and other data length. */ isc_buffer_clear(&databuf); isc_buffer_putuint16(&databuf, tsig.error); isc_buffer_putuint16(&databuf, tsig.otherlen); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; /* * Digest the error and other data. */ if (tsig.otherlen > 0) { r.length = tsig.otherlen; r.base = tsig.other; ret = dst_context_adddata(ctx, &r); if (ret != ISC_R_SUCCESS) goto cleanup_context; } } ret = dst_key_sigsize(key->key, &sigsize); if (ret != ISC_R_SUCCESS) goto cleanup_context; tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize); if (tsig.signature == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_context; } isc_buffer_init(&sigbuf, tsig.signature, sigsize); ret = dst_context_sign(ctx, &sigbuf); if (ret != ISC_R_SUCCESS) goto cleanup_signature; dst_context_destroy(&ctx); tsig.siglen = isc_buffer_usedlength(&sigbuf); } else { tsig.siglen = 0; tsig.signature = NULL; } rdata = NULL; ret = dns_message_gettemprdata(msg, &rdata); if (ret != ISC_R_SUCCESS) goto cleanup_signature; ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512); if (ret != ISC_R_SUCCESS) goto cleanup_signature; ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &tsig, dynbuf); if (ret != ISC_R_SUCCESS) goto cleanup_dynbuf; dns_message_takebuffer(msg, &dynbuf); if (tsig.signature != NULL) { isc_mem_put(mctx, tsig.signature, sigsize); tsig.signature = NULL; } owner = NULL; ret = dns_message_gettempname(msg, &owner); if (ret != ISC_R_SUCCESS) goto cleanup_dynbuf; dns_name_init(owner, NULL); ret = dns_name_dup(&key->name, msg->mctx, owner); if (ret != ISC_R_SUCCESS) goto cleanup_owner; datalist = NULL; ret = dns_message_gettemprdatalist(msg, &datalist); if (ret != ISC_R_SUCCESS) goto cleanup_owner; datalist->rdclass = dns_rdataclass_any; datalist->type = dns_rdatatype_tsig; datalist->covers = 0; datalist->ttl = 0; ISC_LIST_INIT(datalist->rdata); ISC_LIST_APPEND(datalist->rdata, rdata, link); dataset = NULL; ret = dns_message_gettemprdataset(msg, &dataset); if (ret != ISC_R_SUCCESS) goto cleanup_owner; dns_rdataset_init(dataset); RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS); msg->tsig = dataset; msg->tsigname = owner; return (ISC_R_SUCCESS); cleanup_owner: if (owner != NULL) dns_message_puttempname(msg, &owner); cleanup_dynbuf: if (dynbuf != NULL) isc_buffer_free(&dynbuf); cleanup_signature: if (tsig.signature != NULL) isc_mem_put(mctx, tsig.signature, sigsize); cleanup_context: if (ctx != NULL) dst_context_destroy(&ctx); return (ret); }
isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { dns_tsigkey_t *tkey; isc_result_t ret; unsigned int refs = 0; REQUIRE(key == NULL || *key == NULL); REQUIRE(name != NULL); REQUIRE(algorithm != NULL); REQUIRE(mctx != NULL); tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t)); if (tkey == NULL) return (ISC_R_NOMEMORY); dns_name_init(&tkey->name, NULL); ret = dns_name_dup(name, mctx, &tkey->name); if (ret != ISC_R_SUCCESS) goto cleanup_key; (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { tkey->algorithm = DNS_TSIG_HMACMD5_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else { if (key != NULL) { ret = DNS_R_BADALG; goto cleanup_name; } tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->algorithm == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_name; } dns_name_init(tkey->algorithm, NULL); ret = dns_name_dup(algorithm, mctx, tkey->algorithm); if (ret != ISC_R_SUCCESS) goto cleanup_algorithm; (void)dns_name_downcase(tkey->algorithm, tkey->algorithm, NULL); } if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->creator == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_algorithm; } dns_name_init(tkey->creator, NULL); ret = dns_name_dup(creator, mctx, tkey->creator); if (ret != ISC_R_SUCCESS) { isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); goto cleanup_algorithm; } } else tkey->creator = NULL; tkey->key = dstkey; tkey->ring = ring; if (ring != NULL) { RWLOCK(&ring->lock, isc_rwlocktype_write); ret = dns_rbt_addname(ring->keys, name, tkey); if (ret != ISC_R_SUCCESS) { RWUNLOCK(&ring->lock, isc_rwlocktype_write); goto cleanup_algorithm; } refs++; RWUNLOCK(&ring->lock, isc_rwlocktype_write); } if (key != NULL) refs++; isc_refcount_init(&tkey->refs, refs); tkey->generated = generated; tkey->inception = inception; tkey->expire = expire; tkey->mctx = mctx; tkey->magic = TSIG_MAGIC; if (dstkey != NULL && dst_key_size(dstkey) < 64) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, ISC_LOG_INFO, "the key '%s' is too short to be secure", namestr); } if (key != NULL) *key = tkey; return (ISC_R_SUCCESS); cleanup_algorithm: if (algname_is_allocated(tkey->algorithm)) { if (dns_name_dynamic(tkey->algorithm)) dns_name_free(tkey->algorithm, mctx); isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t)); } cleanup_name: dns_name_free(&tkey->name, mctx); cleanup_key: isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t)); return (ret); }
/* * Merge the contents of one ACL into another. Call dns_iptable_merge() * for the IP tables, then concatenate the element arrays. * * If pos is set to false, then the nested ACL is to be negated. This * means reverse the sense of each *positive* element or IP table node, * but leave negatives alone, so as to prevent a double-negative causing * an unexpected positive match in the parent ACL. */ isc_result_t dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos) { isc_result_t result; unsigned int newalloc, nelem, i; int max_node = 0, nodes; /* Resize the element array if needed. */ if (dest->length + source->length > dest->alloc) { void *newmem; newalloc = dest->alloc + source->alloc; if (newalloc < 4) newalloc = 4; newmem = isc_mem_get(dest->mctx, newalloc * sizeof(dns_aclelement_t)); if (newmem == NULL) return (ISC_R_NOMEMORY); /* Copy in the original elements */ memcpy(newmem, dest->elements, dest->length * sizeof(dns_aclelement_t)); /* Release the memory for the old elements array */ isc_mem_put(dest->mctx, dest->elements, dest->alloc * sizeof(dns_aclelement_t)); dest->elements = newmem; dest->alloc = newalloc; } /* * Now copy in the new elements, increasing their node_num * values so as to keep the new ACL consistent. If we're * negating, then negate positive elements, but keep negative * elements the same for security reasons. */ nelem = dest->length; dest->length += source->length; for (i = 0; i < source->length; i++) { if (source->elements[i].node_num > max_node) max_node = source->elements[i].node_num; /* Copy type. */ dest->elements[nelem + i].type = source->elements[i].type; /* Adjust node numbering. */ dest->elements[nelem + i].node_num = source->elements[i].node_num + dest->node_count; /* Duplicate nested acl. */ if (source->elements[i].type == dns_aclelementtype_nestedacl && source->elements[i].nestedacl != NULL) dns_acl_attach(source->elements[i].nestedacl, &dest->elements[nelem + i].nestedacl); /* Duplicate key name. */ if (source->elements[i].type == dns_aclelementtype_keyname) { dns_name_init(&dest->elements[nelem+i].keyname, NULL); result = dns_name_dup(&source->elements[i].keyname, dest->mctx, &dest->elements[nelem+i].keyname); if (result != ISC_R_SUCCESS) return result; } /* reverse sense of positives if this is a negative acl */ if (!pos && source->elements[i].negative == ISC_FALSE) { dest->elements[nelem + i].negative = ISC_TRUE; } else { dest->elements[nelem + i].negative = source->elements[i].negative; } } /* * Merge the iptables. Make sure the destination ACL's * node_count value is set correctly afterward. */ nodes = max_node + dest->node_count; result = dns_iptable_merge(dest->iptable, source->iptable, pos); if (result != ISC_R_SUCCESS) return (result); if (nodes > dest->node_count) dest->node_count = nodes; return (ISC_R_SUCCESS); }
isc_result_t ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, isc_mem_t *mctx, isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, dns_name_t ***keysp, isc_uint32_t *countp) { isc_uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0; isc_uint32_t listcount = 0, l = 0, j; isc_uint32_t stackcount = 0, pushed = 0; isc_result_t result; const cfg_listelt_t *element; const cfg_obj_t *addrlist; const cfg_obj_t *portobj; const cfg_obj_t *dscpobj; in_port_t port; isc_dscp_t dscp = -1; dns_fixedname_t fname; isc_sockaddr_t *addrs = NULL; isc_dscp_t *dscps = NULL; dns_name_t **keys = NULL; struct { const char *name; } *lists = NULL; struct { const cfg_listelt_t *element; in_port_t port; isc_dscp_t dscp; } *stack = NULL; REQUIRE(addrsp != NULL && *addrsp == NULL); REQUIRE(dscpsp != NULL && *dscpsp == NULL); REQUIRE(keysp != NULL && *keysp == NULL); REQUIRE(countp != NULL); /* * Get system defaults. */ result = ns_config_getport(config, &port); if (result != ISC_R_SUCCESS) goto cleanup; result = ns_config_getdscp(config, &dscp); if (result != ISC_R_SUCCESS) goto cleanup; newlist: addrlist = cfg_tuple_get(list, "addresses"); portobj = cfg_tuple_get(list, "port"); dscpobj = cfg_tuple_get(list, "dscp"); if (cfg_obj_isuint32(portobj)) { isc_uint32_t val = cfg_obj_asuint32(portobj); if (val > ISC_UINT16_MAX) { cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, "port '%u' out of range", val); result = ISC_R_RANGE; goto cleanup; } port = (in_port_t) val; } if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { if (cfg_obj_asuint32(dscpobj) > 63) { cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, "dscp value '%u' is out of range", cfg_obj_asuint32(dscpobj)); result = ISC_R_RANGE; goto cleanup; } dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); } result = ISC_R_NOMEMORY; element = cfg_list_first(addrlist); resume: for ( ; element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *addr; const cfg_obj_t *key; const char *keystr; isc_buffer_t b; addr = cfg_tuple_get(cfg_listelt_value(element), "masterselement"); key = cfg_tuple_get(cfg_listelt_value(element), "key"); if (!cfg_obj_issockaddr(addr)) { const char *listname = cfg_obj_asstring(addr); isc_result_t tresult; /* Grow lists? */ if (listcount == l) { void * tmp; isc_uint32_t newlen = listcount + 16; size_t newsize, oldsize; newsize = newlen * sizeof(*lists); oldsize = listcount * sizeof(*lists); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (listcount != 0) { memmove(tmp, lists, oldsize); isc_mem_put(mctx, lists, oldsize); } lists = tmp; listcount = newlen; } /* Seen? */ for (j = 0; j < l; j++) if (strcasecmp(lists[j].name, listname) == 0) break; if (j < l) continue; tresult = get_masters_def(config, listname, &list); if (tresult == ISC_R_NOTFOUND) { cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR, "masters \"%s\" not found", listname); result = tresult; goto cleanup; } if (tresult != ISC_R_SUCCESS) goto cleanup; lists[l++].name = listname; /* Grow stack? */ if (stackcount == pushed) { void * tmp; isc_uint32_t newlen = stackcount + 16; size_t newsize, oldsize; newsize = newlen * sizeof(*stack); oldsize = stackcount * sizeof(*stack); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (stackcount != 0) { memmove(tmp, stack, oldsize); isc_mem_put(mctx, stack, oldsize); } stack = tmp; stackcount = newlen; } /* * We want to resume processing this list on the * next element. */ stack[pushed].element = cfg_list_next(element); stack[pushed].port = port; stack[pushed].dscp = dscp; pushed++; goto newlist; } if (i == addrcount) { void * tmp; isc_uint32_t newlen = addrcount + 16; size_t newsize, oldsize; newsize = newlen * sizeof(isc_sockaddr_t); oldsize = addrcount * sizeof(isc_sockaddr_t); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (addrcount != 0) { memmove(tmp, addrs, oldsize); isc_mem_put(mctx, addrs, oldsize); } addrs = tmp; addrcount = newlen; newsize = newlen * sizeof(isc_dscp_t); oldsize = dscpcount * sizeof(isc_dscp_t); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (dscpcount != 0) { memmove(tmp, dscps, oldsize); isc_mem_put(mctx, dscps, oldsize); } dscps = tmp; dscpcount = newlen; newsize = newlen * sizeof(dns_name_t *); oldsize = keycount * sizeof(dns_name_t *); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (keycount != 0) { memmove(tmp, keys, oldsize); isc_mem_put(mctx, keys, oldsize); } keys = tmp; keycount = newlen; } addrs[i] = *cfg_obj_assockaddr(addr); if (isc_sockaddr_getport(&addrs[i]) == 0) isc_sockaddr_setport(&addrs[i], port); dscps[i] = cfg_obj_getdscp(addr); if (dscps[i] == -1) dscps[i] = dscp; keys[i] = NULL; i++; /* Increment here so that cleanup on error works. */ if (!cfg_obj_isstring(key)) continue; keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t)); if (keys[i - 1] == NULL) goto cleanup; dns_name_init(keys[i - 1], NULL); keystr = cfg_obj_asstring(key); isc_buffer_constinit(&b, keystr, strlen(keystr)); isc_buffer_add(&b, strlen(keystr)); dns_fixedname_init(&fname); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_name_dup(dns_fixedname_name(&fname), mctx, keys[i - 1]); if (result != ISC_R_SUCCESS) goto cleanup; } if (pushed != 0) { pushed--; element = stack[pushed].element; port = stack[pushed].port; dscp = stack[pushed].dscp; goto resume; } if (i < addrcount) { void * tmp; size_t newsize, oldsize; newsize = i * sizeof(isc_sockaddr_t); oldsize = addrcount * sizeof(isc_sockaddr_t); if (i != 0) { tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; memmove(tmp, addrs, newsize); } else tmp = NULL; isc_mem_put(mctx, addrs, oldsize); addrs = tmp; addrcount = i; newsize = i * sizeof(isc_dscp_t); oldsize = dscpcount * sizeof(isc_dscp_t); if (i != 0) { tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; memmove(tmp, dscps, newsize); } else tmp = NULL; isc_mem_put(mctx, dscps, oldsize); dscps = tmp; dscpcount = i; newsize = i * sizeof(dns_name_t *); oldsize = keycount * sizeof(dns_name_t *); if (i != 0) { tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; memmove(tmp, keys, newsize); } else tmp = NULL; isc_mem_put(mctx, keys, oldsize); keys = tmp; keycount = i; } if (lists != NULL) isc_mem_put(mctx, lists, listcount * sizeof(*lists)); if (stack != NULL) isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); INSIST(keycount == addrcount); *addrsp = addrs; *dscpsp = dscps; *keysp = keys; *countp = addrcount; return (ISC_R_SUCCESS); cleanup: if (addrs != NULL) isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t)); if (dscps != NULL) isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t)); if (keys != NULL) { for (j = 0; j < i; j++) { if (keys[j] == NULL) continue; if (dns_name_dynamic(keys[j])) dns_name_free(keys[j], mctx); isc_mem_put(mctx, keys[j], sizeof(dns_name_t)); } isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *)); } if (lists != NULL) isc_mem_put(mctx, lists, listcount * sizeof(*lists)); if (stack != NULL) isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); return (result); }
static isc_result_t configure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj, dns_rdataclass_t rdclass) { isc_mem_t *mctx = conf->mctx; const cfg_obj_t *keys = NULL; const cfg_obj_t *key, *keylist; dns_fixedname_t fkeyname; dns_name_t *keyname_base, *keyname; const cfg_listelt_t *element, *element2; isc_result_t result; isc_uint32_t flags, proto, alg; const char *keystr, *keynamestr; unsigned char keydata[4096]; isc_buffer_t keydatabuf_base, *keydatabuf; dns_rdata_dnskey_t keystruct; unsigned char rrdata[4096]; isc_buffer_t rrdatabuf; isc_region_t r; isc_buffer_t namebuf; irs_dnsconf_dnskey_t *keyent; cfg_map_get(cfgobj, "trusted-keys", &keys); if (keys == NULL) return (ISC_R_SUCCESS); for (element = cfg_list_first(keys); element != NULL; element = cfg_list_next(element)) { keylist = cfg_listelt_value(element); for (element2 = cfg_list_first(keylist); element2 != NULL; element2 = cfg_list_next(element2)) { keydatabuf = NULL; keyname = NULL; key = cfg_listelt_value(element2); flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); keystruct.common.rdclass = rdclass; keystruct.common.rdtype = dns_rdatatype_dnskey; keystruct.mctx = NULL; ISC_LINK_INIT(&keystruct.common, link); if (flags > 0xffff) return (ISC_R_RANGE); if (proto > 0xff) return (ISC_R_RANGE); if (alg > 0xff) return (ISC_R_RANGE); keystruct.flags = (isc_uint16_t)flags; keystruct.protocol = (isc_uint8_t)proto; keystruct.algorithm = (isc_uint8_t)alg; isc_buffer_init(&keydatabuf_base, keydata, sizeof(keydata)); isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); /* Configure key value */ keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); result = isc_base64_decodestring(keystr, &keydatabuf_base); if (result != ISC_R_SUCCESS) return (result); isc_buffer_usedregion(&keydatabuf_base, &r); keystruct.datalen = r.length; keystruct.data = r.base; result = dns_rdata_fromstruct(NULL, keystruct.common.rdclass, keystruct.common.rdtype, &keystruct, &rrdatabuf); if (result != ISC_R_SUCCESS) return (result); isc_buffer_usedregion(&rrdatabuf, &r); result = isc_buffer_allocate(mctx, &keydatabuf, r.length); if (result != ISC_R_SUCCESS) return (result); result = isc_buffer_copyregion(keydatabuf, &r); if (result != ISC_R_SUCCESS) goto cleanup; /* Configure key name */ dns_fixedname_init(&fkeyname); keyname_base = dns_fixedname_name(&fkeyname); isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr)); isc_buffer_add(&namebuf, strlen(keynamestr)); result = dns_name_fromtext(keyname_base, &namebuf, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) return (result); keyname = isc_mem_get(mctx, sizeof(*keyname)); if (keyname == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } dns_name_init(keyname, NULL); result = dns_name_dup(keyname_base, mctx, keyname); if (result != ISC_R_SUCCESS) goto cleanup; /* Add the key data to the list */ keyent = isc_mem_get(mctx, sizeof(*keyent)); if (keyent == NULL) { dns_name_free(keyname, mctx); result = ISC_R_NOMEMORY; goto cleanup; } keyent->keyname = keyname; keyent->keydatabuf = keydatabuf; ISC_LIST_APPEND(conf->trusted_keylist, keyent, link); } } return (ISC_R_SUCCESS); cleanup: if (keydatabuf != NULL) isc_buffer_free(&keydatabuf); if (keyname != NULL) isc_mem_put(mctx, keyname, sizeof(*keyname)); return (result); }