1*00b67f09SDavid van Moolenbroek /* $NetBSD: dlz_sqlite3_dynamic.c,v 1.1.1.3 2014/12/10 03:34:31 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
7*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the
8*00b67f09SDavid van Moolenbroek * above copyright notice and this permission notice appear in all
9*00b67f09SDavid van Moolenbroek * copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12*00b67f09SDavid van Moolenbroek * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13*00b67f09SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14*00b67f09SDavid van Moolenbroek * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15*00b67f09SDavid van Moolenbroek * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16*00b67f09SDavid van Moolenbroek * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18*00b67f09SDavid van Moolenbroek * USE OR PERFORMANCE OF THIS SOFTWARE.
19*00b67f09SDavid van Moolenbroek *
20*00b67f09SDavid van Moolenbroek * The development of Dynamically Loadable Zones (DLZ) for BIND 9 was
21*00b67f09SDavid van Moolenbroek * conceived and contributed by Rob Butler.
22*00b67f09SDavid van Moolenbroek *
23*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
24*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the
25*00b67f09SDavid van Moolenbroek * above copyright notice and this permission notice appear in all
26*00b67f09SDavid van Moolenbroek * copies.
27*00b67f09SDavid van Moolenbroek *
28*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29*00b67f09SDavid van Moolenbroek * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30*00b67f09SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31*00b67f09SDavid van Moolenbroek * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32*00b67f09SDavid van Moolenbroek * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33*00b67f09SDavid van Moolenbroek * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35*00b67f09SDavid van Moolenbroek * USE OR PERFORMANCE OF THIS SOFTWARE.
36*00b67f09SDavid van Moolenbroek */
37*00b67f09SDavid van Moolenbroek
38*00b67f09SDavid van Moolenbroek /*
39*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2001 Internet Software Consortium.
40*00b67f09SDavid van Moolenbroek * Copyright (C) 2013-2014 Internet Systems Consortium.
41*00b67f09SDavid van Moolenbroek *
42*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
43*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
44*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
45*00b67f09SDavid van Moolenbroek *
46*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
47*00b67f09SDavid van Moolenbroek * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
48*00b67f09SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
49*00b67f09SDavid van Moolenbroek * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
50*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
51*00b67f09SDavid van Moolenbroek * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
52*00b67f09SDavid van Moolenbroek * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
53*00b67f09SDavid van Moolenbroek * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
54*00b67f09SDavid van Moolenbroek */
55*00b67f09SDavid van Moolenbroek
56*00b67f09SDavid van Moolenbroek /*
57*00b67f09SDavid van Moolenbroek * This provides the externally loadable SQLitee DLZ module, without
58*00b67f09SDavid van Moolenbroek * update support. Based in part on SQLite code contributed by Tim Tessier.
59*00b67f09SDavid van Moolenbroek */
60*00b67f09SDavid van Moolenbroek
61*00b67f09SDavid van Moolenbroek #include <stdio.h>
62*00b67f09SDavid van Moolenbroek #include <string.h>
63*00b67f09SDavid van Moolenbroek #include <stdarg.h>
64*00b67f09SDavid van Moolenbroek #include <stdint.h>
65*00b67f09SDavid van Moolenbroek #include <stdlib.h>
66*00b67f09SDavid van Moolenbroek
67*00b67f09SDavid van Moolenbroek #include <dlz_minimal.h>
68*00b67f09SDavid van Moolenbroek #include <dlz_list.h>
69*00b67f09SDavid van Moolenbroek #include <dlz_dbi.h>
70*00b67f09SDavid van Moolenbroek #include <dlz_pthread.h>
71*00b67f09SDavid van Moolenbroek
72*00b67f09SDavid van Moolenbroek #include <sqlite3.h>
73*00b67f09SDavid van Moolenbroek
74*00b67f09SDavid van Moolenbroek #define dbc_search_limit 30
75*00b67f09SDavid van Moolenbroek #define ALLNODES 1
76*00b67f09SDavid van Moolenbroek #define ALLOWXFR 2
77*00b67f09SDavid van Moolenbroek #define AUTHORITY 3
78*00b67f09SDavid van Moolenbroek #define FINDZONE 4
79*00b67f09SDavid van Moolenbroek #define COUNTZONE 5
80*00b67f09SDavid van Moolenbroek #define LOOKUP 6
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek #define safeGet(in) in == NULL ? "" : in
83*00b67f09SDavid van Moolenbroek
84*00b67f09SDavid van Moolenbroek /*%
85*00b67f09SDavid van Moolenbroek * Structure to hold everthing needed by this "instance" of the SQLite3
86*00b67f09SDavid van Moolenbroek * module remember, the module code is only loaded once, but may have
87*00b67f09SDavid van Moolenbroek * many separate instances.
88*00b67f09SDavid van Moolenbroek */
89*00b67f09SDavid van Moolenbroek typedef struct {
90*00b67f09SDavid van Moolenbroek #if PTHREADS
91*00b67f09SDavid van Moolenbroek db_list_t *db; /*%< handle to a list of DB */
92*00b67f09SDavid van Moolenbroek int dbcount;
93*00b67f09SDavid van Moolenbroek #else
94*00b67f09SDavid van Moolenbroek dbinstance_t *db; /*%< handle to DB */
95*00b67f09SDavid van Moolenbroek #endif
96*00b67f09SDavid van Moolenbroek
97*00b67f09SDavid van Moolenbroek char *dbname;
98*00b67f09SDavid van Moolenbroek
99*00b67f09SDavid van Moolenbroek /* Helper functions from the dlz_dlopen driver */
100*00b67f09SDavid van Moolenbroek log_t *log;
101*00b67f09SDavid van Moolenbroek dns_sdlz_putrr_t *putrr;
102*00b67f09SDavid van Moolenbroek dns_sdlz_putnamedrr_t *putnamedrr;
103*00b67f09SDavid van Moolenbroek dns_dlz_writeablezone_t *writeable_zone;
104*00b67f09SDavid van Moolenbroek } sqlite3_instance_t;
105*00b67f09SDavid van Moolenbroek
106*00b67f09SDavid van Moolenbroek /*
107*00b67f09SDavid van Moolenbroek * SQLite3 result set
108*00b67f09SDavid van Moolenbroek */
109*00b67f09SDavid van Moolenbroek typedef struct {
110*00b67f09SDavid van Moolenbroek char **pazResult; /* Result of the query */
111*00b67f09SDavid van Moolenbroek unsigned int pnRow; /* Number of result rows */
112*00b67f09SDavid van Moolenbroek unsigned int pnColumn; /* Number of result columns */
113*00b67f09SDavid van Moolenbroek unsigned int curRow; /* Current row */
114*00b67f09SDavid van Moolenbroek char *pzErrmsg; /* Error message */
115*00b67f09SDavid van Moolenbroek } sqlite3_res_t;
116*00b67f09SDavid van Moolenbroek
117*00b67f09SDavid van Moolenbroek /* forward references */
118*00b67f09SDavid van Moolenbroek isc_result_t
119*00b67f09SDavid van Moolenbroek dlz_findzonedb(void *dbdata, const char *name,
120*00b67f09SDavid van Moolenbroek dns_clientinfomethods_t *methods,
121*00b67f09SDavid van Moolenbroek dns_clientinfo_t *clientinfo);
122*00b67f09SDavid van Moolenbroek
123*00b67f09SDavid van Moolenbroek void
124*00b67f09SDavid van Moolenbroek dlz_destroy(void *dbdata);
125*00b67f09SDavid van Moolenbroek
126*00b67f09SDavid van Moolenbroek static void
127*00b67f09SDavid van Moolenbroek b9_add_helper(sqlite3_instance_t *db, const char *helper_name, void *ptr);
128*00b67f09SDavid van Moolenbroek
129*00b67f09SDavid van Moolenbroek /*
130*00b67f09SDavid van Moolenbroek * Private methods
131*00b67f09SDavid van Moolenbroek */
132*00b67f09SDavid van Moolenbroek
133*00b67f09SDavid van Moolenbroek void
sqlite3_destroy(dbinstance_t * db)134*00b67f09SDavid van Moolenbroek sqlite3_destroy(dbinstance_t *db) {
135*00b67f09SDavid van Moolenbroek /* release DB connection */
136*00b67f09SDavid van Moolenbroek if (db->dbconn != NULL)
137*00b67f09SDavid van Moolenbroek sqlite3_close((sqlite3 *) db->dbconn);
138*00b67f09SDavid van Moolenbroek sqlite3_shutdown();
139*00b67f09SDavid van Moolenbroek
140*00b67f09SDavid van Moolenbroek /* destroy DB instance */
141*00b67f09SDavid van Moolenbroek destroy_dbinstance(db);
142*00b67f09SDavid van Moolenbroek }
143*00b67f09SDavid van Moolenbroek
144*00b67f09SDavid van Moolenbroek #if PTHREADS
145*00b67f09SDavid van Moolenbroek /*%
146*00b67f09SDavid van Moolenbroek * Properly cleans up a list of database instances.
147*00b67f09SDavid van Moolenbroek * This function is only used when the module is compiled for
148*00b67f09SDavid van Moolenbroek * multithreaded operation.
149*00b67f09SDavid van Moolenbroek */
150*00b67f09SDavid van Moolenbroek static void
sqlite3_destroy_dblist(db_list_t * dblist)151*00b67f09SDavid van Moolenbroek sqlite3_destroy_dblist(db_list_t *dblist) {
152*00b67f09SDavid van Moolenbroek dbinstance_t *ndbi = NULL;
153*00b67f09SDavid van Moolenbroek dbinstance_t *dbi = NULL;
154*00b67f09SDavid van Moolenbroek
155*00b67f09SDavid van Moolenbroek ndbi = DLZ_LIST_HEAD(*dblist);
156*00b67f09SDavid van Moolenbroek while (ndbi != NULL) {
157*00b67f09SDavid van Moolenbroek dbi = ndbi;
158*00b67f09SDavid van Moolenbroek ndbi = DLZ_LIST_NEXT(dbi, link);
159*00b67f09SDavid van Moolenbroek
160*00b67f09SDavid van Moolenbroek sqlite3_destroy(dbi);
161*00b67f09SDavid van Moolenbroek }
162*00b67f09SDavid van Moolenbroek
163*00b67f09SDavid van Moolenbroek /* release memory for the list structure */
164*00b67f09SDavid van Moolenbroek free(dblist);
165*00b67f09SDavid van Moolenbroek }
166*00b67f09SDavid van Moolenbroek
167*00b67f09SDavid van Moolenbroek /*%
168*00b67f09SDavid van Moolenbroek * Loops through the list of DB instances, attempting to lock
169*00b67f09SDavid van Moolenbroek * on the mutex. If successful, the DBI is reserved for use
170*00b67f09SDavid van Moolenbroek * and the thread can perform queries against the database.
171*00b67f09SDavid van Moolenbroek * If the lock fails, the next one in the list is tried.
172*00b67f09SDavid van Moolenbroek * looping continues until a lock is obtained, or until
173*00b67f09SDavid van Moolenbroek * the list has been searched dbc_search_limit times.
174*00b67f09SDavid van Moolenbroek * This function is only used when the module is compiled for
175*00b67f09SDavid van Moolenbroek * multithreaded operation.
176*00b67f09SDavid van Moolenbroek */
177*00b67f09SDavid van Moolenbroek static dbinstance_t *
sqlite3_find_avail(sqlite3_instance_t * sqlite3)178*00b67f09SDavid van Moolenbroek sqlite3_find_avail(sqlite3_instance_t *sqlite3) {
179*00b67f09SDavid van Moolenbroek dbinstance_t *dbi = NULL, *head;
180*00b67f09SDavid van Moolenbroek int count = 0;
181*00b67f09SDavid van Moolenbroek
182*00b67f09SDavid van Moolenbroek /* get top of list */
183*00b67f09SDavid van Moolenbroek head = dbi = DLZ_LIST_HEAD(*(sqlite3->db));
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek /* loop through list */
186*00b67f09SDavid van Moolenbroek while (count < dbc_search_limit) {
187*00b67f09SDavid van Moolenbroek /* try to lock on the mutex */
188*00b67f09SDavid van Moolenbroek if (dlz_mutex_trylock(&dbi->lock) == 0)
189*00b67f09SDavid van Moolenbroek return (dbi); /* success, return the DBI for use. */
190*00b67f09SDavid van Moolenbroek
191*00b67f09SDavid van Moolenbroek /* not successful, keep trying */
192*00b67f09SDavid van Moolenbroek dbi = DLZ_LIST_NEXT(dbi, link);
193*00b67f09SDavid van Moolenbroek
194*00b67f09SDavid van Moolenbroek /* check to see if we have gone to the top of the list. */
195*00b67f09SDavid van Moolenbroek if (dbi == NULL) {
196*00b67f09SDavid van Moolenbroek count++;
197*00b67f09SDavid van Moolenbroek dbi = head;
198*00b67f09SDavid van Moolenbroek }
199*00b67f09SDavid van Moolenbroek }
200*00b67f09SDavid van Moolenbroek
201*00b67f09SDavid van Moolenbroek sqlite3->log(ISC_LOG_INFO,
202*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to find available connection "
203*00b67f09SDavid van Moolenbroek "after searching %d times", count);
204*00b67f09SDavid van Moolenbroek return (NULL);
205*00b67f09SDavid van Moolenbroek }
206*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
207*00b67f09SDavid van Moolenbroek
208*00b67f09SDavid van Moolenbroek /*%
209*00b67f09SDavid van Moolenbroek * Allocates memory for a new string, and then constructs the new
210*00b67f09SDavid van Moolenbroek * string by "escaping" the input string. The new string is
211*00b67f09SDavid van Moolenbroek * safe to be used in queries. This is necessary because we cannot
212*00b67f09SDavid van Moolenbroek * be sure of what types of strings are passed to us, and we don't
213*00b67f09SDavid van Moolenbroek * want special characters in the string causing problems.
214*00b67f09SDavid van Moolenbroek */
215*00b67f09SDavid van Moolenbroek static char *
escape_string(const char * instr)216*00b67f09SDavid van Moolenbroek escape_string(const char *instr) {
217*00b67f09SDavid van Moolenbroek char *outstr;
218*00b67f09SDavid van Moolenbroek char *ptr;
219*00b67f09SDavid van Moolenbroek unsigned int len;
220*00b67f09SDavid van Moolenbroek unsigned int tlen = 0;
221*00b67f09SDavid van Moolenbroek unsigned int atlen = 0;
222*00b67f09SDavid van Moolenbroek unsigned int i;
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek if (instr == NULL)
225*00b67f09SDavid van Moolenbroek return (NULL);
226*00b67f09SDavid van Moolenbroek len = strlen(instr);
227*00b67f09SDavid van Moolenbroek atlen = (2 * len * sizeof(char)) + 1;
228*00b67f09SDavid van Moolenbroek outstr = malloc(atlen);
229*00b67f09SDavid van Moolenbroek if (outstr == NULL)
230*00b67f09SDavid van Moolenbroek return (NULL);
231*00b67f09SDavid van Moolenbroek
232*00b67f09SDavid van Moolenbroek ptr = outstr;
233*00b67f09SDavid van Moolenbroek for (i = 0; i < len; i++) {
234*00b67f09SDavid van Moolenbroek if (tlen > atlen || instr[i] == '\0')
235*00b67f09SDavid van Moolenbroek break;
236*00b67f09SDavid van Moolenbroek
237*00b67f09SDavid van Moolenbroek if (instr[i] == '\'') {
238*00b67f09SDavid van Moolenbroek *ptr++ = '\'';
239*00b67f09SDavid van Moolenbroek tlen++;
240*00b67f09SDavid van Moolenbroek }
241*00b67f09SDavid van Moolenbroek
242*00b67f09SDavid van Moolenbroek *ptr++ = instr[i];
243*00b67f09SDavid van Moolenbroek tlen++;
244*00b67f09SDavid van Moolenbroek }
245*00b67f09SDavid van Moolenbroek *ptr = '\0';
246*00b67f09SDavid van Moolenbroek
247*00b67f09SDavid van Moolenbroek return (outstr);
248*00b67f09SDavid van Moolenbroek }
249*00b67f09SDavid van Moolenbroek
250*00b67f09SDavid van Moolenbroek /*%
251*00b67f09SDavid van Moolenbroek * This function is the real core of the module. Zone, record
252*00b67f09SDavid van Moolenbroek * and client strings are passed in (or NULL is passed if the
253*00b67f09SDavid van Moolenbroek * string is not available). The type of query we want to run
254*00b67f09SDavid van Moolenbroek * is indicated by the query flag, and the dbdata object is passed
255*00b67f09SDavid van Moolenbroek * passed in too. dbdata really holds a single database instance.
256*00b67f09SDavid van Moolenbroek * The function will construct and run the query, hopefully getting
257*00b67f09SDavid van Moolenbroek * a result set.
258*00b67f09SDavid van Moolenbroek */
259*00b67f09SDavid van Moolenbroek static isc_result_t
sqlite3_get_resultset(const char * zone,const char * record,const char * client,unsigned int query,void * dbdata,sqlite3_res_t ** rsp)260*00b67f09SDavid van Moolenbroek sqlite3_get_resultset(const char *zone, const char *record,
261*00b67f09SDavid van Moolenbroek const char *client, unsigned int query,
262*00b67f09SDavid van Moolenbroek void *dbdata, sqlite3_res_t **rsp)
263*00b67f09SDavid van Moolenbroek {
264*00b67f09SDavid van Moolenbroek isc_result_t result;
265*00b67f09SDavid van Moolenbroek dbinstance_t *dbi = NULL;
266*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *)dbdata;
267*00b67f09SDavid van Moolenbroek char *querystring = NULL;
268*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs = NULL;
269*00b67f09SDavid van Moolenbroek unsigned int i = 0;
270*00b67f09SDavid van Moolenbroek unsigned int j = 0;
271*00b67f09SDavid van Moolenbroek int qres = 0;
272*00b67f09SDavid van Moolenbroek
273*00b67f09SDavid van Moolenbroek if ((query == COUNTZONE && rsp != NULL) ||
274*00b67f09SDavid van Moolenbroek (query != COUNTZONE && (rsp == NULL || *rsp != NULL)))
275*00b67f09SDavid van Moolenbroek {
276*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_DEBUG(2), "Invalid result set pointer.");
277*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
278*00b67f09SDavid van Moolenbroek goto cleanup;
279*00b67f09SDavid van Moolenbroek }
280*00b67f09SDavid van Moolenbroek
281*00b67f09SDavid van Moolenbroek #if PTHREADS
282*00b67f09SDavid van Moolenbroek /* find an available DBI from the list */
283*00b67f09SDavid van Moolenbroek dbi = sqlite3_find_avail(db);
284*00b67f09SDavid van Moolenbroek #else /* PTHREADS */
285*00b67f09SDavid van Moolenbroek /*
286*00b67f09SDavid van Moolenbroek * only 1 DBI - no need to lock instance lock either
287*00b67f09SDavid van Moolenbroek * only 1 thread in the whole process, no possible contention.
288*00b67f09SDavid van Moolenbroek */
289*00b67f09SDavid van Moolenbroek dbi = (dbinstance_t *)(db->db);
290*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
291*00b67f09SDavid van Moolenbroek
292*00b67f09SDavid van Moolenbroek if (dbi == NULL) {
293*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
294*00b67f09SDavid van Moolenbroek goto cleanup;
295*00b67f09SDavid van Moolenbroek }
296*00b67f09SDavid van Moolenbroek
297*00b67f09SDavid van Moolenbroek /* what type of query are we going to run? */
298*00b67f09SDavid van Moolenbroek switch(query) {
299*00b67f09SDavid van Moolenbroek case ALLNODES:
300*00b67f09SDavid van Moolenbroek if (dbi->allnodes_q == NULL) {
301*00b67f09SDavid van Moolenbroek result = ISC_R_NOTIMPLEMENTED;
302*00b67f09SDavid van Moolenbroek goto cleanup;
303*00b67f09SDavid van Moolenbroek }
304*00b67f09SDavid van Moolenbroek break;
305*00b67f09SDavid van Moolenbroek case ALLOWXFR:
306*00b67f09SDavid van Moolenbroek if (dbi->allowxfr_q == NULL) {
307*00b67f09SDavid van Moolenbroek result = ISC_R_NOTIMPLEMENTED;
308*00b67f09SDavid van Moolenbroek goto cleanup;
309*00b67f09SDavid van Moolenbroek }
310*00b67f09SDavid van Moolenbroek break;
311*00b67f09SDavid van Moolenbroek case AUTHORITY:
312*00b67f09SDavid van Moolenbroek if (dbi->authority_q == NULL) {
313*00b67f09SDavid van Moolenbroek result = ISC_R_NOTIMPLEMENTED;
314*00b67f09SDavid van Moolenbroek goto cleanup;
315*00b67f09SDavid van Moolenbroek }
316*00b67f09SDavid van Moolenbroek break;
317*00b67f09SDavid van Moolenbroek case FINDZONE:
318*00b67f09SDavid van Moolenbroek if (dbi->findzone_q == NULL) {
319*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_DEBUG(2),
320*00b67f09SDavid van Moolenbroek "No query specified for findzone. "
321*00b67f09SDavid van Moolenbroek "Findzone requires a query");
322*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
323*00b67f09SDavid van Moolenbroek goto cleanup;
324*00b67f09SDavid van Moolenbroek }
325*00b67f09SDavid van Moolenbroek break;
326*00b67f09SDavid van Moolenbroek case COUNTZONE:
327*00b67f09SDavid van Moolenbroek if (dbi->countzone_q == NULL) {
328*00b67f09SDavid van Moolenbroek result = ISC_R_NOTIMPLEMENTED;
329*00b67f09SDavid van Moolenbroek goto cleanup;
330*00b67f09SDavid van Moolenbroek }
331*00b67f09SDavid van Moolenbroek break;
332*00b67f09SDavid van Moolenbroek case LOOKUP:
333*00b67f09SDavid van Moolenbroek if (dbi->lookup_q == NULL) {
334*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_DEBUG(2),
335*00b67f09SDavid van Moolenbroek "No query specified for lookup. "
336*00b67f09SDavid van Moolenbroek "Lookup requires a query");
337*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
338*00b67f09SDavid van Moolenbroek goto cleanup;
339*00b67f09SDavid van Moolenbroek }
340*00b67f09SDavid van Moolenbroek break;
341*00b67f09SDavid van Moolenbroek default:
342*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
343*00b67f09SDavid van Moolenbroek "Incorrect query flag passed to "
344*00b67f09SDavid van Moolenbroek "sqlite3_get_resultset");
345*00b67f09SDavid van Moolenbroek result = ISC_R_UNEXPECTED;
346*00b67f09SDavid van Moolenbroek goto cleanup;
347*00b67f09SDavid van Moolenbroek }
348*00b67f09SDavid van Moolenbroek
349*00b67f09SDavid van Moolenbroek
350*00b67f09SDavid van Moolenbroek if (zone != NULL) {
351*00b67f09SDavid van Moolenbroek if (dbi->zone != NULL)
352*00b67f09SDavid van Moolenbroek free(dbi->zone);
353*00b67f09SDavid van Moolenbroek
354*00b67f09SDavid van Moolenbroek dbi->zone = escape_string(zone);
355*00b67f09SDavid van Moolenbroek if (dbi->zone == NULL) {
356*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
357*00b67f09SDavid van Moolenbroek goto cleanup;
358*00b67f09SDavid van Moolenbroek }
359*00b67f09SDavid van Moolenbroek } else
360*00b67f09SDavid van Moolenbroek dbi->zone = NULL;
361*00b67f09SDavid van Moolenbroek
362*00b67f09SDavid van Moolenbroek if (record != NULL) {
363*00b67f09SDavid van Moolenbroek if (dbi->record != NULL)
364*00b67f09SDavid van Moolenbroek free(dbi->record);
365*00b67f09SDavid van Moolenbroek
366*00b67f09SDavid van Moolenbroek dbi->record = escape_string(record);
367*00b67f09SDavid van Moolenbroek if (dbi->record == NULL) {
368*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
369*00b67f09SDavid van Moolenbroek goto cleanup;
370*00b67f09SDavid van Moolenbroek }
371*00b67f09SDavid van Moolenbroek } else
372*00b67f09SDavid van Moolenbroek dbi->record = NULL;
373*00b67f09SDavid van Moolenbroek
374*00b67f09SDavid van Moolenbroek if (client != NULL) {
375*00b67f09SDavid van Moolenbroek if (dbi->client != NULL)
376*00b67f09SDavid van Moolenbroek free(dbi->client);
377*00b67f09SDavid van Moolenbroek
378*00b67f09SDavid van Moolenbroek dbi->client = escape_string(client);
379*00b67f09SDavid van Moolenbroek if (dbi->client == NULL) {
380*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
381*00b67f09SDavid van Moolenbroek goto cleanup;
382*00b67f09SDavid van Moolenbroek }
383*00b67f09SDavid van Moolenbroek } else
384*00b67f09SDavid van Moolenbroek dbi->client = NULL;
385*00b67f09SDavid van Moolenbroek
386*00b67f09SDavid van Moolenbroek /*
387*00b67f09SDavid van Moolenbroek * what type of query are we going to run? this time we build
388*00b67f09SDavid van Moolenbroek * the actual query to run.
389*00b67f09SDavid van Moolenbroek */
390*00b67f09SDavid van Moolenbroek switch(query) {
391*00b67f09SDavid van Moolenbroek case ALLNODES:
392*00b67f09SDavid van Moolenbroek querystring = build_querystring(dbi->allnodes_q);
393*00b67f09SDavid van Moolenbroek break;
394*00b67f09SDavid van Moolenbroek case ALLOWXFR:
395*00b67f09SDavid van Moolenbroek querystring = build_querystring(dbi->allowxfr_q);
396*00b67f09SDavid van Moolenbroek break;
397*00b67f09SDavid van Moolenbroek case AUTHORITY:
398*00b67f09SDavid van Moolenbroek querystring = build_querystring(dbi->authority_q);
399*00b67f09SDavid van Moolenbroek break;
400*00b67f09SDavid van Moolenbroek case FINDZONE:
401*00b67f09SDavid van Moolenbroek querystring = build_querystring(dbi->findzone_q);
402*00b67f09SDavid van Moolenbroek break;
403*00b67f09SDavid van Moolenbroek case COUNTZONE:
404*00b67f09SDavid van Moolenbroek querystring = build_querystring(dbi->countzone_q);
405*00b67f09SDavid van Moolenbroek break;
406*00b67f09SDavid van Moolenbroek case LOOKUP:
407*00b67f09SDavid van Moolenbroek querystring = build_querystring(dbi->lookup_q);
408*00b67f09SDavid van Moolenbroek break;
409*00b67f09SDavid van Moolenbroek default:
410*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
411*00b67f09SDavid van Moolenbroek "Incorrect query flag passed to "
412*00b67f09SDavid van Moolenbroek "sqlite3_get_resultset");
413*00b67f09SDavid van Moolenbroek result = ISC_R_UNEXPECTED;
414*00b67f09SDavid van Moolenbroek goto cleanup;
415*00b67f09SDavid van Moolenbroek }
416*00b67f09SDavid van Moolenbroek
417*00b67f09SDavid van Moolenbroek if (querystring == NULL) {
418*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
419*00b67f09SDavid van Moolenbroek goto cleanup;
420*00b67f09SDavid van Moolenbroek }
421*00b67f09SDavid van Moolenbroek
422*00b67f09SDavid van Moolenbroek /* output the full query string when debugging */
423*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring);
424*00b67f09SDavid van Moolenbroek
425*00b67f09SDavid van Moolenbroek rs = malloc(sizeof(sqlite3_res_t));
426*00b67f09SDavid van Moolenbroek if (rs == NULL) {
427*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR, "Failed to allocate result set");
428*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
429*00b67f09SDavid van Moolenbroek goto cleanup;
430*00b67f09SDavid van Moolenbroek }
431*00b67f09SDavid van Moolenbroek memset(rs, 0, sizeof(sqlite3_res_t));
432*00b67f09SDavid van Moolenbroek
433*00b67f09SDavid van Moolenbroek qres = sqlite3_get_table(dbi->dbconn, querystring, &rs->pazResult,
434*00b67f09SDavid van Moolenbroek &rs->pnRow, &rs->pnColumn, &rs->pzErrmsg);
435*00b67f09SDavid van Moolenbroek if (qres != SQLITE_OK) {
436*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_DEBUG(1), "SQLite3 query failed; %s",
437*00b67f09SDavid van Moolenbroek rs->pzErrmsg != NULL ? rs->pzErrmsg : "unknown error");
438*00b67f09SDavid van Moolenbroek sqlite3_free(rs->pzErrmsg);
439*00b67f09SDavid van Moolenbroek rs->pzErrmsg = NULL;
440*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
441*00b67f09SDavid van Moolenbroek goto cleanup;
442*00b67f09SDavid van Moolenbroek }
443*00b67f09SDavid van Moolenbroek
444*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
445*00b67f09SDavid van Moolenbroek if (query == COUNTZONE) {
446*00b67f09SDavid van Moolenbroek sqlite3_free_table(rs->pazResult);
447*00b67f09SDavid van Moolenbroek if (rs == NULL)
448*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
449*00b67f09SDavid van Moolenbroek }
450*00b67f09SDavid van Moolenbroek
451*00b67f09SDavid van Moolenbroek *rsp = rs;
452*00b67f09SDavid van Moolenbroek
453*00b67f09SDavid van Moolenbroek cleanup:
454*00b67f09SDavid van Moolenbroek if (dbi == NULL)
455*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
456*00b67f09SDavid van Moolenbroek
457*00b67f09SDavid van Moolenbroek if (dbi->zone != NULL) {
458*00b67f09SDavid van Moolenbroek free(dbi->zone);
459*00b67f09SDavid van Moolenbroek dbi->zone = NULL;
460*00b67f09SDavid van Moolenbroek }
461*00b67f09SDavid van Moolenbroek if (dbi->record != NULL) {
462*00b67f09SDavid van Moolenbroek free(dbi->record);
463*00b67f09SDavid van Moolenbroek dbi->record = NULL;
464*00b67f09SDavid van Moolenbroek }
465*00b67f09SDavid van Moolenbroek if (dbi->client != NULL) {
466*00b67f09SDavid van Moolenbroek free(dbi->client);
467*00b67f09SDavid van Moolenbroek dbi->client = NULL;
468*00b67f09SDavid van Moolenbroek }
469*00b67f09SDavid van Moolenbroek
470*00b67f09SDavid van Moolenbroek /* release the lock so another thread can use this dbi */
471*00b67f09SDavid van Moolenbroek (void) dlz_mutex_unlock(&dbi->lock);
472*00b67f09SDavid van Moolenbroek
473*00b67f09SDavid van Moolenbroek if (querystring != NULL)
474*00b67f09SDavid van Moolenbroek free(querystring);
475*00b67f09SDavid van Moolenbroek
476*00b67f09SDavid van Moolenbroek return (result);
477*00b67f09SDavid van Moolenbroek }
478*00b67f09SDavid van Moolenbroek
479*00b67f09SDavid van Moolenbroek /*%
480*00b67f09SDavid van Moolenbroek * The processing of result sets for lookup and authority are
481*00b67f09SDavid van Moolenbroek * exactly the same. So that functionality has been moved
482*00b67f09SDavid van Moolenbroek * into this function to minimize code.
483*00b67f09SDavid van Moolenbroek */
484*00b67f09SDavid van Moolenbroek
485*00b67f09SDavid van Moolenbroek char **
sqlite3_fetch_row(sqlite3_res_t * rs)486*00b67f09SDavid van Moolenbroek sqlite3_fetch_row(sqlite3_res_t *rs) {
487*00b67f09SDavid van Moolenbroek char **retval = NULL;
488*00b67f09SDavid van Moolenbroek if (rs != NULL) {
489*00b67f09SDavid van Moolenbroek if (rs->pnRow > 0U && rs->curRow < rs->pnRow) {
490*00b67f09SDavid van Moolenbroek int index = (rs->curRow + 1) * rs->pnColumn;
491*00b67f09SDavid van Moolenbroek retval = &rs->pazResult[index];
492*00b67f09SDavid van Moolenbroek rs->curRow++;
493*00b67f09SDavid van Moolenbroek }
494*00b67f09SDavid van Moolenbroek }
495*00b67f09SDavid van Moolenbroek return (retval);
496*00b67f09SDavid van Moolenbroek }
497*00b67f09SDavid van Moolenbroek
498*00b67f09SDavid van Moolenbroek unsigned int
sqlite3_num_fields(sqlite3_res_t * rs)499*00b67f09SDavid van Moolenbroek sqlite3_num_fields(sqlite3_res_t *rs) {
500*00b67f09SDavid van Moolenbroek unsigned int retval = 0;
501*00b67f09SDavid van Moolenbroek if (rs != NULL)
502*00b67f09SDavid van Moolenbroek retval = rs->pnColumn;
503*00b67f09SDavid van Moolenbroek return (retval);
504*00b67f09SDavid van Moolenbroek }
505*00b67f09SDavid van Moolenbroek
506*00b67f09SDavid van Moolenbroek unsigned int
sqlite3_num_rows(sqlite3_res_t * rs)507*00b67f09SDavid van Moolenbroek sqlite3_num_rows(sqlite3_res_t *rs) {
508*00b67f09SDavid van Moolenbroek unsigned int retval = 0;
509*00b67f09SDavid van Moolenbroek if (rs != NULL)
510*00b67f09SDavid van Moolenbroek retval = rs->pnRow;
511*00b67f09SDavid van Moolenbroek return (retval);
512*00b67f09SDavid van Moolenbroek }
513*00b67f09SDavid van Moolenbroek
514*00b67f09SDavid van Moolenbroek void
sqlite3_free_result(sqlite3_res_t * rs)515*00b67f09SDavid van Moolenbroek sqlite3_free_result(sqlite3_res_t *rs) {
516*00b67f09SDavid van Moolenbroek if (rs != NULL) {
517*00b67f09SDavid van Moolenbroek sqlite3_free_table(rs->pazResult);
518*00b67f09SDavid van Moolenbroek free(rs);
519*00b67f09SDavid van Moolenbroek }
520*00b67f09SDavid van Moolenbroek }
521*00b67f09SDavid van Moolenbroek
522*00b67f09SDavid van Moolenbroek static isc_result_t
sqlite3_process_rs(sqlite3_instance_t * db,dns_sdlzlookup_t * lookup,sqlite3_res_t * rs)523*00b67f09SDavid van Moolenbroek sqlite3_process_rs(sqlite3_instance_t *db, dns_sdlzlookup_t *lookup,
524*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs)
525*00b67f09SDavid van Moolenbroek {
526*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_NOTFOUND;
527*00b67f09SDavid van Moolenbroek char **row;
528*00b67f09SDavid van Moolenbroek unsigned int fields;
529*00b67f09SDavid van Moolenbroek unsigned int i, j;
530*00b67f09SDavid van Moolenbroek char *tmpString;
531*00b67f09SDavid van Moolenbroek char *endp;
532*00b67f09SDavid van Moolenbroek int ttl;
533*00b67f09SDavid van Moolenbroek
534*00b67f09SDavid van Moolenbroek row = sqlite3_fetch_row(rs); /* get a row from the result set */
535*00b67f09SDavid van Moolenbroek fields = sqlite3_num_fields(rs); /* how many columns in result set */
536*00b67f09SDavid van Moolenbroek while (row != NULL) {
537*00b67f09SDavid van Moolenbroek unsigned int len = 0;
538*00b67f09SDavid van Moolenbroek
539*00b67f09SDavid van Moolenbroek switch(fields) {
540*00b67f09SDavid van Moolenbroek case 1:
541*00b67f09SDavid van Moolenbroek /*
542*00b67f09SDavid van Moolenbroek * one column in rs, it's the data field. use
543*00b67f09SDavid van Moolenbroek * default type of A record, and default TTL
544*00b67f09SDavid van Moolenbroek * of 86400
545*00b67f09SDavid van Moolenbroek */
546*00b67f09SDavid van Moolenbroek result = db->putrr(lookup, "a", 86400, safeGet(row[0]));
547*00b67f09SDavid van Moolenbroek break;
548*00b67f09SDavid van Moolenbroek case 2:
549*00b67f09SDavid van Moolenbroek /*
550*00b67f09SDavid van Moolenbroek * two columns, data field, and data type.
551*00b67f09SDavid van Moolenbroek * use default TTL of 86400.
552*00b67f09SDavid van Moolenbroek */
553*00b67f09SDavid van Moolenbroek result = db->putrr(lookup, safeGet(row[0]), 86400,
554*00b67f09SDavid van Moolenbroek safeGet(row[1]));
555*00b67f09SDavid van Moolenbroek break;
556*00b67f09SDavid van Moolenbroek case 3:
557*00b67f09SDavid van Moolenbroek /*
558*00b67f09SDavid van Moolenbroek * three columns, all data no defaults.
559*00b67f09SDavid van Moolenbroek * convert text to int, make sure it worked
560*00b67f09SDavid van Moolenbroek * right.
561*00b67f09SDavid van Moolenbroek */
562*00b67f09SDavid van Moolenbroek ttl = strtol(safeGet(row[0]), &endp, 10);
563*00b67f09SDavid van Moolenbroek if (*endp != '\0' || ttl < 0) {
564*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
565*00b67f09SDavid van Moolenbroek "SQLite3 module: TTL must be "
566*00b67f09SDavid van Moolenbroek "a postive number");
567*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
568*00b67f09SDavid van Moolenbroek }
569*00b67f09SDavid van Moolenbroek
570*00b67f09SDavid van Moolenbroek result = db->putrr(lookup, safeGet(row[1]), ttl,
571*00b67f09SDavid van Moolenbroek safeGet(row[2]));
572*00b67f09SDavid van Moolenbroek break;
573*00b67f09SDavid van Moolenbroek default:
574*00b67f09SDavid van Moolenbroek /*
575*00b67f09SDavid van Moolenbroek * more than 3 fields, concatenate the last
576*00b67f09SDavid van Moolenbroek * ones together. figure out how long to make
577*00b67f09SDavid van Moolenbroek * string.
578*00b67f09SDavid van Moolenbroek */
579*00b67f09SDavid van Moolenbroek for (j = 2; j < fields; j++)
580*00b67f09SDavid van Moolenbroek len += strlen(safeGet(row[j])) + 1;
581*00b67f09SDavid van Moolenbroek
582*00b67f09SDavid van Moolenbroek /*
583*00b67f09SDavid van Moolenbroek * allocate string memory, allow for NULL to
584*00b67f09SDavid van Moolenbroek * term string
585*00b67f09SDavid van Moolenbroek */
586*00b67f09SDavid van Moolenbroek tmpString = malloc(len + 1);
587*00b67f09SDavid van Moolenbroek if (tmpString == NULL) {
588*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
589*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to allocate "
590*00b67f09SDavid van Moolenbroek "memory for temporary string");
591*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
592*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
593*00b67f09SDavid van Moolenbroek }
594*00b67f09SDavid van Moolenbroek
595*00b67f09SDavid van Moolenbroek strcpy(tmpString, safeGet(row[2]));
596*00b67f09SDavid van Moolenbroek for (j = 3; j < fields; j++) {
597*00b67f09SDavid van Moolenbroek strcat(tmpString, " ");
598*00b67f09SDavid van Moolenbroek strcat(tmpString, safeGet(row[j]));
599*00b67f09SDavid van Moolenbroek }
600*00b67f09SDavid van Moolenbroek
601*00b67f09SDavid van Moolenbroek ttl = strtol(safeGet(row[0]), &endp, 10);
602*00b67f09SDavid van Moolenbroek if (*endp != '\0' || ttl < 0) {
603*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
604*00b67f09SDavid van Moolenbroek "SQLite3 module: TTL must be "
605*00b67f09SDavid van Moolenbroek "a postive number");
606*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
607*00b67f09SDavid van Moolenbroek }
608*00b67f09SDavid van Moolenbroek
609*00b67f09SDavid van Moolenbroek result = db->putrr(lookup, safeGet(row[1]),
610*00b67f09SDavid van Moolenbroek ttl, tmpString);
611*00b67f09SDavid van Moolenbroek free(tmpString);
612*00b67f09SDavid van Moolenbroek }
613*00b67f09SDavid van Moolenbroek
614*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
615*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
616*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
617*00b67f09SDavid van Moolenbroek "putrr returned error: %d", result);
618*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
619*00b67f09SDavid van Moolenbroek }
620*00b67f09SDavid van Moolenbroek
621*00b67f09SDavid van Moolenbroek row = sqlite3_fetch_row(rs);
622*00b67f09SDavid van Moolenbroek }
623*00b67f09SDavid van Moolenbroek
624*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
625*00b67f09SDavid van Moolenbroek return (result);
626*00b67f09SDavid van Moolenbroek }
627*00b67f09SDavid van Moolenbroek
628*00b67f09SDavid van Moolenbroek /*
629*00b67f09SDavid van Moolenbroek * DLZ methods
630*00b67f09SDavid van Moolenbroek */
631*00b67f09SDavid van Moolenbroek
632*00b67f09SDavid van Moolenbroek /*% determine if the zone is supported by (in) the database */
633*00b67f09SDavid van Moolenbroek isc_result_t
dlz_findzonedb(void * dbdata,const char * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)634*00b67f09SDavid van Moolenbroek dlz_findzonedb(void *dbdata, const char *name,
635*00b67f09SDavid van Moolenbroek dns_clientinfomethods_t *methods,
636*00b67f09SDavid van Moolenbroek dns_clientinfo_t *clientinfo)
637*00b67f09SDavid van Moolenbroek {
638*00b67f09SDavid van Moolenbroek isc_result_t result;
639*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs = NULL;
640*00b67f09SDavid van Moolenbroek sqlite3_uint64 rows;
641*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *)dbdata;
642*00b67f09SDavid van Moolenbroek
643*00b67f09SDavid van Moolenbroek UNUSED(methods);
644*00b67f09SDavid van Moolenbroek UNUSED(clientinfo);
645*00b67f09SDavid van Moolenbroek
646*00b67f09SDavid van Moolenbroek result = sqlite3_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs);
647*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS || rs == NULL) {
648*00b67f09SDavid van Moolenbroek if (rs != NULL)
649*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
650*00b67f09SDavid van Moolenbroek
651*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
652*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to return "
653*00b67f09SDavid van Moolenbroek "result set for FINDZONE query");
654*00b67f09SDavid van Moolenbroek
655*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
656*00b67f09SDavid van Moolenbroek }
657*00b67f09SDavid van Moolenbroek
658*00b67f09SDavid van Moolenbroek /*
659*00b67f09SDavid van Moolenbroek * if we returned any rows, the zone is supported.
660*00b67f09SDavid van Moolenbroek */
661*00b67f09SDavid van Moolenbroek rows = sqlite3_num_rows(rs);
662*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
663*00b67f09SDavid van Moolenbroek if (rows > 0) {
664*00b67f09SDavid van Moolenbroek sqlite3_get_resultset(name, NULL, NULL, COUNTZONE,
665*00b67f09SDavid van Moolenbroek dbdata, NULL);
666*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
667*00b67f09SDavid van Moolenbroek }
668*00b67f09SDavid van Moolenbroek
669*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
670*00b67f09SDavid van Moolenbroek }
671*00b67f09SDavid van Moolenbroek
672*00b67f09SDavid van Moolenbroek /*% Determine if the client is allowed to perform a zone transfer */
673*00b67f09SDavid van Moolenbroek isc_result_t
dlz_allowzonexfr(void * dbdata,const char * name,const char * client)674*00b67f09SDavid van Moolenbroek dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
675*00b67f09SDavid van Moolenbroek isc_result_t result;
676*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *)dbdata;
677*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs = NULL;
678*00b67f09SDavid van Moolenbroek sqlite3_uint64 rows;
679*00b67f09SDavid van Moolenbroek
680*00b67f09SDavid van Moolenbroek /* first check if the zone is supported by the database. */
681*00b67f09SDavid van Moolenbroek result = dlz_findzonedb(dbdata, name, NULL, NULL);
682*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
683*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
684*00b67f09SDavid van Moolenbroek
685*00b67f09SDavid van Moolenbroek /*
686*00b67f09SDavid van Moolenbroek * if we get to this point we know the zone is supported by
687*00b67f09SDavid van Moolenbroek * the database the only questions now are is the zone
688*00b67f09SDavid van Moolenbroek * transfer is allowed for this client and did the config file
689*00b67f09SDavid van Moolenbroek * have an allow zone xfr query.
690*00b67f09SDavid van Moolenbroek */
691*00b67f09SDavid van Moolenbroek result = sqlite3_get_resultset(name, NULL, client, ALLOWXFR,
692*00b67f09SDavid van Moolenbroek dbdata, &rs);
693*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTIMPLEMENTED)
694*00b67f09SDavid van Moolenbroek return (result);
695*00b67f09SDavid van Moolenbroek
696*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS || rs == NULL) {
697*00b67f09SDavid van Moolenbroek if (rs != NULL)
698*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
699*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
700*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to return "
701*00b67f09SDavid van Moolenbroek "result set for ALLOWXFR query");
702*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
703*00b67f09SDavid van Moolenbroek }
704*00b67f09SDavid van Moolenbroek
705*00b67f09SDavid van Moolenbroek /*
706*00b67f09SDavid van Moolenbroek * count how many rows in result set; if we returned any,
707*00b67f09SDavid van Moolenbroek * zone xfr is allowed.
708*00b67f09SDavid van Moolenbroek */
709*00b67f09SDavid van Moolenbroek rows = sqlite3_num_rows(rs);
710*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
711*00b67f09SDavid van Moolenbroek if (rows > 0)
712*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
713*00b67f09SDavid van Moolenbroek
714*00b67f09SDavid van Moolenbroek return (ISC_R_NOPERM);
715*00b67f09SDavid van Moolenbroek }
716*00b67f09SDavid van Moolenbroek
717*00b67f09SDavid van Moolenbroek /*%
718*00b67f09SDavid van Moolenbroek * If the client is allowed to perform a zone transfer, the next order of
719*00b67f09SDavid van Moolenbroek * business is to get all the nodes in the zone, so bind can respond to the
720*00b67f09SDavid van Moolenbroek * query.
721*00b67f09SDavid van Moolenbroek */
722*00b67f09SDavid van Moolenbroek isc_result_t
dlz_allnodes(const char * zone,void * dbdata,dns_sdlzallnodes_t * allnodes)723*00b67f09SDavid van Moolenbroek dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) {
724*00b67f09SDavid van Moolenbroek isc_result_t result;
725*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *)dbdata;
726*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs = NULL;
727*00b67f09SDavid van Moolenbroek char **row;
728*00b67f09SDavid van Moolenbroek unsigned int fields;
729*00b67f09SDavid van Moolenbroek unsigned int j;
730*00b67f09SDavid van Moolenbroek char *tmpString;
731*00b67f09SDavid van Moolenbroek char *endp;
732*00b67f09SDavid van Moolenbroek int ttl;
733*00b67f09SDavid van Moolenbroek
734*00b67f09SDavid van Moolenbroek result = sqlite3_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs);
735*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTIMPLEMENTED)
736*00b67f09SDavid van Moolenbroek return (result);
737*00b67f09SDavid van Moolenbroek
738*00b67f09SDavid van Moolenbroek /* if we didn't get a result set, log an err msg. */
739*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
740*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
741*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to return "
742*00b67f09SDavid van Moolenbroek "result set for all nodes query");
743*00b67f09SDavid van Moolenbroek goto cleanup;
744*00b67f09SDavid van Moolenbroek }
745*00b67f09SDavid van Moolenbroek
746*00b67f09SDavid van Moolenbroek result = ISC_R_NOTFOUND;
747*00b67f09SDavid van Moolenbroek
748*00b67f09SDavid van Moolenbroek fields = sqlite3_num_fields(rs);
749*00b67f09SDavid van Moolenbroek row = sqlite3_fetch_row(rs);
750*00b67f09SDavid van Moolenbroek while (row != NULL) {
751*00b67f09SDavid van Moolenbroek if (fields < 4) {
752*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
753*00b67f09SDavid van Moolenbroek "SQLite3 module: too few fields returned "
754*00b67f09SDavid van Moolenbroek "by ALLNODES query");
755*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
756*00b67f09SDavid van Moolenbroek goto cleanup;
757*00b67f09SDavid van Moolenbroek }
758*00b67f09SDavid van Moolenbroek
759*00b67f09SDavid van Moolenbroek ttl = strtol(safeGet(row[0]), &endp, 10);
760*00b67f09SDavid van Moolenbroek if (*endp != '\0' || ttl < 0) {
761*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
762*00b67f09SDavid van Moolenbroek "SQLite3 module: TTL must be "
763*00b67f09SDavid van Moolenbroek "a postive number");
764*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
765*00b67f09SDavid van Moolenbroek goto cleanup;
766*00b67f09SDavid van Moolenbroek }
767*00b67f09SDavid van Moolenbroek
768*00b67f09SDavid van Moolenbroek if (fields == 4) {
769*00b67f09SDavid van Moolenbroek result = db->putnamedrr(allnodes, safeGet(row[2]),
770*00b67f09SDavid van Moolenbroek safeGet(row[1]), ttl,
771*00b67f09SDavid van Moolenbroek safeGet(row[3]));
772*00b67f09SDavid van Moolenbroek } else {
773*00b67f09SDavid van Moolenbroek unsigned int len = 0;
774*00b67f09SDavid van Moolenbroek
775*00b67f09SDavid van Moolenbroek /*
776*00b67f09SDavid van Moolenbroek * more than 4 fields, concatenate the last
777*00b67f09SDavid van Moolenbroek * ones together.
778*00b67f09SDavid van Moolenbroek */
779*00b67f09SDavid van Moolenbroek for (j = 3; j < fields; j++)
780*00b67f09SDavid van Moolenbroek len += strlen(safeGet(row[j])) + 1;
781*00b67f09SDavid van Moolenbroek
782*00b67f09SDavid van Moolenbroek tmpString = malloc(len + 1);
783*00b67f09SDavid van Moolenbroek if (tmpString == NULL) {
784*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
785*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to allocate "
786*00b67f09SDavid van Moolenbroek "memory for temporary string");
787*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
788*00b67f09SDavid van Moolenbroek goto cleanup;
789*00b67f09SDavid van Moolenbroek }
790*00b67f09SDavid van Moolenbroek
791*00b67f09SDavid van Moolenbroek strcpy(tmpString, safeGet(row[3]));
792*00b67f09SDavid van Moolenbroek for (j = 4; j < fields; j++) {
793*00b67f09SDavid van Moolenbroek strcat(tmpString, " ");
794*00b67f09SDavid van Moolenbroek strcat(tmpString, safeGet(row[j]));
795*00b67f09SDavid van Moolenbroek }
796*00b67f09SDavid van Moolenbroek
797*00b67f09SDavid van Moolenbroek result = db->putnamedrr(allnodes, safeGet(row[2]),
798*00b67f09SDavid van Moolenbroek safeGet(row[1]),
799*00b67f09SDavid van Moolenbroek ttl, tmpString);
800*00b67f09SDavid van Moolenbroek free(tmpString);
801*00b67f09SDavid van Moolenbroek }
802*00b67f09SDavid van Moolenbroek
803*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
804*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
805*00b67f09SDavid van Moolenbroek "putnamedrr returned error: %s", result);
806*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
807*00b67f09SDavid van Moolenbroek break;
808*00b67f09SDavid van Moolenbroek }
809*00b67f09SDavid van Moolenbroek
810*00b67f09SDavid van Moolenbroek row = sqlite3_fetch_row(rs);
811*00b67f09SDavid van Moolenbroek }
812*00b67f09SDavid van Moolenbroek
813*00b67f09SDavid van Moolenbroek cleanup:
814*00b67f09SDavid van Moolenbroek if (rs != NULL)
815*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
816*00b67f09SDavid van Moolenbroek
817*00b67f09SDavid van Moolenbroek return (result);
818*00b67f09SDavid van Moolenbroek }
819*00b67f09SDavid van Moolenbroek
820*00b67f09SDavid van Moolenbroek /*%
821*00b67f09SDavid van Moolenbroek * If the lookup function does not return SOA or NS records for the zone,
822*00b67f09SDavid van Moolenbroek * use this function to get that information for named.
823*00b67f09SDavid van Moolenbroek */
824*00b67f09SDavid van Moolenbroek isc_result_t
dlz_authority(const char * zone,void * dbdata,dns_sdlzlookup_t * lookup)825*00b67f09SDavid van Moolenbroek dlz_authority(const char *zone, void *dbdata, dns_sdlzlookup_t *lookup) {
826*00b67f09SDavid van Moolenbroek isc_result_t result;
827*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs = NULL;
828*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *) dbdata;
829*00b67f09SDavid van Moolenbroek
830*00b67f09SDavid van Moolenbroek result = sqlite3_get_resultset(zone, NULL, NULL, AUTHORITY,
831*00b67f09SDavid van Moolenbroek dbdata, &rs);
832*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTIMPLEMENTED)
833*00b67f09SDavid van Moolenbroek return (result);
834*00b67f09SDavid van Moolenbroek
835*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
836*00b67f09SDavid van Moolenbroek if (rs != NULL)
837*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
838*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
839*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to return "
840*00b67f09SDavid van Moolenbroek "result set for AUTHORITY query");
841*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
842*00b67f09SDavid van Moolenbroek }
843*00b67f09SDavid van Moolenbroek
844*00b67f09SDavid van Moolenbroek /*
845*00b67f09SDavid van Moolenbroek * lookup and authority result sets are processed in the same
846*00b67f09SDavid van Moolenbroek * manner: sqlite3_process_rs does the job for both functions.
847*00b67f09SDavid van Moolenbroek */
848*00b67f09SDavid van Moolenbroek return (sqlite3_process_rs(db, lookup, rs));
849*00b67f09SDavid van Moolenbroek }
850*00b67f09SDavid van Moolenbroek
851*00b67f09SDavid van Moolenbroek /*% If zone is supported, lookup up a (or multiple) record(s) in it */
852*00b67f09SDavid van Moolenbroek isc_result_t
dlz_lookup(const char * zone,const char * name,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)853*00b67f09SDavid van Moolenbroek dlz_lookup(const char *zone, const char *name,
854*00b67f09SDavid van Moolenbroek void *dbdata, dns_sdlzlookup_t *lookup,
855*00b67f09SDavid van Moolenbroek dns_clientinfomethods_t *methods,
856*00b67f09SDavid van Moolenbroek dns_clientinfo_t *clientinfo)
857*00b67f09SDavid van Moolenbroek {
858*00b67f09SDavid van Moolenbroek isc_result_t result;
859*00b67f09SDavid van Moolenbroek sqlite3_res_t *rs = NULL;
860*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *) dbdata;
861*00b67f09SDavid van Moolenbroek
862*00b67f09SDavid van Moolenbroek UNUSED(methods);
863*00b67f09SDavid van Moolenbroek UNUSED(clientinfo);
864*00b67f09SDavid van Moolenbroek
865*00b67f09SDavid van Moolenbroek result = sqlite3_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
866*00b67f09SDavid van Moolenbroek
867*00b67f09SDavid van Moolenbroek /* if we didn't get a result set, log an err msg. */
868*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
869*00b67f09SDavid van Moolenbroek if (rs != NULL)
870*00b67f09SDavid van Moolenbroek sqlite3_free_result(rs);
871*00b67f09SDavid van Moolenbroek db->log(ISC_LOG_ERROR,
872*00b67f09SDavid van Moolenbroek "SQLite3 module: unable to return "
873*00b67f09SDavid van Moolenbroek "result set for LOOKUP query");
874*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
875*00b67f09SDavid van Moolenbroek }
876*00b67f09SDavid van Moolenbroek
877*00b67f09SDavid van Moolenbroek /*
878*00b67f09SDavid van Moolenbroek * lookup and authority result sets are processed in the same
879*00b67f09SDavid van Moolenbroek * manner: sqlite3_process_rs does the job for both functions.
880*00b67f09SDavid van Moolenbroek */
881*00b67f09SDavid van Moolenbroek return (sqlite3_process_rs(db, lookup, rs));
882*00b67f09SDavid van Moolenbroek }
883*00b67f09SDavid van Moolenbroek
884*00b67f09SDavid van Moolenbroek /*%
885*00b67f09SDavid van Moolenbroek * Create an instance of the module.
886*00b67f09SDavid van Moolenbroek */
887*00b67f09SDavid van Moolenbroek isc_result_t
dlz_create(const char * dlzname,unsigned int argc,char * argv[],void ** dbdata,...)888*00b67f09SDavid van Moolenbroek dlz_create(const char *dlzname, unsigned int argc, char *argv[],
889*00b67f09SDavid van Moolenbroek void **dbdata, ...)
890*00b67f09SDavid van Moolenbroek {
891*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_FAILURE;
892*00b67f09SDavid van Moolenbroek sqlite3_instance_t *s3 = NULL;
893*00b67f09SDavid van Moolenbroek dbinstance_t *dbi = NULL;
894*00b67f09SDavid van Moolenbroek sqlite3 *dbc = NULL;
895*00b67f09SDavid van Moolenbroek char *tmp = NULL;
896*00b67f09SDavid van Moolenbroek char *endp;
897*00b67f09SDavid van Moolenbroek const char *helper_name;
898*00b67f09SDavid van Moolenbroek #if SQLITE3_VERSION_ID >= 50000
899*00b67f09SDavid van Moolenbroek my_bool auto_reconnect = 1;
900*00b67f09SDavid van Moolenbroek #endif
901*00b67f09SDavid van Moolenbroek #if PTHREADS
902*00b67f09SDavid van Moolenbroek int dbcount;
903*00b67f09SDavid van Moolenbroek int i, ret;
904*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
905*00b67f09SDavid van Moolenbroek va_list ap;
906*00b67f09SDavid van Moolenbroek
907*00b67f09SDavid van Moolenbroek UNUSED(dlzname);
908*00b67f09SDavid van Moolenbroek
909*00b67f09SDavid van Moolenbroek /* allocate memory for SQLite3 instance */
910*00b67f09SDavid van Moolenbroek s3 = calloc(1, sizeof(sqlite3_instance_t));
911*00b67f09SDavid van Moolenbroek if (s3 == NULL)
912*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
913*00b67f09SDavid van Moolenbroek memset(s3, 0, sizeof(sqlite3_instance_t));
914*00b67f09SDavid van Moolenbroek
915*00b67f09SDavid van Moolenbroek /* Fill in the helper functions */
916*00b67f09SDavid van Moolenbroek va_start(ap, dbdata);
917*00b67f09SDavid van Moolenbroek while ((helper_name = va_arg(ap, const char*)) != NULL)
918*00b67f09SDavid van Moolenbroek b9_add_helper(s3, helper_name, va_arg(ap, void*));
919*00b67f09SDavid van Moolenbroek va_end(ap);
920*00b67f09SDavid van Moolenbroek
921*00b67f09SDavid van Moolenbroek #if PTHREADS
922*00b67f09SDavid van Moolenbroek /* if debugging, let user know we are multithreaded. */
923*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_DEBUG(1), "SQLite3 module: running multithreaded");
924*00b67f09SDavid van Moolenbroek #else /* PTHREADS */
925*00b67f09SDavid van Moolenbroek /* if debugging, let user know we are single threaded. */
926*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_DEBUG(1), "SQLite3 module: running single threaded");
927*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
928*00b67f09SDavid van Moolenbroek
929*00b67f09SDavid van Moolenbroek /* verify we have at least 4 arg's passed to the module */
930*00b67f09SDavid van Moolenbroek if (argc < 4) {
931*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
932*00b67f09SDavid van Moolenbroek "SQLite3 module requires "
933*00b67f09SDavid van Moolenbroek "at least 4 command line args.");
934*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
935*00b67f09SDavid van Moolenbroek }
936*00b67f09SDavid van Moolenbroek
937*00b67f09SDavid van Moolenbroek /* no more than 8 arg's should be passed to the module */
938*00b67f09SDavid van Moolenbroek if (argc > 8) {
939*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
940*00b67f09SDavid van Moolenbroek "SQLite3 module cannot accept "
941*00b67f09SDavid van Moolenbroek "more than 8 command line args.");
942*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
943*00b67f09SDavid van Moolenbroek }
944*00b67f09SDavid van Moolenbroek
945*00b67f09SDavid van Moolenbroek /* get db name - required */
946*00b67f09SDavid van Moolenbroek s3->dbname = get_parameter_value(argv[1], "dbname=");
947*00b67f09SDavid van Moolenbroek if (s3->dbname == NULL) {
948*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
949*00b67f09SDavid van Moolenbroek "SQLite3 module requires a dbname parameter.");
950*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
951*00b67f09SDavid van Moolenbroek goto cleanup;
952*00b67f09SDavid van Moolenbroek }
953*00b67f09SDavid van Moolenbroek
954*00b67f09SDavid van Moolenbroek #if PTHREADS
955*00b67f09SDavid van Moolenbroek /* multithreaded build can have multiple DB connections */
956*00b67f09SDavid van Moolenbroek tmp = get_parameter_value(argv[1], "threads=");
957*00b67f09SDavid van Moolenbroek if (tmp == NULL)
958*00b67f09SDavid van Moolenbroek dbcount = 1;
959*00b67f09SDavid van Moolenbroek else {
960*00b67f09SDavid van Moolenbroek dbcount = strtol(tmp, &endp, 10);
961*00b67f09SDavid van Moolenbroek if (*endp != '\0' || dbcount < 1) {
962*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
963*00b67f09SDavid van Moolenbroek "SQLite3 module: database connection count "
964*00b67f09SDavid van Moolenbroek "must be positive.");
965*00b67f09SDavid van Moolenbroek free(tmp);
966*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
967*00b67f09SDavid van Moolenbroek goto cleanup;
968*00b67f09SDavid van Moolenbroek }
969*00b67f09SDavid van Moolenbroek free(tmp);
970*00b67f09SDavid van Moolenbroek }
971*00b67f09SDavid van Moolenbroek
972*00b67f09SDavid van Moolenbroek /* allocate memory for database connection list */
973*00b67f09SDavid van Moolenbroek s3->db = calloc(1, sizeof(db_list_t));
974*00b67f09SDavid van Moolenbroek if (s3->db == NULL) {
975*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
976*00b67f09SDavid van Moolenbroek goto cleanup;
977*00b67f09SDavid van Moolenbroek }
978*00b67f09SDavid van Moolenbroek
979*00b67f09SDavid van Moolenbroek /* initialize DB connection list */
980*00b67f09SDavid van Moolenbroek DLZ_LIST_INIT(*(s3->db));
981*00b67f09SDavid van Moolenbroek
982*00b67f09SDavid van Moolenbroek /*
983*00b67f09SDavid van Moolenbroek * create the appropriate number of database instances (DBI)
984*00b67f09SDavid van Moolenbroek * append each new DBI to the end of the list
985*00b67f09SDavid van Moolenbroek */
986*00b67f09SDavid van Moolenbroek for (i = 0; i < dbcount; i++) {
987*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
988*00b67f09SDavid van Moolenbroek switch(argc) {
989*00b67f09SDavid van Moolenbroek case 4:
990*00b67f09SDavid van Moolenbroek result = build_dbinstance(NULL, NULL, NULL,
991*00b67f09SDavid van Moolenbroek argv[2], argv[3], NULL,
992*00b67f09SDavid van Moolenbroek &dbi, s3->log);
993*00b67f09SDavid van Moolenbroek break;
994*00b67f09SDavid van Moolenbroek case 5:
995*00b67f09SDavid van Moolenbroek result = build_dbinstance(NULL, NULL, argv[4],
996*00b67f09SDavid van Moolenbroek argv[2], argv[3], NULL,
997*00b67f09SDavid van Moolenbroek &dbi, s3->log);
998*00b67f09SDavid van Moolenbroek break;
999*00b67f09SDavid van Moolenbroek case 6:
1000*00b67f09SDavid van Moolenbroek result = build_dbinstance(argv[5], NULL, argv[4],
1001*00b67f09SDavid van Moolenbroek argv[2], argv[3], NULL,
1002*00b67f09SDavid van Moolenbroek &dbi, s3->log);
1003*00b67f09SDavid van Moolenbroek break;
1004*00b67f09SDavid van Moolenbroek case 7:
1005*00b67f09SDavid van Moolenbroek result = build_dbinstance(argv[5], argv[6], argv[4],
1006*00b67f09SDavid van Moolenbroek argv[2], argv[3], NULL,
1007*00b67f09SDavid van Moolenbroek &dbi, s3->log);
1008*00b67f09SDavid van Moolenbroek break;
1009*00b67f09SDavid van Moolenbroek case 8:
1010*00b67f09SDavid van Moolenbroek result = build_dbinstance(argv[5], argv[6], argv[4],
1011*00b67f09SDavid van Moolenbroek argv[2], argv[3], argv[7],
1012*00b67f09SDavid van Moolenbroek &dbi, s3->log);
1013*00b67f09SDavid van Moolenbroek break;
1014*00b67f09SDavid van Moolenbroek default:
1015*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
1016*00b67f09SDavid van Moolenbroek }
1017*00b67f09SDavid van Moolenbroek
1018*00b67f09SDavid van Moolenbroek
1019*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
1020*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
1021*00b67f09SDavid van Moolenbroek "SQLite3 module: could not create "
1022*00b67f09SDavid van Moolenbroek "database instance object.");
1023*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
1024*00b67f09SDavid van Moolenbroek goto cleanup;
1025*00b67f09SDavid van Moolenbroek }
1026*00b67f09SDavid van Moolenbroek
1027*00b67f09SDavid van Moolenbroek /* create and set db connection */
1028*00b67f09SDavid van Moolenbroek ret = sqlite3_initialize();
1029*00b67f09SDavid van Moolenbroek if (ret != SQLITE_OK) {
1030*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
1031*00b67f09SDavid van Moolenbroek "SQLite3 module: could not "
1032*00b67f09SDavid van Moolenbroek "initialize database object.");
1033*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
1034*00b67f09SDavid van Moolenbroek goto cleanup;
1035*00b67f09SDavid van Moolenbroek }
1036*00b67f09SDavid van Moolenbroek
1037*00b67f09SDavid van Moolenbroek ret = sqlite3_open(s3->dbname, &dbc);
1038*00b67f09SDavid van Moolenbroek if (ret != SQLITE_OK) {
1039*00b67f09SDavid van Moolenbroek s3->log(ISC_LOG_ERROR,
1040*00b67f09SDavid van Moolenbroek "SQLite3 module: could not "
1041*00b67f09SDavid van Moolenbroek "open '%s'.", s3->dbname);
1042*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
1043*00b67f09SDavid van Moolenbroek goto cleanup;
1044*00b67f09SDavid van Moolenbroek }
1045*00b67f09SDavid van Moolenbroek
1046*00b67f09SDavid van Moolenbroek #if PTHREADS
1047*00b67f09SDavid van Moolenbroek /* when multithreaded, build a list of DBI's */
1048*00b67f09SDavid van Moolenbroek DLZ_LINK_INIT(dbi, link);
1049*00b67f09SDavid van Moolenbroek DLZ_LIST_APPEND(*(s3->db), dbi, link);
1050*00b67f09SDavid van Moolenbroek #else
1051*00b67f09SDavid van Moolenbroek /*
1052*00b67f09SDavid van Moolenbroek * when single threaded, hold onto the one connection
1053*00b67f09SDavid van Moolenbroek * instance.
1054*00b67f09SDavid van Moolenbroek */
1055*00b67f09SDavid van Moolenbroek s3->db = dbi;
1056*00b67f09SDavid van Moolenbroek #endif
1057*00b67f09SDavid van Moolenbroek
1058*00b67f09SDavid van Moolenbroek dbi->dbconn = dbc;
1059*00b67f09SDavid van Moolenbroek dbc = NULL;
1060*00b67f09SDavid van Moolenbroek #if PTHREADS
1061*00b67f09SDavid van Moolenbroek /* set DBI = null for next loop through. */
1062*00b67f09SDavid van Moolenbroek dbi = NULL;
1063*00b67f09SDavid van Moolenbroek }
1064*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
1065*00b67f09SDavid van Moolenbroek
1066*00b67f09SDavid van Moolenbroek *dbdata = s3;
1067*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1068*00b67f09SDavid van Moolenbroek
1069*00b67f09SDavid van Moolenbroek cleanup:
1070*00b67f09SDavid van Moolenbroek dlz_destroy(s3);
1071*00b67f09SDavid van Moolenbroek
1072*00b67f09SDavid van Moolenbroek return (result);
1073*00b67f09SDavid van Moolenbroek }
1074*00b67f09SDavid van Moolenbroek
1075*00b67f09SDavid van Moolenbroek /*%
1076*00b67f09SDavid van Moolenbroek * Destroy the module.
1077*00b67f09SDavid van Moolenbroek */
1078*00b67f09SDavid van Moolenbroek void
dlz_destroy(void * dbdata)1079*00b67f09SDavid van Moolenbroek dlz_destroy(void *dbdata) {
1080*00b67f09SDavid van Moolenbroek sqlite3_instance_t *db = (sqlite3_instance_t *)dbdata;
1081*00b67f09SDavid van Moolenbroek #if PTHREADS
1082*00b67f09SDavid van Moolenbroek /* cleanup the list of DBI's */
1083*00b67f09SDavid van Moolenbroek if (db->db != NULL)
1084*00b67f09SDavid van Moolenbroek sqlite3_destroy_dblist((db_list_t *)(db->db));
1085*00b67f09SDavid van Moolenbroek #else /* PTHREADS */
1086*00b67f09SDavid van Moolenbroek sqlite3_destroy(db);
1087*00b67f09SDavid van Moolenbroek #endif /* PTHREADS */
1088*00b67f09SDavid van Moolenbroek
1089*00b67f09SDavid van Moolenbroek if (db->dbname != NULL)
1090*00b67f09SDavid van Moolenbroek free(db->dbname);
1091*00b67f09SDavid van Moolenbroek }
1092*00b67f09SDavid van Moolenbroek
1093*00b67f09SDavid van Moolenbroek /*
1094*00b67f09SDavid van Moolenbroek * Return the version of the API
1095*00b67f09SDavid van Moolenbroek */
1096*00b67f09SDavid van Moolenbroek int
dlz_version(unsigned int * flags)1097*00b67f09SDavid van Moolenbroek dlz_version(unsigned int *flags) {
1098*00b67f09SDavid van Moolenbroek *flags |= (DNS_SDLZFLAG_RELATIVEOWNER |
1099*00b67f09SDavid van Moolenbroek DNS_SDLZFLAG_RELATIVERDATA |
1100*00b67f09SDavid van Moolenbroek DNS_SDLZFLAG_THREADSAFE);
1101*00b67f09SDavid van Moolenbroek return (DLZ_DLOPEN_VERSION);
1102*00b67f09SDavid van Moolenbroek }
1103*00b67f09SDavid van Moolenbroek
1104*00b67f09SDavid van Moolenbroek /*
1105*00b67f09SDavid van Moolenbroek * Register a helper function from the bind9 dlz_dlopen driver
1106*00b67f09SDavid van Moolenbroek */
1107*00b67f09SDavid van Moolenbroek static void
b9_add_helper(sqlite3_instance_t * db,const char * helper_name,void * ptr)1108*00b67f09SDavid van Moolenbroek b9_add_helper(sqlite3_instance_t *db, const char *helper_name, void *ptr) {
1109*00b67f09SDavid van Moolenbroek if (strcmp(helper_name, "log") == 0)
1110*00b67f09SDavid van Moolenbroek db->log = (log_t *)ptr;
1111*00b67f09SDavid van Moolenbroek if (strcmp(helper_name, "putrr") == 0)
1112*00b67f09SDavid van Moolenbroek db->putrr = (dns_sdlz_putrr_t *)ptr;
1113*00b67f09SDavid van Moolenbroek if (strcmp(helper_name, "putnamedrr") == 0)
1114*00b67f09SDavid van Moolenbroek db->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr;
1115*00b67f09SDavid van Moolenbroek if (strcmp(helper_name, "writeable_zone") == 0)
1116*00b67f09SDavid van Moolenbroek db->writeable_zone = (dns_dlz_writeablezone_t *)ptr;
1117*00b67f09SDavid van Moolenbroek }
1118