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