Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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);
}
Example #4
0
/*%
 * 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);
}
Example #5
0
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);
}
Example #6
0
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);
	}
}
Example #7
0
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);
}
Example #8
0
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));
}
Example #9
0
/*%
 * 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);
}
Example #11
0
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);
}
Example #12
0
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);
}
Example #13
0
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);
}
Example #14
0
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);
}
Example #15
0
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);
}
Example #16
0
/*
 * 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);
}
Example #17
0
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);
}
Example #18
0
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);
}