]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/ssu.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / ssu.c
1 /*
2  * Copyright (C) 2004-2008, 2010, 2011  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 = mctx;
86         ISC_LIST_INIT(table->rules);
87         table->magic = SSUTABLEMAGIC;
88         *tablep = table;
89         return (ISC_R_SUCCESS);
90 }
91
92 static inline void
93 destroy(dns_ssutable_t *table) {
94         isc_mem_t *mctx;
95
96         REQUIRE(VALID_SSUTABLE(table));
97
98         mctx = table->mctx;
99         while (!ISC_LIST_EMPTY(table->rules)) {
100                 dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
101                 if (rule->identity != NULL) {
102                         dns_name_free(rule->identity, mctx);
103                         isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
104                 }
105                 if (rule->name != NULL) {
106                         dns_name_free(rule->name, mctx);
107                         isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
108                 }
109                 if (rule->types != NULL)
110                         isc_mem_put(mctx, rule->types,
111                                     rule->ntypes * sizeof(dns_rdatatype_t));
112                 ISC_LIST_UNLINK(table->rules, rule, link);
113                 rule->magic = 0;
114                 isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
115         }
116         DESTROYLOCK(&table->lock);
117         table->magic = 0;
118         isc_mem_put(mctx, table, sizeof(dns_ssutable_t));
119 }
120
121 void
122 dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
123         REQUIRE(VALID_SSUTABLE(source));
124         REQUIRE(targetp != NULL && *targetp == NULL);
125
126         LOCK(&source->lock);
127
128         INSIST(source->references > 0);
129         source->references++;
130         INSIST(source->references != 0);
131
132         UNLOCK(&source->lock);
133
134         *targetp = source;
135 }
136
137 void
138 dns_ssutable_detach(dns_ssutable_t **tablep) {
139         dns_ssutable_t *table;
140         isc_boolean_t done = ISC_FALSE;
141
142         REQUIRE(tablep != NULL);
143         table = *tablep;
144         REQUIRE(VALID_SSUTABLE(table));
145
146         LOCK(&table->lock);
147
148         INSIST(table->references > 0);
149         if (--table->references == 0)
150                 done = ISC_TRUE;
151         UNLOCK(&table->lock);
152
153         *tablep = NULL;
154
155         if (done)
156                 destroy(table);
157 }
158
159 isc_result_t
160 dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
161                      dns_name_t *identity, unsigned int matchtype,
162                      dns_name_t *name, unsigned int ntypes,
163                      dns_rdatatype_t *types)
164 {
165         dns_ssurule_t *rule;
166         isc_mem_t *mctx;
167         isc_result_t result;
168
169         REQUIRE(VALID_SSUTABLE(table));
170         REQUIRE(dns_name_isabsolute(identity));
171         REQUIRE(dns_name_isabsolute(name));
172         REQUIRE(matchtype <= DNS_SSUMATCHTYPE_MAX);
173         if (matchtype == DNS_SSUMATCHTYPE_WILDCARD)
174                 REQUIRE(dns_name_iswildcard(name));
175         if (ntypes > 0)
176                 REQUIRE(types != NULL);
177
178         mctx = table->mctx;
179         rule = isc_mem_get(mctx, sizeof(dns_ssurule_t));
180         if (rule == NULL)
181                 return (ISC_R_NOMEMORY);
182
183         rule->identity = NULL;
184         rule->name = NULL;
185         rule->types = NULL;
186
187         rule->grant = grant;
188
189         rule->identity = isc_mem_get(mctx, sizeof(dns_name_t));
190         if (rule->identity == NULL) {
191                 result = ISC_R_NOMEMORY;
192                 goto failure;
193         }
194         dns_name_init(rule->identity, NULL);
195         result = dns_name_dup(identity, mctx, rule->identity);
196         if (result != ISC_R_SUCCESS)
197                 goto failure;
198
199         rule->name = isc_mem_get(mctx, sizeof(dns_name_t));
200         if (rule->name == NULL) {
201                 result = ISC_R_NOMEMORY;
202                 goto failure;
203         }
204         dns_name_init(rule->name, NULL);
205         result = dns_name_dup(name, mctx, rule->name);
206         if (result != ISC_R_SUCCESS)
207                 goto failure;
208
209         rule->matchtype = matchtype;
210
211         rule->ntypes = ntypes;
212         if (ntypes > 0) {
213                 rule->types = isc_mem_get(mctx,
214                                           ntypes * sizeof(dns_rdatatype_t));
215                 if (rule->types == NULL) {
216                         result = ISC_R_NOMEMORY;
217                         goto failure;
218                 }
219                 memcpy(rule->types, types, ntypes * sizeof(dns_rdatatype_t));
220         } else
221                 rule->types = NULL;
222
223         rule->magic = SSURULEMAGIC;
224         ISC_LIST_INITANDAPPEND(table->rules, rule, link);
225
226         return (ISC_R_SUCCESS);
227
228  failure:
229         if (rule->identity != NULL) {
230                 if (dns_name_dynamic(rule->identity))
231                         dns_name_free(rule->identity, mctx);
232                 isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
233         }
234         if (rule->name != NULL) {
235                 if (dns_name_dynamic(rule->name))
236                         dns_name_free(rule->name, mctx);
237                 isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
238         }
239         if (rule->types != NULL)
240                 isc_mem_put(mctx, rule->types,
241                             ntypes * sizeof(dns_rdatatype_t));
242         isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
243
244         return (result);
245 }
246
247 static inline isc_boolean_t
248 isusertype(dns_rdatatype_t type) {
249         return (ISC_TF(type != dns_rdatatype_ns &&
250                        type != dns_rdatatype_soa &&
251                        type != dns_rdatatype_rrsig));
252 }
253
254 static void
255 reverse_from_address(dns_name_t *tcpself, isc_netaddr_t *tcpaddr) {
256         char buf[16 * 4 + sizeof("IP6.ARPA.")];
257         isc_result_t result;
258         unsigned char *ap;
259         isc_buffer_t b;
260         unsigned long l;
261
262         switch (tcpaddr->family) {
263         case AF_INET:
264                 l = ntohl(tcpaddr->type.in.s_addr);
265                 result = isc_string_printf(buf, sizeof(buf),
266                                            "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.",
267                                            (l >> 0) & 0xff, (l >> 8) & 0xff,
268                                            (l >> 16) & 0xff, (l >> 24) & 0xff);
269                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
270                 break;
271         case AF_INET6:
272                 ap = tcpaddr->type.in6.s6_addr;
273                 result = isc_string_printf(buf, sizeof(buf),
274                                            "%x.%x.%x.%x.%x.%x.%x.%x."
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                                            "IP6.ARPA.",
279                                            ap[15] & 0x0f, (ap[15] >> 4) & 0x0f,
280                                            ap[14] & 0x0f, (ap[14] >> 4) & 0x0f,
281                                            ap[13] & 0x0f, (ap[13] >> 4) & 0x0f,
282                                            ap[12] & 0x0f, (ap[12] >> 4) & 0x0f,
283                                            ap[11] & 0x0f, (ap[11] >> 4) & 0x0f,
284                                            ap[10] & 0x0f, (ap[10] >> 4) & 0x0f,
285                                            ap[9] & 0x0f, (ap[9] >> 4) & 0x0f,
286                                            ap[8] & 0x0f, (ap[8] >> 4) & 0x0f,
287                                            ap[7] & 0x0f, (ap[7] >> 4) & 0x0f,
288                                            ap[6] & 0x0f, (ap[6] >> 4) & 0x0f,
289                                            ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
290                                            ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
291                                            ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
292                                            ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
293                                            ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
294                                            ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
295                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
296                 break;
297         default:
298                 INSIST(0);
299         }
300         isc_buffer_init(&b, buf, strlen(buf));
301         isc_buffer_add(&b, strlen(buf));
302         result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL);
303         RUNTIME_CHECK(result == ISC_R_SUCCESS);
304 }
305
306 static void
307 stf_from_address(dns_name_t *stfself, isc_netaddr_t *tcpaddr) {
308         char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")];
309         isc_result_t result;
310         unsigned char *ap;
311         isc_buffer_t b;
312         unsigned long l;
313
314         switch(tcpaddr->family) {
315         case AF_INET:
316                 l = ntohl(tcpaddr->type.in.s_addr);
317                 result = isc_string_printf(buf, sizeof(buf),
318                                            "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx"
319                                            "2.0.0.2.IP6.ARPA.",
320                                            l & 0xf, (l >> 4) & 0xf,
321                                            (l >> 8) & 0xf, (l >> 12) & 0xf,
322                                            (l >> 16) & 0xf, (l >> 20) & 0xf,
323                                            (l >> 24) & 0xf, (l >> 28) & 0xf);
324                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
325                 break;
326         case AF_INET6:
327                 ap = tcpaddr->type.in6.s6_addr;
328                 result = isc_string_printf(buf, sizeof(buf),
329                                            "%x.%x.%x.%x.%x.%x.%x.%x."
330                                            "%x.%x.%x.%x.IP6.ARPA.",
331                                            ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
332                                            ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
333                                            ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
334                                            ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
335                                            ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
336                                            ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
337                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
338                 break;
339         default:
340                 INSIST(0);
341         }
342         isc_buffer_init(&b, buf, strlen(buf));
343         isc_buffer_add(&b, strlen(buf));
344         result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL);
345         RUNTIME_CHECK(result == ISC_R_SUCCESS);
346 }
347
348 isc_boolean_t
349 dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
350                         dns_name_t *name, isc_netaddr_t *tcpaddr,
351                         dns_rdatatype_t type,
352                         const dst_key_t *key)
353 {
354         dns_ssurule_t *rule;
355         unsigned int i;
356         dns_fixedname_t fixed;
357         dns_name_t *wildcard;
358         dns_name_t *tcpself;
359         dns_name_t *stfself;
360         isc_result_t result;
361
362         REQUIRE(VALID_SSUTABLE(table));
363         REQUIRE(signer == NULL || dns_name_isabsolute(signer));
364         REQUIRE(dns_name_isabsolute(name));
365
366         if (signer == NULL && tcpaddr == NULL)
367                 return (ISC_FALSE);
368
369         for (rule = ISC_LIST_HEAD(table->rules);
370              rule != NULL;
371              rule = ISC_LIST_NEXT(rule, link))
372         {
373                 switch (rule->matchtype) {
374                 case DNS_SSUMATCHTYPE_NAME:
375                 case DNS_SSUMATCHTYPE_SUBDOMAIN:
376                 case DNS_SSUMATCHTYPE_WILDCARD:
377                 case DNS_SSUMATCHTYPE_SELF:
378                 case DNS_SSUMATCHTYPE_SELFSUB:
379                 case DNS_SSUMATCHTYPE_SELFWILD:
380                         if (signer == NULL)
381                                 continue;
382                         if (dns_name_iswildcard(rule->identity)) {
383                                 if (!dns_name_matcheswildcard(signer,
384                                                               rule->identity))
385                                         continue;
386                         } else {
387                                 if (!dns_name_equal(signer, rule->identity))
388                                         continue;
389                         }
390                         break;
391                 case DNS_SSUMATCHTYPE_SELFKRB5:
392                 case DNS_SSUMATCHTYPE_SELFMS:
393                 case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
394                 case DNS_SSUMATCHTYPE_SUBDOMAINMS:
395                         if (signer == NULL)
396                                 continue;
397                         break;
398                 case DNS_SSUMATCHTYPE_TCPSELF:
399                 case DNS_SSUMATCHTYPE_6TO4SELF:
400                         if (tcpaddr == NULL)
401                                 continue;
402                         break;
403                 }
404
405                 switch (rule->matchtype) {
406                 case DNS_SSUMATCHTYPE_NAME:
407                         if (!dns_name_equal(name, rule->name))
408                                 continue;
409                         break;
410                 case DNS_SSUMATCHTYPE_SUBDOMAIN:
411                         if (!dns_name_issubdomain(name, rule->name))
412                                 continue;
413                         break;
414                 case DNS_SSUMATCHTYPE_WILDCARD:
415                         if (!dns_name_matcheswildcard(name, rule->name))
416                                 continue;
417                         break;
418                 case DNS_SSUMATCHTYPE_SELF:
419                         if (!dns_name_equal(signer, name))
420                                 continue;
421                         break;
422                 case DNS_SSUMATCHTYPE_SELFSUB:
423                         if (!dns_name_issubdomain(name, signer))
424                                 continue;
425                         break;
426                 case DNS_SSUMATCHTYPE_SELFWILD:
427                         dns_fixedname_init(&fixed);
428                         wildcard = dns_fixedname_name(&fixed);
429                         result = dns_name_concatenate(dns_wildcardname, signer,
430                                                       wildcard, NULL);
431                         if (result != ISC_R_SUCCESS)
432                                 continue;
433                         if (!dns_name_matcheswildcard(name, wildcard))
434                                 continue;
435                         break;
436                 case DNS_SSUMATCHTYPE_SELFKRB5:
437                         if (!dst_gssapi_identitymatchesrealmkrb5(signer, name,
438                                                                rule->identity))
439                                 continue;
440                         break;
441                 case DNS_SSUMATCHTYPE_SELFMS:
442                         if (!dst_gssapi_identitymatchesrealmms(signer, name,
443                                                                rule->identity))
444                                 continue;
445                         break;
446                 case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
447                         if (!dns_name_issubdomain(name, rule->name))
448                                 continue;
449                         if (!dst_gssapi_identitymatchesrealmkrb5(signer, NULL,
450                                                                rule->identity))
451                                 continue;
452                         break;
453                 case DNS_SSUMATCHTYPE_SUBDOMAINMS:
454                         if (!dns_name_issubdomain(name, rule->name))
455                                 continue;
456                         if (!dst_gssapi_identitymatchesrealmms(signer, NULL,
457                                                                rule->identity))
458                                 continue;
459                         break;
460                 case DNS_SSUMATCHTYPE_TCPSELF:
461                         dns_fixedname_init(&fixed);
462                         tcpself = dns_fixedname_name(&fixed);
463                         reverse_from_address(tcpself, tcpaddr);
464                         if (dns_name_iswildcard(rule->identity)) {
465                                 if (!dns_name_matcheswildcard(tcpself,
466                                                               rule->identity))
467                                         continue;
468                         } else {
469                                 if (!dns_name_equal(tcpself, rule->identity))
470                                         continue;
471                         }
472                         if (!dns_name_equal(tcpself, name))
473                                 continue;
474                         break;
475                 case DNS_SSUMATCHTYPE_6TO4SELF:
476                         dns_fixedname_init(&fixed);
477                         stfself = dns_fixedname_name(&fixed);
478                         stf_from_address(stfself, tcpaddr);
479                         if (dns_name_iswildcard(rule->identity)) {
480                                 if (!dns_name_matcheswildcard(stfself,
481                                                               rule->identity))
482                                         continue;
483                         } else {
484                                 if (!dns_name_equal(stfself, rule->identity))
485                                         continue;
486                         }
487                         if (!dns_name_equal(stfself, name))
488                                 continue;
489                         break;
490                 case DNS_SSUMATCHTYPE_EXTERNAL:
491                         if (!dns_ssu_external_match(rule->identity, signer,
492                                                     name, tcpaddr, type, key,
493                                                     table->mctx))
494                                 continue;
495                         break;
496                 case DNS_SSUMATCHTYPE_DLZ:
497                         if (!dns_dlz_ssumatch(table->dlzdatabase, signer,
498                                               name, tcpaddr, type, key))
499                                 continue;
500                         break;
501                 }
502
503                 if (rule->ntypes == 0) {
504                         /*
505                          * If this is a DLZ rule, then the DLZ ssu
506                          * checks will have already checked
507                          * the type.
508                          */
509                         if (rule->matchtype != DNS_SSUMATCHTYPE_DLZ &&
510                             !isusertype(type))
511                                 continue;
512                 } else {
513                         for (i = 0; i < rule->ntypes; i++) {
514                                 if (rule->types[i] == dns_rdatatype_any ||
515                                     rule->types[i] == type)
516                                         break;
517                         }
518                         if (i == rule->ntypes)
519                                 continue;
520                 }
521                 return (rule->grant);
522         }
523
524         return (ISC_FALSE);
525 }
526
527 isc_boolean_t
528 dns_ssurule_isgrant(const dns_ssurule_t *rule) {
529         REQUIRE(VALID_SSURULE(rule));
530         return (rule->grant);
531 }
532
533 dns_name_t *
534 dns_ssurule_identity(const dns_ssurule_t *rule) {
535         REQUIRE(VALID_SSURULE(rule));
536         return (rule->identity);
537 }
538
539 unsigned int
540 dns_ssurule_matchtype(const dns_ssurule_t *rule) {
541         REQUIRE(VALID_SSURULE(rule));
542         return (rule->matchtype);
543 }
544
545 dns_name_t *
546 dns_ssurule_name(const dns_ssurule_t *rule) {
547         REQUIRE(VALID_SSURULE(rule));
548         return (rule->name);
549 }
550
551 unsigned int
552 dns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types) {
553         REQUIRE(VALID_SSURULE(rule));
554         REQUIRE(types != NULL && *types != NULL);
555         *types = rule->types;
556         return (rule->ntypes);
557 }
558
559 isc_result_t
560 dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
561         REQUIRE(VALID_SSUTABLE(table));
562         REQUIRE(rule != NULL && *rule == NULL);
563         *rule = ISC_LIST_HEAD(table->rules);
564         return (*rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
565 }
566
567 isc_result_t
568 dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
569         REQUIRE(VALID_SSURULE(rule));
570         REQUIRE(nextrule != NULL && *nextrule == NULL);
571         *nextrule = ISC_LIST_NEXT(rule, link);
572         return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
573 }
574
575 /*
576  * Create a specialised SSU table that points at an external DLZ database
577  */
578 isc_result_t
579 dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
580                        dns_dlzdb_t *dlzdatabase)
581 {
582         isc_result_t result;
583         dns_ssurule_t *rule;
584         dns_ssutable_t *table = NULL;
585
586         REQUIRE(tablep != NULL && *tablep == NULL);
587
588         result = dns_ssutable_create(mctx, &table);
589         if (result != ISC_R_SUCCESS)
590                 return (result);
591
592         table->dlzdatabase = dlzdatabase;
593
594         rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t));
595         if (rule == NULL) {
596                 dns_ssutable_detach(&table);
597                 return (ISC_R_NOMEMORY);
598         }
599
600         rule->identity = NULL;
601         rule->name = NULL;
602         rule->types = NULL;
603         rule->grant = ISC_TRUE;
604         rule->matchtype = DNS_SSUMATCHTYPE_DLZ;
605         rule->ntypes = 0;
606         rule->types = NULL;
607         rule->magic = SSURULEMAGIC;
608
609         ISC_LIST_INITANDAPPEND(table->rules, rule, link);
610         *tablep = table;
611         return (ISC_R_SUCCESS);
612 }