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