/contrib/bind9/lib/dns/keytable.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 672 lines · 468 code · 131 blank · 73 comment · 169 complexity · e79990afe7938abd99c692a1fc7a1b72 MD5 · raw file

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