xref: /minix/external/bsd/bind/dist/lib/dns/ssu.c (revision bb9622b5)
1 /*	$NetBSD: ssu.c,v 1.6 2014/12/10 04:37:58 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2008, 2010, 2011, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*! \file */
21 /*
22  * Id: ssu.c,v 1.38 2011/01/06 23:47:00 tbox Exp
23  * Principal Author: Brian Wellington
24  */
25 
26 #include <config.h>
27 
28 #include <isc/magic.h>
29 #include <isc/mem.h>
30 #include <isc/netaddr.h>
31 #include <isc/result.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34 
35 #include <dns/dlz.h>
36 #include <dns/fixedname.h>
37 #include <dns/name.h>
38 #include <dns/ssu.h>
39 
40 #include <dst/gssapi.h>
41 #include <dst/dst.h>
42 
43 #define SSUTABLEMAGIC		ISC_MAGIC('S', 'S', 'U', 'T')
44 #define VALID_SSUTABLE(table)	ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
45 
46 #define SSURULEMAGIC		ISC_MAGIC('S', 'S', 'U', 'R')
47 #define VALID_SSURULE(table)	ISC_MAGIC_VALID(table, SSURULEMAGIC)
48 
49 struct dns_ssurule {
50 	unsigned int magic;
51 	isc_boolean_t grant;	/*%< is this a grant or a deny? */
52 	unsigned int matchtype;	/*%< which type of pattern match? */
53 	dns_name_t *identity;	/*%< the identity to match */
54 	dns_name_t *name;	/*%< the name being updated */
55 	unsigned int ntypes;	/*%< number of data types covered */
56 	dns_rdatatype_t *types;	/*%< the data types.  Can include ANY, */
57 				/*%< defaults to all but SIG,SOA,NS if NULL */
58 	ISC_LINK(dns_ssurule_t) link;
59 };
60 
61 struct dns_ssutable {
62 	unsigned int magic;
63 	isc_mem_t *mctx;
64 	unsigned int references;
65 	isc_mutex_t lock;
66 	dns_dlzdb_t *dlzdatabase;
67 	ISC_LIST(dns_ssurule_t) rules;
68 };
69 
70 isc_result_t
71 dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) {
72 	isc_result_t result;
73 	dns_ssutable_t *table;
74 
75 	REQUIRE(tablep != NULL && *tablep == NULL);
76 	REQUIRE(mctx != NULL);
77 
78 	table = isc_mem_get(mctx, sizeof(dns_ssutable_t));
79 	if (table == NULL)
80 		return (ISC_R_NOMEMORY);
81 	result = isc_mutex_init(&table->lock);
82 	if (result != ISC_R_SUCCESS) {
83 		isc_mem_put(mctx, table, sizeof(dns_ssutable_t));
84 		return (result);
85 	}
86 	table->references = 1;
87 	table->mctx = NULL;
88 	isc_mem_attach(mctx, &table->mctx);
89 	ISC_LIST_INIT(table->rules);
90 	table->magic = SSUTABLEMAGIC;
91 	*tablep = table;
92 	return (ISC_R_SUCCESS);
93 }
94 
95 static inline void
96 destroy(dns_ssutable_t *table) {
97 	isc_mem_t *mctx;
98 
99 	REQUIRE(VALID_SSUTABLE(table));
100 
101 	mctx = table->mctx;
102 	while (!ISC_LIST_EMPTY(table->rules)) {
103 		dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
104 		if (rule->identity != NULL) {
105 			dns_name_free(rule->identity, mctx);
106 			isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
107 		}
108 		if (rule->name != NULL) {
109 			dns_name_free(rule->name, mctx);
110 			isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
111 		}
112 		if (rule->types != NULL)
113 			isc_mem_put(mctx, rule->types,
114 				    rule->ntypes * sizeof(dns_rdatatype_t));
115 		ISC_LIST_UNLINK(table->rules, rule, link);
116 		rule->magic = 0;
117 		isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
118 	}
119 	DESTROYLOCK(&table->lock);
120 	table->magic = 0;
121 	isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t));
122 }
123 
124 void
125 dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
126 	REQUIRE(VALID_SSUTABLE(source));
127 	REQUIRE(targetp != NULL && *targetp == NULL);
128 
129 	LOCK(&source->lock);
130 
131 	INSIST(source->references > 0);
132 	source->references++;
133 	INSIST(source->references != 0);
134 
135 	UNLOCK(&source->lock);
136 
137 	*targetp = source;
138 }
139 
140 void
141 dns_ssutable_detach(dns_ssutable_t **tablep) {
142 	dns_ssutable_t *table;
143 	isc_boolean_t done = ISC_FALSE;
144 
145 	REQUIRE(tablep != NULL);
146 	table = *tablep;
147 	REQUIRE(VALID_SSUTABLE(table));
148 
149 	LOCK(&table->lock);
150 
151 	INSIST(table->references > 0);
152 	if (--table->references == 0)
153 		done = ISC_TRUE;
154 	UNLOCK(&table->lock);
155 
156 	*tablep = NULL;
157 
158 	if (done)
159 		destroy(table);
160 }
161 
162 isc_result_t
163 dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
164 		     dns_name_t *identity, unsigned int matchtype,
165 		     dns_name_t *name, unsigned int ntypes,
166 		     dns_rdatatype_t *types)
167 {
168 	dns_ssurule_t *rule;
169 	isc_mem_t *mctx;
170 	isc_result_t result;
171 
172 	REQUIRE(VALID_SSUTABLE(table));
173 	REQUIRE(dns_name_isabsolute(identity));
174 	REQUIRE(dns_name_isabsolute(name));
175 	REQUIRE(matchtype <= DNS_SSUMATCHTYPE_MAX);
176 	if (matchtype == DNS_SSUMATCHTYPE_WILDCARD)
177 		REQUIRE(dns_name_iswildcard(name));
178 	if (ntypes > 0)
179 		REQUIRE(types != NULL);
180 
181 	mctx = table->mctx;
182 	rule = isc_mem_get(mctx, sizeof(dns_ssurule_t));
183 	if (rule == NULL)
184 		return (ISC_R_NOMEMORY);
185 
186 	rule->identity = NULL;
187 	rule->name = NULL;
188 	rule->types = NULL;
189 
190 	rule->grant = grant;
191 
192 	rule->identity = isc_mem_get(mctx, sizeof(dns_name_t));
193 	if (rule->identity == NULL) {
194 		result = ISC_R_NOMEMORY;
195 		goto failure;
196 	}
197 	dns_name_init(rule->identity, NULL);
198 	result = dns_name_dup(identity, mctx, rule->identity);
199 	if (result != ISC_R_SUCCESS)
200 		goto failure;
201 
202 	rule->name = isc_mem_get(mctx, sizeof(dns_name_t));
203 	if (rule->name == NULL) {
204 		result = ISC_R_NOMEMORY;
205 		goto failure;
206 	}
207 	dns_name_init(rule->name, NULL);
208 	result = dns_name_dup(name, mctx, rule->name);
209 	if (result != ISC_R_SUCCESS)
210 		goto failure;
211 
212 	rule->matchtype = matchtype;
213 
214 	rule->ntypes = ntypes;
215 	if (ntypes > 0) {
216 		rule->types = isc_mem_get(mctx,
217 					  ntypes * sizeof(dns_rdatatype_t));
218 		if (rule->types == NULL) {
219 			result = ISC_R_NOMEMORY;
220 			goto failure;
221 		}
222 		memmove(rule->types, types, ntypes * sizeof(dns_rdatatype_t));
223 	} else
224 		rule->types = NULL;
225 
226 	rule->magic = SSURULEMAGIC;
227 	ISC_LIST_INITANDAPPEND(table->rules, rule, link);
228 
229 	return (ISC_R_SUCCESS);
230 
231  failure:
232 	if (rule->identity != NULL) {
233 		if (dns_name_dynamic(rule->identity))
234 			dns_name_free(rule->identity, mctx);
235 		isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
236 	}
237 	if (rule->name != NULL) {
238 		if (dns_name_dynamic(rule->name))
239 			dns_name_free(rule->name, mctx);
240 		isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
241 	}
242 	if (rule->types != NULL)
243 		isc_mem_put(mctx, rule->types,
244 			    ntypes * sizeof(dns_rdatatype_t));
245 	isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
246 
247 	return (result);
248 }
249 
250 static inline isc_boolean_t
251 isusertype(dns_rdatatype_t type) {
252 	return (ISC_TF(type != dns_rdatatype_ns &&
253 		       type != dns_rdatatype_soa &&
254 		       type != dns_rdatatype_rrsig));
255 }
256 
257 static void
258 reverse_from_address(dns_name_t *tcpself, isc_netaddr_t *tcpaddr) {
259 	char buf[16 * 4 + sizeof("IP6.ARPA.")];
260 	isc_result_t result;
261 	unsigned char *ap;
262 	isc_buffer_t b;
263 	unsigned long l;
264 
265 	switch (tcpaddr->family) {
266 	case AF_INET:
267 		l = ntohl(tcpaddr->type.in.s_addr);
268 		result = isc_string_printf(buf, sizeof(buf),
269 					   "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.",
270 					   (l >> 0) & 0xff, (l >> 8) & 0xff,
271 					   (l >> 16) & 0xff, (l >> 24) & 0xff);
272 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
273 		break;
274 	case AF_INET6:
275 		ap = tcpaddr->type.in6.s6_addr;
276 		result = isc_string_printf(buf, sizeof(buf),
277 					   "%x.%x.%x.%x.%x.%x.%x.%x."
278 					   "%x.%x.%x.%x.%x.%x.%x.%x."
279 					   "%x.%x.%x.%x.%x.%x.%x.%x."
280 					   "%x.%x.%x.%x.%x.%x.%x.%x."
281 					   "IP6.ARPA.",
282 					   ap[15] & 0x0f, (ap[15] >> 4) & 0x0f,
283 					   ap[14] & 0x0f, (ap[14] >> 4) & 0x0f,
284 					   ap[13] & 0x0f, (ap[13] >> 4) & 0x0f,
285 					   ap[12] & 0x0f, (ap[12] >> 4) & 0x0f,
286 					   ap[11] & 0x0f, (ap[11] >> 4) & 0x0f,
287 					   ap[10] & 0x0f, (ap[10] >> 4) & 0x0f,
288 					   ap[9] & 0x0f, (ap[9] >> 4) & 0x0f,
289 					   ap[8] & 0x0f, (ap[8] >> 4) & 0x0f,
290 					   ap[7] & 0x0f, (ap[7] >> 4) & 0x0f,
291 					   ap[6] & 0x0f, (ap[6] >> 4) & 0x0f,
292 					   ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
293 					   ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
294 					   ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
295 					   ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
296 					   ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
297 					   ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
298 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
299 		break;
300 	default:
301 		INSIST(0);
302 	}
303 	isc_buffer_init(&b, buf, strlen(buf));
304 	isc_buffer_add(&b, strlen(buf));
305 	result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL);
306 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
307 }
308 
309 static void
310 stf_from_address(dns_name_t *stfself, isc_netaddr_t *tcpaddr) {
311 	char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")];
312 	isc_result_t result;
313 	unsigned char *ap;
314 	isc_buffer_t b;
315 	unsigned long l;
316 
317 	switch(tcpaddr->family) {
318 	case AF_INET:
319 		l = ntohl(tcpaddr->type.in.s_addr);
320 		result = isc_string_printf(buf, sizeof(buf),
321 					   "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx"
322 					   "2.0.0.2.IP6.ARPA.",
323 					   l & 0xf, (l >> 4) & 0xf,
324 					   (l >> 8) & 0xf, (l >> 12) & 0xf,
325 					   (l >> 16) & 0xf, (l >> 20) & 0xf,
326 					   (l >> 24) & 0xf, (l >> 28) & 0xf);
327 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
328 		break;
329 	case AF_INET6:
330 		ap = tcpaddr->type.in6.s6_addr;
331 		result = isc_string_printf(buf, sizeof(buf),
332 					   "%x.%x.%x.%x.%x.%x.%x.%x."
333 					   "%x.%x.%x.%x.IP6.ARPA.",
334 					   ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
335 					   ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
336 					   ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
337 					   ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
338 					   ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
339 					   ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
340 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
341 		break;
342 	default:
343 		INSIST(0);
344 	}
345 	isc_buffer_init(&b, buf, strlen(buf));
346 	isc_buffer_add(&b, strlen(buf));
347 	result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL);
348 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
349 }
350 
351 isc_boolean_t
352 dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
353 			dns_name_t *name, isc_netaddr_t *tcpaddr,
354 			dns_rdatatype_t type,
355 			const dst_key_t *key)
356 {
357 	dns_ssurule_t *rule;
358 	unsigned int i;
359 	dns_fixedname_t fixed;
360 	dns_name_t *wildcard;
361 	dns_name_t *tcpself;
362 	dns_name_t *stfself;
363 	isc_result_t result;
364 
365 	REQUIRE(VALID_SSUTABLE(table));
366 	REQUIRE(signer == NULL || dns_name_isabsolute(signer));
367 	REQUIRE(dns_name_isabsolute(name));
368 
369 	if (signer == NULL && tcpaddr == NULL)
370 		return (ISC_FALSE);
371 
372 	for (rule = ISC_LIST_HEAD(table->rules);
373 	     rule != NULL;
374 	     rule = ISC_LIST_NEXT(rule, link))
375 	{
376 		switch (rule->matchtype) {
377 		case DNS_SSUMATCHTYPE_NAME:
378 		case DNS_SSUMATCHTYPE_SUBDOMAIN:
379 		case DNS_SSUMATCHTYPE_WILDCARD:
380 		case DNS_SSUMATCHTYPE_SELF:
381 		case DNS_SSUMATCHTYPE_SELFSUB:
382 		case DNS_SSUMATCHTYPE_SELFWILD:
383 			if (signer == NULL)
384 				continue;
385 			if (dns_name_iswildcard(rule->identity)) {
386 				if (!dns_name_matcheswildcard(signer,
387 							      rule->identity))
388 					continue;
389 			} else {
390 				if (!dns_name_equal(signer, rule->identity))
391 					continue;
392 			}
393 			break;
394 		case DNS_SSUMATCHTYPE_SELFKRB5:
395 		case DNS_SSUMATCHTYPE_SELFMS:
396 		case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
397 		case DNS_SSUMATCHTYPE_SUBDOMAINMS:
398 			if (signer == NULL)
399 				continue;
400 			break;
401 		case DNS_SSUMATCHTYPE_TCPSELF:
402 		case DNS_SSUMATCHTYPE_6TO4SELF:
403 			if (tcpaddr == NULL)
404 				continue;
405 			break;
406 		}
407 
408 		switch (rule->matchtype) {
409 		case DNS_SSUMATCHTYPE_NAME:
410 			if (!dns_name_equal(name, rule->name))
411 				continue;
412 			break;
413 		case DNS_SSUMATCHTYPE_SUBDOMAIN:
414 			if (!dns_name_issubdomain(name, rule->name))
415 				continue;
416 			break;
417 		case DNS_SSUMATCHTYPE_WILDCARD:
418 			if (!dns_name_matcheswildcard(name, rule->name))
419 				continue;
420 			break;
421 		case DNS_SSUMATCHTYPE_SELF:
422 			if (!dns_name_equal(signer, name))
423 				continue;
424 			break;
425 		case DNS_SSUMATCHTYPE_SELFSUB:
426 			if (!dns_name_issubdomain(name, signer))
427 				continue;
428 			break;
429 		case DNS_SSUMATCHTYPE_SELFWILD:
430 			dns_fixedname_init(&fixed);
431 			wildcard = dns_fixedname_name(&fixed);
432 			result = dns_name_concatenate(dns_wildcardname, signer,
433 						      wildcard, NULL);
434 			if (result != ISC_R_SUCCESS)
435 				continue;
436 			if (!dns_name_matcheswildcard(name, wildcard))
437 				continue;
438 			break;
439 		case DNS_SSUMATCHTYPE_SELFKRB5:
440 			if (!dst_gssapi_identitymatchesrealmkrb5(signer, name,
441 							       rule->identity))
442 				continue;
443 			break;
444 		case DNS_SSUMATCHTYPE_SELFMS:
445 			if (!dst_gssapi_identitymatchesrealmms(signer, name,
446 							       rule->identity))
447 				continue;
448 			break;
449 		case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
450 			if (!dns_name_issubdomain(name, rule->name))
451 				continue;
452 			if (!dst_gssapi_identitymatchesrealmkrb5(signer, NULL,
453 							       rule->identity))
454 				continue;
455 			break;
456 		case DNS_SSUMATCHTYPE_SUBDOMAINMS:
457 			if (!dns_name_issubdomain(name, rule->name))
458 				continue;
459 			if (!dst_gssapi_identitymatchesrealmms(signer, NULL,
460 							       rule->identity))
461 				continue;
462 			break;
463 		case DNS_SSUMATCHTYPE_TCPSELF:
464 			dns_fixedname_init(&fixed);
465 			tcpself = dns_fixedname_name(&fixed);
466 			reverse_from_address(tcpself, tcpaddr);
467 			if (dns_name_iswildcard(rule->identity)) {
468 				if (!dns_name_matcheswildcard(tcpself,
469 							      rule->identity))
470 					continue;
471 			} else {
472 				if (!dns_name_equal(tcpself, rule->identity))
473 					continue;
474 			}
475 			if (!dns_name_equal(tcpself, name))
476 				continue;
477 			break;
478 		case DNS_SSUMATCHTYPE_6TO4SELF:
479 			dns_fixedname_init(&fixed);
480 			stfself = dns_fixedname_name(&fixed);
481 			stf_from_address(stfself, tcpaddr);
482 			if (dns_name_iswildcard(rule->identity)) {
483 				if (!dns_name_matcheswildcard(stfself,
484 							      rule->identity))
485 					continue;
486 			} else {
487 				if (!dns_name_equal(stfself, rule->identity))
488 					continue;
489 			}
490 			if (!dns_name_equal(stfself, name))
491 				continue;
492 			break;
493 		case DNS_SSUMATCHTYPE_EXTERNAL:
494 			if (!dns_ssu_external_match(rule->identity, signer,
495 						    name, tcpaddr, type, key,
496 						    table->mctx))
497 				continue;
498 			break;
499 		case DNS_SSUMATCHTYPE_DLZ:
500 			if (!dns_dlz_ssumatch(table->dlzdatabase, signer,
501 					      name, tcpaddr, type, key))
502 				continue;
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 		} else {
516 			for (i = 0; i < rule->ntypes; i++) {
517 				if (rule->types[i] == dns_rdatatype_any ||
518 				    rule->types[i] == type)
519 					break;
520 			}
521 			if (i == rule->ntypes)
522 				continue;
523 		}
524 		return (rule->grant);
525 	}
526 
527 	return (ISC_FALSE);
528 }
529 
530 isc_boolean_t
531 dns_ssurule_isgrant(const dns_ssurule_t *rule) {
532 	REQUIRE(VALID_SSURULE(rule));
533 	return (rule->grant);
534 }
535 
536 dns_name_t *
537 dns_ssurule_identity(const dns_ssurule_t *rule) {
538 	REQUIRE(VALID_SSURULE(rule));
539 	return (rule->identity);
540 }
541 
542 unsigned int
543 dns_ssurule_matchtype(const dns_ssurule_t *rule) {
544 	REQUIRE(VALID_SSURULE(rule));
545 	return (rule->matchtype);
546 }
547 
548 dns_name_t *
549 dns_ssurule_name(const dns_ssurule_t *rule) {
550 	REQUIRE(VALID_SSURULE(rule));
551 	return (rule->name);
552 }
553 
554 unsigned int
555 dns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types) {
556 	REQUIRE(VALID_SSURULE(rule));
557 	REQUIRE(types != NULL && *types != NULL);
558 	*types = rule->types;
559 	return (rule->ntypes);
560 }
561 
562 isc_result_t
563 dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
564 	REQUIRE(VALID_SSUTABLE(table));
565 	REQUIRE(rule != NULL && *rule == NULL);
566 	*rule = ISC_LIST_HEAD(table->rules);
567 	return (*rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
568 }
569 
570 isc_result_t
571 dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
572 	REQUIRE(VALID_SSURULE(rule));
573 	REQUIRE(nextrule != NULL && *nextrule == NULL);
574 	*nextrule = ISC_LIST_NEXT(rule, link);
575 	return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
576 }
577 
578 /*
579  * Create a specialised SSU table that points at an external DLZ database
580  */
581 isc_result_t
582 dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
583 		       dns_dlzdb_t *dlzdatabase)
584 {
585 	isc_result_t result;
586 	dns_ssurule_t *rule;
587 	dns_ssutable_t *table = NULL;
588 
589 	REQUIRE(tablep != NULL && *tablep == NULL);
590 
591 	result = dns_ssutable_create(mctx, &table);
592 	if (result != ISC_R_SUCCESS)
593 		return (result);
594 
595 	table->dlzdatabase = dlzdatabase;
596 
597 	rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t));
598 	if (rule == NULL) {
599 		dns_ssutable_detach(&table);
600 		return (ISC_R_NOMEMORY);
601 	}
602 
603 	rule->identity = NULL;
604 	rule->name = NULL;
605 	rule->types = NULL;
606 	rule->grant = ISC_TRUE;
607 	rule->matchtype = DNS_SSUMATCHTYPE_DLZ;
608 	rule->ntypes = 0;
609 	rule->types = NULL;
610 	rule->magic = SSURULEMAGIC;
611 
612 	ISC_LIST_INITANDAPPEND(table->rules, rule, link);
613 	*tablep = table;
614 	return (ISC_R_SUCCESS);
615 }
616