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