Example #1
0
/*%
 * herror --
 *	print the error indicated by the h_errno value.
 */
void
herror(const char *s) {
#ifndef T2EX
	struct iovec iov[4], *v = iov;
	char *t;

	if (s != NULL && *s != '\0') {
		DE_CONST(s, t);
		v->iov_base = t;
		v->iov_len = strlen(t);
		v++;
		DE_CONST(": ", t);
		v->iov_base = t;
		v->iov_len = 2;
		v++;
	}
	DE_CONST(hstrerror(*__h_errno()), t);
	v->iov_base = t;
	v->iov_len = strlen(v->iov_base);
	v++;
	DE_CONST("\n", t);
	v->iov_base = t;
	v->iov_len = 1;
	writev(STDERR_FILENO, iov, (v - iov) + 1);
#else
	(void)s;
#endif
}
Example #2
0
static char *
city_string(GeoIPRecord *record, dns_geoip_subtype_t subtype, int *maxlen) {
	const char *s;
	char *deconst;

	REQUIRE(record != NULL);
	REQUIRE(maxlen != NULL);

	/* Set '*maxlen' to the maximum length of this subtype, if any */
	switch (subtype) {
	case dns_geoip_city_countrycode:
	case dns_geoip_city_region:
	case dns_geoip_city_continentcode:
		*maxlen = 2;
		break;

	case dns_geoip_city_countrycode3:
		*maxlen = 3;
		break;

	default:
		/* No fixed length; just use strcasecmp() for comparison */
		*maxlen = 255;
	}

	switch (subtype) {
	case dns_geoip_city_countrycode:
		return (record->country_code);
	case dns_geoip_city_countrycode3:
		return (record->country_code3);
	case dns_geoip_city_countryname:
		return (record->country_name);
	case dns_geoip_city_region:
		return (record->region);
	case dns_geoip_city_regionname:
		s = GeoIP_region_name_by_code(record->country_code,
					      record->region);
		DE_CONST(s, deconst);
		return (deconst);
	case dns_geoip_city_name:
		return (record->city);
	case dns_geoip_city_postalcode:
		return (record->postal_code);
	case dns_geoip_city_continentcode:
		return (record->continent_code);
	case dns_geoip_city_timezonecode:
		s = GeoIP_time_zone_by_country_and_region(record->country_code,
							  record->region);
		DE_CONST(s, deconst);
		return (deconst);
	default:
		INSIST(0);
	}
}
Example #3
0
NGR_R_RETURN
innetgr_r(const char *netgroup, const char *host, const char *user,
          const char *domain) {
    char *ng, *ho, *us, *dom;

    DE_CONST(netgroup, ng);
    DE_CONST(host, ho);
    DE_CONST(user, us);
    DE_CONST(domain, dom);

    return (innetgr(ng, ho, us, dom));
}
Example #4
0
int
getnetgrent(const char **host, const char **user, const char **domain) {
	struct net_data *net_data = init();
	const char *ch, *cu, *cd;
	int ret;

	ret = getnetgrent_p(&ch, &cu, &cd, net_data);
	if (ret != 1)
		return (ret);

	DE_CONST(ch, *host);
	DE_CONST(cu, *user);
	DE_CONST(cd, *domain);
	return (ret);
}
Example #5
0
isc_event_t *
isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
		   isc_taskaction_t action, const void *arg, size_t size)
{
	isc_event_t *event;
	void *deconst_arg;

	REQUIRE(size >= sizeof(struct isc_event));
	REQUIRE(action != NULL);

	event = isc_mem_get(mctx, size);
	if (event == NULL)
		return (NULL);

	/*
	 * Removing the const attribute from "arg" is the best of two
	 * evils here.  If the event->ev_arg member is made const, then
	 * it affects a great many users of the task/event subsystem
	 * which are not passing in an "arg" which starts its life as
	 * const.  Changing isc_event_allocate() and isc_task_onshutdown()
	 * to not have "arg" prototyped as const (which is quite legitimate,
	 * because neither of those functions modify arg) can cause
	 * compiler whining anytime someone does want to use a const
	 * arg that they themselves never modify, such as with
	 * gcc -Wwrite-strings and using a string "arg".
	 */
	DE_CONST(arg, deconst_arg);

	ISC_EVENT_INIT(event, size, 0, NULL, type, action, deconst_arg,
		       sender, destroy, mctx);

	return (event);
}
Example #6
0
static char *
region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) {
	const char *s;
	char *deconst;

	REQUIRE(region != NULL);
	REQUIRE(maxlen != NULL);

	switch (subtype) {
	case dns_geoip_region_countrycode:
		*maxlen = 2;
		return (region->country_code);
	case dns_geoip_region_code:
		*maxlen = 2;
		return (region->region);
	case dns_geoip_region_name:
		*maxlen = 255;
		s = GeoIP_region_name_by_code(region->country_code,
					      region->region);
		DE_CONST(s, deconst);
		return (deconst);
	default:
		INSIST(0);
	}
}
Example #7
0
void
isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
		 unsigned int len)
{
	CK_RV rv;
	CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 };
	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
	CK_KEY_TYPE keyType = CKK_MD5_HMAC;
	CK_ATTRIBUTE keyTemplate[] =
	{
		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
		{ CKA_VALUE, NULL, (CK_ULONG) len }
	};

	DE_CONST(key, keyTemplate[5].pValue);
	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
	ctx->object = CK_INVALID_HANDLE;
	PK11_FATALCHECK(pkcs_C_CreateObject,
			(ctx->session, keyTemplate,
			 (CK_ULONG) 6, &ctx->object));
	INSIST(ctx->object != CK_INVALID_HANDLE);
	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
}
Example #8
0
static inline isc_result_t
fromtext_txt(ARGS_FROMTEXT) {
	isc_token_t token;
	int strings;

	REQUIRE(type == 16);

	UNUSED(type);
	UNUSED(rdclass);
	UNUSED(origin);
	UNUSED(options);
	UNUSED(callbacks);

	strings = 0;
	if ((options & DNS_RDATA_UNKNOWNESCAPE) != 0) {
		isc_textregion_t r;
		DE_CONST("#", r.base);
		r.length = 1;
		RETERR(txt_fromtext(&r, target));
		strings++;
	}
	for (;;) {
		RETERR(isc_lex_getmastertoken(lexer, &token,
					      isc_tokentype_qstring,
					      ISC_TRUE));
		if (token.type != isc_tokentype_qstring &&
		    token.type != isc_tokentype_string)
			break;
		RETTOK(txt_fromtext(&token.value.as_textregion, target));
		strings++;
	}
	/* Let upper layer handle eol/eof. */
	isc_lex_ungettoken(lexer, &token);
	return (strings == 0 ? ISC_R_UNEXPECTEDEND : ISC_R_SUCCESS);
}
Example #9
0
void
isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
		 unsigned int len)
{
	CK_RV rv;
	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
	unsigned char ipad[PADLEN];
	unsigned int i;

	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
	RUNTIME_CHECK((ctx->key = pk11_mem_get(PADLEN)) != NULL);
	if (len > PADLEN) {
		CK_BYTE_PTR kPart;
		CK_ULONG kl;

		PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
		DE_CONST(key, kPart);
		PK11_FATALCHECK(pkcs_C_DigestUpdate,
				(ctx->session, kPart, (CK_ULONG) len));
		kl = ISC_MD5_DIGESTLENGTH;
		PK11_FATALCHECK(pkcs_C_DigestFinal,
				(ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
	} else
		memmove(ctx->key, key, len);
	PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
	memset(ipad, IPAD, PADLEN);
	for (i = 0; i < PADLEN; i++)
		ipad[i] ^= ctx->key[i];
	PK11_FATALCHECK(pkcs_C_DigestUpdate,
			(ctx->session, ipad, (CK_ULONG) PADLEN));
}
Example #10
0
/*!
 * Convert a string to an unsigned long integer.
 *
 * Ignores `locale' stuff.  Assumes that the upper and lower case
 * alphabets and digits are each contiguous.
 */
unsigned long
lwres_strtoul(const char *nptr, char **endptr, int base) {
	const char *s = nptr;
	unsigned long acc;
	unsigned char c;
	unsigned long cutoff;
	int neg = 0, any, cutlim;

	/*
	 * See strtol for comments as to the logic used.
	 */
	do {
		c = *s++;
	} while (isspace(c));
	if (c == '-') {
		neg = 1;
		c = *s++;
	} else if (c == '+')
		c = *s++;
	if ((base == 0 || base == 16) &&
	    c == '0' && (*s == 'x' || *s == 'X')) {
		c = s[1];
		s += 2;
		base = 16;
	}
	if (base == 0)
		base = c == '0' ? 8 : 10;
	cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
	cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
	for (acc = 0, any = 0;; c = *s++) {
		if (!isascii(c))
			break;
		if (isdigit(c))
			c -= '0';
		else if (isalpha(c))
			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
		else
			break;
		if (c >= base)
			break;
		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
			any = -1;
		else {
			any = 1;
			acc *= base;
			acc += c;
		}
	}
	if (any < 0) {
		acc = ULONG_MAX;
		errno = ERANGE;
	} else if (neg)
		/* XXX: acc was declared unsigned! */
		acc = -acc;
	if (endptr != 0)
		DE_CONST(any ? s - 1 : nptr, *endptr);
	return (acc);
}
Example #11
0
static void
isc_aes_crypt(const unsigned char *key, CK_ULONG keylen,
	      const unsigned char *in, unsigned char *out)
{
	CK_RV rv;
	CK_MECHANISM mech = { CKM_AES_ECB, NULL, 0 };
	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
	CK_KEY_TYPE keyType = CKK_AES;
	CK_ATTRIBUTE keyTemplate[] =
	{
		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
		{ CKA_ENCRYPT, &truevalue, (CK_ULONG) sizeof(truevalue) },
		{ CKA_VALUE, NULL, keylen }
	};
	CK_ULONG blocklen;
	CK_BYTE_PTR pData;
	pk11_context_t ctx;

	DE_CONST(key, keyTemplate[5].pValue);
	RUNTIME_CHECK(pk11_get_session(&ctx, OP_AES, ISC_TRUE, ISC_FALSE,
				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
	ctx.object = CK_INVALID_HANDLE;
	PK11_FATALCHECK(pkcs_C_CreateObject,
			(ctx.session, keyTemplate,
			 (CK_ULONG) 6, &ctx.object));
	INSIST(ctx.object != CK_INVALID_HANDLE);
	PK11_FATALCHECK(pkcs_C_EncryptInit,
			(ctx.session, &mech, ctx.object));

	DE_CONST(in, pData);
	blocklen = (CK_ULONG) ISC_AES_BLOCK_LENGTH;
	PK11_FATALCHECK(pkcs_C_Encrypt,
			(ctx.session,
			 pData, (CK_ULONG) ISC_AES_BLOCK_LENGTH,
			 out, &blocklen));
	RUNTIME_CHECK(blocklen == (CK_ULONG) ISC_AES_BLOCK_LENGTH);

	(void) pkcs_C_DestroyObject(ctx.session, ctx.object);
	ctx.object = CK_INVALID_HANDLE;
	pk11_return_session(&ctx);

}
Example #12
0
/*% load the zone */
isc_result_t
load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
	  dns_masterformat_t fileformat, const char *classname,
	  dns_zone_t **zonep)
{
	isc_result_t result;
	dns_rdataclass_t rdclass;
	isc_textregion_t region;
	isc_buffer_t buffer;
	dns_fixedname_t fixorigin;
	dns_name_t *origin;
	dns_zone_t *zone = NULL;

	REQUIRE(zonep == NULL || *zonep == NULL);

	if (debug)
		fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
			zonename, filename, classname);

	CHECK(dns_zone_create(&zone, mctx));

	dns_zone_settype(zone, dns_zone_master);

	isc_buffer_init(&buffer, zonename, strlen(zonename));
	isc_buffer_add(&buffer, strlen(zonename));
	dns_fixedname_init(&fixorigin);
	origin = dns_fixedname_name(&fixorigin);
	CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
	CHECK(dns_zone_setorigin(zone, origin));
	CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
	CHECK(dns_zone_setfile2(zone, filename, fileformat));

	DE_CONST(classname, region.base);
	region.length = strlen(classname);
	CHECK(dns_rdataclass_fromtext(&rdclass, &region));

	dns_zone_setclass(zone, rdclass);
	dns_zone_setoption(zone, zone_options, ISC_TRUE);
	dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
	if (docheckmx)
		dns_zone_setcheckmx(zone, checkmx);
	if (docheckns)
		dns_zone_setcheckns(zone, checkns);
	if (dochecksrv)
		dns_zone_setchecksrv(zone, checksrv);

	CHECK(dns_zone_load(zone));
	if (zonep != NULL) {
		*zonep = zone;
		zone = NULL;
	}

 cleanup:
	if (zone != NULL)
		dns_zone_detach(&zone);
	return (result);
}
Example #13
0
static isc_result_t
convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx,
		  isc_log_t *lctx, cfg_aclconfctx_t *ctx,
		  isc_mem_t *mctx, unsigned int nest_level,
		  dns_acl_t **target)
{
	isc_result_t result;
	const cfg_obj_t *cacl = NULL;
	dns_acl_t *dacl;
	dns_acl_t loop;
	const char *aclname = cfg_obj_asstring(nameobj);

	/* Look for an already-converted version. */
	for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache);
	     dacl != NULL;
	     dacl = ISC_LIST_NEXT(dacl, nextincache))
	{
		if (strcasecmp(aclname, dacl->name) == 0) {
			if (ISC_MAGIC_VALID(dacl, LOOP_MAGIC)) {
				cfg_obj_log(nameobj, lctx, ISC_LOG_ERROR,
					    "acl loop detected: %s", aclname);
				return (ISC_R_FAILURE);
			}
			dns_acl_attach(dacl, target);
			return (ISC_R_SUCCESS);
		}
	}
	/* Not yet converted.  Convert now. */
	result = get_acl_def(cctx, aclname, &cacl);
	if (result != ISC_R_SUCCESS) {
		cfg_obj_log(nameobj, lctx, ISC_LOG_WARNING,
			    "undefined ACL '%s'", aclname);
		return (result);
	}
	/*
	 * Add a loop detection element.
	 */
	memset(&loop, 0, sizeof(loop));
	ISC_LINK_INIT(&loop, nextincache);
	DE_CONST(aclname, loop.name);
	loop.magic = LOOP_MAGIC;
	ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache);
	result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx,
				    nest_level, &dacl);
	ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache);
	loop.magic = 0;
	loop.name = NULL;
	if (result != ISC_R_SUCCESS)
		return (result);
	dacl->name = isc_mem_strdup(dacl->mctx, aclname);
	if (dacl->name == NULL)
		return (ISC_R_NOMEMORY);
	ISC_LIST_APPEND(ctx->named_acl_cache, dacl, nextincache);
	dns_acl_attach(dacl, target);
	return (ISC_R_SUCCESS);
}
Example #14
0
isccc_sexpr_t *
isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str) {
	size_t len;
	isccc_region_t r;

	len = strlen(str);
	DE_CONST(str, r.rstart);
	r.rend = r.rstart + len;

	return (isccc_alist_definebinary(alist, key, &r));
}
Example #15
0
void
isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
		   unsigned int len)
{
	CK_RV rv;
	CK_BYTE_PTR pPart;

	DE_CONST(buf, pPart);
	PK11_FATALCHECK(pkcs_C_DigestUpdate,
			(ctx->session, pPart, (CK_ULONG) len));
}
Example #16
0
isc_result_t
isc_gost_update(isc_gost_t *ctx, const unsigned char *buf, unsigned int len) {
	CK_RV rv;
	CK_BYTE_PTR pPart;
	int ret = ISC_R_SUCCESS;

	DE_CONST(buf, pPart);
	PK11_CALL(pkcs_C_DigestUpdate,
		  (ctx->session, pPart, (CK_ULONG) len),
		  ISC_R_FAILURE);
	return (ret);
}
Example #17
0
isc_result_t
isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
		  isc_symvalue_t value, isc_symexists_t exists_policy)
{
	unsigned int bucket;
	elt_t *elt;

	REQUIRE(VALID_SYMTAB(symtab));
	REQUIRE(key != NULL);
	REQUIRE(type != 0);

	FIND(symtab, key, type, bucket, elt);

	if (exists_policy != isc_symexists_add && elt != NULL) {
		if (exists_policy == isc_symexists_reject)
			return (ISC_R_EXISTS);
		INSIST(exists_policy == isc_symexists_replace);
		UNLINK(symtab->table[bucket], elt, link);
		if (symtab->undefine_action != NULL)
			(symtab->undefine_action)(elt->key, elt->type,
						  elt->value,
						  symtab->undefine_arg);
	} else {
		elt = (elt_t *)isc_mem_get(symtab->mctx, sizeof(*elt));
		if (elt == NULL)
			return (ISC_R_NOMEMORY);
		ISC_LINK_INIT(elt, link);
		symtab->count++;
	}

	/*
	 * Though the "key" can be const coming in, it is not stored as const
	 * so that the calling program can easily have writable access to
	 * it in its undefine_action function.  In the event that it *was*
	 * truly const coming in and then the caller modified it anyway ...
	 * well, don't do that!
	 */
	DE_CONST(key, elt->key);
	elt->type = type;
	elt->value = value;

	/*
	 * We prepend so that the most recent definition will be found.
	 */
	PREPEND(symtab->table[bucket], elt, link);

	if (symtab->count > symtab->maxload)
		grow_table(symtab);

	return (ISC_R_SUCCESS);
}
Example #18
0
static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
get_types(isc_mem_t *mctx, const cfg_obj_t *obj, dns_rdatatype_t **typesp,
	  unsigned int *np)
{
	isc_result_t result = ISC_R_SUCCESS;
	unsigned int i;
	unsigned int n = 0;
	const cfg_listelt_t *el;
	dns_rdatatype_t *types = NULL;

	REQUIRE(obj != NULL);
	REQUIRE(typesp != NULL && *typesp == NULL);
	REQUIRE(np != NULL);

	obj = cfg_tuple_get(obj, "types");

	n = count_list_elements(obj);
	if (n > 0)
		CHECKED_MEM_GET(mctx, types, n * sizeof(dns_rdatatype_t));

	i = 0;
	for (el = cfg_list_first(obj); el != NULL; el = cfg_list_next(el)) {
		const cfg_obj_t *typeobj;
		const char *str;
		isc_textregion_t r;

		INSIST(i < n);

		typeobj = cfg_listelt_value(el);
		str = cfg_obj_asstring(typeobj);
		DE_CONST(str, r.base);
		r.length = strlen(str);

		result = dns_rdatatype_fromtext(&types[i++], &r);
		if (result != ISC_R_SUCCESS) {
			log_error("'%s' is not a valid type", str);
			goto cleanup;
		}
	}
	INSIST(i == n);

	*typesp = types;
	*np = n;
	return result;

cleanup:
	SAFE_MEM_PUT(mctx, types, n * sizeof(dns_rdatatype_t));

	return result;
}
Example #19
0
static isc_result_t
config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
		dns_rdataclass_t *classp)
{
	isc_textregion_t r;

	if (!cfg_obj_isstring(classobj)) {
		*classp = defclass;
		return (ISC_R_SUCCESS);
	}
	DE_CONST(cfg_obj_asstring(classobj), r.base);
	r.length = strlen(r.base);
	return (dns_rdataclass_fromtext(classp, &r));
}
Example #20
0
dns_rdataclass_t
strtoclass(const char *str) {
	isc_textregion_t r;
	dns_rdataclass_t rdclass;
	isc_result_t ret;

	if (str == NULL)
		return dns_rdataclass_in;
	DE_CONST(str, r.base);
	r.length = strlen(str);
	ret = dns_rdataclass_fromtext(&rdclass, &r);
	if (ret != ISC_R_SUCCESS)
		fatal("unknown class %s", str);
	return (rdclass);
}
Example #21
0
isc_result_t
ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
		   dns_rdataclass_t *classp) {
	isc_textregion_t r;
	isc_result_t result;

	if (!cfg_obj_isstring(classobj)) {
		*classp = defclass;
		return (ISC_R_SUCCESS);
	}
	DE_CONST(cfg_obj_asstring(classobj), r.base);
	r.length = strlen(r.base);
	result = dns_rdataclass_fromtext(classp, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR,
			    "unknown class '%s'", r.base);
	return (result);
}
Example #22
0
isc_result_t
ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype,
		   dns_rdatatype_t *typep) {
	isc_textregion_t r;
	isc_result_t result;

	if (!cfg_obj_isstring(typeobj)) {
		*typep = deftype;
		return (ISC_R_SUCCESS);
	}
	DE_CONST(cfg_obj_asstring(typeobj), r.base);
	r.length = strlen(r.base);
	result = dns_rdatatype_fromtext(typep, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR,
			    "unknown type '%s'", r.base);
	return (result);
}
Example #23
0
char *
isc_string_strcasestr(const char *str, const char *search) {
	char c, sc, *s;
	size_t len;

	if ((c = *search++) != 0) {
		c = tolower((unsigned char) c);
		len = strlen(search);
		do {
			do {
				if ((sc = *str++) == 0)
					return (NULL);
			} while ((char) tolower((unsigned char) sc) != c);
		} while (strncasecmp(str, search, len) != 0);
		str--;
	}
	DE_CONST(str, s);
	return (s);

}
Example #24
0
static isc_result_t
configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
	isc_result_t result;
	dns_db_t *db = NULL;
	dns_rdataclass_t rdclass;
	isc_textregion_t r;

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

	DE_CONST(zclass, r.base);
	r.length = strlen(zclass);
	result = dns_rdataclass_fromtext(&rdclass, &r);
	if (result != ISC_R_SUCCESS)
		return (result);

	result = dns_rootns_create(mctx, rdclass, zfile, &db);
	if (result != ISC_R_SUCCESS)
		return (result);

	dns_db_detach(&db);
	return (ISC_R_SUCCESS);
}
Example #25
0
ISC_TIMERFUNC_SCOPE isc_result_t
isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type,
		  isc_time_t *expires, isc_interval_t *interval,
		  isc_task_t *task, isc_taskaction_t action, const void *arg,
		  isc_timer_t **timerp)
{
	isc__timermgr_t *manager = (isc__timermgr_t *)manager0;
	isc__timer_t *timer;
	isc_result_t result;
	isc_time_t now;

	/*
	 * Create a new 'type' timer managed by 'manager'.  The timers
	 * parameters are specified by 'expires' and 'interval'.  Events
	 * will be posted to 'task' and when dispatched 'action' will be
	 * called with 'arg' as the arg value.  The new timer is returned
	 * in 'timerp'.
	 */

	REQUIRE(VALID_MANAGER(manager));
	REQUIRE(task != NULL);
	REQUIRE(action != NULL);
	if (expires == NULL)
		expires = isc_time_epoch;
	if (interval == NULL)
		interval = isc_interval_zero;
	REQUIRE(type == isc_timertype_inactive ||
		!(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
	REQUIRE(timerp != NULL && *timerp == NULL);
	REQUIRE(type != isc_timertype_limited ||
		!(isc_time_isepoch(expires) || isc_interval_iszero(interval)));

	/*
	 * Get current time.
	 */
	if (type != isc_timertype_inactive) {
		TIME_NOW(&now);
	} else {
		/*
		 * We don't have to do this, but it keeps the compiler from
		 * complaining about "now" possibly being used without being
		 * set, even though it will never actually happen.
		 */
		isc_time_settoepoch(&now);
	}


	timer = isc_mem_get(manager->mctx, sizeof(*timer));
	if (timer == NULL)
		return (ISC_R_NOMEMORY);

	timer->manager = manager;
	timer->references = 1;

	if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
		result = isc_time_add(&now, interval, &timer->idle);
		if (result != ISC_R_SUCCESS) {
			isc_mem_put(manager->mctx, timer, sizeof(*timer));
			return (result);
		}
	} else
		isc_time_settoepoch(&timer->idle);

	timer->type = type;
	timer->expires = *expires;
	timer->interval = *interval;
	timer->task = NULL;
	isc_task_attach(task, &timer->task);
	timer->action = action;
	/*
	 * Removing the const attribute from "arg" is the best of two
	 * evils here.  If the timer->arg member is made const, then
	 * it affects a great many recipients of the timer event
	 * which did not pass in an "arg" that was truly const.
	 * Changing isc_timer_create() to not have "arg" prototyped as const,
	 * though, can cause compilers warnings for calls that *do*
	 * have a truly const arg.  The caller will have to carefully
	 * keep track of whether arg started as a true const.
	 */
	DE_CONST(arg, timer->arg);
	timer->index = 0;
	result = isc_mutex_init(&timer->lock);
	if (result != ISC_R_SUCCESS) {
		isc_task_detach(&timer->task);
		isc_mem_put(manager->mctx, timer, sizeof(*timer));
		return (result);
	}
	ISC_LINK_INIT(timer, link);
	timer->common.impmagic = TIMER_MAGIC;
	timer->common.magic = ISCAPI_TIMER_MAGIC;
	timer->common.methods = (isc_timermethods_t *)&timermethods;

	LOCK(&manager->lock);

	/*
	 * Note we don't have to lock the timer like we normally would because
	 * there are no external references to it yet.
	 */

	if (type != isc_timertype_inactive)
		result = schedule(timer, &now, ISC_TRUE);
	else
		result = ISC_R_SUCCESS;
	if (result == ISC_R_SUCCESS)
		APPEND(manager->timers, timer, link);

	UNLOCK(&manager->lock);

	if (result != ISC_R_SUCCESS) {
		timer->common.impmagic = 0;
		timer->common.magic = 0;
		DESTROYLOCK(&timer->lock);
		isc_task_detach(&timer->task);
		isc_mem_put(manager->mctx, timer, sizeof(*timer));
		return (result);
	}

	*timerp = (isc_timer_t *)timer;

	return (ISC_R_SUCCESS);
}
static void
test_noop(void) {
	int ret;
	lwres_lwpacket_t pkt, pkt2;
	lwres_nooprequest_t nooprequest, *nooprequest2;
	lwres_noopresponse_t noopresponse, *noopresponse2;
	lwres_buffer_t b;

	pkt.pktflags = 0;
	pkt.serial = 0x11223344;
	pkt.recvlength = 0x55667788;
	pkt.result = 0;

	nooprequest.datalength = strlen(TESTSTRING);
	/* XXXDCL maybe "nooprequest.data" should be const. */
	DE_CONST(TESTSTRING, nooprequest.data);
	ret = lwres_nooprequest_render(ctx, &nooprequest, &pkt, &b);
	CHECK(ret, "lwres_nooprequest_render");

	hexdump("rendered noop request", b.base, b.used);

	/*
	 * Now, parse it into a new structure.
	 */
	lwres_buffer_first(&b);
	ret = lwres_lwpacket_parseheader(&b, &pkt2);
	CHECK(ret, "lwres_lwpacket_parseheader");

	hexdump("parsed pkt2", &pkt2, sizeof(pkt2));

	nooprequest2 = NULL;
	ret = lwres_nooprequest_parse(ctx, &b, &pkt2, &nooprequest2);
	CHECK(ret, "lwres_nooprequest_parse");

	assert(nooprequest.datalength == nooprequest2->datalength);
	assert(memcmp(nooprequest.data, nooprequest2->data,
		       nooprequest.datalength) == 0);

	lwres_nooprequest_free(ctx, &nooprequest2);

	lwres_context_freemem(ctx, b.base, b.length);
	b.base = NULL;
	b.length = 0;

	pkt.pktflags = 0;
	pkt.serial = 0x11223344;
	pkt.recvlength = 0x55667788;
	pkt.result = 0xdeadbeef;

	noopresponse.datalength = strlen(TESTSTRING);
	/* XXXDCL maybe "noopresponse.data" should be const. */
	DE_CONST(TESTSTRING, noopresponse.data);
	ret = lwres_noopresponse_render(ctx, &noopresponse, &pkt, &b);
	CHECK(ret, "lwres_noopresponse_render");

	hexdump("rendered noop response", b.base, b.used);

	/*
	 * Now, parse it into a new structure.
	 */
	lwres_buffer_first(&b);
	ret = lwres_lwpacket_parseheader(&b, &pkt2);
	CHECK(ret, "lwres_lwpacket_parseheader");

	hexdump("parsed pkt2", &pkt2, sizeof(pkt2));

	noopresponse2 = NULL;
	ret = lwres_noopresponse_parse(ctx, &b, &pkt2, &noopresponse2);
	CHECK(ret, "lwres_noopresponse_parse");

	assert(noopresponse.datalength == noopresponse2->datalength);
	assert(memcmp(noopresponse.data, noopresponse2->data,
		       noopresponse.datalength) == 0);

	lwres_noopresponse_free(ctx, &noopresponse2);

	lwres_context_freemem(ctx, b.base, b.length);
	b.base = NULL;
	b.length = 0;
}
Example #27
0
File: send.c Project: aosm/bind
int
SendRequest(union res_sockaddr_union *nsAddrPtr, const u_char *buf,
	    int buflen, u_char *answer, u_int anslen, int *trueLenPtr)
{
	int n, try, v_circuit, resplen;
	ISC_SOCKLEN_T salen;
	int gotsomewhere = 0, connected = 0;
	int connreset = 0;
	u_short id, len;
	u_char *cp;
	fd_set dsmask;
	struct timeval timeout;
	const HEADER *hp = (const HEADER *) buf;
	HEADER *anhp = (HEADER *) answer;
	struct iovec iov[2];
	int terrno = ETIMEDOUT;
	char junk[512];
	struct sockaddr_storage sa;
	int family = nsAddrPtr->sin.sin_family;
	int clen = (family == AF_INET) ? sizeof(struct sockaddr_in) :
				         sizeof(struct sockaddr_in6);

	if (res.options & RES_DEBUG2) {
	    printf("------------\nSendRequest(), len %d\n", buflen);
	    Print_query(buf, buf + buflen, 1);
	}
	v_circuit = (res.options & RES_USEVC) || buflen > PACKETSZ;
	id = hp->id;
	/*
	 * Send request, RETRY times, or until successful
	 */
	for (try = 0; try < res.retry; try++) {
	usevc:
		if (v_circuit) {
			int truncated = 0;

			/*
			 * Use virtual circuit;
			 * at most one attempt per server.
			 */
			try = res.retry;
			if (s < 0) {
				s = socket(family, SOCK_STREAM, 0);
				if (s < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("socket (vc) failed");
					continue;
				}
				if (connect(s, (struct sockaddr *)nsAddrPtr,
				    clen) < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("connect failed");
					(void) close(s);
					s = -1;
					continue;
				}
			}
			/*
			 * Send length & message
			 */
			__putshort(buflen, (u_char *)&len);
			iov[0].iov_base = (caddr_t)&len;
			iov[0].iov_len = INT16SZ;
			DE_CONST(buf, iov[1].iov_base);
			iov[1].iov_len = buflen;
			if (writev(s, iov, 2) != INT16SZ + buflen) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("write failed");
				(void) close(s);
				s = -1;
				continue;
			}
			/*
			 * Receive length & response
			 */
			cp = answer;
			len = INT16SZ;
			while ((n = read(s, (char *)cp, (int)len)) > 0) {
				cp += n;
				if ((len -= n) <= 0)
					break;
			}
			if (n <= 0) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("read failed");
				(void) close(s);
				s = -1;
				/*
				 * A long running process might get its TCP
				 * connection reset if the remote server was
				 * restarted.  Requery the server instead of
				 * trying a new one.  When there is only one
				 * server, this means that a query might work
				 * instead of failing.  We only allow one reset
				 * per query to prevent looping.
				 */
				if (terrno == ECONNRESET && !connreset) {
					connreset = 1;
				}
				continue;
			}
			cp = answer;
			if ((resplen = ns_get16((u_char*)cp)) > (int)anslen) {
				if (res.options & RES_DEBUG)
					fprintf(stderr, "response truncated\n");
				len = anslen;
				truncated = 1;
			} else
				len = resplen;
			while (len != 0 &&
			   (n = read(s, (char *)cp, (int)len)) > 0) {
				cp += n;
				len -= n;
			}
			if (n <= 0) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("read failed");
				(void) close(s);
				s = -1;
				continue;
			}
			if (truncated) {
				/*
				 * Flush rest of answer
				 * so connection stays in synch.
				 */
				anhp->tc = 1;
				len = resplen - anslen;
				while (len != 0) {
					n = (len > sizeof(junk) ?
					    sizeof(junk) : len);
					if ((n = read(s, junk, n)) > 0)
						len -= n;
					else
						break;
				}
			}
		} else {
			/*
			 * Use datagrams.
			 */
			if (s < 0) {
				s = socket(family, SOCK_DGRAM, 0);
				if (s < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("socket (dg) failed");
					continue;
				}
			}
#if BSD >= 43
			if (connected == 0) {
				if (connect(s, (struct sockaddr *)nsAddrPtr,
				    clen) < 0) {
					if (res.options & RES_DEBUG)
						perror("connect");
					continue;
				}
				connected = 1;
			}
			if (send(s, buf, buflen, 0) != buflen) {
				if (res.options & RES_DEBUG)
					perror("send");
				continue;
			}
#else /* BSD */
			if (sendto(s, (const char *)buf, buflen, 0,
				   (struct sockaddr *) nsAddrPtr,
				   clen) != buflen) {
				if (res.options & RES_DEBUG)
					perror("sendto");
				continue;
			}
#endif

			/*
			 * Wait for reply
			 */
			timeout.tv_sec = (res.retrans << try);
			if (timeout.tv_sec <= 0)
				timeout.tv_sec = 1;
			timeout.tv_usec = 0;
 wait:
			FD_ZERO(&dsmask);
			FD_SET(s, &dsmask);
			n = select(s+1, &dsmask, (fd_set *)NULL,
				(fd_set *)NULL, &timeout);
			if (n < 0) {
				if (res.options & RES_DEBUG)
					perror("select");
				continue;
			}
			if (n == 0) {
				/*
				 * timeout
				 */
				if (res.options & RES_DEBUG)
					printf("timeout\n");
#if BSD >= 43
				gotsomewhere = 1;
#endif
				continue;
			}

			salen = sizeof sa;
			resplen = recvfrom(s, (char *)answer, anslen, 0,
					   (struct sockaddr *)&sa, &salen);
			if (resplen <= 0) {
				if (res.options & RES_DEBUG)
					perror("recvfrom");
				continue;
			}
			gotsomewhere = 1;
			if (id != anhp->id) {
				/*
				 * response from old query, ignore it
				 */
				if (res.options & RES_DEBUG2) {
					printf("------------\nOld answer:\n");
					Print_query(answer, answer+resplen, 1);
				}
				goto wait;
			}
			if (!(res.options & RES_IGNTC) && anhp->tc) {
				/*
				 * get rest of answer;
				 * use TCP with same server.
				 */
				if (res.options & RES_DEBUG)
					printf("truncated answer\n");
				(void) close(s);
				s = -1;
				v_circuit = 1;
				goto usevc;
			}
		}
		if (res.options & RES_DEBUG) {
		    if (res.options & RES_DEBUG2)
			printf("------------\nGot answer (%d bytes):\n",
			    resplen);
		    else
			printf("------------\nGot answer:\n");
		    Print_query(answer, answer+resplen, 1);
		}
		(void) close(s);
		s = -1;
		*trueLenPtr = resplen;
		return (SUCCESS);
	}
	if (s >= 0) {
		(void) close(s);
		s = -1;
	}
	if (v_circuit == 0)
		if (gotsomewhere == 0)
			return NO_RESPONSE;	/* no nameservers found */
		else
			return TIME_OUT;	/* no answer obtained */
	else
		if (errno == ECONNREFUSED)
			return NO_RESPONSE;
		else
			return ERROR;
}
Example #28
0
/*% load the zone */
isc_result_t
load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
	  dns_masterformat_t fileformat, const char *classname,
	  dns_ttl_t maxttl, dns_zone_t **zonep)
{
	isc_result_t result;
	dns_rdataclass_t rdclass;
	isc_textregion_t region;
	isc_buffer_t buffer;
	dns_fixedname_t fixorigin;
	dns_name_t *origin;
	dns_zone_t *zone = NULL;

	REQUIRE(zonep == NULL || *zonep == NULL);

	if (debug)
		fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
			zonename, filename, classname);

	CHECK(dns_zone_create(&zone, mctx));

	dns_zone_settype(zone, dns_zone_master);

	isc_buffer_constinit(&buffer, zonename, strlen(zonename));
	isc_buffer_add(&buffer, strlen(zonename));
	dns_fixedname_init(&fixorigin);
	origin = dns_fixedname_name(&fixorigin);
	CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
	CHECK(dns_zone_setorigin(zone, origin));
	CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
	CHECK(dns_zone_setfile2(zone, filename, fileformat));
	if (journal != NULL)
		CHECK(dns_zone_setjournal(zone, journal));

	DE_CONST(classname, region.base);
	region.length = strlen(classname);
	CHECK(dns_rdataclass_fromtext(&rdclass, &region));

	dns_zone_setclass(zone, rdclass);
	dns_zone_setoption(zone, zone_options, ISC_TRUE);
	dns_zone_setoption2(zone, zone_options2, ISC_TRUE);
	dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);

	dns_zone_setmaxttl(zone, maxttl);

	if (docheckmx)
		dns_zone_setcheckmx(zone, checkmx);
	if (docheckns)
		dns_zone_setcheckns(zone, checkns);
	if (dochecksrv)
		dns_zone_setchecksrv(zone, checksrv);

	CHECK(dns_zone_load(zone));

	/*
	 * When loading map files we can't catch oversize TTLs during
	 * load, so we check for them here.
	 */
	if (fileformat == dns_masterformat_map && maxttl != 0) {
		CHECK(check_ttls(zone, maxttl));
	}

	if (zonep != NULL) {
		*zonep = zone;
		zone = NULL;
	}

 cleanup:
	if (zone != NULL)
		dns_zone_detach(&zone);
	return (result);
}
Example #29
0
struct hostent *
getipnodebyname(const char *name, int af, int flags, int *error_num) {
	int have_v4 = 1, have_v6 = 1;
	struct in_addr in4;
	struct in6_addr in6;
	struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
	int v4 = 0, v6 = 0;
	struct net_data *net_data = init();
	u_long options;
	int tmp_err;

	if (net_data == NULL) {
		*error_num = NO_RECOVERY;
		return (NULL);
	}

	/* If we care about active interfaces then check. */
	if ((flags & AI_ADDRCONFIG) != 0)
		if (scan_interfaces(&have_v4, &have_v6) == -1) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}

	/* Check for literal address. */
	if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
		v6 = inet_pton(AF_INET6, name, &in6);

	/* Impossible combination? */
	 
	if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
	    (af == AF_INET && v6 == 1) ||
	    (have_v4 == 0 && v4 == 1) ||
	    (have_v6 == 0 && v6 == 1) ||
	    (have_v4 == 0 && af == AF_INET) ||
	    (have_v6 == 0 && af == AF_INET6)) {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}

	/* Literal address? */
	if (v4 == 1 || v6 == 1) {
		char *addr_list[2];
		char *aliases[1];

		DE_CONST(name, he.h_name);
		he.h_addr_list = addr_list;
		he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
		he.h_addr_list[1] = NULL;
		he.h_aliases = aliases;
		he.h_aliases[0] = NULL;
		he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
		he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
		return (copyandmerge(&he, NULL, af, error_num));
	}

	options = net_data->res->options;
	net_data->res->options &= ~RES_USE_INET6;

	tmp_err = NO_RECOVERY;
	if (have_v6 && af == AF_INET6) {
		he2 = gethostbyname2_p(name, AF_INET6, net_data);
		if (he2 != NULL) {
			he1 = copyandmerge(he2, NULL, af, error_num);
			if (he1 == NULL)
				return (NULL);
			he2 = NULL;
		} else {
			tmp_err = net_data->res->res_h_errno;
		}
	}

	if (have_v4 &&
	    ((af == AF_INET) ||
	     (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
	      (he1 == NULL || (flags & AI_ALL) != 0)))) {
		he2 = gethostbyname2_p(name, AF_INET, net_data);
		if (he1 == NULL && he2 == NULL) {
			*error_num = net_data->res->res_h_errno;
			return (NULL);
		} 
	} else
		*error_num = tmp_err;

	net_data->res->options = options;

	he3 = copyandmerge(he1, he2, af, error_num);

	if (he1 != NULL)
		freehostent(he1);
	return (he3);
}
Example #30
0
/*%
 * Parse the zone update-policy statement.
 */
static isc_result_t
configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
			const char *zname)
{
	const cfg_obj_t *updatepolicy = NULL;
	const cfg_listelt_t *element, *element2;
	dns_ssutable_t *table = NULL;
	isc_mem_t *mctx = dns_zone_getmctx(zone);
	isc_boolean_t autoddns = ISC_FALSE;
	isc_result_t result;

	(void)cfg_map_get(zconfig, "update-policy", &updatepolicy);

	if (updatepolicy == NULL) {
		dns_zone_setssutable(zone, NULL);
		return (ISC_R_SUCCESS);
	}

	if (cfg_obj_isstring(updatepolicy) &&
	    strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) {
		autoddns = ISC_TRUE;
		updatepolicy = NULL;
	}

	result = dns_ssutable_create(mctx, &table);
	if (result != ISC_R_SUCCESS)
		return (result);

	for (element = cfg_list_first(updatepolicy);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		const cfg_obj_t *stmt = cfg_listelt_value(element);
		const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
		const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
		const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
		const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
		const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
		const char *str;
		isc_boolean_t grant = ISC_FALSE;
		isc_boolean_t usezone = ISC_FALSE;
		unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
		dns_fixedname_t fname, fident;
		isc_buffer_t b;
		dns_rdatatype_t *types;
		unsigned int i, n;

		str = cfg_obj_asstring(mode);
		if (strcasecmp(str, "grant") == 0)
			grant = ISC_TRUE;
		else if (strcasecmp(str, "deny") == 0)
			grant = ISC_FALSE;
		else
			INSIST(0);

		str = cfg_obj_asstring(matchtype);
		if (strcasecmp(str, "name") == 0)
			mtype = DNS_SSUMATCHTYPE_NAME;
		else if (strcasecmp(str, "subdomain") == 0)
			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
		else if (strcasecmp(str, "wildcard") == 0)
			mtype = DNS_SSUMATCHTYPE_WILDCARD;
		else if (strcasecmp(str, "self") == 0)
			mtype = DNS_SSUMATCHTYPE_SELF;
		else if (strcasecmp(str, "selfsub") == 0)
			mtype = DNS_SSUMATCHTYPE_SELFSUB;
		else if (strcasecmp(str, "selfwild") == 0)
			mtype = DNS_SSUMATCHTYPE_SELFWILD;
		else if (strcasecmp(str, "ms-self") == 0)
			mtype = DNS_SSUMATCHTYPE_SELFMS;
		else if (strcasecmp(str, "krb5-self") == 0)
			mtype = DNS_SSUMATCHTYPE_SELFKRB5;
		else if (strcasecmp(str, "ms-subdomain") == 0)
			mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
		else if (strcasecmp(str, "krb5-subdomain") == 0)
			mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
		else if (strcasecmp(str, "tcp-self") == 0)
			mtype = DNS_SSUMATCHTYPE_TCPSELF;
		else if (strcasecmp(str, "6to4-self") == 0)
			mtype = DNS_SSUMATCHTYPE_6TO4SELF;
		else if (strcasecmp(str, "zonesub") == 0) {
			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
			usezone = ISC_TRUE;
		} else if (strcasecmp(str, "external") == 0)
			mtype = DNS_SSUMATCHTYPE_EXTERNAL;
		else
			INSIST(0);

		dns_fixedname_init(&fident);
		str = cfg_obj_asstring(identity);
		isc_buffer_init(&b, str, strlen(str));
		isc_buffer_add(&b, strlen(str));
		result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
					   dns_rootname, 0, NULL);
		if (result != ISC_R_SUCCESS) {
			cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
				    "'%s' is not a valid name", str);
			goto cleanup;
		}

		dns_fixedname_init(&fname);
		if (usezone) {
			result = dns_name_copy(dns_zone_getorigin(zone),
					       dns_fixedname_name(&fname),
					       NULL);
			if (result != ISC_R_SUCCESS) {
				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
					    "error copying origin: %s",
					    isc_result_totext(result));
				goto cleanup;
			}
		} else {
			str = cfg_obj_asstring(dname);
			isc_buffer_init(&b, str, strlen(str));
			isc_buffer_add(&b, strlen(str));
			result = dns_name_fromtext(dns_fixedname_name(&fname),
						   &b, dns_rootname, 0, NULL);
			if (result != ISC_R_SUCCESS) {
				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
					    "'%s' is not a valid name", str);
				goto cleanup;
			}
		}

		n = ns_config_listcount(typelist);
		if (n == 0)
			types = NULL;
		else {
			types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
			if (types == NULL) {
				result = ISC_R_NOMEMORY;
				goto cleanup;
			}
		}

		i = 0;
		for (element2 = cfg_list_first(typelist);
		     element2 != NULL;
		     element2 = cfg_list_next(element2))
		{
			const cfg_obj_t *typeobj;
			isc_textregion_t r;

			INSIST(i < n);

			typeobj = cfg_listelt_value(element2);
			str = cfg_obj_asstring(typeobj);
			DE_CONST(str, r.base);
			r.length = strlen(str);

			result = dns_rdatatype_fromtext(&types[i++], &r);
			if (result != ISC_R_SUCCESS) {
				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
					    "'%s' is not a valid type", str);
				isc_mem_put(mctx, types,
					    n * sizeof(dns_rdatatype_t));
				goto cleanup;
			}
		}
		INSIST(i == n);

		result = dns_ssutable_addrule(table, grant,
					      dns_fixedname_name(&fident),
					      mtype,
					      dns_fixedname_name(&fname),
					      n, types);
		if (types != NULL)
			isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
		if (result != ISC_R_SUCCESS) {
			goto cleanup;
		}
	}

	/*
	 * If "update-policy local;" and a session key exists,
	 * then use the default policy, which is equivalent to:
	 * update-policy { grant <session-keyname> zonesub any; };
	 */
	if (autoddns) {
		dns_rdatatype_t any = dns_rdatatype_any;

		if (ns_g_server->session_keyname == NULL) {
			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
				      "failed to enable auto DDNS policy "
				      "for zone %s: session key not found",
				      zname);
			result = ISC_R_NOTFOUND;
			goto cleanup;
		}

		result = dns_ssutable_addrule(table, ISC_TRUE,
					      ns_g_server->session_keyname,
					      DNS_SSUMATCHTYPE_SUBDOMAIN,
					      dns_zone_getorigin(zone),
					      1, &any);

		if (result != ISC_R_SUCCESS)
			goto cleanup;
	}

	result = ISC_R_SUCCESS;
	dns_zone_setssutable(zone, table);

 cleanup:
	dns_ssutable_detach(&table);
	return (result);
}