1135446Strhodes/*
2262706Serwin * Copyright (C) 2004-2008, 2010, 2011, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18170222Sdougb/*! \file */
19135446Strhodes/*
20234010Sdougb * $Id: ssu.c,v 1.38 2011/01/06 23:47:00 tbox Exp $
21135446Strhodes * Principal Author: Brian Wellington
22135446Strhodes */
23135446Strhodes
24135446Strhodes#include <config.h>
25135446Strhodes
26135446Strhodes#include <isc/magic.h>
27135446Strhodes#include <isc/mem.h>
28193149Sdougb#include <isc/netaddr.h>
29170222Sdougb#include <isc/result.h>
30193149Sdougb#include <isc/string.h>
31135446Strhodes#include <isc/util.h>
32135446Strhodes
33224092Sdougb#include <dns/dlz.h>
34170222Sdougb#include <dns/fixedname.h>
35135446Strhodes#include <dns/name.h>
36135446Strhodes#include <dns/ssu.h>
37135446Strhodes
38193149Sdougb#include <dst/gssapi.h>
39224092Sdougb#include <dst/dst.h>
40193149Sdougb
41135446Strhodes#define SSUTABLEMAGIC		ISC_MAGIC('S', 'S', 'U', 'T')
42135446Strhodes#define VALID_SSUTABLE(table)	ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
43135446Strhodes
44135446Strhodes#define SSURULEMAGIC		ISC_MAGIC('S', 'S', 'U', 'R')
45135446Strhodes#define VALID_SSURULE(table)	ISC_MAGIC_VALID(table, SSURULEMAGIC)
46135446Strhodes
47135446Strhodesstruct dns_ssurule {
48135446Strhodes	unsigned int magic;
49170222Sdougb	isc_boolean_t grant;	/*%< is this a grant or a deny? */
50170222Sdougb	unsigned int matchtype;	/*%< which type of pattern match? */
51170222Sdougb	dns_name_t *identity;	/*%< the identity to match */
52170222Sdougb	dns_name_t *name;	/*%< the name being updated */
53170222Sdougb	unsigned int ntypes;	/*%< number of data types covered */
54170222Sdougb	dns_rdatatype_t *types;	/*%< the data types.  Can include ANY, */
55170222Sdougb				/*%< defaults to all but SIG,SOA,NS if NULL */
56135446Strhodes	ISC_LINK(dns_ssurule_t) link;
57135446Strhodes};
58135446Strhodes
59135446Strhodesstruct dns_ssutable {
60135446Strhodes	unsigned int magic;
61135446Strhodes	isc_mem_t *mctx;
62135446Strhodes	unsigned int references;
63135446Strhodes	isc_mutex_t lock;
64224092Sdougb	dns_dlzdb_t *dlzdatabase;
65135446Strhodes	ISC_LIST(dns_ssurule_t) rules;
66135446Strhodes};
67135446Strhodes
68135446Strhodesisc_result_t
69135446Strhodesdns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) {
70135446Strhodes	isc_result_t result;
71135446Strhodes	dns_ssutable_t *table;
72135446Strhodes
73135446Strhodes	REQUIRE(tablep != NULL && *tablep == NULL);
74135446Strhodes	REQUIRE(mctx != NULL);
75135446Strhodes
76135446Strhodes	table = isc_mem_get(mctx, sizeof(dns_ssutable_t));
77135446Strhodes	if (table == NULL)
78135446Strhodes		return (ISC_R_NOMEMORY);
79135446Strhodes	result = isc_mutex_init(&table->lock);
80135446Strhodes	if (result != ISC_R_SUCCESS) {
81135446Strhodes		isc_mem_put(mctx, table, sizeof(dns_ssutable_t));
82135446Strhodes		return (result);
83135446Strhodes	}
84135446Strhodes	table->references = 1;
85254402Serwin	table->mctx = NULL;
86254402Serwin	isc_mem_attach(mctx, &table->mctx);
87135446Strhodes	ISC_LIST_INIT(table->rules);
88135446Strhodes	table->magic = SSUTABLEMAGIC;
89135446Strhodes	*tablep = table;
90135446Strhodes	return (ISC_R_SUCCESS);
91135446Strhodes}
92135446Strhodes
93135446Strhodesstatic inline void
94135446Strhodesdestroy(dns_ssutable_t *table) {
95135446Strhodes	isc_mem_t *mctx;
96135446Strhodes
97135446Strhodes	REQUIRE(VALID_SSUTABLE(table));
98135446Strhodes
99135446Strhodes	mctx = table->mctx;
100135446Strhodes	while (!ISC_LIST_EMPTY(table->rules)) {
101135446Strhodes		dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
102135446Strhodes		if (rule->identity != NULL) {
103135446Strhodes			dns_name_free(rule->identity, mctx);
104135446Strhodes			isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
105135446Strhodes		}
106135446Strhodes		if (rule->name != NULL) {
107135446Strhodes			dns_name_free(rule->name, mctx);
108135446Strhodes			isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
109135446Strhodes		}
110135446Strhodes		if (rule->types != NULL)
111135446Strhodes			isc_mem_put(mctx, rule->types,
112135446Strhodes				    rule->ntypes * sizeof(dns_rdatatype_t));
113135446Strhodes		ISC_LIST_UNLINK(table->rules, rule, link);
114135446Strhodes		rule->magic = 0;
115135446Strhodes		isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
116135446Strhodes	}
117135446Strhodes	DESTROYLOCK(&table->lock);
118135446Strhodes	table->magic = 0;
119254402Serwin	isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t));
120135446Strhodes}
121135446Strhodes
122135446Strhodesvoid
123135446Strhodesdns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
124135446Strhodes	REQUIRE(VALID_SSUTABLE(source));
125135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
126135446Strhodes
127135446Strhodes	LOCK(&source->lock);
128135446Strhodes
129135446Strhodes	INSIST(source->references > 0);
130135446Strhodes	source->references++;
131135446Strhodes	INSIST(source->references != 0);
132135446Strhodes
133135446Strhodes	UNLOCK(&source->lock);
134135446Strhodes
135135446Strhodes	*targetp = source;
136135446Strhodes}
137135446Strhodes
138135446Strhodesvoid
139135446Strhodesdns_ssutable_detach(dns_ssutable_t **tablep) {
140135446Strhodes	dns_ssutable_t *table;
141135446Strhodes	isc_boolean_t done = ISC_FALSE;
142135446Strhodes
143135446Strhodes	REQUIRE(tablep != NULL);
144135446Strhodes	table = *tablep;
145135446Strhodes	REQUIRE(VALID_SSUTABLE(table));
146135446Strhodes
147135446Strhodes	LOCK(&table->lock);
148135446Strhodes
149135446Strhodes	INSIST(table->references > 0);
150135446Strhodes	if (--table->references == 0)
151135446Strhodes		done = ISC_TRUE;
152135446Strhodes	UNLOCK(&table->lock);
153135446Strhodes
154135446Strhodes	*tablep = NULL;
155135446Strhodes
156135446Strhodes	if (done)
157135446Strhodes		destroy(table);
158135446Strhodes}
159135446Strhodes
160135446Strhodesisc_result_t
161135446Strhodesdns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
162135446Strhodes		     dns_name_t *identity, unsigned int matchtype,
163135446Strhodes		     dns_name_t *name, unsigned int ntypes,
164135446Strhodes		     dns_rdatatype_t *types)
165135446Strhodes{
166135446Strhodes	dns_ssurule_t *rule;
167135446Strhodes	isc_mem_t *mctx;
168135446Strhodes	isc_result_t result;
169135446Strhodes
170135446Strhodes	REQUIRE(VALID_SSUTABLE(table));
171135446Strhodes	REQUIRE(dns_name_isabsolute(identity));
172135446Strhodes	REQUIRE(dns_name_isabsolute(name));
173170222Sdougb	REQUIRE(matchtype <= DNS_SSUMATCHTYPE_MAX);
174135446Strhodes	if (matchtype == DNS_SSUMATCHTYPE_WILDCARD)
175135446Strhodes		REQUIRE(dns_name_iswildcard(name));
176135446Strhodes	if (ntypes > 0)
177135446Strhodes		REQUIRE(types != NULL);
178135446Strhodes
179135446Strhodes	mctx = table->mctx;
180135446Strhodes	rule = isc_mem_get(mctx, sizeof(dns_ssurule_t));
181135446Strhodes	if (rule == NULL)
182135446Strhodes		return (ISC_R_NOMEMORY);
183135446Strhodes
184135446Strhodes	rule->identity = NULL;
185135446Strhodes	rule->name = NULL;
186135446Strhodes	rule->types = NULL;
187135446Strhodes
188135446Strhodes	rule->grant = grant;
189135446Strhodes
190135446Strhodes	rule->identity = isc_mem_get(mctx, sizeof(dns_name_t));
191135446Strhodes	if (rule->identity == NULL) {
192135446Strhodes		result = ISC_R_NOMEMORY;
193135446Strhodes		goto failure;
194135446Strhodes	}
195135446Strhodes	dns_name_init(rule->identity, NULL);
196135446Strhodes	result = dns_name_dup(identity, mctx, rule->identity);
197135446Strhodes	if (result != ISC_R_SUCCESS)
198135446Strhodes		goto failure;
199135446Strhodes
200135446Strhodes	rule->name = isc_mem_get(mctx, sizeof(dns_name_t));
201135446Strhodes	if (rule->name == NULL) {
202135446Strhodes		result = ISC_R_NOMEMORY;
203135446Strhodes		goto failure;
204135446Strhodes	}
205135446Strhodes	dns_name_init(rule->name, NULL);
206135446Strhodes	result = dns_name_dup(name, mctx, rule->name);
207135446Strhodes	if (result != ISC_R_SUCCESS)
208135446Strhodes		goto failure;
209135446Strhodes
210135446Strhodes	rule->matchtype = matchtype;
211135446Strhodes
212135446Strhodes	rule->ntypes = ntypes;
213135446Strhodes	if (ntypes > 0) {
214135446Strhodes		rule->types = isc_mem_get(mctx,
215135446Strhodes					  ntypes * sizeof(dns_rdatatype_t));
216135446Strhodes		if (rule->types == NULL) {
217135446Strhodes			result = ISC_R_NOMEMORY;
218135446Strhodes			goto failure;
219135446Strhodes		}
220262706Serwin		memmove(rule->types, types, ntypes * sizeof(dns_rdatatype_t));
221170222Sdougb	} else
222135446Strhodes		rule->types = NULL;
223135446Strhodes
224135446Strhodes	rule->magic = SSURULEMAGIC;
225135446Strhodes	ISC_LIST_INITANDAPPEND(table->rules, rule, link);
226135446Strhodes
227135446Strhodes	return (ISC_R_SUCCESS);
228135446Strhodes
229135446Strhodes failure:
230135446Strhodes	if (rule->identity != NULL) {
231135446Strhodes		if (dns_name_dynamic(rule->identity))
232135446Strhodes			dns_name_free(rule->identity, mctx);
233135446Strhodes		isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
234135446Strhodes	}
235135446Strhodes	if (rule->name != NULL) {
236135446Strhodes		if (dns_name_dynamic(rule->name))
237135446Strhodes			dns_name_free(rule->name, mctx);
238135446Strhodes		isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
239135446Strhodes	}
240135446Strhodes	if (rule->types != NULL)
241135446Strhodes		isc_mem_put(mctx, rule->types,
242135446Strhodes			    ntypes * sizeof(dns_rdatatype_t));
243135446Strhodes	isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
244135446Strhodes
245135446Strhodes	return (result);
246135446Strhodes}
247135446Strhodes
248135446Strhodesstatic inline isc_boolean_t
249135446Strhodesisusertype(dns_rdatatype_t type) {
250135446Strhodes	return (ISC_TF(type != dns_rdatatype_ns &&
251135446Strhodes		       type != dns_rdatatype_soa &&
252135446Strhodes		       type != dns_rdatatype_rrsig));
253135446Strhodes}
254135446Strhodes
255193149Sdougbstatic void
256193149Sdougbreverse_from_address(dns_name_t *tcpself, isc_netaddr_t *tcpaddr) {
257193149Sdougb	char buf[16 * 4 + sizeof("IP6.ARPA.")];
258193149Sdougb	isc_result_t result;
259193149Sdougb	unsigned char *ap;
260193149Sdougb	isc_buffer_t b;
261193149Sdougb	unsigned long l;
262193149Sdougb
263193149Sdougb	switch (tcpaddr->family) {
264193149Sdougb	case AF_INET:
265193149Sdougb		l = ntohl(tcpaddr->type.in.s_addr);
266193149Sdougb		result = isc_string_printf(buf, sizeof(buf),
267193149Sdougb					   "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.",
268193149Sdougb					   (l >> 0) & 0xff, (l >> 8) & 0xff,
269193149Sdougb					   (l >> 16) & 0xff, (l >> 24) & 0xff);
270193149Sdougb		RUNTIME_CHECK(result == ISC_R_SUCCESS);
271193149Sdougb		break;
272193149Sdougb	case AF_INET6:
273193149Sdougb		ap = tcpaddr->type.in6.s6_addr;
274193149Sdougb		result = isc_string_printf(buf, sizeof(buf),
275193149Sdougb					   "%x.%x.%x.%x.%x.%x.%x.%x."
276193149Sdougb					   "%x.%x.%x.%x.%x.%x.%x.%x."
277193149Sdougb					   "%x.%x.%x.%x.%x.%x.%x.%x."
278193149Sdougb					   "%x.%x.%x.%x.%x.%x.%x.%x."
279193149Sdougb					   "IP6.ARPA.",
280193149Sdougb					   ap[15] & 0x0f, (ap[15] >> 4) & 0x0f,
281193149Sdougb					   ap[14] & 0x0f, (ap[14] >> 4) & 0x0f,
282193149Sdougb					   ap[13] & 0x0f, (ap[13] >> 4) & 0x0f,
283193149Sdougb					   ap[12] & 0x0f, (ap[12] >> 4) & 0x0f,
284193149Sdougb					   ap[11] & 0x0f, (ap[11] >> 4) & 0x0f,
285193149Sdougb					   ap[10] & 0x0f, (ap[10] >> 4) & 0x0f,
286193149Sdougb					   ap[9] & 0x0f, (ap[9] >> 4) & 0x0f,
287193149Sdougb					   ap[8] & 0x0f, (ap[8] >> 4) & 0x0f,
288193149Sdougb					   ap[7] & 0x0f, (ap[7] >> 4) & 0x0f,
289193149Sdougb					   ap[6] & 0x0f, (ap[6] >> 4) & 0x0f,
290193149Sdougb					   ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
291193149Sdougb					   ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
292193149Sdougb					   ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
293193149Sdougb					   ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
294193149Sdougb					   ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
295193149Sdougb					   ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
296193149Sdougb		RUNTIME_CHECK(result == ISC_R_SUCCESS);
297193149Sdougb		break;
298193149Sdougb	default:
299193149Sdougb		INSIST(0);
300193149Sdougb	}
301193149Sdougb	isc_buffer_init(&b, buf, strlen(buf));
302193149Sdougb	isc_buffer_add(&b, strlen(buf));
303193149Sdougb	result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL);
304193149Sdougb	RUNTIME_CHECK(result == ISC_R_SUCCESS);
305193149Sdougb}
306193149Sdougb
307193149Sdougbstatic void
308193149Sdougbstf_from_address(dns_name_t *stfself, isc_netaddr_t *tcpaddr) {
309193149Sdougb	char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")];
310193149Sdougb	isc_result_t result;
311193149Sdougb	unsigned char *ap;
312193149Sdougb	isc_buffer_t b;
313193149Sdougb	unsigned long l;
314193149Sdougb
315193149Sdougb	switch(tcpaddr->family) {
316193149Sdougb	case AF_INET:
317193149Sdougb		l = ntohl(tcpaddr->type.in.s_addr);
318193149Sdougb		result = isc_string_printf(buf, sizeof(buf),
319193149Sdougb					   "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx"
320193149Sdougb					   "2.0.0.2.IP6.ARPA.",
321193149Sdougb					   l & 0xf, (l >> 4) & 0xf,
322193149Sdougb					   (l >> 8) & 0xf, (l >> 12) & 0xf,
323193149Sdougb					   (l >> 16) & 0xf, (l >> 20) & 0xf,
324193149Sdougb					   (l >> 24) & 0xf, (l >> 28) & 0xf);
325193149Sdougb		RUNTIME_CHECK(result == ISC_R_SUCCESS);
326193149Sdougb		break;
327193149Sdougb	case AF_INET6:
328193149Sdougb		ap = tcpaddr->type.in6.s6_addr;
329193149Sdougb		result = isc_string_printf(buf, sizeof(buf),
330193149Sdougb					   "%x.%x.%x.%x.%x.%x.%x.%x."
331193149Sdougb					   "%x.%x.%x.%x.IP6.ARPA.",
332193149Sdougb					   ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
333193149Sdougb					   ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
334193149Sdougb					   ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
335193149Sdougb					   ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
336193149Sdougb					   ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
337193149Sdougb					   ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
338193149Sdougb		RUNTIME_CHECK(result == ISC_R_SUCCESS);
339193149Sdougb		break;
340193149Sdougb	default:
341193149Sdougb		INSIST(0);
342193149Sdougb	}
343193149Sdougb	isc_buffer_init(&b, buf, strlen(buf));
344193149Sdougb	isc_buffer_add(&b, strlen(buf));
345193149Sdougb	result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL);
346193149Sdougb	RUNTIME_CHECK(result == ISC_R_SUCCESS);
347193149Sdougb}
348193149Sdougb
349135446Strhodesisc_boolean_t
350135446Strhodesdns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
351193149Sdougb			dns_name_t *name, isc_netaddr_t *tcpaddr,
352224092Sdougb			dns_rdatatype_t type,
353224092Sdougb			const dst_key_t *key)
354135446Strhodes{
355135446Strhodes	dns_ssurule_t *rule;
356135446Strhodes	unsigned int i;
357170222Sdougb	dns_fixedname_t fixed;
358170222Sdougb	dns_name_t *wildcard;
359193149Sdougb	dns_name_t *tcpself;
360193149Sdougb	dns_name_t *stfself;
361170222Sdougb	isc_result_t result;
362135446Strhodes
363135446Strhodes	REQUIRE(VALID_SSUTABLE(table));
364135446Strhodes	REQUIRE(signer == NULL || dns_name_isabsolute(signer));
365135446Strhodes	REQUIRE(dns_name_isabsolute(name));
366135446Strhodes
367193149Sdougb	if (signer == NULL && tcpaddr == NULL)
368135446Strhodes		return (ISC_FALSE);
369193149Sdougb
370135446Strhodes	for (rule = ISC_LIST_HEAD(table->rules);
371135446Strhodes	     rule != NULL;
372135446Strhodes	     rule = ISC_LIST_NEXT(rule, link))
373135446Strhodes	{
374193149Sdougb		switch (rule->matchtype) {
375193149Sdougb		case DNS_SSUMATCHTYPE_NAME:
376193149Sdougb		case DNS_SSUMATCHTYPE_SUBDOMAIN:
377193149Sdougb		case DNS_SSUMATCHTYPE_WILDCARD:
378193149Sdougb		case DNS_SSUMATCHTYPE_SELF:
379193149Sdougb		case DNS_SSUMATCHTYPE_SELFSUB:
380193149Sdougb		case DNS_SSUMATCHTYPE_SELFWILD:
381193149Sdougb			if (signer == NULL)
382135446Strhodes				continue;
383193149Sdougb			if (dns_name_iswildcard(rule->identity)) {
384193149Sdougb				if (!dns_name_matcheswildcard(signer,
385193149Sdougb							      rule->identity))
386193149Sdougb					continue;
387193149Sdougb			} else {
388193149Sdougb				if (!dns_name_equal(signer, rule->identity))
389193149Sdougb					continue;
390193149Sdougb			}
391193149Sdougb			break;
392193149Sdougb		case DNS_SSUMATCHTYPE_SELFKRB5:
393193149Sdougb		case DNS_SSUMATCHTYPE_SELFMS:
394193149Sdougb		case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
395193149Sdougb		case DNS_SSUMATCHTYPE_SUBDOMAINMS:
396193149Sdougb			if (signer == NULL)
397135446Strhodes				continue;
398193149Sdougb			break;
399193149Sdougb		case DNS_SSUMATCHTYPE_TCPSELF:
400193149Sdougb		case DNS_SSUMATCHTYPE_6TO4SELF:
401193149Sdougb			if (tcpaddr == NULL)
402193149Sdougb				continue;
403193149Sdougb			break;
404193149Sdougb		}
405135446Strhodes
406193149Sdougb		switch (rule->matchtype) {
407193149Sdougb		case DNS_SSUMATCHTYPE_NAME:
408135446Strhodes			if (!dns_name_equal(name, rule->name))
409135446Strhodes				continue;
410193149Sdougb			break;
411193149Sdougb		case DNS_SSUMATCHTYPE_SUBDOMAIN:
412135446Strhodes			if (!dns_name_issubdomain(name, rule->name))
413135446Strhodes				continue;
414193149Sdougb			break;
415193149Sdougb		case DNS_SSUMATCHTYPE_WILDCARD:
416135446Strhodes			if (!dns_name_matcheswildcard(name, rule->name))
417135446Strhodes				continue;
418193149Sdougb			break;
419193149Sdougb		case DNS_SSUMATCHTYPE_SELF:
420135446Strhodes			if (!dns_name_equal(signer, name))
421135446Strhodes				continue;
422193149Sdougb			break;
423193149Sdougb		case DNS_SSUMATCHTYPE_SELFSUB:
424170222Sdougb			if (!dns_name_issubdomain(name, signer))
425170222Sdougb				continue;
426193149Sdougb			break;
427193149Sdougb		case DNS_SSUMATCHTYPE_SELFWILD:
428170222Sdougb			dns_fixedname_init(&fixed);
429170222Sdougb			wildcard = dns_fixedname_name(&fixed);
430170222Sdougb			result = dns_name_concatenate(dns_wildcardname, signer,
431170222Sdougb						      wildcard, NULL);
432170222Sdougb			if (result != ISC_R_SUCCESS)
433170222Sdougb				continue;
434170222Sdougb			if (!dns_name_matcheswildcard(name, wildcard))
435170222Sdougb				continue;
436193149Sdougb			break;
437193149Sdougb		case DNS_SSUMATCHTYPE_SELFKRB5:
438193149Sdougb			if (!dst_gssapi_identitymatchesrealmkrb5(signer, name,
439193149Sdougb							       rule->identity))
440193149Sdougb				continue;
441193149Sdougb			break;
442193149Sdougb		case DNS_SSUMATCHTYPE_SELFMS:
443193149Sdougb			if (!dst_gssapi_identitymatchesrealmms(signer, name,
444193149Sdougb							       rule->identity))
445193149Sdougb				continue;
446193149Sdougb			break;
447193149Sdougb		case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
448193149Sdougb			if (!dns_name_issubdomain(name, rule->name))
449193149Sdougb				continue;
450193149Sdougb			if (!dst_gssapi_identitymatchesrealmkrb5(signer, NULL,
451193149Sdougb							       rule->identity))
452193149Sdougb				continue;
453193149Sdougb			break;
454193149Sdougb		case DNS_SSUMATCHTYPE_SUBDOMAINMS:
455193149Sdougb			if (!dns_name_issubdomain(name, rule->name))
456193149Sdougb				continue;
457193149Sdougb			if (!dst_gssapi_identitymatchesrealmms(signer, NULL,
458193149Sdougb							       rule->identity))
459193149Sdougb				continue;
460193149Sdougb			break;
461193149Sdougb		case DNS_SSUMATCHTYPE_TCPSELF:
462193149Sdougb			dns_fixedname_init(&fixed);
463193149Sdougb			tcpself = dns_fixedname_name(&fixed);
464193149Sdougb			reverse_from_address(tcpself, tcpaddr);
465193149Sdougb			if (dns_name_iswildcard(rule->identity)) {
466193149Sdougb				if (!dns_name_matcheswildcard(tcpself,
467193149Sdougb							      rule->identity))
468193149Sdougb					continue;
469193149Sdougb			} else {
470193149Sdougb				if (!dns_name_equal(tcpself, rule->identity))
471193149Sdougb					continue;
472193149Sdougb			}
473193149Sdougb			if (!dns_name_equal(tcpself, name))
474193149Sdougb				continue;
475193149Sdougb			break;
476193149Sdougb		case DNS_SSUMATCHTYPE_6TO4SELF:
477193149Sdougb			dns_fixedname_init(&fixed);
478193149Sdougb			stfself = dns_fixedname_name(&fixed);
479193149Sdougb			stf_from_address(stfself, tcpaddr);
480193149Sdougb			if (dns_name_iswildcard(rule->identity)) {
481193149Sdougb				if (!dns_name_matcheswildcard(stfself,
482193149Sdougb							      rule->identity))
483193149Sdougb					continue;
484193149Sdougb			} else {
485193149Sdougb				if (!dns_name_equal(stfself, rule->identity))
486193149Sdougb					continue;
487193149Sdougb			}
488193149Sdougb			if (!dns_name_equal(stfself, name))
489193149Sdougb				continue;
490193149Sdougb			break;
491224092Sdougb		case DNS_SSUMATCHTYPE_EXTERNAL:
492224092Sdougb			if (!dns_ssu_external_match(rule->identity, signer,
493224092Sdougb						    name, tcpaddr, type, key,
494224092Sdougb						    table->mctx))
495224092Sdougb				continue;
496224092Sdougb			break;
497224092Sdougb		case DNS_SSUMATCHTYPE_DLZ:
498224092Sdougb			if (!dns_dlz_ssumatch(table->dlzdatabase, signer,
499224092Sdougb					      name, tcpaddr, type, key))
500224092Sdougb				continue;
501224092Sdougb			break;
502135446Strhodes		}
503135446Strhodes
504135446Strhodes		if (rule->ntypes == 0) {
505224092Sdougb			/*
506224092Sdougb			 * If this is a DLZ rule, then the DLZ ssu
507224092Sdougb			 * checks will have already checked
508224092Sdougb			 * the type.
509224092Sdougb			 */
510224092Sdougb			if (rule->matchtype != DNS_SSUMATCHTYPE_DLZ &&
511224092Sdougb			    !isusertype(type))
512135446Strhodes				continue;
513170222Sdougb		} else {
514135446Strhodes			for (i = 0; i < rule->ntypes; i++) {
515135446Strhodes				if (rule->types[i] == dns_rdatatype_any ||
516135446Strhodes				    rule->types[i] == type)
517135446Strhodes					break;
518135446Strhodes			}
519135446Strhodes			if (i == rule->ntypes)
520135446Strhodes				continue;
521135446Strhodes		}
522135446Strhodes		return (rule->grant);
523135446Strhodes	}
524135446Strhodes
525135446Strhodes	return (ISC_FALSE);
526135446Strhodes}
527135446Strhodes
528135446Strhodesisc_boolean_t
529135446Strhodesdns_ssurule_isgrant(const dns_ssurule_t *rule) {
530135446Strhodes	REQUIRE(VALID_SSURULE(rule));
531135446Strhodes	return (rule->grant);
532135446Strhodes}
533135446Strhodes
534135446Strhodesdns_name_t *
535135446Strhodesdns_ssurule_identity(const dns_ssurule_t *rule) {
536135446Strhodes	REQUIRE(VALID_SSURULE(rule));
537135446Strhodes	return (rule->identity);
538135446Strhodes}
539135446Strhodes
540135446Strhodesunsigned int
541135446Strhodesdns_ssurule_matchtype(const dns_ssurule_t *rule) {
542135446Strhodes	REQUIRE(VALID_SSURULE(rule));
543135446Strhodes	return (rule->matchtype);
544135446Strhodes}
545135446Strhodes
546135446Strhodesdns_name_t *
547135446Strhodesdns_ssurule_name(const dns_ssurule_t *rule) {
548135446Strhodes	REQUIRE(VALID_SSURULE(rule));
549135446Strhodes	return (rule->name);
550135446Strhodes}
551135446Strhodes
552135446Strhodesunsigned int
553135446Strhodesdns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types) {
554135446Strhodes	REQUIRE(VALID_SSURULE(rule));
555135446Strhodes	REQUIRE(types != NULL && *types != NULL);
556135446Strhodes	*types = rule->types;
557135446Strhodes	return (rule->ntypes);
558135446Strhodes}
559135446Strhodes
560135446Strhodesisc_result_t
561135446Strhodesdns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
562135446Strhodes	REQUIRE(VALID_SSUTABLE(table));
563135446Strhodes	REQUIRE(rule != NULL && *rule == NULL);
564135446Strhodes	*rule = ISC_LIST_HEAD(table->rules);
565135446Strhodes	return (*rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
566135446Strhodes}
567135446Strhodes
568135446Strhodesisc_result_t
569135446Strhodesdns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
570135446Strhodes	REQUIRE(VALID_SSURULE(rule));
571135446Strhodes	REQUIRE(nextrule != NULL && *nextrule == NULL);
572135446Strhodes	*nextrule = ISC_LIST_NEXT(rule, link);
573135446Strhodes	return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
574135446Strhodes}
575224092Sdougb
576224092Sdougb/*
577224092Sdougb * Create a specialised SSU table that points at an external DLZ database
578224092Sdougb */
579224092Sdougbisc_result_t
580224092Sdougbdns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
581224092Sdougb		       dns_dlzdb_t *dlzdatabase)
582224092Sdougb{
583224092Sdougb	isc_result_t result;
584224092Sdougb	dns_ssurule_t *rule;
585224092Sdougb	dns_ssutable_t *table = NULL;
586224092Sdougb
587224092Sdougb	REQUIRE(tablep != NULL && *tablep == NULL);
588224092Sdougb
589224092Sdougb	result = dns_ssutable_create(mctx, &table);
590224092Sdougb	if (result != ISC_R_SUCCESS)
591224092Sdougb		return (result);
592224092Sdougb
593224092Sdougb	table->dlzdatabase = dlzdatabase;
594224092Sdougb
595224092Sdougb	rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t));
596224092Sdougb	if (rule == NULL) {
597224092Sdougb		dns_ssutable_detach(&table);
598224092Sdougb		return (ISC_R_NOMEMORY);
599224092Sdougb	}
600224092Sdougb
601224092Sdougb	rule->identity = NULL;
602224092Sdougb	rule->name = NULL;
603224092Sdougb	rule->types = NULL;
604224092Sdougb	rule->grant = ISC_TRUE;
605224092Sdougb	rule->matchtype = DNS_SSUMATCHTYPE_DLZ;
606224092Sdougb	rule->ntypes = 0;
607224092Sdougb	rule->types = NULL;
608224092Sdougb	rule->magic = SSURULEMAGIC;
609224092Sdougb
610224092Sdougb	ISC_LIST_INITANDAPPEND(table->rules, rule, link);
611224092Sdougb	*tablep = table;
612224092Sdougb	return (ISC_R_SUCCESS);
613224092Sdougb}
614