]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/keytable.c
Update BIND to 9.9.8
[FreeBSD/stable/9.git] / contrib / bind9 / lib / dns / keytable.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009, 2010, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  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 /* $Id: keytable.c,v 1.41 2010/06/25 23:46:51 tbox Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/rwlock.h>
27 #include <isc/string.h>         /* Required for HP/UX (and others?) */
28 #include <isc/util.h>
29
30 #include <dns/keytable.h>
31 #include <dns/fixedname.h>
32 #include <dns/rbt.h>
33 #include <dns/result.h>
34
35 static void
36 free_keynode(void *node, void *arg) {
37         dns_keynode_t *keynode = node;
38         isc_mem_t *mctx = arg;
39
40         dns_keynode_detachall(mctx, &keynode);
41 }
42
43 isc_result_t
44 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
45         dns_keytable_t *keytable;
46         isc_result_t result;
47
48         /*
49          * Create a keytable.
50          */
51
52         REQUIRE(keytablep != NULL && *keytablep == NULL);
53
54         keytable = isc_mem_get(mctx, sizeof(*keytable));
55         if (keytable == NULL)
56                 return (ISC_R_NOMEMORY);
57
58         keytable->table = NULL;
59         result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
60         if (result != ISC_R_SUCCESS)
61                 goto cleanup_keytable;
62
63         result = isc_mutex_init(&keytable->lock);
64         if (result != ISC_R_SUCCESS)
65                 goto cleanup_rbt;
66
67         result = isc_rwlock_init(&keytable->rwlock, 0, 0);
68         if (result != ISC_R_SUCCESS)
69                 goto cleanup_lock;
70
71         keytable->mctx = NULL;
72         isc_mem_attach(mctx, &keytable->mctx);
73         keytable->active_nodes = 0;
74         keytable->references = 1;
75         keytable->magic = KEYTABLE_MAGIC;
76         *keytablep = keytable;
77
78         return (ISC_R_SUCCESS);
79
80    cleanup_lock:
81         DESTROYLOCK(&keytable->lock);
82
83    cleanup_rbt:
84         dns_rbt_destroy(&keytable->table);
85
86    cleanup_keytable:
87         isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
88
89         return (result);
90 }
91
92 void
93 dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
94
95         /*
96          * Attach *targetp to source.
97          */
98
99         REQUIRE(VALID_KEYTABLE(source));
100         REQUIRE(targetp != NULL && *targetp == NULL);
101
102         RWLOCK(&source->rwlock, isc_rwlocktype_write);
103
104         INSIST(source->references > 0);
105         source->references++;
106         INSIST(source->references != 0);
107
108         RWUNLOCK(&source->rwlock, isc_rwlocktype_write);
109
110         *targetp = source;
111 }
112
113 void
114 dns_keytable_detach(dns_keytable_t **keytablep) {
115         isc_boolean_t destroy = ISC_FALSE;
116         dns_keytable_t *keytable;
117
118         /*
119          * Detach *keytablep from its keytable.
120          */
121
122         REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
123
124         keytable = *keytablep;
125
126         RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
127
128         INSIST(keytable->references > 0);
129         keytable->references--;
130         LOCK(&keytable->lock);
131         if (keytable->references == 0 && keytable->active_nodes == 0)
132                 destroy = ISC_TRUE;
133         UNLOCK(&keytable->lock);
134
135         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
136
137         if (destroy) {
138                 dns_rbt_destroy(&keytable->table);
139                 isc_rwlock_destroy(&keytable->rwlock);
140                 DESTROYLOCK(&keytable->lock);
141                 keytable->magic = 0;
142                 isc_mem_putanddetach(&keytable->mctx,
143                                      keytable, sizeof(*keytable));
144         }
145
146         *keytablep = NULL;
147 }
148
149 static isc_result_t
150 insert(dns_keytable_t *keytable, isc_boolean_t managed,
151        dns_name_t *keyname, dst_key_t **keyp)
152 {
153         isc_result_t result;
154         dns_keynode_t *knode = NULL;
155         dns_rbtnode_t *node;
156
157         REQUIRE(keyp == NULL || *keyp != NULL);
158         REQUIRE(VALID_KEYTABLE(keytable));
159
160         result = dns_keynode_create(keytable->mctx, &knode);
161         if (result != ISC_R_SUCCESS)
162                 return (result);
163
164         knode->managed = managed;
165
166         RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
167
168         node = NULL;
169         result = dns_rbt_addnode(keytable->table, keyname, &node);
170
171         if (keyp != NULL) {
172                 if (result == ISC_R_EXISTS) {
173                         /* Key already in table? */
174                         dns_keynode_t *k;
175                         for (k = node->data; k != NULL; k = k->next) {
176                                 if (k->key == NULL) {
177                                         k->key = *keyp;
178                                         *keyp = NULL; /* transfer ownership */
179                                         break;
180                                 }
181                                 if (dst_key_compare(k->key, *keyp) == ISC_TRUE)
182                                         break;
183                         }
184
185                         if (k == NULL)
186                                 result = ISC_R_SUCCESS;
187                         else if (*keyp != NULL)
188                                 dst_key_free(keyp);
189                 }
190
191                 if (result == ISC_R_SUCCESS) {
192                         knode->key = *keyp;
193                         knode->next = node->data;
194                         *keyp = NULL;
195                 }
196         }
197
198         if (result == ISC_R_SUCCESS) {
199                 node->data = knode;
200                 knode = NULL;
201         }
202
203         /* Key was already there?  That's the same as a success */
204         if (result == ISC_R_EXISTS)
205                 result = ISC_R_SUCCESS;
206
207         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
208
209         if (knode != NULL)
210                 dns_keynode_detach(keytable->mctx, &knode);
211
212         return (result);
213 }
214
215 isc_result_t
216 dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
217                  dst_key_t **keyp)
218 {
219         REQUIRE(keyp != NULL && *keyp != NULL);
220         return (insert(keytable, managed, dst_key_name(*keyp), keyp));
221 }
222
223 isc_result_t
224 dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name) {
225         return (insert(keytable, ISC_TRUE, name, NULL));
226 }
227
228 isc_result_t
229 dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname) {
230         isc_result_t result;
231         dns_rbtnode_t *node = NULL;
232
233         REQUIRE(VALID_KEYTABLE(keytable));
234         REQUIRE(keyname != NULL);
235
236         RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
237         result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
238                                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
239         if (result == ISC_R_SUCCESS) {
240                 if (node->data != NULL)
241                         result = dns_rbt_deletenode(keytable->table,
242                                                     node, ISC_FALSE);
243                 else
244                         result = ISC_R_NOTFOUND;
245         } else if (result == DNS_R_PARTIALMATCH)
246                 result = ISC_R_NOTFOUND;
247         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
248
249         return (result);
250 }
251
252 isc_result_t
253 dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) {
254         isc_result_t result;
255         dns_name_t *keyname;
256         dns_rbtnode_t *node = NULL;
257         dns_keynode_t *knode = NULL, **kprev = NULL;
258
259         REQUIRE(VALID_KEYTABLE(keytable));
260         REQUIRE(dstkey != NULL);
261
262         keyname = dst_key_name(dstkey);
263
264         RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
265         result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
266                                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
267
268         if (result == DNS_R_PARTIALMATCH)
269                 result = ISC_R_NOTFOUND;
270         if (result != ISC_R_SUCCESS)
271                 goto finish;
272
273         if (node->data == NULL) {
274                 result = ISC_R_NOTFOUND;
275                 goto finish;
276         }
277
278         knode = node->data;
279         if (knode->next == NULL && knode->key != NULL &&
280             dst_key_compare(knode->key, dstkey) == ISC_TRUE)
281         {
282                 result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE);
283                 goto finish;
284         }
285
286         kprev = (dns_keynode_t **) &node->data;
287         while (knode != NULL) {
288                 if (knode->key != NULL &&
289                     dst_key_compare(knode->key, dstkey) == ISC_TRUE)
290                         break;
291                 kprev = &knode->next;
292                 knode = knode->next;
293         }
294
295         if (knode != NULL) {
296                 if (knode->key != NULL)
297                         dst_key_free(&knode->key);
298                 /*
299                  * This is equivalent to:
300                  * dns_keynode_attach(knode->next, &tmp);
301                  * dns_keynode_detach(kprev);
302                  * dns_keynode_attach(tmp, &kprev);
303                  * dns_keynode_detach(&tmp);
304                  */
305                 *kprev = knode->next;
306                 knode->next = NULL;
307                 dns_keynode_detach(keytable->mctx, &knode);
308         } else
309                 result = DNS_R_PARTIALMATCH;
310   finish:
311         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
312         return (result);
313 }
314
315 isc_result_t
316 dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname,
317                   dns_keynode_t **keynodep)
318 {
319         isc_result_t result;
320         dns_rbtnode_t *node = NULL;
321
322         REQUIRE(VALID_KEYTABLE(keytable));
323         REQUIRE(keyname != NULL);
324         REQUIRE(keynodep != NULL && *keynodep == NULL);
325
326         RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
327         result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
328                                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
329         if (result == ISC_R_SUCCESS) {
330                 if (node->data != NULL) {
331                         LOCK(&keytable->lock);
332                         keytable->active_nodes++;
333                         UNLOCK(&keytable->lock);
334                         dns_keynode_attach(node->data, keynodep);
335                 } else
336                         result = ISC_R_NOTFOUND;
337         } else if (result == DNS_R_PARTIALMATCH)
338                 result = ISC_R_NOTFOUND;
339         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
340
341         return (result);
342 }
343
344 isc_result_t
345 dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
346                          dns_keynode_t **nextnodep)
347 {
348         /*
349          * Return the next key after 'keynode', regardless of
350          * properties.
351          */
352
353         REQUIRE(VALID_KEYTABLE(keytable));
354         REQUIRE(VALID_KEYNODE(keynode));
355         REQUIRE(nextnodep != NULL && *nextnodep == NULL);
356
357         if (keynode->next == NULL)
358                 return (ISC_R_NOTFOUND);
359
360         dns_keynode_attach(keynode->next, nextnodep);
361         LOCK(&keytable->lock);
362         keytable->active_nodes++;
363         UNLOCK(&keytable->lock);
364
365         return (ISC_R_SUCCESS);
366 }
367
368 isc_result_t
369 dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name,
370                          dns_secalg_t algorithm, dns_keytag_t tag,
371                          dns_keynode_t **keynodep)
372 {
373         isc_result_t result;
374         dns_keynode_t *knode;
375         void *data;
376
377         /*
378          * Search for a key named 'name', matching 'algorithm' and 'tag' in
379          * 'keytable'.
380          */
381
382         REQUIRE(VALID_KEYTABLE(keytable));
383         REQUIRE(dns_name_isabsolute(name));
384         REQUIRE(keynodep != NULL && *keynodep == NULL);
385
386         RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
387
388         /*
389          * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
390          * as that indicates that 'name' was not found.
391          *
392          * DNS_R_PARTIALMATCH indicates that the name was found but we
393          * didn't get a match on algorithm and key id arguments.
394          */
395         knode = NULL;
396         data = NULL;
397         result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
398
399         if (result == ISC_R_SUCCESS) {
400                 INSIST(data != NULL);
401                 for (knode = data; knode != NULL; knode = knode->next) {
402                         if (knode->key == NULL) {
403                                 knode = NULL;
404                                 break;
405                         }
406                         if (algorithm == dst_key_alg(knode->key)
407                             && tag == dst_key_id(knode->key))
408                                 break;
409                 }
410                 if (knode != NULL) {
411                         LOCK(&keytable->lock);
412                         keytable->active_nodes++;
413                         UNLOCK(&keytable->lock);
414                         dns_keynode_attach(knode, keynodep);
415                 } else
416                         result = DNS_R_PARTIALMATCH;
417         } else if (result == DNS_R_PARTIALMATCH)
418                 result = ISC_R_NOTFOUND;
419
420         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
421
422         return (result);
423 }
424
425 isc_result_t
426 dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
427                              dns_keynode_t **nextnodep)
428 {
429         isc_result_t result;
430         dns_keynode_t *knode;
431
432         /*
433          * Search for the next key with the same properties as 'keynode' in
434          * 'keytable'.
435          */
436
437         REQUIRE(VALID_KEYTABLE(keytable));
438         REQUIRE(VALID_KEYNODE(keynode));
439         REQUIRE(nextnodep != NULL && *nextnodep == NULL);
440
441         for (knode = keynode->next; knode != NULL; knode = knode->next) {
442                 if (knode->key == NULL) {
443                         knode = NULL;
444                         break;
445                 }
446                 if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) &&
447                     dst_key_id(keynode->key) == dst_key_id(knode->key))
448                         break;
449         }
450         if (knode != NULL) {
451                 LOCK(&keytable->lock);
452                 keytable->active_nodes++;
453                 UNLOCK(&keytable->lock);
454                 result = ISC_R_SUCCESS;
455                 dns_keynode_attach(knode, nextnodep);
456         } else
457                 result = ISC_R_NOTFOUND;
458
459         return (result);
460 }
461
462 isc_result_t
463 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name,
464                               dns_name_t *foundname)
465 {
466         isc_result_t result;
467         void *data;
468
469         /*
470          * Search for the deepest match in 'keytable'.
471          */
472
473         REQUIRE(VALID_KEYTABLE(keytable));
474         REQUIRE(dns_name_isabsolute(name));
475         REQUIRE(foundname != NULL);
476
477         RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
478
479         data = NULL;
480         result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
481
482         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
483                 result = ISC_R_SUCCESS;
484
485         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
486
487         return (result);
488 }
489
490 void
491 dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source,
492                            dns_keynode_t **target)
493 {
494         /*
495          * Give back a keynode found via dns_keytable_findkeynode().
496          */
497
498         REQUIRE(VALID_KEYTABLE(keytable));
499         REQUIRE(VALID_KEYNODE(source));
500         REQUIRE(target != NULL && *target == NULL);
501
502         LOCK(&keytable->lock);
503         keytable->active_nodes++;
504         UNLOCK(&keytable->lock);
505
506         dns_keynode_attach(source, target);
507 }
508
509 void
510 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep)
511 {
512         /*
513          * Give back a keynode found via dns_keytable_findkeynode().
514          */
515
516         REQUIRE(VALID_KEYTABLE(keytable));
517         REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
518
519         LOCK(&keytable->lock);
520         INSIST(keytable->active_nodes > 0);
521         keytable->active_nodes--;
522         UNLOCK(&keytable->lock);
523
524         dns_keynode_detach(keytable->mctx, keynodep);
525 }
526
527 isc_result_t
528 dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
529                             isc_boolean_t *wantdnssecp)
530 {
531         isc_result_t result;
532         void *data;
533
534         /*
535          * Is 'name' at or beneath a trusted key?
536          */
537
538         REQUIRE(VALID_KEYTABLE(keytable));
539         REQUIRE(dns_name_isabsolute(name));
540         REQUIRE(wantdnssecp != NULL);
541
542         RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
543
544         data = NULL;
545         result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
546
547         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
548                 INSIST(data != NULL);
549                 *wantdnssecp = ISC_TRUE;
550                 result = ISC_R_SUCCESS;
551         } else if (result == ISC_R_NOTFOUND) {
552                 *wantdnssecp = ISC_FALSE;
553                 result = ISC_R_SUCCESS;
554         }
555
556         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
557
558         return (result);
559 }
560
561 isc_result_t
562 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp)
563 {
564         isc_result_t result;
565         dns_keynode_t *knode;
566         dns_rbtnode_t *node;
567         dns_rbtnodechain_t chain;
568
569         REQUIRE(VALID_KEYTABLE(keytable));
570
571         RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
572         dns_rbtnodechain_init(&chain, keytable->mctx);
573         result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
574         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
575                 goto cleanup;
576         for (;;) {
577                 char pbuf[DST_KEY_FORMATSIZE];
578
579                 dns_rbtnodechain_current(&chain, NULL, NULL, &node);
580                 for (knode = node->data; knode != NULL; knode = knode->next) {
581                         if (knode->key == NULL)
582                                 continue;
583                         dst_key_format(knode->key, pbuf, sizeof(pbuf));
584                         fprintf(fp, "%s ; %s\n", pbuf,
585                                 knode->managed ? "managed" : "trusted");
586                 }
587                 result = dns_rbtnodechain_next(&chain, NULL, NULL);
588                 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
589                         if (result == ISC_R_NOMORE)
590                                 result = ISC_R_SUCCESS;
591                         break;
592                 }
593         }
594
595    cleanup:
596         dns_rbtnodechain_invalidate(&chain);
597         RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
598         return (result);
599 }
600
601 dst_key_t *
602 dns_keynode_key(dns_keynode_t *keynode) {
603
604         /*
605          * Get the DST key associated with keynode.
606          */
607
608         REQUIRE(VALID_KEYNODE(keynode));
609
610         return (keynode->key);
611 }
612
613 isc_boolean_t
614 dns_keynode_managed(dns_keynode_t *keynode) {
615         /*
616          * Is this a managed key?
617          */
618         REQUIRE(VALID_KEYNODE(keynode));
619
620         return (keynode->managed);
621 }
622
623 isc_result_t
624 dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) {
625         isc_result_t result;
626         dns_keynode_t *knode = NULL;
627
628         REQUIRE(target != NULL && *target == NULL);
629
630         knode = isc_mem_get(mctx, sizeof(dns_keynode_t));
631         if (knode == NULL)
632                 return (ISC_R_NOMEMORY);
633
634         knode->magic = KEYNODE_MAGIC;
635         knode->managed = ISC_FALSE;
636         knode->key = NULL;
637         knode->next = NULL;
638
639         result = isc_refcount_init(&knode->refcount, 1);
640         if (result != ISC_R_SUCCESS)
641                 return (result);
642
643         *target = knode;
644         return (ISC_R_SUCCESS);
645 }
646
647 void
648 dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
649         REQUIRE(VALID_KEYNODE(source));
650         isc_refcount_increment(&source->refcount, NULL);
651         *target = source;
652 }
653
654 void
655 dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) {
656         unsigned int refs;
657         dns_keynode_t *node = *keynode;
658         REQUIRE(VALID_KEYNODE(node));
659         isc_refcount_decrement(&node->refcount, &refs);
660         if (refs == 0) {
661                 if (node->key != NULL)
662                         dst_key_free(&node->key);
663                 isc_refcount_destroy(&node->refcount);
664                 isc_mem_put(mctx, node, sizeof(dns_keynode_t));
665         }
666         *keynode = NULL;
667 }
668
669 void
670 dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **keynode) {
671         dns_keynode_t *next = NULL, *node = *keynode;
672         REQUIRE(VALID_KEYNODE(node));
673         while (node != NULL) {
674                 next = node->next;
675                 dns_keynode_detach(mctx, &node);
676                 node = next;
677         }
678         *keynode = NULL;
679 }