sqlite driver
"Tim Tessier" <[email protected]> Fri, 1 Jan 2010 13:47:52 -0500
| Newsgroups | gmane.network.dns.bind9.dlz |
|---|---|
| Message-ID | <8891C28C2E38482DA5CF4C99215649EA@lappy> |
I have modified the mysql driver to support sqlite. I left the original copyright in the top of the file and a mention of myself in the file. I have used this successfully with bind 9.4.3 on windows and will be porting to solaris/linux which should require minimal effort Thanks, Tim Tessier ------------------------------------------------------------------------------ This SF.Net email is sponsored by the Verizon Developer Community Take advantage of Verizon's best-in-class app development support A streamlined, 14 day to market process makes app distribution fast and easy Join now and get one step closer to millions of Verizon customers http://p.sf.net/sfu/verizon-dev2dev _______________________________________________ Bind-dlz-testers mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/bind-dlz-testers
dlz_sqlite_driver.h
(text/plain, 1.8 KB)
/* * Copyright (C) 2002 Stichting NLnet, Netherlands, [email protected]. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE * USE OR PERFORMANCE OF THIS SOFTWARE. * * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was * conceived and contributed by Rob Butler. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE * USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef DLZ_SQLITE_DRIVER_H #define DLZ_SQLITE_DRIVER_H isc_result_t dlz_sqlite_init(void); void dlz_sqlite_clear(void); #endif
dlz_sqlite_driver.c
(text/plain, 26.9 KB)
/* * Copyright (C) 2002 Stichting NLnet, Netherlands, [email protected]. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE * USE OR PERFORMANCE OF THIS SOFTWARE. * * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was * conceived and contributed by Rob Butler. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE * USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This driver is based on the mysql driver and contains the original copyright above Modified by Tim Tessier to provide sqlite database driver. */ #ifdef DLZ_SQLITE #include <config.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <dns/log.h> #include <dns/sdlz.h> #include <dns/result.h> #include <isc/mem.h> #include <isc/platform.h> #include <isc/print.h> #include <isc/result.h> #include <isc/string.h> #include <isc/util.h> #include <named/globals.h> #include <sqlite3.h> #include <dlz/sdlz_helper.h> #include <dlz/dlz_sqlite_driver.h> #define dbc_search_limit 30 #define ALLNODES 1 #define ALLOWXFR 2 #define AUTHORITY 3 #define FINDZONE 4 #define COUNTZONE 5 #define LOOKUP 6 #define safeGet(in,v) in[v] == NULL ? "" : in[v] static dns_sdlzimplementation_t *dlz_sqlite = NULL; typedef struct config_data { char *myzone; char *myname; char *myip; isc_mem_t *mctx; } config_data_t; typedef struct st_sqlite_rs{ const char *zSql; /* SQL to be evaluated */ char **pzResult; /* Results of the query */ unsigned int pnRow; /* Number of result rows written here */ unsigned int pnColumn; /* Number of result columns written here */ unsigned int curRow; char *pzErrmsg; /* Error msg written here */ }SQLITE_RS, * LPSQLITE_RS; /* * SDLZ methods */ static char * sqlitedrv_unescape_string(const char * instr){ char *outstr; char * ptr ; unsigned int len; unsigned int tlen = 0 ; unsigned int atlen = 0 ; unsigned int i = 0 ; if (instr == NULL) return NULL; len = strlen(instr); atlen = (len * sizeof(char)) + 1 ; outstr = ( char * ) isc_mem_allocate(ns_g_mctx ,atlen); if (outstr == NULL) return NULL; ptr = outstr ; for ( i = 0 ; i < len ; i++ ){ if ( tlen >= atlen ){ break ; } if ( instr[i] == '\'' && instr[i+1] == '\'' ){ i++; tlen ++ ; } *ptr = instr[i] ; ptr++ ; tlen ++ ; if ( instr=='\0' ){ break ; } } *ptr = '\0' ; return outstr; } static char * sqlitedrv_escape_string(const char *instr) { char *outstr; char * ptr ; unsigned int len; unsigned int tlen = 0 ; unsigned int atlen = 0 ; unsigned int i = 0 ; if (instr == NULL) return NULL; len = strlen(instr); atlen = (2 * len * sizeof(char)) + 1 ; outstr = ( char * ) isc_mem_allocate(ns_g_mctx ,atlen); if (outstr == NULL) return NULL; ptr = outstr ; for ( i = 0 ; i < len ; i++ ){ if ( tlen >= atlen ){ break ; } if ( instr[i] == '\'' ){ *ptr = '\'' ; ptr++ ; tlen ++ ; } *ptr = instr[i] ; ptr++ ; tlen ++ ; if ( instr=='\0' ){ break ; } } *ptr = '\0' ; return outstr; } static isc_result_t sqlite_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, SQLITE_RS **rs) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; if ( !rs || rs && *rs ){ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Result set is not null before query or result set ptr invalid"); result = ISC_R_FAILURE; goto cleanup; } if (query != COUNTZONE) REQUIRE(*rs == NULL); else REQUIRE(rs == NULL); /* get db instance / connection */ dbi = (dbinstance_t *) dbdata; /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } switch(query) { case ALLNODES: if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case COUNTZONE: if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* this should never happen. If it does, the code is screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "sqlite_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* was a zone string passed? If so, make it safe for use in queries.*/ if (zone != NULL) { dbi->zone = sqlitedrv_escape_string(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { dbi->zone = NULL; } /* was a record string passed? If so, make it safe for use in queries. */ if (record != NULL) { dbi->record = sqlitedrv_escape_string(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { dbi->record = NULL; } /* was a client string passed? If so, make it safe for use in queries.*/ if (client != NULL) { dbi->client = sqlitedrv_escape_string(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { dbi->client = NULL; } switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case COUNTZONE: querystring = build_querystring(ns_g_mctx, dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "sqlite_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); (*rs)= isc_mem_allocate(ns_g_mctx , sizeof ( SQLITE_RS ) ) ; if ( !*rs ){ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nFailed to allocate result set\n"); result = ISC_R_NOMEMORY; goto cleanup; } memset ( (*rs),0, sizeof ( SQLITE_RS ) ) ; (*rs)->zSql = querystring ; for (i=0; i < 10; i++) { qres = sqlite3_get_table ( dbi->dbconn, querystring, &(*rs)->pzResult, &(*rs)->pnRow, &(*rs)->pnColumn, &(*rs)->pzErrmsg ) ; if (qres == SQLITE_OK) break; #ifdef WIN32 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nFailed query: %s\n",(*rs)->pzErrmsg?(*rs)->pzErrmsg:"NULL"); sqlite3_free ( (*rs)->pzErrmsg ) ; (*rs)->pzErrmsg = NULL ; Sleep ( 100 ) ; #else #endif } if ( (*rs)->pzErrmsg ){ sqlite3_free ( (*rs)->pzErrmsg ) ; (*rs)->pzErrmsg = NULL ; } if (qres == SQLITE_OK) { result = ISC_R_SUCCESS; if (query == COUNTZONE) { sqlite3_free_table ( (*rs)->pzResult ) ; } } else { result = ISC_R_FAILURE; } cleanup: /* it's always good to cleanup after yourself */ /* if we couldn't even get DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring); /* return result */ return result; } char ** sqlite_fetch_row(SQLITE_RS * rs){ char ** result = NULL ; if ( rs != NULL ){ if ( rs->pnRow > (unsigned int )0 && rs->curRow < rs->pnRow ){ result = &rs->pzResult[(rs->curRow+1)*rs->pnColumn]; rs->curRow++ ; } } return result ; } unsigned int sqlite_num_fields(SQLITE_RS * rs){ unsigned int result = 0 ; if ( rs != NULL ){ result = rs->pnColumn ; } return result ; } unsigned int sqlite_num_rows(SQLITE_RS *rs){ unsigned int result = 0 ; if ( rs != NULL ){ result = rs->pnRow; } return result ; } void sqlite_free_result ( SQLITE_RS * rs ) { if ( rs != NULL ){ sqlite3_free_table ( rs->pzResult ) ; isc_mem_free(ns_g_mctx, rs ) ; } } static isc_result_t sqlite_process_rs(dns_sdlzlookup_t *lookup, SQLITE_RS *rs) { isc_result_t result = ISC_R_NOTFOUND; char ** row; unsigned int fields; unsigned int j; unsigned int len; unsigned int i = 0 ; char *tmpString; char *endp; int ttl; row = sqlite_fetch_row(rs); /* get a row from the result set */ fields = sqlite_num_fields(rs); /* how many columns in result set */ while (row != NULL) { for ( i = 0 ; i < fields ; i++ ){ char * f = safeGet(row,i ) ; isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_INFO, "%s\n", f ); } switch(fields) { case 1: /* default type A record, default TTL 86400 */ result = dns_sdlz_putrr(lookup, "a", 86400, safeGet(row,0)); break; case 2: /* data field, and data type. use default TTL of 86400.*/ result = dns_sdlz_putrr(lookup, safeGet(row,0), 86400, safeGet(row,1)); break; case 3: /* all data no defaults. convert text to int, make sure it worked */ ttl = strtol(safeGet(row,0), &endp, 10); if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver ttl must be " "a postive number"); } result = dns_sdlz_putrr(lookup, safeGet(row,1), ttl, safeGet(row,2)); break; default: /* * more than 3 fields, concatenate the last * ones together. figure out how long to make * string. */ for (j=2, len=0; j < fields; j++) { len += strlen(safeGet(row,j)) + 1; } /* * allocate string memory, allow for NULL to * term string */ tmpString = isc_mem_allocate(ns_g_mctx, len + 1); if (tmpString == NULL) { /* major bummer, need more ram */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable " "to allocate memory for " "temporary string"); sqlite_free_result(rs); return (ISC_R_FAILURE); /* Yeah, I'd say! */ } /* copy field to tmpString */ strcpy(tmpString, safeGet(row,2)); /* concat the rest of fields together, space between each one.*/ for (j=3; j < fields; j++) { strcat(tmpString, " "); strcat(tmpString, safeGet(row,j)); } /* convert text to int, make sure it worked right */ ttl = strtol(safeGet(row,0), &endp, 10); if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver ttl must be " "a postive number"); } /* ok, now tell Bind about it. */ result = dns_sdlz_putrr(lookup, safeGet(row,1),ttl, tmpString); /* done, get rid of this thing. */ isc_mem_free(ns_g_mctx, tmpString); } /* I sure hope we were successful */ if (result != ISC_R_SUCCESS) { /* nope, get rid of the Result set, and log a msg */ sqlite_free_result(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "dns_sdlz_putrr returned error. " "Error code was: %s", isc_result_totext(result)); return (ISC_R_FAILURE); } row = sqlite_fetch_row(rs); /* get next row */ } /* free result set memory */ sqlite_free_result(rs); /* return result code */ return result; } static isc_result_t sqlite_findzone(void *driverarg, void *dbdata, const char *name) { isc_result_t result; SQLITE_RS *rs = NULL; unsigned long long rows; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = sqlite_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs); /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS || rs == NULL) { if (rs != NULL) sqlite_free_result(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable to return " "result set for findzone query"); return (ISC_R_FAILURE); } /* count how many rows in result set */ rows = sqlite_num_rows(rs); /* get rid of result set, we are done with it. */ sqlite_free_result(rs); /* if we returned any rows, zone is supported. */ if (rows > 0) { sqlite_get_resultset(name, NULL, NULL, COUNTZONE, dbdata, NULL); return (ISC_R_SUCCESS); } /* no rows returned, zone is not supported. */ return (ISC_R_NOTFOUND); } /*% Determine if the client is allowed to perform a zone transfer */ static isc_result_t sqlite_allowzonexfr(void *driverarg, void *dbdata, const char *name, const char *client) { isc_result_t result; SQLITE_RS *rs = NULL; unsigned long long rows; UNUSED(driverarg); /* first check if the zone is supported by the database. */ result = sqlite_findzone(driverarg, dbdata, name); if (result != ISC_R_SUCCESS) return (ISC_R_NOTFOUND); /* if we get to this point we know the zone is supported by the database the only questions now are; is the zone transfer allowed for this client and did the config file have an allow zone xfr query. Run our query, and get a result set from the database.*/ result = sqlite_get_resultset(name, NULL, client, ALLOWXFR,dbdata, &rs); /* if we get "not implemented", send it along. */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS || rs == NULL) { if (rs != NULL) sqlite_free_result(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable to return " "result set for allow xfr query"); return (ISC_R_FAILURE); } /* count how many rows in result set */ rows = sqlite_num_rows(rs); /* get rid of result set, we are done with it. */ sqlite_free_result(rs); /* if we returned any rows, zone xfr is allowed. */ if (rows > 0) return (ISC_R_SUCCESS); /* no rows returned, zone xfr not allowed */ return (ISC_R_NOPERM); } /*% * If the client is allowed to perform a zone transfer, the next order of * business is to get all the nodes in the zone, so bind can respond to the * query. */ static isc_result_t sqlite_allnodes(const char *zone, void *driverarg, void *dbdata, dns_sdlzallnodes_t *allnodes) { isc_result_t result; SQLITE_RS *rs = NULL; char ** row; unsigned int fields; unsigned int j; unsigned int len; char *tmpString; char *endp; int ttl; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = sqlite_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs); /* if we get "not implemented", send it along */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { if (rs != NULL) sqlite_free_result(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable to return " "result set for all nodes query"); return (ISC_R_FAILURE); } result = ISC_R_NOTFOUND; row = sqlite_fetch_row(rs); /* get a row from the result set */ fields = sqlite_num_fields(rs); /* how many columns in result set */ while (row != NULL) { if (fields < 4) { /* gotta have at least 4 columns */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver too few fields returned " "by all nodes query"); } /* convert text to int, make sure it worked right */ ttl = strtol(safeGet(row,0), &endp, 10); if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver ttl must be " "a postive number"); } if (fields == 4) { /* tell Bind about it. */ result = dns_sdlz_putnamedrr(allnodes, safeGet(row,2),safeGet(row,1), ttl,safeGet(row,3)); } else { /* * more than 4 fields, concatenate the last * ones together. figure out how long to make * string. */ for (j=3, len=0; j < fields; j++) { len += strlen(safeGet(row,j)) + 1; } /* allocate memory, allow for NULL to term string */ tmpString = isc_mem_allocate(ns_g_mctx, len + 1); if (tmpString == NULL) { /* we need more ram. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable " "to allocate memory for " "temporary string"); sqlite_free_result(rs); return (ISC_R_FAILURE); } /* copy this field to tmpString */ strcpy(tmpString, safeGet(row,3)); /* concatonate the rest, with spaces between */ for (j=4; j < fields; j++) { strcat(tmpString, " "); strcat(tmpString, safeGet(row,j)); } /* tell Bind about it. */ result = dns_sdlz_putnamedrr(allnodes, safeGet(row,2),safeGet(row,1),ttl, tmpString); isc_mem_free(ns_g_mctx, tmpString); } /* if we weren't successful, log err msg */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "dns_sdlz_putnamedrr returned error. " "Error code was: %s", isc_result_totext(result)); result = ISC_R_FAILURE; break; } /* get next row from the result set */ row = sqlite_fetch_row(rs); } /* free result set memory */ sqlite_free_result(rs); return result; } static isc_result_t sqlite_authority(const char *zone, void *driverarg, void *dbdata,dns_sdlzlookup_t *lookup) { isc_result_t result; SQLITE_RS *rs = NULL; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = sqlite_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &rs); /* if we get "not implemented", send it along */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { if (rs != NULL) sqlite_free_result(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable to return " "result set for authority query"); return (ISC_R_FAILURE); } /* lookup and authority result sets are processed in the same manner sqlite_process_rs does the job for both functions.*/ return sqlite_process_rs(lookup, rs); } /*% if zone is supported, lookup up a (or multiple) record(s) in it */ static isc_result_t sqlite_lookup(const char *zone, const char *name, void *driverarg, void *dbdata, dns_sdlzlookup_t *lookup) { isc_result_t result; SQLITE_RS *rs = NULL; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = sqlite_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs); /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { if (rs != NULL) sqlite_free_result(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver unable to return " "result set for lookup query"); return (ISC_R_FAILURE); } /* * lookup and authority result sets are processed in the same manner * sqlite_process_rs does the job for both functions. */ return sqlite_process_rs(lookup, rs); } /*% * create an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument which is * passed into all query functions. */ static isc_result_t sqlite_create(const char *dlzname, unsigned int argc, char *argv[],void *driverarg, void **dbdata) { isc_result_t result; dbinstance_t *dbi = NULL; char *tmp = NULL; char *dbname = NULL; char *host = NULL; sqlite3 * dbc; unsigned int flags = 0; UNUSED(driverarg); UNUSED(dlzname); /* verify we have at least 4 arg's passed to the driver */ if (argc < 4) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver requires " "at least 4 command line args."); return (ISC_R_FAILURE); } /* no more than 8 arg's should be passed to the driver */ if (argc > 8) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver cannot accept " "more than 7 command line args."); return (ISC_R_FAILURE); } /* parse connection string and get paramters. */ /* get db name - required */ dbname = getParameterValue(argv[1], "dbname="); if (dbname == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver requires a dbname parameter."); result = ISC_R_FAILURE; goto full_cleanup; } /* how many queries were passed in from config file? */ switch(argc) { case 4: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL, argv[2], argv[3], NULL, &dbi); break; case 5: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[4],argv[2], argv[3], NULL, &dbi); break; case 6: result = build_sqldbinstance(ns_g_mctx, argv[5], NULL, argv[4],argv[2], argv[3], NULL, &dbi); break; case 7: result = build_sqldbinstance(ns_g_mctx, argv[5],argv[6], argv[4],argv[2], argv[3], NULL, &dbi); break; case 8: result = build_sqldbinstance(ns_g_mctx, argv[5],argv[6], argv[4],argv[2], argv[3], argv[7], &dbi); break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } /* unsuccessful?, log err msg and cleanup. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver could not create " "database instance object."); result = ISC_R_FAILURE; goto full_cleanup; } /* create and set db connection */ if ( sqlite3_initialize ( ) == SQLITE_OK ){ if ( sqlite3_open( dbname, ( sqlite3**)&dbi->dbconn ) == SQLITE_OK ){ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver opened successfully "); }else{ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver could not open the db: %s",dbname); result = ISC_R_FAILURE; goto full_cleanup; } }else{ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "sqlite driver could not create failed to initialize"); result = ISC_R_FAILURE; goto full_cleanup; } /* if db connection cannot be created, log err msg and cleanup. */ if (dbi->dbconn == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_INFO, "sqlite driver could not allocate " "memory for database connection"); result = ISC_R_FAILURE; goto full_cleanup; } dbc = NULL; host = getParameterValue(argv[1], "host="); /* return db connection via dbdata */ *dbdata = dbi; result = ISC_R_SUCCESS; goto cleanup; full_cleanup: destroy_sqldbinstance(dbi); cleanup: if (dbname != NULL) isc_mem_free(ns_g_mctx, dbname); if (host != NULL) isc_mem_free(ns_g_mctx, host); return result; } static void sqlite_destroy(void *driverarg, void *dbdata) { dbinstance_t *dbi; UNUSED(driverarg); dbi = (dbinstance_t *) dbdata; /* release DB connection */ if (dbi->dbconn != NULL){ if ( sqlite3_close((sqlite3 *) dbi->dbconn)!= SQLITE_OK ){ } } if ( sqlite3_shutdown() != SQLITE_OK ){ } /* destroy DB instance */ destroy_sqldbinstance(dbi); } static dns_sdlzmethods_t dlz_sqlite_methods = { sqlite_create, sqlite_destroy, sqlite_findzone, sqlite_lookup, sqlite_authority, sqlite_allnodes, sqlite_allowzonexfr }; /* Wrapper around dns_sdlzregister(). */ isc_result_t dlz_sqlite_init(void) { isc_result_t result; /* Write debugging message to log*/ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Registering DLZ_sqlite driver."); result = dns_sdlzregister("dlz_sqlite", &dlz_sqlite_methods, NULL, DNS_SDLZFLAG_RELATIVEOWNER | DNS_SDLZFLAG_RELATIVERDATA, ns_g_mctx, &dlz_sqlite); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "dns_sdlzregister() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; } return result; } /* * Wrapper around dns_sdlzunregister(). */ void dlz_sqlite_clear(void) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),"Unregistering DLZ_sqlite driver."); if (dlz_sqlite != NULL) dns_sdlzunregister(&dlz_sqlite); } #endif