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