ssu.c revision 1.3
1/*	$NetBSD: ssu.c,v 1.3 2019/01/09 16:55:12 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14/*! \file */
15
16#include <config.h>
17
18#include <stdbool.h>
19
20#include <isc/magic.h>
21#include <isc/mem.h>
22#include <isc/netaddr.h>
23#include <isc/print.h>
24#include <isc/result.h>
25#include <isc/string.h>
26#include <isc/util.h>
27
28#include <dns/dlz.h>
29#include <dns/fixedname.h>
30#include <dns/name.h>
31#include <dns/ssu.h>
32
33#include <dst/gssapi.h>
34#include <dst/dst.h>
35
36#define SSUTABLEMAGIC		ISC_MAGIC('S', 'S', 'U', 'T')
37#define VALID_SSUTABLE(table)	ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
38
39#define SSURULEMAGIC		ISC_MAGIC('S', 'S', 'U', 'R')
40#define VALID_SSURULE(table)	ISC_MAGIC_VALID(table, SSURULEMAGIC)
41
42struct dns_ssurule {
43	unsigned int magic;
44	bool grant;		/*%< is this a grant or a deny? */
45	dns_ssumatchtype_t matchtype;	/*%< which type of pattern match? */
46	dns_name_t *identity;		/*%< the identity to match */
47	dns_name_t *name;		/*%< the name being updated */
48	unsigned int ntypes;		/*%< number of data types covered */
49	dns_rdatatype_t *types;		/*%< the data types.  Can include */
50					/*   ANY. if NULL, defaults to all */
51					/*   types except SIG, SOA, and NS */
52	ISC_LINK(dns_ssurule_t) link;
53};
54
55struct dns_ssutable {
56	unsigned int magic;
57	isc_mem_t *mctx;
58	unsigned int references;
59	isc_mutex_t lock;
60	dns_dlzdb_t *dlzdatabase;
61	ISC_LIST(dns_ssurule_t) rules;
62};
63
64isc_result_t
65dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) {
66	dns_ssutable_t *table;
67
68	REQUIRE(tablep != NULL && *tablep == NULL);
69	REQUIRE(mctx != NULL);
70
71	table = isc_mem_get(mctx, sizeof(dns_ssutable_t));
72	if (table == NULL)
73		return (ISC_R_NOMEMORY);
74	isc_mutex_init(&table->lock);
75	table->references = 1;
76	table->mctx = NULL;
77	isc_mem_attach(mctx, &table->mctx);
78	ISC_LIST_INIT(table->rules);
79	table->magic = SSUTABLEMAGIC;
80	*tablep = table;
81	return (ISC_R_SUCCESS);
82}
83
84static inline void
85destroy(dns_ssutable_t *table) {
86	isc_mem_t *mctx;
87
88	REQUIRE(VALID_SSUTABLE(table));
89
90	mctx = table->mctx;
91	while (!ISC_LIST_EMPTY(table->rules)) {
92		dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
93		if (rule->identity != NULL) {
94			dns_name_free(rule->identity, mctx);
95			isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
96		}
97		if (rule->name != NULL) {
98			dns_name_free(rule->name, mctx);
99			isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
100		}
101		if (rule->types != NULL)
102			isc_mem_put(mctx, rule->types,
103				    rule->ntypes * sizeof(dns_rdatatype_t));
104		ISC_LIST_UNLINK(table->rules, rule, link);
105		rule->magic = 0;
106		isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
107	}
108	isc_mutex_destroy(&table->lock);
109	table->magic = 0;
110	isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t));
111}
112
113void
114dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
115	REQUIRE(VALID_SSUTABLE(source));
116	REQUIRE(targetp != NULL && *targetp == NULL);
117
118	LOCK(&source->lock);
119
120	INSIST(source->references > 0);
121	source->references++;
122	INSIST(source->references != 0);
123
124	UNLOCK(&source->lock);
125
126	*targetp = source;
127}
128
129void
130dns_ssutable_detach(dns_ssutable_t **tablep) {
131	dns_ssutable_t *table;
132	bool done = false;
133
134	REQUIRE(tablep != NULL);
135	table = *tablep;
136	REQUIRE(VALID_SSUTABLE(table));
137
138	LOCK(&table->lock);
139
140	INSIST(table->references > 0);
141	if (--table->references == 0)
142		done = true;
143	UNLOCK(&table->lock);
144
145	*tablep = NULL;
146
147	if (done)
148		destroy(table);
149}
150
151isc_result_t
152dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
153		     const dns_name_t *identity, dns_ssumatchtype_t matchtype,
154		     const dns_name_t *name, unsigned int ntypes,
155		     dns_rdatatype_t *types)
156{
157	dns_ssurule_t *rule;
158	isc_mem_t *mctx;
159	isc_result_t result;
160
161	REQUIRE(VALID_SSUTABLE(table));
162	REQUIRE(dns_name_isabsolute(identity));
163	REQUIRE(dns_name_isabsolute(name));
164	REQUIRE(matchtype <= dns_ssumatchtype_max);
165	if (matchtype == dns_ssumatchtype_wildcard)
166		REQUIRE(dns_name_iswildcard(name));
167	if (ntypes > 0)
168		REQUIRE(types != NULL);
169
170	mctx = table->mctx;
171	rule = isc_mem_get(mctx, sizeof(dns_ssurule_t));
172	if (rule == NULL)
173		return (ISC_R_NOMEMORY);
174
175	rule->identity = NULL;
176	rule->name = NULL;
177	rule->types = NULL;
178
179	rule->grant = grant;
180
181	rule->identity = isc_mem_get(mctx, sizeof(dns_name_t));
182	if (rule->identity == NULL) {
183		result = ISC_R_NOMEMORY;
184		goto failure;
185	}
186	dns_name_init(rule->identity, NULL);
187	result = dns_name_dup(identity, mctx, rule->identity);
188	if (result != ISC_R_SUCCESS)
189		goto failure;
190
191	rule->name = isc_mem_get(mctx, sizeof(dns_name_t));
192	if (rule->name == NULL) {
193		result = ISC_R_NOMEMORY;
194		goto failure;
195	}
196	dns_name_init(rule->name, NULL);
197	result = dns_name_dup(name, mctx, rule->name);
198	if (result != ISC_R_SUCCESS)
199		goto failure;
200
201	rule->matchtype = matchtype;
202
203	rule->ntypes = ntypes;
204	if (ntypes > 0) {
205		rule->types = isc_mem_get(mctx,
206					  ntypes * sizeof(dns_rdatatype_t));
207		if (rule->types == NULL) {
208			result = ISC_R_NOMEMORY;
209			goto failure;
210		}
211		memmove(rule->types, types, ntypes * sizeof(dns_rdatatype_t));
212	} else
213		rule->types = NULL;
214
215	rule->magic = SSURULEMAGIC;
216	ISC_LIST_INITANDAPPEND(table->rules, rule, link);
217
218	return (ISC_R_SUCCESS);
219
220 failure:
221	if (rule->identity != NULL) {
222		if (dns_name_dynamic(rule->identity))
223			dns_name_free(rule->identity, mctx);
224		isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
225	}
226	if (rule->name != NULL) {
227		if (dns_name_dynamic(rule->name))
228			dns_name_free(rule->name, mctx);
229		isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
230	}
231	if (rule->types != NULL)
232		isc_mem_put(mctx, rule->types,
233			    ntypes * sizeof(dns_rdatatype_t));
234	isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
235
236	return (result);
237}
238
239static inline bool
240isusertype(dns_rdatatype_t type) {
241	return (type != dns_rdatatype_ns &&
242		type != dns_rdatatype_soa &&
243		type != dns_rdatatype_rrsig);
244}
245
246static void
247reverse_from_address(dns_name_t *tcpself, const isc_netaddr_t *tcpaddr) {
248	char buf[16 * 4 + sizeof("IP6.ARPA.")];
249	isc_result_t result;
250	const unsigned char *ap;
251	isc_buffer_t b;
252	unsigned long l;
253
254	switch (tcpaddr->family) {
255	case AF_INET:
256		l = ntohl(tcpaddr->type.in.s_addr);
257		result = snprintf(buf, sizeof(buf),
258				  "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.",
259				  (l >> 0) & 0xff, (l >> 8) & 0xff,
260				  (l >> 16) & 0xff, (l >> 24) & 0xff);
261		RUNTIME_CHECK(result < sizeof(buf));
262		break;
263	case AF_INET6:
264		ap = tcpaddr->type.in6.s6_addr;
265		result = snprintf(buf, sizeof(buf),
266				  "%x.%x.%x.%x.%x.%x.%x.%x."
267				  "%x.%x.%x.%x.%x.%x.%x.%x."
268				  "%x.%x.%x.%x.%x.%x.%x.%x."
269				  "%x.%x.%x.%x.%x.%x.%x.%x."
270				  "IP6.ARPA.",
271				  ap[15] & 0x0f, (ap[15] >> 4) & 0x0f,
272				  ap[14] & 0x0f, (ap[14] >> 4) & 0x0f,
273				  ap[13] & 0x0f, (ap[13] >> 4) & 0x0f,
274				  ap[12] & 0x0f, (ap[12] >> 4) & 0x0f,
275				  ap[11] & 0x0f, (ap[11] >> 4) & 0x0f,
276				  ap[10] & 0x0f, (ap[10] >> 4) & 0x0f,
277				  ap[9] & 0x0f, (ap[9] >> 4) & 0x0f,
278				  ap[8] & 0x0f, (ap[8] >> 4) & 0x0f,
279				  ap[7] & 0x0f, (ap[7] >> 4) & 0x0f,
280				  ap[6] & 0x0f, (ap[6] >> 4) & 0x0f,
281				  ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
282				  ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
283				  ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
284				  ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
285				  ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
286				  ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
287		RUNTIME_CHECK(result < sizeof(buf));
288		break;
289	default:
290		INSIST(0);
291		ISC_UNREACHABLE();
292	}
293	isc_buffer_init(&b, buf, strlen(buf));
294	isc_buffer_add(&b, strlen(buf));
295	result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL);
296	RUNTIME_CHECK(result == ISC_R_SUCCESS);
297}
298
299static void
300stf_from_address(dns_name_t *stfself, const isc_netaddr_t *tcpaddr) {
301	char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")];
302	isc_result_t result;
303	const unsigned char *ap;
304	isc_buffer_t b;
305	unsigned long l;
306
307	switch(tcpaddr->family) {
308	case AF_INET:
309		l = ntohl(tcpaddr->type.in.s_addr);
310		result = snprintf(buf, sizeof(buf),
311				  "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx"
312				  "2.0.0.2.IP6.ARPA.",
313				  l & 0xf, (l >> 4) & 0xf,
314				  (l >> 8) & 0xf, (l >> 12) & 0xf,
315				  (l >> 16) & 0xf, (l >> 20) & 0xf,
316				  (l >> 24) & 0xf, (l >> 28) & 0xf);
317		RUNTIME_CHECK(result < sizeof(buf));
318		break;
319	case AF_INET6:
320		ap = tcpaddr->type.in6.s6_addr;
321		result = snprintf(buf, sizeof(buf),
322				  "%x.%x.%x.%x.%x.%x.%x.%x."
323				  "%x.%x.%x.%x.IP6.ARPA.",
324				  ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
325				  ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
326				  ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
327				  ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
328				  ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
329				  ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
330		RUNTIME_CHECK(result < sizeof(buf));
331		break;
332	default:
333		INSIST(0);
334		ISC_UNREACHABLE();
335	}
336	isc_buffer_init(&b, buf, strlen(buf));
337	isc_buffer_add(&b, strlen(buf));
338	result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL);
339	RUNTIME_CHECK(result == ISC_R_SUCCESS);
340}
341
342bool
343dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
344			const dns_name_t *name, const isc_netaddr_t *addr,
345			bool tcp, const dns_aclenv_t *env,
346			dns_rdatatype_t type, const dst_key_t *key)
347{
348	dns_ssurule_t *rule;
349	unsigned int i;
350	dns_fixedname_t fixed;
351	dns_name_t *wildcard;
352	dns_name_t *tcpself;
353	dns_name_t *stfself;
354	isc_result_t result;
355	int match;
356
357	REQUIRE(VALID_SSUTABLE(table));
358	REQUIRE(signer == NULL || dns_name_isabsolute(signer));
359	REQUIRE(dns_name_isabsolute(name));
360	REQUIRE(addr == NULL || env != NULL);
361
362	if (signer == NULL && addr == NULL)
363		return (false);
364
365	for (rule = ISC_LIST_HEAD(table->rules);
366	     rule != NULL;
367	     rule = ISC_LIST_NEXT(rule, link))
368	{
369		switch (rule->matchtype) {
370		case dns_ssumatchtype_name:
371		case dns_ssumatchtype_local:
372		case dns_ssumatchtype_subdomain:
373		case dns_ssumatchtype_wildcard:
374		case dns_ssumatchtype_self:
375		case dns_ssumatchtype_selfsub:
376		case dns_ssumatchtype_selfwild:
377			if (signer == NULL)
378				continue;
379			if (dns_name_iswildcard(rule->identity)) {
380				if (!dns_name_matcheswildcard(signer,
381							      rule->identity))
382					continue;
383			} else {
384				if (!dns_name_equal(signer, rule->identity))
385					continue;
386			}
387			break;
388		case dns_ssumatchtype_selfkrb5:
389		case dns_ssumatchtype_selfms:
390		case dns_ssumatchtype_selfsubkrb5:
391		case dns_ssumatchtype_selfsubms:
392		case dns_ssumatchtype_subdomainkrb5:
393		case dns_ssumatchtype_subdomainms:
394			if (signer == NULL)
395				continue;
396			break;
397		case dns_ssumatchtype_tcpself:
398		case dns_ssumatchtype_6to4self:
399			if (!tcp || addr == NULL)
400				continue;
401			break;
402		case dns_ssumatchtype_external:
403		case dns_ssumatchtype_dlz:
404			break;
405		}
406
407		switch (rule->matchtype) {
408		case dns_ssumatchtype_name:
409			if (!dns_name_equal(name, rule->name))
410				continue;
411			break;
412		case dns_ssumatchtype_subdomain:
413			if (!dns_name_issubdomain(name, rule->name))
414				continue;
415			break;
416		case dns_ssumatchtype_local:
417			if (addr == NULL) {
418				continue;
419			}
420			if (!dns_name_issubdomain(name, rule->name)) {
421				continue;
422			}
423			dns_acl_match(addr, NULL, env->localhost,
424				      NULL, &match, NULL);
425			if (match == 0) {
426				if (signer != NULL) {
427					isc_log_write(dns_lctx,
428						      DNS_LOGCATEGORY_GENERAL,
429						      DNS_LOGMODULE_SSU,
430						      ISC_LOG_WARNING,
431						      "update-policy local: "
432						      "match on session "
433						      "key not from "
434						      "localhost");
435				}
436				continue;
437			}
438			break;
439		case dns_ssumatchtype_wildcard:
440			if (!dns_name_matcheswildcard(name, rule->name))
441				continue;
442			break;
443		case dns_ssumatchtype_self:
444			if (!dns_name_equal(signer, name))
445				continue;
446			break;
447		case dns_ssumatchtype_selfsub:
448			if (!dns_name_issubdomain(name, signer))
449				continue;
450			break;
451		case dns_ssumatchtype_selfwild:
452			wildcard = dns_fixedname_initname(&fixed);
453			result = dns_name_concatenate(dns_wildcardname, signer,
454						      wildcard, NULL);
455			if (result != ISC_R_SUCCESS)
456				continue;
457			if (!dns_name_matcheswildcard(name, wildcard))
458				continue;
459			break;
460		case dns_ssumatchtype_selfkrb5:
461			if (dst_gssapi_identitymatchesrealmkrb5(signer, name,
462								rule->identity,
463								false))
464			{
465				break;
466			}
467			continue;
468		case dns_ssumatchtype_selfms:
469			if (dst_gssapi_identitymatchesrealmms(signer, name,
470							      rule->identity,
471							      false))
472			{
473				break;
474			}
475			continue;
476		case dns_ssumatchtype_selfsubkrb5:
477			if (dst_gssapi_identitymatchesrealmkrb5(signer, name,
478								rule->identity,
479								true))
480			{
481				break;
482			}
483			continue;
484		case dns_ssumatchtype_selfsubms:
485			if (dst_gssapi_identitymatchesrealmms(signer, name,
486							      rule->identity,
487							      true))
488				break;
489			continue;
490		case dns_ssumatchtype_subdomainkrb5:
491			if (!dns_name_issubdomain(name, rule->name))
492				continue;
493			if (dst_gssapi_identitymatchesrealmkrb5(signer, NULL,
494								rule->identity,
495								false))
496			{
497				break;
498			}
499			continue;
500		case dns_ssumatchtype_subdomainms:
501			if (!dns_name_issubdomain(name, rule->name))
502				continue;
503			if (dst_gssapi_identitymatchesrealmms(signer, NULL,
504							      rule->identity,
505							      false))
506			{
507				break;
508			}
509			continue;
510		case dns_ssumatchtype_tcpself:
511			tcpself = dns_fixedname_initname(&fixed);
512			reverse_from_address(tcpself, addr);
513			if (dns_name_iswildcard(rule->identity)) {
514				if (!dns_name_matcheswildcard(tcpself,
515							      rule->identity))
516					continue;
517			} else {
518				if (!dns_name_equal(tcpself, rule->identity))
519					continue;
520			}
521			if (!dns_name_equal(tcpself, name))
522				continue;
523			break;
524		case dns_ssumatchtype_6to4self:
525			stfself = dns_fixedname_initname(&fixed);
526			stf_from_address(stfself, addr);
527			if (dns_name_iswildcard(rule->identity)) {
528				if (!dns_name_matcheswildcard(stfself,
529							      rule->identity))
530					continue;
531			} else {
532				if (!dns_name_equal(stfself, rule->identity))
533					continue;
534			}
535			if (!dns_name_equal(stfself, name))
536				continue;
537			break;
538		case dns_ssumatchtype_external:
539			if (!dns_ssu_external_match(rule->identity, signer,
540						    name, addr, type, key,
541						    table->mctx))
542				continue;
543			break;
544		case dns_ssumatchtype_dlz:
545			if (!dns_dlz_ssumatch(table->dlzdatabase, signer,
546					      name, addr, type, key))
547				continue;
548			break;
549		}
550
551		if (rule->ntypes == 0) {
552			/*
553			 * If this is a DLZ rule, then the DLZ ssu
554			 * checks will have already checked
555			 * the type.
556			 */
557			if (rule->matchtype != dns_ssumatchtype_dlz &&
558			    !isusertype(type))
559				continue;
560		} else {
561			for (i = 0; i < rule->ntypes; i++) {
562				if (rule->types[i] == dns_rdatatype_any ||
563				    rule->types[i] == type)
564					break;
565			}
566			if (i == rule->ntypes)
567				continue;
568		}
569		return (rule->grant);
570	}
571
572	return (false);
573}
574
575bool
576dns_ssurule_isgrant(const dns_ssurule_t *rule) {
577	REQUIRE(VALID_SSURULE(rule));
578	return (rule->grant);
579}
580
581dns_name_t *
582dns_ssurule_identity(const dns_ssurule_t *rule) {
583	REQUIRE(VALID_SSURULE(rule));
584	return (rule->identity);
585}
586
587unsigned int
588dns_ssurule_matchtype(const dns_ssurule_t *rule) {
589	REQUIRE(VALID_SSURULE(rule));
590	return (rule->matchtype);
591}
592
593dns_name_t *
594dns_ssurule_name(const dns_ssurule_t *rule) {
595	REQUIRE(VALID_SSURULE(rule));
596	return (rule->name);
597}
598
599unsigned int
600dns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types) {
601	REQUIRE(VALID_SSURULE(rule));
602	REQUIRE(types != NULL && *types != NULL);
603	*types = rule->types;
604	return (rule->ntypes);
605}
606
607isc_result_t
608dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
609	REQUIRE(VALID_SSUTABLE(table));
610	REQUIRE(rule != NULL && *rule == NULL);
611	*rule = ISC_LIST_HEAD(table->rules);
612	return (*rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
613}
614
615isc_result_t
616dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
617	REQUIRE(VALID_SSURULE(rule));
618	REQUIRE(nextrule != NULL && *nextrule == NULL);
619	*nextrule = ISC_LIST_NEXT(rule, link);
620	return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
621}
622
623/*
624 * Create a specialised SSU table that points at an external DLZ database
625 */
626isc_result_t
627dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
628		       dns_dlzdb_t *dlzdatabase)
629{
630	isc_result_t result;
631	dns_ssurule_t *rule;
632	dns_ssutable_t *table = NULL;
633
634	REQUIRE(tablep != NULL && *tablep == NULL);
635
636	result = dns_ssutable_create(mctx, &table);
637	if (result != ISC_R_SUCCESS)
638		return (result);
639
640	table->dlzdatabase = dlzdatabase;
641
642	rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t));
643	if (rule == NULL) {
644		dns_ssutable_detach(&table);
645		return (ISC_R_NOMEMORY);
646	}
647
648	rule->identity = NULL;
649	rule->name = NULL;
650	rule->types = NULL;
651	rule->grant = true;
652	rule->matchtype = dns_ssumatchtype_dlz;
653	rule->ntypes = 0;
654	rule->types = NULL;
655	rule->magic = SSURULEMAGIC;
656
657	ISC_LIST_INITANDAPPEND(table->rules, rule, link);
658	*tablep = table;
659	return (ISC_R_SUCCESS);
660}
661
662isc_result_t
663dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype) {
664
665	REQUIRE(str != NULL);
666	REQUIRE(mtype != NULL);
667
668	if (strcasecmp(str, "name") == 0) {
669		*mtype = dns_ssumatchtype_name;
670	} else if (strcasecmp(str, "subdomain") == 0) {
671		*mtype = dns_ssumatchtype_subdomain;
672	} else if (strcasecmp(str, "wildcard") == 0) {
673		*mtype = dns_ssumatchtype_wildcard;
674	} else if (strcasecmp(str, "self") == 0) {
675		*mtype = dns_ssumatchtype_self;
676	} else if (strcasecmp(str, "selfsub") == 0) {
677		*mtype = dns_ssumatchtype_selfsub;
678	} else if (strcasecmp(str, "selfwild") == 0) {
679		*mtype = dns_ssumatchtype_selfwild;
680	} else if (strcasecmp(str, "ms-self") == 0) {
681		*mtype = dns_ssumatchtype_selfms;
682	} else if (strcasecmp(str, "ms-selfsub") == 0) {
683		*mtype = dns_ssumatchtype_selfsubms;
684	} else if (strcasecmp(str, "krb5-self") == 0) {
685		*mtype = dns_ssumatchtype_selfkrb5;
686	} else if (strcasecmp(str, "krb5-selfsub") == 0) {
687		*mtype = dns_ssumatchtype_selfsubkrb5;
688	} else if (strcasecmp(str, "ms-subdomain") == 0) {
689		*mtype = dns_ssumatchtype_subdomainms;
690	} else if (strcasecmp(str, "krb5-subdomain") == 0) {
691		*mtype = dns_ssumatchtype_subdomainkrb5;
692	} else if (strcasecmp(str, "tcp-self") == 0) {
693		*mtype = dns_ssumatchtype_tcpself;
694	} else if (strcasecmp(str, "6to4-self") == 0) {
695		*mtype = dns_ssumatchtype_6to4self;
696	} else if (strcasecmp(str, "zonesub") == 0) {
697		*mtype = dns_ssumatchtype_subdomain;
698	} else if (strcasecmp(str, "external") == 0) {
699		*mtype = dns_ssumatchtype_external;
700	} else {
701		return (ISC_R_NOTFOUND);
702	}
703	return (ISC_R_SUCCESS);
704}
705