Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / contrib / dlz / modules / sqlite3 / dlz_sqlite3_dynamic.c
blobe60731199d88a5e1446d86a822e82042b501746f
1 /* $NetBSD: dlz_sqlite3_dynamic.c,v 1.1.1.3 2014/12/10 03:34:31 christos Exp $ */
3 /*
4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
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.
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.
20 * The development of Dynamically Loadable Zones (DLZ) for BIND 9 was
21 * conceived and contributed by Rob Butler.
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.
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.
39 * Copyright (C) 1999-2001 Internet Software Consortium.
40 * Copyright (C) 2013-2014 Internet Systems Consortium.
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.
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.
57 * This provides the externally loadable SQLitee DLZ module, without
58 * update support. Based in part on SQLite code contributed by Tim Tessier.
61 #include <stdio.h>
62 #include <string.h>
63 #include <stdarg.h>
64 #include <stdint.h>
65 #include <stdlib.h>
67 #include <dlz_minimal.h>
68 #include <dlz_list.h>
69 #include <dlz_dbi.h>
70 #include <dlz_pthread.h>
72 #include <sqlite3.h>
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
82 #define safeGet(in) in == NULL ? "" : in
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.
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
97 char *dbname;
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;
107 * SQLite3 result set
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;
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);
123 void
124 dlz_destroy(void *dbdata);
126 static void
127 b9_add_helper(sqlite3_instance_t *db, const char *helper_name, void *ptr);
130 * Private methods
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();
140 /* destroy DB instance */
141 destroy_dbinstance(db);
144 #if PTHREADS
146 * Properly cleans up a list of database instances.
147 * This function is only used when the module is compiled for
148 * multithreaded operation.
150 static void
151 sqlite3_destroy_dblist(db_list_t *dblist) {
152 dbinstance_t *ndbi = NULL;
153 dbinstance_t *dbi = NULL;
155 ndbi = DLZ_LIST_HEAD(*dblist);
156 while (ndbi != NULL) {
157 dbi = ndbi;
158 ndbi = DLZ_LIST_NEXT(dbi, link);
160 sqlite3_destroy(dbi);
163 /* release memory for the list structure */
164 free(dblist);
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.
177 static dbinstance_t *
178 sqlite3_find_avail(sqlite3_instance_t *sqlite3) {
179 dbinstance_t *dbi = NULL, *head;
180 int count = 0;
182 /* get top of list */
183 head = dbi = DLZ_LIST_HEAD(*(sqlite3->db));
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. */
191 /* not successful, keep trying */
192 dbi = DLZ_LIST_NEXT(dbi, link);
194 /* check to see if we have gone to the top of the list. */
195 if (dbi == NULL) {
196 count++;
197 dbi = head;
201 sqlite3->log(ISC_LOG_INFO,
202 "SQLite3 module: unable to find available connection "
203 "after searching %d times", count);
204 return (NULL);
206 #endif /* PTHREADS */
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.
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;
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);
232 ptr = outstr;
233 for (i = 0; i < len; i++) {
234 if (tlen > atlen || instr[i] == '\0')
235 break;
237 if (instr[i] == '\'') {
238 *ptr++ = '\'';
239 tlen++;
242 *ptr++ = instr[i];
243 tlen++;
245 *ptr = '\0';
247 return (outstr);
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.
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)
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;
273 if ((query == COUNTZONE && rsp != NULL) ||
274 (query != COUNTZONE && (rsp == NULL || *rsp != NULL)))
276 db->log(ISC_LOG_DEBUG(2), "Invalid result set pointer.");
277 result = ISC_R_FAILURE;
278 goto cleanup;
281 #if PTHREADS
282 /* find an available DBI from the list */
283 dbi = sqlite3_find_avail(db);
284 #else /* PTHREADS */
286 * only 1 DBI - no need to lock instance lock either
287 * only 1 thread in the whole process, no possible contention.
289 dbi = (dbinstance_t *)(db->db);
290 #endif /* PTHREADS */
292 if (dbi == NULL) {
293 result = ISC_R_FAILURE;
294 goto cleanup;
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;
304 break;
305 case ALLOWXFR:
306 if (dbi->allowxfr_q == NULL) {
307 result = ISC_R_NOTIMPLEMENTED;
308 goto cleanup;
310 break;
311 case AUTHORITY:
312 if (dbi->authority_q == NULL) {
313 result = ISC_R_NOTIMPLEMENTED;
314 goto cleanup;
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;
325 break;
326 case COUNTZONE:
327 if (dbi->countzone_q == NULL) {
328 result = ISC_R_NOTIMPLEMENTED;
329 goto cleanup;
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;
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;
350 if (zone != NULL) {
351 if (dbi->zone != NULL)
352 free(dbi->zone);
354 dbi->zone = escape_string(zone);
355 if (dbi->zone == NULL) {
356 result = ISC_R_NOMEMORY;
357 goto cleanup;
359 } else
360 dbi->zone = NULL;
362 if (record != NULL) {
363 if (dbi->record != NULL)
364 free(dbi->record);
366 dbi->record = escape_string(record);
367 if (dbi->record == NULL) {
368 result = ISC_R_NOMEMORY;
369 goto cleanup;
371 } else
372 dbi->record = NULL;
374 if (client != NULL) {
375 if (dbi->client != NULL)
376 free(dbi->client);
378 dbi->client = escape_string(client);
379 if (dbi->client == NULL) {
380 result = ISC_R_NOMEMORY;
381 goto cleanup;
383 } else
384 dbi->client = NULL;
387 * what type of query are we going to run? this time we build
388 * the actual query to run.
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;
417 if (querystring == NULL) {
418 result = ISC_R_NOMEMORY;
419 goto cleanup;
422 /* output the full query string when debugging */
423 db->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring);
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;
431 memset(rs, 0, sizeof(sqlite3_res_t));
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;
444 result = ISC_R_SUCCESS;
445 if (query == COUNTZONE) {
446 sqlite3_free_table(rs->pazResult);
447 if (rs == NULL)
448 result = ISC_R_FAILURE;
451 *rsp = rs;
453 cleanup:
454 if (dbi == NULL)
455 return (ISC_R_FAILURE);
457 if (dbi->zone != NULL) {
458 free(dbi->zone);
459 dbi->zone = NULL;
461 if (dbi->record != NULL) {
462 free(dbi->record);
463 dbi->record = NULL;
465 if (dbi->client != NULL) {
466 free(dbi->client);
467 dbi->client = NULL;
470 /* release the lock so another thread can use this dbi */
471 (void) dlz_mutex_unlock(&dbi->lock);
473 if (querystring != NULL)
474 free(querystring);
476 return (result);
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.
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++;
495 return (retval);
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);
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);
514 void
515 sqlite3_free_result(sqlite3_res_t *rs) {
516 if (rs != NULL) {
517 sqlite3_free_table(rs->pazResult);
518 free(rs);
522 static isc_result_t
523 sqlite3_process_rs(sqlite3_instance_t *db, dns_sdlzlookup_t *lookup,
524 sqlite3_res_t *rs)
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;
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;
539 switch(fields) {
540 case 1:
542 * one column in rs, it's the data field. use
543 * default type of A record, and default TTL
544 * of 86400
546 result = db->putrr(lookup, "a", 86400, safeGet(row[0]));
547 break;
548 case 2:
550 * two columns, data field, and data type.
551 * use default TTL of 86400.
553 result = db->putrr(lookup, safeGet(row[0]), 86400,
554 safeGet(row[1]));
555 break;
556 case 3:
558 * three columns, all data no defaults.
559 * convert text to int, make sure it worked
560 * right.
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);
570 result = db->putrr(lookup, safeGet(row[1]), ttl,
571 safeGet(row[2]));
572 break;
573 default:
575 * more than 3 fields, concatenate the last
576 * ones together. figure out how long to make
577 * string.
579 for (j = 2; j < fields; j++)
580 len += strlen(safeGet(row[j])) + 1;
583 * allocate string memory, allow for NULL to
584 * term string
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);
595 strcpy(tmpString, safeGet(row[2]));
596 for (j = 3; j < fields; j++) {
597 strcat(tmpString, " ");
598 strcat(tmpString, safeGet(row[j]));
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);
609 result = db->putrr(lookup, safeGet(row[1]),
610 ttl, tmpString);
611 free(tmpString);
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);
621 row = sqlite3_fetch_row(rs);
624 sqlite3_free_result(rs);
625 return (result);
629 * DLZ methods
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)
638 isc_result_t result;
639 sqlite3_res_t *rs = NULL;
640 sqlite3_uint64 rows;
641 sqlite3_instance_t *db = (sqlite3_instance_t *)dbdata;
643 UNUSED(methods);
644 UNUSED(clientinfo);
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);
651 db->log(ISC_LOG_ERROR,
652 "SQLite3 module: unable to return "
653 "result set for FINDZONE query");
655 return (ISC_R_FAILURE);
659 * if we returned any rows, the zone is supported.
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);
669 return (ISC_R_NOTFOUND);
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;
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);
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.
691 result = sqlite3_get_resultset(name, NULL, client, ALLOWXFR,
692 dbdata, &rs);
693 if (result == ISC_R_NOTIMPLEMENTED)
694 return (result);
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);
706 * count how many rows in result set; if we returned any,
707 * zone xfr is allowed.
709 rows = sqlite3_num_rows(rs);
710 sqlite3_free_result(rs);
711 if (rows > 0)
712 return (ISC_R_SUCCESS);
714 return (ISC_R_NOPERM);
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.
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;
734 result = sqlite3_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs);
735 if (result == ISC_R_NOTIMPLEMENTED)
736 return (result);
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;
746 result = ISC_R_NOTFOUND;
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;
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;
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;
776 * more than 4 fields, concatenate the last
777 * ones together.
779 for (j = 3; j < fields; j++)
780 len += strlen(safeGet(row[j])) + 1;
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;
791 strcpy(tmpString, safeGet(row[3]));
792 for (j = 4; j < fields; j++) {
793 strcat(tmpString, " ");
794 strcat(tmpString, safeGet(row[j]));
797 result = db->putnamedrr(allnodes, safeGet(row[2]),
798 safeGet(row[1]),
799 ttl, tmpString);
800 free(tmpString);
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;
810 row = sqlite3_fetch_row(rs);
813 cleanup:
814 if (rs != NULL)
815 sqlite3_free_result(rs);
817 return (result);
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.
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;
830 result = sqlite3_get_resultset(zone, NULL, NULL, AUTHORITY,
831 dbdata, &rs);
832 if (result == ISC_R_NOTIMPLEMENTED)
833 return (result);
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);
845 * lookup and authority result sets are processed in the same
846 * manner: sqlite3_process_rs does the job for both functions.
848 return (sqlite3_process_rs(db, lookup, rs));
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)
858 isc_result_t result;
859 sqlite3_res_t *rs = NULL;
860 sqlite3_instance_t *db = (sqlite3_instance_t *) dbdata;
862 UNUSED(methods);
863 UNUSED(clientinfo);
865 result = sqlite3_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
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);
878 * lookup and authority result sets are processed in the same
879 * manner: sqlite3_process_rs does the job for both functions.
881 return (sqlite3_process_rs(db, lookup, rs));
885 * Create an instance of the module.
887 isc_result_t
888 dlz_create(const char *dlzname, unsigned int argc, char *argv[],
889 void **dbdata, ...)
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;
907 UNUSED(dlzname);
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));
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);
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 */
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);
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);
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;
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;
969 free(tmp);
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;
979 /* initialize DB connection list */
980 DLZ_LIST_INIT(*(s3->db));
983 * create the appropriate number of database instances (DBI)
984 * append each new DBI to the end of the list
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;
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;
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;
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;
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
1052 * when single threaded, hold onto the one connection
1053 * instance.
1055 s3->db = dbi;
1056 #endif
1058 dbi->dbconn = dbc;
1059 dbc = NULL;
1060 #if PTHREADS
1061 /* set DBI = null for next loop through. */
1062 dbi = NULL;
1064 #endif /* PTHREADS */
1066 *dbdata = s3;
1067 return (ISC_R_SUCCESS);
1069 cleanup:
1070 dlz_destroy(s3);
1072 return (result);
1076 * Destroy the module.
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 */
1089 if (db->dbname != NULL)
1090 free(db->dbname);
1094 * Return the version of the API
1097 dlz_version(unsigned int *flags) {
1098 *flags |= (DNS_SDLZFLAG_RELATIVEOWNER |
1099 DNS_SDLZFLAG_RELATIVERDATA |
1100 DNS_SDLZFLAG_THREADSAFE);
1101 return (DLZ_DLOPEN_VERSION);
1105 * Register a helper function from the bind9 dlz_dlopen driver
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;