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