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