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