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
sqlite3_destroy(dbinstance_t * db)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
sqlite3_destroy_dblist(db_list_t * dblist)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 *
sqlite3_find_avail(sqlite3_instance_t * sqlite3)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 *
escape_string(const char * instr)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
sqlite3_get_resultset(const char * zone,const char * record,const char * client,unsigned int query,void * dbdata,sqlite3_res_t ** rsp)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 **
sqlite3_fetch_row(sqlite3_res_t * rs)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
sqlite3_num_fields(sqlite3_res_t * rs)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
sqlite3_num_rows(sqlite3_res_t * rs)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
sqlite3_free_result(sqlite3_res_t * rs)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
sqlite3_process_rs(sqlite3_instance_t * db,dns_sdlzlookup_t * lookup,sqlite3_res_t * rs)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
dlz_findzonedb(void * dbdata,const char * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)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
dlz_allowzonexfr(void * dbdata,const char * name,const char * client)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
dlz_allnodes(const char * zone,void * dbdata,dns_sdlzallnodes_t * allnodes)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
dlz_authority(const char * zone,void * dbdata,dns_sdlzlookup_t * lookup)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
dlz_lookup(const char * zone,const char * name,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)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
dlz_create(const char * dlzname,unsigned int argc,char * argv[],void ** dbdata,...)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
dlz_destroy(void * dbdata)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
dlz_version(unsigned int * flags)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
b9_add_helper(sqlite3_instance_t * db,const char * helper_name,void * ptr)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