1/*
2 * Copyright (C) 2002  Nuno M. Rodrigues.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND NUNO M. RODRIGUES
9 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
11 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
13 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
15 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id$ */
19
20/*
21 * BIND 9.1.x simple database driver
22 * implementation, using Berkeley DB.
23 */
24
25#include <errno.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29
30#include <isc/file.h>
31#include <isc/log.h>
32#include <isc/lib.h>
33#include <isc/mem.h>
34#include <isc/msgs.h>
35#include <isc/msgcat.h>
36#include <isc/region.h>
37#include <isc/result.h>
38#include <isc/types.h>
39#include <isc/util.h>
40
41#include <dns/sdb.h>
42#include <dns/log.h>
43#include <dns/lib.h>
44#include <dns/ttl.h>
45
46#include <named/bdb.h>
47#include <named/globals.h>
48#include <named/config.h>
49
50#include <db.h>
51
52#define DRIVERNAME	"bdb"
53
54static dns_sdbimplementation_t *bdb_imp;
55
56static isc_result_t
57bdb_create(const char *zone, int argc, char **argv,
58	   void *unused, void **dbdata)
59{
60	int ret;
61
62	UNUSED(zone);
63	UNUSED(unused);
64
65	if (argc < 1)
66		return ISC_R_FAILURE;	/* database path must be given */
67
68	if (db_create((DB **)dbdata, NULL, 0) != 0) {
69		/*
70		 * XXX Should use dns_msgcat et al
71		 * but seems to be unavailable.
72		 */
73		isc_log_iwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
74			       DNS_LOGMODULE_SDB, ISC_LOG_CRITICAL, isc_msgcat,
75			       ISC_MSGSET_GENERAL, ISC_MSG_FATALERROR,
76			       "db_create");
77		return ISC_R_FAILURE;
78	}
79
80	if (isc_file_exists(*argv) != ISC_TRUE) {
81		isc_log_iwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
82			       DNS_LOGMODULE_SDB, ISC_LOG_CRITICAL, isc_msgcat,
83			       ISC_MSGSET_GENERAL, ISC_MSG_FATALERROR,
84			       "isc_file_exists: %s", *argv);
85		return ISC_R_FAILURE;
86	}
87
88	if ((ret = (*(DB **)dbdata)->open(*(DB **)dbdata, *argv, NULL, DB_HASH,
89	    DB_RDONLY, 0)) != 0) {
90			isc_log_iwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
91				       DNS_LOGMODULE_SDB, ISC_LOG_CRITICAL,
92				       isc_msgcat, ISC_MSGSET_GENERAL,
93				       ISC_MSG_FATALERROR, "DB->open: %s",
94				       db_strerror(ret));
95			return ISC_R_FAILURE;
96	}
97	return ISC_R_SUCCESS;
98}
99
100static isc_result_t
101bdb_lookup(const char *zone, const char *name, void *dbdata,
102	   dns_sdblookup_t *l)
103{
104	int ret;
105	char *type, *rdata;
106	dns_ttl_t ttl;
107	isc_consttextregion_t ttltext;
108	DBC *c;
109	DBT key, data;
110
111	UNUSED(zone);
112
113	if ((ret = ((DB *)dbdata)->cursor((DB *)dbdata, NULL, &c, 0)) != 0) {
114		isc_log_iwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
115			       DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
116			       isc_msgcat, ISC_MSGSET_GENERAL,
117			       ISC_MSG_FAILED, "DB->cursor: %s",
118			       db_strerror(ret));
119		return ISC_R_FAILURE;
120	}
121
122	memset(&key, 0, sizeof(DBT));
123	memset(&data, 0, sizeof(DBT));
124
125	(const char *)key.data = name;
126	key.size = strlen(name);
127
128	ret = c->c_get(c, &key, &data, DB_SET);
129	while (ret == 0) {
130		((char *)key.data)[key.size] = 0;
131		((char *)data.data)[data.size] = 0;
132		ttltext.base = strtok((char *)data.data, " ");
133		ttltext.length = strlen(ttltext.base);
134		dns_ttl_fromtext((isc_textregion_t *)&ttltext, &ttl);
135		type = strtok(NULL, " ");
136		rdata = type + strlen(type) + 1;
137
138		if (dns_sdb_putrr(l, type, ttl, rdata) != ISC_R_SUCCESS) {
139			isc_log_iwrite(dns_lctx,
140				       DNS_LOGCATEGORY_DATABASE,
141				       DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
142				       isc_msgcat, ISC_MSGSET_GENERAL,
143				       ISC_MSG_FAILED, "dns_sdb_putrr");
144			return ISC_R_FAILURE;
145		}
146		ret = c->c_get(c, &key, &data, DB_NEXT_DUP);
147	}
148
149	c->c_close(c);
150	return ISC_R_SUCCESS;
151}
152
153static isc_result_t
154bdb_allnodes(const char *zone, void *dbdata, dns_sdballnodes_t *n)
155{
156	int ret;
157	char *type, *rdata;
158	dns_ttl_t ttl;
159	isc_consttextregion_t ttltext;
160	DBC *c;
161	DBT key, data;
162
163	UNUSED(zone);
164
165	if ((ret = ((DB *)dbdata)->cursor((DB *)dbdata, NULL, &c, 0)) != 0) {
166		isc_log_iwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
167			       DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
168			       isc_msgcat, ISC_MSGSET_GENERAL,
169			       ISC_MSG_FAILED, "DB->cursor: %s",
170			       db_strerror(ret));
171		return ISC_R_FAILURE;
172	}
173
174	memset(&key, 0, sizeof(DBT));
175	memset(&data, 0, sizeof(DBT));
176
177	while (c->c_get(c, &key, &data, DB_NEXT) == 0) {
178		((char *)key.data)[key.size] = 0;
179		((char *)data.data)[data.size] = 0;
180		ttltext.base = strtok((char *)data.data, " ");
181		ttltext.length = strlen(ttltext.base);
182		dns_ttl_fromtext((isc_textregion_t *)&ttltext, &ttl);
183		type = strtok(NULL, " ");
184		rdata = type + strlen(type) + 1;
185
186		if (dns_sdb_putnamedrr(n, key.data, type, ttl, rdata) !=
187		    ISC_R_SUCCESS) {
188			isc_log_iwrite(dns_lctx,
189				       DNS_LOGCATEGORY_DATABASE,
190				       DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
191				       isc_msgcat, ISC_MSGSET_GENERAL,
192				       ISC_MSG_FAILED, "dns_sdb_putnamedrr");
193			return ISC_R_FAILURE;
194		}
195
196	}
197
198	c->c_close(c);
199	return ISC_R_SUCCESS;
200}
201
202static isc_result_t
203bdb_destroy(const char *zone, void *unused, void **dbdata)
204{
205
206	UNUSED(zone);
207	UNUSED(unused);
208
209	(*(DB **)dbdata)->close(*(DB **)dbdata, 0);
210
211	return ISC_R_SUCCESS;
212}
213
214isc_result_t
215bdb_init(void)
216{
217	static dns_sdbmethods_t bdb_methods = {
218		bdb_lookup,
219		NULL,
220		bdb_allnodes,
221		bdb_create,
222		bdb_destroy
223	};
224
225	return dns_sdb_register(DRIVERNAME, &bdb_methods, NULL, 0, ns_g_mctx,
226				&bdb_imp);
227}
228
229void
230bdb_clear(void)
231{
232
233	if (bdb_imp != NULL)
234		dns_sdb_unregister(&bdb_imp);
235}
236