コード例 #1
0
ファイル: config.c プロジェクト: jaredmcneill/netbsd-src
isc_result_t
ns_config_getport(const cfg_obj_t *config, in_port_t *portp) {
	const cfg_obj_t *maps[3];
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *portobj = NULL;
	isc_result_t result;
	int i;

	(void)cfg_map_get(config, "options", &options);
	i = 0;
	if (options != NULL)
		maps[i++] = options;
	maps[i++] = ns_g_defaults;
	maps[i] = NULL;

	result = ns_config_get(maps, "port", &portobj);
	INSIST(result == ISC_R_SUCCESS);
	if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
		cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
			    "port '%u' out of range",
			    cfg_obj_asuint32(portobj));
		return (ISC_R_RANGE);
	}
	*portp = (in_port_t)cfg_obj_asuint32(portobj);
	return (ISC_R_SUCCESS);
}
コード例 #2
0
ファイル: config.c プロジェクト: jaredmcneill/netbsd-src
isc_result_t
ns_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) {
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *dscpobj = NULL;
	isc_result_t result;

	(void)cfg_map_get(config, "options", &options);
	if (options == NULL)
		return (ISC_R_SUCCESS);

	result = cfg_map_get(options, "dscp", &dscpobj);
	if (result != ISC_R_SUCCESS || dscpobj == NULL) {
		*dscpp = -1;
		return (ISC_R_SUCCESS);
	}
	if (cfg_obj_asuint32(dscpobj) >= 64) {
		cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
			    "dscp '%u' out of range",
			    cfg_obj_asuint32(dscpobj));
		return (ISC_R_RANGE);
	}
	*dscpp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
	return (ISC_R_SUCCESS);
}
コード例 #3
0
ファイル: lwresd.c プロジェクト: gosudream/netbsd-src
/*
 * Handle lwresd manager objects
 */
isc_result_t
ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres,
		     ns_lwresd_t **lwresdp)
{
	ns_lwresd_t *lwresd;
	const char *vname;
	dns_rdataclass_t vclass;
	const cfg_obj_t *obj, *viewobj, *searchobj;
	const cfg_listelt_t *element;
	isc_result_t result;

	INSIST(lwresdp != NULL && *lwresdp == NULL);

	lwresd = isc_mem_get(mctx, sizeof(ns_lwresd_t));
	if (lwresd == NULL)
		return (ISC_R_NOMEMORY);

	lwresd->mctx = NULL;
	isc_mem_attach(mctx, &lwresd->mctx);
	lwresd->view = NULL;
	lwresd->search = NULL;
	lwresd->refs = 1;

	obj = NULL;
	(void)cfg_map_get(lwres, "ndots", &obj);
	if (obj != NULL)
		lwresd->ndots = cfg_obj_asuint32(obj);
	else
		lwresd->ndots = 1;

	RUNTIME_CHECK(isc_mutex_init(&lwresd->lock) == ISC_R_SUCCESS);

	lwresd->shutting_down = ISC_FALSE;

	viewobj = NULL;
	(void)cfg_map_get(lwres, "view", &viewobj);
	if (viewobj != NULL) {
		vname = cfg_obj_asstring(cfg_tuple_get(viewobj, "name"));
		obj = cfg_tuple_get(viewobj, "class");
		result = ns_config_getclass(obj, dns_rdataclass_in, &vclass);
		if (result != ISC_R_SUCCESS)
			goto fail;
	} else {
		vname = "_default";
		vclass = dns_rdataclass_in;
	}

	result = dns_viewlist_find(&ns_g_server->viewlist, vname, vclass,
				   &lwresd->view);
	if (result != ISC_R_SUCCESS) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
			      "couldn't find view %s", vname);
		goto fail;
	}

	searchobj = NULL;
	(void)cfg_map_get(lwres, "search", &searchobj);
	if (searchobj != NULL) {
		lwresd->search = NULL;
		result = ns_lwsearchlist_create(lwresd->mctx,
						&lwresd->search);
		if (result != ISC_R_SUCCESS) {
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
				      "couldn't create searchlist");
			goto fail;
		}
		for (element = cfg_list_first(searchobj);
		     element != NULL;
		     element = cfg_list_next(element))
		{
			const cfg_obj_t *search;
			const char *searchstr;
			isc_buffer_t namebuf;
			dns_fixedname_t fname;
			dns_name_t *name;

			search = cfg_listelt_value(element);
			searchstr = cfg_obj_asstring(search);

			dns_fixedname_init(&fname);
			name = dns_fixedname_name(&fname);
			isc_buffer_init(&namebuf, searchstr,
					strlen(searchstr));
			isc_buffer_add(&namebuf, strlen(searchstr));
			result = dns_name_fromtext(name, &namebuf,
						   dns_rootname, 0, NULL);
			if (result != ISC_R_SUCCESS) {
				isc_log_write(ns_g_lctx,
					      NS_LOGCATEGORY_GENERAL,
					      NS_LOGMODULE_LWRESD,
					      ISC_LOG_WARNING,
					      "invalid name %s in searchlist",
					      searchstr);
				continue;
			}

			result = ns_lwsearchlist_append(lwresd->search, name);
			if (result != ISC_R_SUCCESS) {
				isc_log_write(ns_g_lctx,
					      NS_LOGCATEGORY_GENERAL,
					      NS_LOGMODULE_LWRESD,
					      ISC_LOG_WARNING,
					      "couldn't update searchlist");
				goto fail;
			}
		}
	}

	lwresd->magic = LWRESD_MAGIC;

	*lwresdp = lwresd;
	return (ISC_R_SUCCESS);

 fail:
	if (lwresd->view != NULL)
		dns_view_detach(&lwresd->view);
	if (lwresd->search != NULL)
		ns_lwsearchlist_detach(&lwresd->search);
	if (lwresd->mctx != NULL)
		isc_mem_detach(&lwresd->mctx);
	isc_mem_put(mctx, lwresd, sizeof(ns_lwresd_t));
	return (result);
}
コード例 #4
0
ファイル: controlconf.c プロジェクト: krichter722/bind9
static void
update_listener(ns_controls_t *cp, controllistener_t **listenerp,
		const cfg_obj_t *control, const cfg_obj_t *config,
		isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
		const char *socktext, isc_sockettype_t type)
{
	controllistener_t *listener;
	const cfg_obj_t *allow;
	const cfg_obj_t *global_keylist = NULL;
	const cfg_obj_t *control_keylist = NULL;
	dns_acl_t *new_acl = NULL;
	controlkeylist_t keys;
	isc_result_t result = ISC_R_SUCCESS;

	for (listener = ISC_LIST_HEAD(cp->listeners);
	     listener != NULL;
	     listener = ISC_LIST_NEXT(listener, link))
		if (isc_sockaddr_equal(addr, &listener->address))
			break;

	if (listener == NULL) {
		*listenerp = NULL;
		return;
	}

	/*
	 * There is already a listener for this sockaddr.
	 * Update the access list and key information.
	 *
	 * First try to deal with the key situation.  There are a few
	 * possibilities:
	 *  (a)	It had an explicit keylist and still has an explicit keylist.
	 *  (b)	It had an automagic key and now has an explicit keylist.
	 *  (c)	It had an explicit keylist and now needs an automagic key.
	 *  (d) It has an automagic key and still needs the automagic key.
	 *
	 * (c) and (d) are the annoying ones.  The caller needs to know
	 * that it should use the automagic configuration for key information
	 * in place of the named.conf configuration.
	 *
	 * XXXDCL There is one other hazard that has not been dealt with,
	 * the problem that if a key change is being caused by a control
	 * channel reload, then the response will be with the new key
	 * and not able to be decrypted by the client.
	 */
	if (control != NULL)
		get_key_info(config, control, &global_keylist,
			     &control_keylist);

	if (control_keylist != NULL) {
		INSIST(global_keylist != NULL);

		ISC_LIST_INIT(keys);
		result = controlkeylist_fromcfg(control_keylist,
						listener->mctx, &keys);
		if (result == ISC_R_SUCCESS) {
			free_controlkeylist(&listener->keys, listener->mctx);
			listener->keys = keys;
			register_keys(control, global_keylist, &listener->keys,
				      listener->mctx, socktext);
		}
	} else {
		free_controlkeylist(&listener->keys, listener->mctx);
		result = get_rndckey(listener->mctx, &listener->keys);
	}

	if (result != ISC_R_SUCCESS && global_keylist != NULL) {
		/*
		 * This message might be a little misleading since the
		 * "new keys" might in fact be identical to the old ones,
		 * but tracking whether they are identical just for the
		 * sake of avoiding this message would be too much trouble.
		 */
		if (control != NULL)
			cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
				    "couldn't install new keys for "
				    "command channel %s: %s",
				    socktext, isc_result_totext(result));
		else
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
				      "couldn't install new keys for "
				      "command channel %s: %s",
				      socktext, isc_result_totext(result));
	}

	/*
	 * Now, keep the old access list unless a new one can be made.
	 */
	if (control != NULL && type == isc_sockettype_tcp) {
		allow = cfg_tuple_get(control, "allow");
		result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
					    aclconfctx, listener->mctx, 0,
					    &new_acl);
	} else {
		result = dns_acl_any(listener->mctx, &new_acl);
	}

	if (result == ISC_R_SUCCESS) {
		dns_acl_detach(&listener->acl);
		dns_acl_attach(new_acl, &listener->acl);
		dns_acl_detach(&new_acl);
		/* XXXDCL say the old acl is still used? */
	} else if (control != NULL)
		cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
			    "couldn't install new acl for "
			    "command channel %s: %s",
			    socktext, isc_result_totext(result));
	else
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
			      "couldn't install new acl for "
			      "command channel %s: %s",
			      socktext, isc_result_totext(result));

	if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
		isc_uint32_t perm, owner, group;
		perm  = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
		owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
		group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
		result = ISC_R_SUCCESS;
		if (listener->perm != perm || listener->owner != owner ||
		    listener->group != group)
			result = isc_socket_permunix(&listener->address, perm,
						     owner, group);
		if (result == ISC_R_SUCCESS) {
			listener->perm = perm;
			listener->owner = owner;
			listener->group = group;
		} else if (control != NULL)
			cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
				    "couldn't update ownership/permission for "
				    "command channel %s", socktext);
	}

	*listenerp = listener;
}
コード例 #5
0
ファイル: controlconf.c プロジェクト: krichter722/bind9
static void
add_listener(ns_controls_t *cp, controllistener_t **listenerp,
	     const cfg_obj_t *control, const cfg_obj_t *config,
	     isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx,
	     const char *socktext, isc_sockettype_t type)
{
	isc_mem_t *mctx = cp->server->mctx;
	controllistener_t *listener;
	const cfg_obj_t *allow;
	const cfg_obj_t *global_keylist = NULL;
	const cfg_obj_t *control_keylist = NULL;
	dns_acl_t *new_acl = NULL;
	isc_result_t result = ISC_R_SUCCESS;

	listener = isc_mem_get(mctx, sizeof(*listener));
	if (listener == NULL)
		result = ISC_R_NOMEMORY;

	if (result == ISC_R_SUCCESS) {
		listener->mctx = NULL;
		isc_mem_attach(mctx, &listener->mctx);
		listener->controls = cp;
		listener->task = cp->server->task;
		listener->address = *addr;
		listener->sock = NULL;
		listener->listening = ISC_FALSE;
		listener->exiting = ISC_FALSE;
		listener->acl = NULL;
		listener->type = type;
		listener->perm = 0;
		listener->owner = 0;
		listener->group = 0;
		ISC_LINK_INIT(listener, link);
		ISC_LIST_INIT(listener->keys);
		ISC_LIST_INIT(listener->connections);

		/*
		 * Make the acl.
		 */
		if (control != NULL && type == isc_sockettype_tcp) {
			allow = cfg_tuple_get(control, "allow");
			result = cfg_acl_fromconfig(allow, config, ns_g_lctx,
						    aclconfctx, mctx, 0,
						    &new_acl);
		} else {
			result = dns_acl_any(mctx, &new_acl);
		}
	}

	if (result == ISC_R_SUCCESS) {
		dns_acl_attach(new_acl, &listener->acl);
		dns_acl_detach(&new_acl);

		if (config != NULL)
			get_key_info(config, control, &global_keylist,
				     &control_keylist);

		if (control_keylist != NULL) {
			result = controlkeylist_fromcfg(control_keylist,
							listener->mctx,
							&listener->keys);
			if (result == ISC_R_SUCCESS)
				register_keys(control, global_keylist,
					      &listener->keys,
					      listener->mctx, socktext);
		} else
			result = get_rndckey(mctx, &listener->keys);

		if (result != ISC_R_SUCCESS && control != NULL)
			cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
				    "couldn't install keys for "
				    "command channel %s: %s",
				    socktext, isc_result_totext(result));
	}

	if (result == ISC_R_SUCCESS) {
		int pf = isc_sockaddr_pf(&listener->address);
		if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
#ifdef ISC_PLATFORM_HAVESYSUNH
		    (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
#endif
		    (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
			result = ISC_R_FAMILYNOSUPPORT;
	}

	if (result == ISC_R_SUCCESS && type == isc_sockettype_unix)
		isc_socket_cleanunix(&listener->address, ISC_FALSE);

	if (result == ISC_R_SUCCESS)
		result = isc_socket_create(ns_g_socketmgr,
					   isc_sockaddr_pf(&listener->address),
					   type, &listener->sock);
	if (result == ISC_R_SUCCESS)
		isc_socket_setname(listener->sock, "control", NULL);

#ifndef ISC_ALLOW_MAPPED
	if (result == ISC_R_SUCCESS)
		isc_socket_ipv6only(listener->sock, ISC_TRUE);
#endif

	if (result == ISC_R_SUCCESS)
		result = isc_socket_bind(listener->sock, &listener->address,
					 ISC_SOCKET_REUSEADDRESS);

	if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) {
		listener->perm = cfg_obj_asuint32(cfg_tuple_get(control,
								"perm"));
		listener->owner = cfg_obj_asuint32(cfg_tuple_get(control,
								 "owner"));
		listener->group = cfg_obj_asuint32(cfg_tuple_get(control,
								 "group"));
		result = isc_socket_permunix(&listener->address, listener->perm,
					     listener->owner, listener->group);
	}
	if (result == ISC_R_SUCCESS)
		result = control_listen(listener);

	if (result == ISC_R_SUCCESS)
		result = control_accept(listener);

	if (result == ISC_R_SUCCESS) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
			      "command channel listening on %s", socktext);
		*listenerp = listener;

	} else {
		if (listener != NULL) {
			listener->exiting = ISC_TRUE;
			free_listener(listener);
		}

		if (control != NULL)
			cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
				    "couldn't add command channel %s: %s",
				    socktext, isc_result_totext(result));
		else
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
				      "couldn't add command channel %s: %s",
				      socktext, isc_result_totext(result));

		*listenerp = NULL;
	}

	/* XXXDCL return error results? fail hard? */
}
コード例 #6
0
ファイル: logconf.c プロジェクト: NZRS/bind9-collab
/*%
 * Set up a logging channel according to the named.conf data
 * in 'cchan' and add it to 'logconfig'.
 */
static isc_result_t
channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig)
{
	isc_result_t result;
	isc_logdestination_t dest;
	unsigned int type;
	unsigned int flags = 0;
	int level;
	const char *channelname;
	const cfg_obj_t *fileobj = NULL;
	const cfg_obj_t *syslogobj = NULL;
	const cfg_obj_t *nullobj = NULL;
	const cfg_obj_t *stderrobj = NULL;
	const cfg_obj_t *severity = NULL;
	int i;

	channelname = cfg_obj_asstring(cfg_map_getname(channel));

	(void)cfg_map_get(channel, "file", &fileobj);
	(void)cfg_map_get(channel, "syslog", &syslogobj);
	(void)cfg_map_get(channel, "null", &nullobj);
	(void)cfg_map_get(channel, "stderr", &stderrobj);

	i = 0;
	if (fileobj != NULL)
		i++;
	if (syslogobj != NULL)
		i++;
	if (nullobj != NULL)
		i++;
	if (stderrobj != NULL)
		i++;

	if (i != 1) {
		cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
			      "channel '%s': exactly one of file, syslog, "
			      "null, and stderr must be present", channelname);
		return (ISC_R_FAILURE);
	}

	type = ISC_LOG_TONULL;

	if (fileobj != NULL) {
		const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
		const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
		const cfg_obj_t *versionsobj =
				 cfg_tuple_get(fileobj, "versions");
		isc_int32_t versions = ISC_LOG_ROLLNEVER;
		isc_offset_t size = 0;

		type = ISC_LOG_TOFILE;

		if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
			versions = cfg_obj_asuint32(versionsobj);
		if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
		    strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
			versions = ISC_LOG_ROLLINFINITE;
		if (sizeobj != NULL &&
		    cfg_obj_isuint64(sizeobj) &&
		    cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
			size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
		dest.file.stream = NULL;
		dest.file.name = cfg_obj_asstring(pathobj);
		dest.file.versions = versions;
		dest.file.maximum_size = size;
	} else if (syslogobj != NULL) {
		int facility = LOG_DAEMON;

		type = ISC_LOG_TOSYSLOG;

		if (cfg_obj_isstring(syslogobj)) {
			const char *facilitystr = cfg_obj_asstring(syslogobj);
			(void)isc_syslog_facilityfromstring(facilitystr,
							    &facility);
		}
		dest.facility = facility;
	} else if (stderrobj != NULL) {
		type = ISC_LOG_TOFILEDESC;
		dest.file.stream = stderr;
		dest.file.name = NULL;
		dest.file.versions = ISC_LOG_ROLLNEVER;
		dest.file.maximum_size = 0;
	}

	/*
	 * Munge flags.
	 */
	{
		const cfg_obj_t *printcat = NULL;
		const cfg_obj_t *printsev = NULL;
		const cfg_obj_t *printtime = NULL;
		const cfg_obj_t *buffered = NULL;

		(void)cfg_map_get(channel, "print-category", &printcat);
		(void)cfg_map_get(channel, "print-severity", &printsev);
		(void)cfg_map_get(channel, "print-time", &printtime);
		(void)cfg_map_get(channel, "buffered", &buffered);

		if (printcat != NULL && cfg_obj_asboolean(printcat))
			flags |= ISC_LOG_PRINTCATEGORY;
		if (printtime != NULL && cfg_obj_asboolean(printtime))
			flags |= ISC_LOG_PRINTTIME;
		if (printsev != NULL && cfg_obj_asboolean(printsev))
			flags |= ISC_LOG_PRINTLEVEL;
		if (buffered != NULL && cfg_obj_asboolean(buffered))
			flags |= ISC_LOG_BUFFERED;
	}

	level = ISC_LOG_INFO;
	if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
		if (cfg_obj_isstring(severity)) {
			const char *str = cfg_obj_asstring(severity);
			if (strcasecmp(str, "critical") == 0)
				level = ISC_LOG_CRITICAL;
			else if (strcasecmp(str, "error") == 0)
				level = ISC_LOG_ERROR;
			else if (strcasecmp(str, "warning") == 0)
				level = ISC_LOG_WARNING;
			else if (strcasecmp(str, "notice") == 0)
				level = ISC_LOG_NOTICE;
			else if (strcasecmp(str, "info") == 0)
				level = ISC_LOG_INFO;
			else if (strcasecmp(str, "dynamic") == 0)
				level = ISC_LOG_DYNAMIC;
		} else
			/* debug */
			level = cfg_obj_asuint32(severity);
	}

	if (logconfig == NULL)
		result = ISC_R_SUCCESS;
	else
		result = isc_log_createchannel(logconfig, channelname,
					       type, level, &dest, flags);

	if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
		FILE *fp;

		/*
		 * Test to make sure that file is a plain file.
		 * Fix defect #22771
		*/
		result = isc_file_isplainfile(dest.file.name);
		if (result == ISC_R_SUCCESS || result == ISC_R_FILENOTFOUND) {
			/*
			 * Test that the file can be opened, since
			 * isc_log_open() can't effectively report
			 * failures when called in isc_log_doit().
			 */
			result = isc_stdio_open(dest.file.name, "a", &fp);
			if (result != ISC_R_SUCCESS) {
				if (logconfig != NULL && !ns_g_nosyslog)
					syslog(LOG_ERR,
						"isc_stdio_open '%s' failed: "
						"%s", dest.file.name,
						isc_result_totext(result));
				fprintf(stderr,
					"isc_stdio_open '%s' failed: %s\n",
					dest.file.name,
					isc_result_totext(result));
			} else
				(void)isc_stdio_close(fp);
			goto done;
		}
		if (logconfig != NULL && !ns_g_nosyslog)
			syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s",
			       dest.file.name, isc_result_totext(result));
		fprintf(stderr, "isc_file_isplainfile '%s' failed: %s\n",
			dest.file.name, isc_result_totext(result));
	}

 done:
	return (result);
}
コード例 #7
0
ファイル: named-checkconf.c プロジェクト: NZRS/bind9-collab
/*% configure the zone */
static isc_result_t
configure_zone(const char *vclass, const char *view,
	       const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
	       const cfg_obj_t *config, isc_mem_t *mctx)
{
	int i = 0;
	isc_result_t result;
	const char *zclass;
	const char *zname;
	const char *zfile = NULL;
	const cfg_obj_t *maps[4];
	const cfg_obj_t *mastersobj = NULL;
	const cfg_obj_t *inviewobj = NULL;
	const cfg_obj_t *zoptions = NULL;
	const cfg_obj_t *classobj = NULL;
	const cfg_obj_t *typeobj = NULL;
	const cfg_obj_t *fileobj = NULL;
	const cfg_obj_t *dlzobj = NULL;
	const cfg_obj_t *dbobj = NULL;
	const cfg_obj_t *obj = NULL;
	const cfg_obj_t *fmtobj = NULL;
	dns_masterformat_t masterformat;
	dns_ttl_t maxttl = 0;

	zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;

	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
	classobj = cfg_tuple_get(zconfig, "class");
	if (!cfg_obj_isstring(classobj))
		zclass = vclass;
	else
		zclass = cfg_obj_asstring(classobj);

	zoptions = cfg_tuple_get(zconfig, "options");
	maps[i++] = zoptions;
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
		cfg_map_get(config, "options", &obj);
		if (obj != NULL)
			maps[i++] = obj;
	}
	maps[i] = NULL;

	cfg_map_get(zoptions, "in-view", &inviewobj);
	if (inviewobj != NULL)
		return (ISC_R_SUCCESS);

	cfg_map_get(zoptions, "type", &typeobj);
	if (typeobj == NULL)
		return (ISC_R_FAILURE);

	/*
	 * Skip checks when using an alternate data source.
	 */
	cfg_map_get(zoptions, "database", &dbobj);
	if (dbobj != NULL &&
	    strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 &&
	    strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0)
		return (ISC_R_SUCCESS);

	cfg_map_get(zoptions, "dlz", &dlzobj);
	if (dlzobj != NULL)
		return (ISC_R_SUCCESS);

	cfg_map_get(zoptions, "file", &fileobj);
	if (fileobj != NULL)
		zfile = cfg_obj_asstring(fileobj);

	/*
	 * Check hints files for hint zones.
	 * Skip loading checks for any type other than
	 * master and redirect
	 */
	if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0)
		return (configure_hint(zfile, zclass, mctx));
	else if ((strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
		  (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
		return (ISC_R_SUCCESS);

	/*
	 * Is the redirect zone configured as a slave?
	 */
	if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) {
		cfg_map_get(zoptions, "masters", &mastersobj);
		if (mastersobj != NULL)
			return (ISC_R_SUCCESS);
	}

	if (zfile == NULL)
		return (ISC_R_FAILURE);

	obj = NULL;
	if (get_maps(maps, "check-dup-records", &obj)) {
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
			zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
		} else
			INSIST(0);
	} else {
		zone_options |= DNS_ZONEOPT_CHECKDUPRR;
		zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
	}

	obj = NULL;
	if (get_maps(maps, "check-mx", &obj)) {
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKMX;
			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKMX;
			zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			zone_options &= ~DNS_ZONEOPT_CHECKMX;
			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
		} else
			INSIST(0);
	} else {
		zone_options |= DNS_ZONEOPT_CHECKMX;
		zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
	}

	obj = NULL;
	if (get_maps(maps, "check-integrity", &obj)) {
		if (cfg_obj_asboolean(obj))
			zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
		else
			zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
	} else
		zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;

	obj = NULL;
	if (get_maps(maps, "check-mx-cname", &obj)) {
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
			zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
		} else
			INSIST(0);
	} else {
		zone_options |= DNS_ZONEOPT_WARNMXCNAME;
		zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
	}

	obj = NULL;
	if (get_maps(maps, "check-srv-cname", &obj)) {
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
			zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
		} else
			INSIST(0);
	} else {
		zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
		zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
	}

	obj = NULL;
	if (get_maps(maps, "check-sibling", &obj)) {
		if (cfg_obj_asboolean(obj))
			zone_options |= DNS_ZONEOPT_CHECKSIBLING;
		else
			zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
	}

	obj = NULL;
	if (get_maps(maps, "check-spf", &obj)) {
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKSPF;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			zone_options &= ~DNS_ZONEOPT_CHECKSPF;
		} else
			INSIST(0);
	} else {
		zone_options |= DNS_ZONEOPT_CHECKSPF;
	}

	obj = NULL;
	if (get_checknames(maps, &obj)) {
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKNAMES;
			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			zone_options |= DNS_ZONEOPT_CHECKNAMES;
			zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
		} else
			INSIST(0);
	} else {
	       zone_options |= DNS_ZONEOPT_CHECKNAMES;
	       zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
	}

	masterformat = dns_masterformat_text;
	fmtobj = NULL;
	if (get_maps(maps, "masterfile-format", &fmtobj)) {
		const char *masterformatstr = cfg_obj_asstring(fmtobj);
		if (strcasecmp(masterformatstr, "text") == 0)
			masterformat = dns_masterformat_text;
		else if (strcasecmp(masterformatstr, "raw") == 0)
			masterformat = dns_masterformat_raw;
		else if (strcasecmp(masterformatstr, "map") == 0)
			masterformat = dns_masterformat_map;
		else
			INSIST(0);
	}

	obj = NULL;
	if (get_maps(maps, "max-zone-ttl", &obj)) {
		maxttl = cfg_obj_asuint32(obj);
		zone_options2 |= DNS_ZONEOPT2_CHECKTTL;
	}

	result = load_zone(mctx, zname, zfile, masterformat,
			   zclass, maxttl, NULL);
	if (result != ISC_R_SUCCESS)
		fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
			dns_result_totext(result));
	return (result);
}
コード例 #8
0
ファイル: tkeyconf.c プロジェクト: jhbsz/netbsd
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);
}
コード例 #9
0
static void
parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
	     cfg_parser_t **pctxp, cfg_obj_t **configp)
{
	isc_result_t result;
	const char *conffile = admin_conffile;
	cfg_obj_t *defkey = NULL;
	cfg_obj_t *options = NULL;
	cfg_obj_t *servers = NULL;
	cfg_obj_t *server = NULL;
	cfg_obj_t *keys = NULL;
	cfg_obj_t *key = NULL;
	cfg_obj_t *defport = NULL;
	cfg_obj_t *secretobj = NULL;
	cfg_obj_t *algorithmobj = NULL;
	cfg_obj_t *config = NULL;
	cfg_listelt_t *elt;
	const char *secretstr;
	const char *algorithm;
	static char secretarray[1024];
	const cfg_type_t *conftype = &cfg_type_rndcconf;
	isc_boolean_t key_only = ISC_FALSE;

	if (! isc_file_exists(conffile)) {
		conffile = admin_keyfile;
		conftype = &cfg_type_rndckey;

		if (! isc_file_exists(conffile))
			fatal("neither %s nor %s was found",
			      admin_conffile, admin_keyfile);
		key_only = ISC_TRUE;
	}

	DO("create parser", cfg_parser_create(mctx, log, pctxp));

	/*
	 * The parser will output its own errors, so DO() is not used.
	 */
	result = cfg_parse_file(*pctxp, conffile, conftype, &config);
	if (result != ISC_R_SUCCESS)
		fatal("could not load rndc configuration");

	if (!key_only)
		(void)cfg_map_get(config, "options", &options);

	if (key_only && servername == NULL)
		servername = "127.0.0.1";
	else if (servername == NULL && options != NULL) {
		cfg_obj_t *defserverobj = NULL;
		(void)cfg_map_get(options, "default-server", &defserverobj);
		if (defserverobj != NULL)
			servername = cfg_obj_asstring(defserverobj);
	}

	if (servername == NULL)
		fatal("no server specified and no default");

	if (!key_only) {
		(void)cfg_map_get(config, "server", &servers);
		if (servers != NULL) {
			for (elt = cfg_list_first(servers);
			     elt != NULL; 
			     elt = cfg_list_next(elt))
			{
				const char *name;
				server = cfg_listelt_value(elt);
				name = cfg_obj_asstring(cfg_map_getname(server));
				if (strcasecmp(name, servername) == 0)
					break;
				server = NULL;
			}
		}
	}

	/*
	 * Look for the name of the key to use.
	 */
	if (keyname != NULL)
		;		/* Was set on command line, do nothing. */
	else if (server != NULL) {
		DO("get key for server", cfg_map_get(server, "key", &defkey));
		keyname = cfg_obj_asstring(defkey);
	} else if (options != NULL) {
		DO("get default key", cfg_map_get(options, "default-key",
						  &defkey));
		keyname = cfg_obj_asstring(defkey);
	} else if (!key_only)
		fatal("no key for server and no default");

	/*
	 * Get the key's definition.
	 */
	if (key_only)
		DO("get key", cfg_map_get(config, "key", &key));
	else {
		DO("get config key list", cfg_map_get(config, "key", &keys));
		for (elt = cfg_list_first(keys);
		     elt != NULL; 
		     elt = cfg_list_next(elt))
		{
			key = cfg_listelt_value(elt);
			if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
				       keyname) == 0)
				break;
		}
		if (elt == NULL)
			fatal("no key definition for name %s", keyname);
	}
	(void)cfg_map_get(key, "secret", &secretobj);
	(void)cfg_map_get(key, "algorithm", &algorithmobj);
	if (secretobj == NULL || algorithmobj == NULL)
		fatal("key must have algorithm and secret");

	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

	if (strcasecmp(algorithm, "hmac-md5") != 0)
		fatal("unsupported algorithm: %s", algorithm);

	secret.rstart = (unsigned char *)secretarray;
	secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
	DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
	secret.rend = secret.rstart;
	secret.rstart = (unsigned char *)secretarray;

	/*
	 * Find the port to connect to.
	 */
	if (remoteport != 0)
		;		/* Was set on command line, do nothing. */
	else {
		if (server != NULL)
			(void)cfg_map_get(server, "port", &defport);
		if (defport == NULL && options != NULL)
			(void)cfg_map_get(options, "default-port", &defport);
	}
	if (defport != NULL) {
		remoteport = cfg_obj_asuint32(defport);
		if (remoteport > 65535 || remoteport == 0)
			fatal("port %d out of range", remoteport);
	} else if (remoteport == 0)
		remoteport = NS_CONTROL_PORT;

	*configp = config;
}
コード例 #10
0
ファイル: rndc.c プロジェクト: OPSF/uClinux
static void
parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
	     cfg_parser_t **pctxp, cfg_obj_t **configp)
{
	isc_result_t result;
	const char *conffile = admin_conffile;
	const cfg_obj_t *addresses = NULL;
	const cfg_obj_t *defkey = NULL;
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *servers = NULL;
	const cfg_obj_t *server = NULL;
	const cfg_obj_t *keys = NULL;
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *defport = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
	cfg_obj_t *config = NULL;
	const cfg_obj_t *address = NULL;
	const cfg_listelt_t *elt;
	const char *secretstr;
	const char *algorithm;
	static char secretarray[1024];
	const cfg_type_t *conftype = &cfg_type_rndcconf;
	isc_boolean_t key_only = ISC_FALSE;
	const cfg_listelt_t *element;

	if (! isc_file_exists(conffile)) {
		conffile = admin_keyfile;
		conftype = &cfg_type_rndckey;

		if (! isc_file_exists(conffile))
			fatal("neither %s nor %s was found",
			      admin_conffile, admin_keyfile);
		key_only = ISC_TRUE;
	}

	DO("create parser", cfg_parser_create(mctx, log, pctxp));

	/*
	 * The parser will output its own errors, so DO() is not used.
	 */
	result = cfg_parse_file(*pctxp, conffile, conftype, &config);
	if (result != ISC_R_SUCCESS)
		fatal("could not load rndc configuration");

	if (!key_only)
		(void)cfg_map_get(config, "options", &options);

	if (key_only && servername == NULL)
		servername = "127.0.0.1";
	else if (servername == NULL && options != NULL) {
		const cfg_obj_t *defserverobj = NULL;
		(void)cfg_map_get(options, "default-server", &defserverobj);
		if (defserverobj != NULL)
			servername = cfg_obj_asstring(defserverobj);
	}

	if (servername == NULL)
		fatal("no server specified and no default");

	if (!key_only) {
		(void)cfg_map_get(config, "server", &servers);
		if (servers != NULL) {
			for (elt = cfg_list_first(servers);
			     elt != NULL; 
			     elt = cfg_list_next(elt))
			{
				const char *name;
				server = cfg_listelt_value(elt);
				name = cfg_obj_asstring(cfg_map_getname(server));
				if (strcasecmp(name, servername) == 0)
					break;
				server = NULL;
			}
		}
	}

	/*
	 * Look for the name of the key to use.
	 */
	if (keyname != NULL)
		;		/* Was set on command line, do nothing. */
	else if (server != NULL) {
		DO("get key for server", cfg_map_get(server, "key", &defkey));
		keyname = cfg_obj_asstring(defkey);
	} else if (options != NULL) {
		DO("get default key", cfg_map_get(options, "default-key",
						  &defkey));
		keyname = cfg_obj_asstring(defkey);
	} else if (!key_only)
		fatal("no key for server and no default");

	/*
	 * Get the key's definition.
	 */
	if (key_only)
		DO("get key", cfg_map_get(config, "key", &key));
	else {
		DO("get config key list", cfg_map_get(config, "key", &keys));
		for (elt = cfg_list_first(keys);
		     elt != NULL; 
		     elt = cfg_list_next(elt))
		{
			key = cfg_listelt_value(elt);
			if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
				       keyname) == 0)
				break;
		}
		if (elt == NULL)
			fatal("no key definition for name %s", keyname);
	}
	(void)cfg_map_get(key, "secret", &secretobj);
	(void)cfg_map_get(key, "algorithm", &algorithmobj);
	if (secretobj == NULL || algorithmobj == NULL)
		fatal("key must have algorithm and secret");

	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

	if (strcasecmp(algorithm, "hmac-md5") != 0)
		fatal("unsupported algorithm: %s", algorithm);

	secret.rstart = (unsigned char *)secretarray;
	secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
	DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
	secret.rend = secret.rstart;
	secret.rstart = (unsigned char *)secretarray;

	/*
	 * Find the port to connect to.
	 */
	if (remoteport != 0)
		;		/* Was set on command line, do nothing. */
	else {
		if (server != NULL)
			(void)cfg_map_get(server, "port", &defport);
		if (defport == NULL && options != NULL)
			(void)cfg_map_get(options, "default-port", &defport);
	}
	if (defport != NULL) {
		remoteport = cfg_obj_asuint32(defport);
		if (remoteport > 65535 || remoteport == 0)
			fatal("port %u out of range", remoteport);
	} else if (remoteport == 0)
		remoteport = NS_CONTROL_PORT;

	if (server != NULL)
		result = cfg_map_get(server, "addresses", &addresses);
	else
		result = ISC_R_NOTFOUND;
	if (result == ISC_R_SUCCESS) {
		for (element = cfg_list_first(addresses);
		     element != NULL;
		     element = cfg_list_next(element))
		{
			isc_sockaddr_t sa;

			address = cfg_listelt_value(element);
			if (!cfg_obj_issockaddr(address)) {
				unsigned int myport;
				const char *name;
				const cfg_obj_t *obj;

				obj = cfg_tuple_get(address, "name");
				name = cfg_obj_asstring(obj);
				obj = cfg_tuple_get(address, "port");
				if (cfg_obj_isuint32(obj)) {
					myport = cfg_obj_asuint32(obj);
					if (myport > ISC_UINT16_MAX ||
					    myport == 0)
						fatal("port %u out of range",
						      myport);
				} else
					myport = remoteport;
				if (nserveraddrs < SERVERADDRS)
					get_addresses(name, (in_port_t) myport);
				else
					fprintf(stderr, "too many address: "
					        "%s: dropped\n", name);
				continue;
			}
			sa = *cfg_obj_assockaddr(address);
			if (isc_sockaddr_getport(&sa) == 0)
				isc_sockaddr_setport(&sa, remoteport);
			if (nserveraddrs < SERVERADDRS)
				serveraddrs[nserveraddrs++] = sa;
			else {
				char socktext[ISC_SOCKADDR_FORMATSIZE];

				isc_sockaddr_format(&sa, socktext,
						    sizeof(socktext));
				fprintf(stderr,
					"too many address: %s: dropped\n",
					socktext);
			}
		}
	}

	if (!local4set && server != NULL) {
		address = NULL;
		cfg_map_get(server, "source-address", &address);
		if (address != NULL) {
			local4 = *cfg_obj_assockaddr(address);
			local4set = ISC_TRUE;
		}
	}
	if (!local4set && options != NULL) {
		address = NULL;
		cfg_map_get(options, "default-source-address", &address);
		if (address != NULL) {
			local4 = *cfg_obj_assockaddr(address);
			local4set = ISC_TRUE;
		}
	}

	if (!local6set && server != NULL) {
		address = NULL;
		cfg_map_get(server, "source-address-v6", &address);
		if (address != NULL) {
			local6 = *cfg_obj_assockaddr(address);
			local6set = ISC_TRUE;
		}
	}
	if (!local6set && options != NULL) {
		address = NULL;
		cfg_map_get(options, "default-source-address-v6", &address);
		if (address != NULL) {
			local6 = *cfg_obj_assockaddr(address);
			local6set = ISC_TRUE;
		}
	}

	*configp = config;
}
コード例 #11
0
ファイル: zoneconf.c プロジェクト: ElRevo/xia-core
isc_result_t
ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
		  const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
		  dns_zone_t *zone)
{
	isc_result_t result;
	const char *zname;
	dns_rdataclass_t zclass;
	dns_rdataclass_t vclass;
	const cfg_obj_t *maps[5];
	const cfg_obj_t *zoptions = NULL;
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *obj;
	const char *filename = NULL;
	dns_notifytype_t notifytype = dns_notifytype_yes;
	isc_sockaddr_t *addrs;
	dns_name_t **keynames;
	isc_uint32_t count;
	char *cpval;
	unsigned int dbargc;
	char **dbargv;
	static char default_dbtype[] = "rbt";
	isc_mem_t *mctx = dns_zone_getmctx(zone);
	dns_dialuptype_t dialup = dns_dialuptype_no;
	dns_zonetype_t ztype;
	int i;
	isc_int32_t journal_size;
	isc_boolean_t multi;
	isc_boolean_t alt;
	dns_view_t *view;
	isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE;
	isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE;
	isc_boolean_t ixfrdiff;
	dns_masterformat_t masterformat;
	isc_stats_t *zoneqrystats;
	isc_boolean_t zonestats_on;
	int seconds;

	i = 0;
	if (zconfig != NULL) {
		zoptions = cfg_tuple_get(zconfig, "options");
		maps[i++] = zoptions;
	}
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i++] = ns_g_defaults;
	maps[i] = NULL;

	if (vconfig != NULL)
		RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
					  dns_rdataclass_in, &vclass));
	else
		vclass = dns_rdataclass_in;

	/*
	 * Configure values common to all zone types.
	 */

	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));

	RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
				  vclass, &zclass));
	dns_zone_setclass(zone, zclass);

	ztype = zonetype_fromconfig(zoptions);
	dns_zone_settype(zone, ztype);

	obj = NULL;
	result = cfg_map_get(zoptions, "database", &obj);
	if (result == ISC_R_SUCCESS)
		cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
	else
		cpval = default_dbtype;

	if (cpval == NULL)
		return(ISC_R_NOMEMORY);

	result = strtoargv(mctx, cpval, &dbargc, &dbargv);
	if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
		isc_mem_free(mctx, cpval);
		return (result);
	}

	/*
	 * ANSI C is strange here.  There is no logical reason why (char **)
	 * cannot be promoted automatically to (const char * const *) by the
	 * compiler w/o generating a warning.
	 */
	result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv);
	isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
	if (cpval != default_dbtype)
		isc_mem_free(mctx, cpval);
	if (result != ISC_R_SUCCESS)
		return (result);

	obj = NULL;
	result = cfg_map_get(zoptions, "file", &obj);
	if (result == ISC_R_SUCCESS)
		filename = cfg_obj_asstring(obj);

	/*
	 * Unless we're using some alternative database, a master zone
	 * will be needing a master file.
	 */
	if (ztype == dns_zone_master && cpval == default_dbtype &&
	    filename == NULL) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
			      "zone '%s': 'file' not specified",
			      zname);
		return (ISC_R_FAILURE);
	}

	masterformat = dns_masterformat_text;
	obj = NULL;
	result= ns_config_get(maps, "masterfile-format", &obj);
	if (result == ISC_R_SUCCESS) {
		const char *masterformatstr = cfg_obj_asstring(obj);

		if (strcasecmp(masterformatstr, "text") == 0)
			masterformat = dns_masterformat_text;
		else if (strcasecmp(masterformatstr, "raw") == 0)
			masterformat = dns_masterformat_raw;
		else
			INSIST(0);
	}
	RETERR(dns_zone_setfile2(zone, filename, masterformat));

	obj = NULL;
	result = cfg_map_get(zoptions, "journal", &obj);
	if (result == ISC_R_SUCCESS)
		RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj)));

	if (ztype == dns_zone_slave)
		RETERR(configure_zone_acl(zconfig, vconfig, config,
					  allow_notify, ac, zone,
					  dns_zone_setnotifyacl,
					  dns_zone_clearnotifyacl));
	/*
	 * XXXAG This probably does not make sense for stubs.
	 */
	RETERR(configure_zone_acl(zconfig, vconfig, config,
				  allow_query, ac, zone,
				  dns_zone_setqueryacl,
				  dns_zone_clearqueryacl));

	obj = NULL;
	result = ns_config_get(maps, "dialup", &obj);
	INSIST(result == ISC_R_SUCCESS && obj != NULL);
	if (cfg_obj_isboolean(obj)) {
		if (cfg_obj_asboolean(obj))
			dialup = dns_dialuptype_yes;
		else
			dialup = dns_dialuptype_no;
	} else {
		const char *dialupstr = cfg_obj_asstring(obj);
		if (strcasecmp(dialupstr, "notify") == 0)
			dialup = dns_dialuptype_notify;
		else if (strcasecmp(dialupstr, "notify-passive") == 0)
			dialup = dns_dialuptype_notifypassive;
		else if (strcasecmp(dialupstr, "refresh") == 0)
			dialup = dns_dialuptype_refresh;
		else if (strcasecmp(dialupstr, "passive") == 0)
			dialup = dns_dialuptype_passive;
		else
			INSIST(0);
	}
	dns_zone_setdialup(zone, dialup);

	obj = NULL;
	result = ns_config_get(maps, "zone-statistics", &obj);
	INSIST(result == ISC_R_SUCCESS && obj != NULL);
	zonestats_on = cfg_obj_asboolean(obj);
	zoneqrystats = NULL;
	if (zonestats_on) {
		RETERR(isc_stats_create(mctx, &zoneqrystats,
					dns_nsstatscounter_max));
	}
	dns_zone_setrequeststats(zone, zoneqrystats);
	if (zoneqrystats != NULL)
		isc_stats_detach(&zoneqrystats);

	/*
	 * Configure master functionality.  This applies
	 * to primary masters (type "master") and slaves
	 * acting as masters (type "slave"), but not to stubs.
	 */
	if (ztype != dns_zone_stub && ztype != dns_zone_staticstub) {
		obj = NULL;
		result = ns_config_get(maps, "notify", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		if (cfg_obj_isboolean(obj)) {
			if (cfg_obj_asboolean(obj))
				notifytype = dns_notifytype_yes;
			else
				notifytype = dns_notifytype_no;
		} else {
			const char *notifystr = cfg_obj_asstring(obj);
			if (strcasecmp(notifystr, "explicit") == 0)
				notifytype = dns_notifytype_explicit;
			else if (strcasecmp(notifystr, "master-only") == 0)
				notifytype = dns_notifytype_masteronly;
			else
				INSIST(0);
		}
		dns_zone_setnotifytype(zone, notifytype);

		obj = NULL;
		result = ns_config_get(maps, "also-notify", &obj);
		if (result == ISC_R_SUCCESS) {
			isc_sockaddr_t *addrs = NULL;
			isc_uint32_t addrcount;
			result = ns_config_getiplist(config, obj, 0, mctx,
						     &addrs, &addrcount);
			if (result != ISC_R_SUCCESS)
				return (result);
			result = dns_zone_setalsonotify(zone, addrs,
							addrcount);
			ns_config_putiplist(mctx, &addrs, addrcount);
			if (result != ISC_R_SUCCESS)
				return (result);
		} else
			RETERR(dns_zone_setalsonotify(zone, NULL, 0));

		obj = NULL;
		result = ns_config_get(maps, "notify-source", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));

		obj = NULL;
		result = ns_config_get(maps, "notify-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));

		obj = NULL;
		result = ns_config_get(maps, "notify-to-soa", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
				   cfg_obj_asboolean(obj));

		dns_zone_setisself(zone, ns_client_isself, NULL);

		RETERR(configure_zone_acl(zconfig, vconfig, config,
					  allow_transfer, ac, zone,
					  dns_zone_setxfracl,
					  dns_zone_clearxfracl));

		obj = NULL;
		result = ns_config_get(maps, "max-transfer-time-out", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);

		obj = NULL;
		result = ns_config_get(maps, "max-transfer-idle-out", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);

		obj = NULL;
		result =  ns_config_get(maps, "max-journal-size", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setjournalsize(zone, -1);
		if (cfg_obj_isstring(obj)) {
			const char *str = cfg_obj_asstring(obj);
			INSIST(strcasecmp(str, "unlimited") == 0);
			journal_size = ISC_UINT32_MAX / 2;
		} else {
			isc_resourcevalue_t value;
			value = cfg_obj_asuint64(obj);
			if (value > ISC_UINT32_MAX / 2) {
				cfg_obj_log(obj, ns_g_lctx,
					    ISC_LOG_ERROR,
					    "'max-journal-size "
					    "%" ISC_PRINT_QUADFORMAT "d' "
					    "is too large",
					    value);
				RETERR(ISC_R_RANGE);
			}
			journal_size = (isc_uint32_t)value;
		}
		dns_zone_setjournalsize(zone, journal_size);

		obj = NULL;
		result = ns_config_get(maps, "ixfr-from-differences", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		if (cfg_obj_isboolean(obj))
			ixfrdiff = cfg_obj_asboolean(obj);
		else if (!strcasecmp(cfg_obj_asstring(obj), "master") &&
			 ztype == dns_zone_master)
			ixfrdiff = ISC_TRUE;
		else if (!strcasecmp(cfg_obj_asstring(obj), "slave") &&
			ztype == dns_zone_slave)
			ixfrdiff = ISC_TRUE;
		else
			ixfrdiff = ISC_FALSE;
		dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff);

		checknames(ztype, maps, &obj);
		INSIST(obj != NULL);
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			fail = ISC_FALSE;
			check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			fail = check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			fail = check = ISC_FALSE;
		} else
			INSIST(0);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail);

		obj = NULL;
		result = ns_config_get(maps, "notify-delay", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "check-sibling", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
				   cfg_obj_asboolean(obj));

		obj = NULL;
		result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));

		obj = NULL;
		result = ns_config_get(maps, "nsec3-test-zone", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
				   cfg_obj_asboolean(obj));
	}

	/*
	 * Configure update-related options.  These apply to
	 * primary masters only.
	 */
	if (ztype == dns_zone_master) {
		dns_acl_t *updateacl;

		RETERR(configure_zone_acl(zconfig, vconfig, config,
					  allow_update, ac, zone,
					  dns_zone_setupdateacl,
					  dns_zone_clearupdateacl));

		updateacl = dns_zone_getupdateacl(zone);
		if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
			isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
				      "zone '%s' allows updates by IP "
				      "address, which is insecure",
				      zname);

		RETERR(configure_zone_ssutable(zoptions, zone, zname));

		obj = NULL;
		result = ns_config_get(maps, "sig-validity-interval", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		{
			const cfg_obj_t *validity, *resign;

			validity = cfg_tuple_get(obj, "validity");
			seconds = cfg_obj_asuint32(validity) * 86400;
			dns_zone_setsigvalidityinterval(zone, seconds);

			resign = cfg_tuple_get(obj, "re-sign");
			if (cfg_obj_isvoid(resign)) {
				seconds /= 4;
			} else {
				if (seconds > 7 * 86400)
					seconds = cfg_obj_asuint32(resign) *
							86400;
				else
					seconds = cfg_obj_asuint32(resign) *
							3600;
			}
			dns_zone_setsigresigninginterval(zone, seconds);
		}

		obj = NULL;
		result = ns_config_get(maps, "key-directory", &obj);
		if (result == ISC_R_SUCCESS) {
			filename = cfg_obj_asstring(obj);
			RETERR(dns_zone_setkeydirectory(zone, filename));
		}

		obj = NULL;
		result = ns_config_get(maps, "sig-signing-signatures", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "sig-signing-nodes", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setnodes(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "sig-signing-type", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "update-check-ksk", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
				   cfg_obj_asboolean(obj));

		obj = NULL;
		result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
				   cfg_obj_asboolean(obj));
	} else if (ztype == dns_zone_slave) {
		RETERR(configure_zone_acl(zconfig, vconfig, config,
					  allow_update_forwarding, ac, zone,
					  dns_zone_setforwardacl,
					  dns_zone_clearforwardacl));
	}

	/*%
	 * Primary master functionality.
	 */
	if (ztype == dns_zone_master) {
		isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;

		obj = NULL;
		result = ns_config_get(maps, "check-wildcard", &obj);
		if (result == ISC_R_SUCCESS)
			check = cfg_obj_asboolean(obj);
		else
			check = ISC_FALSE;
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check);

		obj = NULL;
		result = ns_config_get(maps, "check-dup-records", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			fail = ISC_FALSE;
			check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			fail = check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			fail = check = ISC_FALSE;
		} else
			INSIST(0);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRR, check);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRRFAIL, fail);

		obj = NULL;
		result = ns_config_get(maps, "check-mx", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			fail = ISC_FALSE;
			check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			fail = check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			fail = check = ISC_FALSE;
		} else
			INSIST(0);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail);

		obj = NULL;
		result = ns_config_get(maps, "check-integrity", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY,
				   cfg_obj_asboolean(obj));

		obj = NULL;
		result = ns_config_get(maps, "check-mx-cname", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			warn = ISC_TRUE;
			ignore = ISC_FALSE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			warn = ignore = ISC_FALSE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			warn = ignore = ISC_TRUE;
		} else
			INSIST(0);
		dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn);
		dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore);

		obj = NULL;
		result = ns_config_get(maps, "check-srv-cname", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			warn = ISC_TRUE;
			ignore = ISC_FALSE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			warn = ignore = ISC_FALSE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			warn = ignore = ISC_TRUE;
		} else
			INSIST(0);
		dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn);
		dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore);

		obj = NULL;
		result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE,
				   cfg_obj_asboolean(obj));

		obj = NULL;
		result = cfg_map_get(zoptions, "auto-dnssec", &obj);
		if (result == ISC_R_SUCCESS) {
			const char *arg = cfg_obj_asstring(obj);
			if (strcasecmp(arg, "allow") == 0)
				allow = ISC_TRUE;
			else if (strcasecmp(arg, "maintain") == 0)
				allow = maint = ISC_TRUE;
			else if (strcasecmp(arg, "off") == 0)
				;
			else
				INSIST(0);
			dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
			dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
		}
	}

	/*
	 * Configure slave functionality.
	 */
	switch (ztype) {
	case dns_zone_slave:
	case dns_zone_stub:
		count = 0;
		obj = NULL;
		(void)cfg_map_get(zoptions, "masters", &obj);
		if (obj != NULL) {
			addrs = NULL;
			keynames = NULL;
			RETERR(ns_config_getipandkeylist(config, obj, mctx,
							 &addrs, &keynames,
							 &count));
			result = dns_zone_setmasterswithkeys(zone, addrs,
							     keynames, count);
			ns_config_putipandkeylist(mctx, &addrs, &keynames,
						  count);
		} else
			result = dns_zone_setmasters(zone, NULL, 0);
		RETERR(result);

		multi = ISC_FALSE;
		if (count > 1) {
			obj = NULL;
			result = ns_config_get(maps, "multi-master", &obj);
			INSIST(result == ISC_R_SUCCESS && obj != NULL);
			multi = cfg_obj_asboolean(obj);
		}
		dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi);

		obj = NULL;
		result = ns_config_get(maps, "max-transfer-time-in", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);

		obj = NULL;
		result = ns_config_get(maps, "max-transfer-idle-in", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);

		obj = NULL;
		result = ns_config_get(maps, "max-refresh-time", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "min-refresh-time", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "max-retry-time", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "min-retry-time", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));

		obj = NULL;
		result = ns_config_get(maps, "transfer-source", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj)));
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));

		obj = NULL;
		result = ns_config_get(maps, "transfer-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)));
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));

		obj = NULL;
		result = ns_config_get(maps, "alt-transfer-source", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj)));

		obj = NULL;
		result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS && obj != NULL);
		RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj)));

		obj = NULL;
		(void)ns_config_get(maps, "use-alt-transfer-source", &obj);
		if (obj == NULL) {
			/*
			 * Default off when views are in use otherwise
			 * on for BIND 8 compatibility.
			 */
			view = dns_zone_getview(zone);
			if (view != NULL && strcmp(view->name, "_default") == 0)
				alt = ISC_TRUE;
			else
				alt = ISC_FALSE;
		} else
			alt = cfg_obj_asboolean(obj);
		dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt);

		obj = NULL;
		(void)ns_config_get(maps, "try-tcp-refresh", &obj);
		dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH,
				   cfg_obj_asboolean(obj));
		break;

	case dns_zone_staticstub:
		RETERR(configure_staticstub(zoptions, zone, zname,
					    default_dbtype));
		break;

	default:
		break;
	}

	return (ISC_R_SUCCESS);
}
コード例 #12
0
ファイル: dnsconf.c プロジェクト: crossbuild/bind
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);
}
コード例 #13
0
ファイル: config.c プロジェクト: jaredmcneill/netbsd-src
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);
}
コード例 #14
0
ファイル: config.c プロジェクト: jaredmcneill/netbsd-src
isc_result_t
ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
		    in_port_t defport, isc_mem_t *mctx,
		    isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp,
		    isc_uint32_t *countp)
{
	int count, i = 0;
	const cfg_obj_t *addrlist;
	const cfg_obj_t *portobj, *dscpobj;
	const cfg_listelt_t *element;
	isc_sockaddr_t *addrs;
	in_port_t port;
	isc_dscp_t dscp = -1, *dscps = NULL;
	isc_result_t result;

	INSIST(addrsp != NULL && *addrsp == NULL);
	INSIST(dscpsp == NULL || *dscpsp == NULL);
	INSIST(countp != NULL);

	addrlist = cfg_tuple_get(list, "addresses");
	count = ns_config_listcount(addrlist);

	portobj = cfg_tuple_get(list, "port");
	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);
			return (ISC_R_RANGE);
		}
		port = (in_port_t) val;
	} else if (defport != 0)
		port = defport;
	else {
		result = ns_config_getport(config, &port);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

	if (dscpsp != NULL) {
		dscpobj = cfg_tuple_get(list, "dscp");
		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));
				return (ISC_R_RANGE);
			}
			dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
		}

		dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t));
		if (dscps == NULL)
			return (ISC_R_NOMEMORY);
	}

	addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
	if (addrs == NULL) {
		if (dscps != NULL)
			isc_mem_put(mctx, dscps, count * sizeof(isc_dscp_t));
		return (ISC_R_NOMEMORY);
	}

	for (element = cfg_list_first(addrlist);
	     element != NULL;
	     element = cfg_list_next(element), i++)
	{
		const cfg_obj_t *addr;
		INSIST(i < count);
		addr = cfg_listelt_value(element);
		addrs[i] = *cfg_obj_assockaddr(addr);
		if (dscpsp != NULL) {
			isc_dscp_t innerdscp;
			innerdscp = cfg_obj_getdscp(addr);
			if (innerdscp == -1)
				innerdscp = dscp;
			dscps[i] = innerdscp;
		}
		if (isc_sockaddr_getport(&addrs[i]) == 0)
			isc_sockaddr_setport(&addrs[i], port);
	}
	INSIST(i == count);

	*addrsp = addrs;
	*countp = count;

	if (dscpsp != NULL)
		*dscpsp = dscps;

	return (ISC_R_SUCCESS);
}
コード例 #15
0
ファイル: delv.c プロジェクト: jaredmcneill/netbsd-src
static isc_result_t
key_fromconfig(const cfg_obj_t *key, dns_client_t *client) {
	dns_rdata_dnskey_t keystruct;
	isc_uint32_t flags, proto, alg;
	const char *keystr, *keynamestr;
	unsigned char keydata[4096];
	isc_buffer_t keydatabuf;
	unsigned char rrdata[4096];
	isc_buffer_t rrdatabuf;
	isc_region_t r;
	dns_fixedname_t fkeyname;
	dns_name_t *keyname;
	isc_result_t result;
	isc_boolean_t match_root = ISC_FALSE, match_dlv = ISC_FALSE;

	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
	CHECK(convert_name(&fkeyname, &keyname, keynamestr));

	if (!root_validation && !dlv_validation)
		return (ISC_R_SUCCESS);

	if (anchor_name)
		match_root = dns_name_equal(keyname, anchor_name);
	if (dlv_name)
		match_dlv = dns_name_equal(keyname, dlv_name);

	if (!match_root && !match_dlv)
		return (ISC_R_SUCCESS);
	if ((!root_validation && match_root) || (!dlv_validation && match_dlv))
		return (ISC_R_SUCCESS);

	if (match_root)
		delv_log(ISC_LOG_DEBUG(3), "adding trust anchor %s",
			  trust_anchor);
	if (match_dlv)
		delv_log(ISC_LOG_DEBUG(3), "adding DLV trust anchor %s",
			  dlv_anchor);

	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"));

	keystruct.common.rdclass = dns_rdataclass_in;
	keystruct.common.rdtype = dns_rdatatype_dnskey;
	/*
	 * The key data in keystruct is not dynamically allocated.
	 */
	keystruct.mctx = NULL;

	ISC_LINK_INIT(&keystruct.common, link);

	if (flags > 0xffff)
		CHECK(ISC_R_RANGE);
	if (proto > 0xff)
		CHECK(ISC_R_RANGE);
	if (alg > 0xff)
		CHECK(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, keydata, sizeof(keydata));
	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));

	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
	isc_buffer_usedregion(&keydatabuf, &r);
	keystruct.datalen = r.length;
	keystruct.data = r.base;

	CHECK(dns_rdata_fromstruct(NULL,
				   keystruct.common.rdclass,
				   keystruct.common.rdtype,
				   &keystruct, &rrdatabuf));

	CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in,
				       keyname, &rrdatabuf));
	trusted_keys++;

 cleanup:
	if (result == DST_R_NOCRYPTO)
		cfg_obj_log(key, lctx, ISC_LOG_ERROR, "no crypto support");
	else if (result == DST_R_UNSUPPORTEDALG) {
		cfg_obj_log(key, lctx, ISC_LOG_WARNING,
			    "skipping trusted key '%s': %s",
			    keynamestr, isc_result_totext(result));
		result = ISC_R_SUCCESS;
	} else if (result != ISC_R_SUCCESS) {
		cfg_obj_log(key, lctx, ISC_LOG_ERROR,
			    "failed to add trusted key '%s': %s",
			    keynamestr, isc_result_totext(result));
		result = ISC_R_FAILURE;
	}

	return (result);
}