1 /* $NetBSD: sqlitedb.c,v 1.4 2014/12/10 04:37:57 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2007 Internet Software Consortium. 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 above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 11 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 12 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 13 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 15 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 16 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 17 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: sqlitedb.c,v 1.2 2011/10/11 00:09:02 each Exp */ 21 22 #include <config.h> 23 24 #include <stdio.h> 25 #include <string.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 29 #include <sqlite3.h> 30 31 #include <isc/mem.h> 32 #include <isc/print.h> 33 #include <isc/result.h> 34 #include <isc/util.h> 35 36 #include <dns/sdb.h> 37 #include <dns/result.h> 38 39 #include <named/globals.h> 40 41 #include "sqlitedb.h" 42 43 /* 44 * A simple database driver that interfaces to a SQLite database. 45 * 46 * The table must contain the fields "name", "rdtype", and "rdata", and 47 * is expected to contain a properly constructed zone. The program "zonetodb" 48 * creates such a table. 49 */ 50 51 static dns_sdbimplementation_t *sqlitedb = NULL; 52 53 typedef struct _dbinfo { 54 sqlite3 *db; 55 char *filename; 56 char *table; 57 } dbinfo_t; 58 59 60 static isc_result_t 61 db_connect(dbinfo_t *dbi) 62 { 63 if (sqlite3_open(dbi->filename, &dbi->db) == SQLITE_OK) { 64 return (ISC_R_SUCCESS); 65 } else { 66 /* a connection is returned even if the open fails */ 67 sqlite3_close(dbi->db); 68 dbi->db = NULL; 69 return (ISC_R_FAILURE); 70 } 71 } 72 73 74 typedef struct _lookup_parm_t { 75 int i; 76 dns_sdblookup_t *lookup; 77 isc_result_t result; 78 } lookup_parm_t; 79 80 81 static int 82 sqlitedb_lookup_cb(void *p, int cc, char **cv, char **cn) 83 { 84 lookup_parm_t *parm = p; 85 dns_ttl_t ttl; 86 char *endp; 87 88 /* FIXME - check these(num/names); I'm assuming a mapping for now */ 89 char *ttlstr = cv[0]; 90 char *type = cv[1]; 91 char *data = cv[2]; 92 93 UNUSED(cc); 94 UNUSED(cn); 95 96 ttl = strtol(ttlstr, &endp, 10); 97 if (*endp) { 98 parm->result = DNS_R_BADTTL; 99 return 1; 100 } 101 102 parm->result = dns_sdb_putrr(parm->lookup, type, ttl, data); 103 104 if (parm->result != ISC_R_SUCCESS) 105 return 1; 106 107 (parm->i)++; 108 109 return 0; 110 } 111 112 113 #ifdef DNS_CLIENTINFO_VERSION 114 static isc_result_t 115 sqlitedb_lookup(const char *zone, const char *name, void *dbdata, 116 dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods, 117 dns_clientinfo_t *clientinfo) 118 #else 119 static isc_result_t 120 sqlitedb_lookup(const char *zone, const char *name, void *dbdata, 121 dns_sdblookup_t *lookup) 122 #endif /* DNS_CLIENTINFO_VERSION */ 123 /* 124 * synchronous absolute name lookup 125 */ 126 { 127 dbinfo_t *dbi = (dbinfo_t *) dbdata; 128 char *sql; 129 lookup_parm_t parm = { 0, lookup, ISC_R_SUCCESS }; 130 char *errmsg = NULL; 131 int result; 132 133 UNUSED(zone); 134 #ifdef DNS_CLIENTINFO_VERSION 135 UNUSED(methods); 136 UNUSED(clientinfo); 137 #endif /* DNS_CLIENTINFO_VERSION */ 138 139 sql = sqlite3_mprintf( 140 "SELECT TTL,RDTYPE,RDATA FROM \"%q\" WHERE " 141 "lower(NAME) = lower('%q')", 142 dbi->table, name); 143 144 result = sqlite3_exec(dbi->db, sql, 145 &sqlitedb_lookup_cb, &parm, 146 &errmsg); 147 sqlite3_free(sql); 148 149 if (result != SQLITE_OK) 150 return (ISC_R_FAILURE); 151 if (parm.i == 0) 152 return (ISC_R_NOTFOUND); 153 154 return (ISC_R_SUCCESS); 155 } 156 157 158 typedef struct _allnodes_parm_t { 159 int i; 160 dns_sdballnodes_t *allnodes; 161 isc_result_t result; 162 } allnodes_parm_t; 163 164 165 static int 166 sqlitedb_allnodes_cb(void *p, int cc, char **cv, char **cn) 167 { 168 allnodes_parm_t *parm = p; 169 dns_ttl_t ttl; 170 char *endp; 171 172 /* FIXME - check these(num/names); I'm assuming a mapping for now */ 173 char *ttlstr = cv[0]; 174 char *name = cv[1]; 175 char *type = cv[2]; 176 char *data = cv[3]; 177 178 UNUSED(cc); 179 UNUSED(cn); 180 181 ttl = strtol(ttlstr, &endp, 10); 182 if (*endp) { 183 parm->result = DNS_R_BADTTL; 184 return 1; 185 } 186 187 parm->result = dns_sdb_putnamedrr(parm->allnodes, name, type, ttl, data); 188 189 if (parm->result != ISC_R_SUCCESS) 190 return 1; 191 192 (parm->i)++; 193 194 return 0; 195 } 196 197 198 static isc_result_t 199 sqlitedb_allnodes(const char *zone, 200 void *dbdata, 201 dns_sdballnodes_t *allnodes) 202 { 203 dbinfo_t *dbi = (dbinfo_t *) dbdata; 204 char *sql; 205 allnodes_parm_t parm = { 0, allnodes, ISC_R_SUCCESS }; 206 char *errmsg = NULL; 207 int result; 208 209 UNUSED(zone); 210 211 sql = sqlite3_mprintf( 212 "SELECT TTL,NAME,RDTYPE,RDATA FROM \"%q\" ORDER BY NAME", 213 dbi->table); 214 215 result = sqlite3_exec(dbi->db, sql, 216 &sqlitedb_allnodes_cb, &parm, 217 &errmsg); 218 sqlite3_free(sql); 219 220 if (result != SQLITE_OK) 221 return (ISC_R_FAILURE); 222 if (parm.i == 0) 223 return (ISC_R_NOTFOUND); 224 225 return (ISC_R_SUCCESS); 226 } 227 228 229 static void 230 sqlitedb_destroy(const char *zone, void *driverdata, void **dbdata) 231 { 232 dbinfo_t *dbi = *dbdata; 233 234 UNUSED(zone); 235 UNUSED(driverdata); 236 237 if (dbi->db != NULL) 238 sqlite3_close(dbi->db); 239 if (dbi->table != NULL) 240 isc_mem_free(ns_g_mctx, dbi->table); 241 if (dbi->filename != NULL) 242 isc_mem_free(ns_g_mctx, dbi->filename); 243 244 isc_mem_put(ns_g_mctx, dbi, sizeof(dbinfo_t)); 245 } 246 247 248 #define STRDUP_OR_FAIL(target, source) \ 249 do { \ 250 target = isc_mem_strdup(ns_g_mctx, source); \ 251 if (target == NULL) { \ 252 result = ISC_R_NOMEMORY; \ 253 goto cleanup; \ 254 } \ 255 } while (/*CONSTCOND*/0); 256 257 /* 258 * Create a connection to the database and save any necessary information 259 * in dbdata. 260 * 261 * argv[0] is the name of the database file 262 * argv[1] is the name of the table 263 */ 264 static isc_result_t 265 sqlitedb_create(const char *zone, 266 int argc, char **argv, 267 void *driverdata, void **dbdata) 268 { 269 dbinfo_t *dbi; 270 isc_result_t result; 271 272 UNUSED(zone); 273 UNUSED(driverdata); 274 275 if (argc < 2) 276 return (ISC_R_FAILURE); 277 278 dbi = isc_mem_get(ns_g_mctx, sizeof(dbinfo_t)); 279 if (dbi == NULL) 280 return (ISC_R_NOMEMORY); 281 dbi->db = NULL; 282 dbi->filename = NULL; 283 dbi->table = NULL; 284 285 STRDUP_OR_FAIL(dbi->filename, argv[0]); 286 STRDUP_OR_FAIL(dbi->table, argv[1]); 287 288 result = db_connect(dbi); 289 if (result != ISC_R_SUCCESS) 290 goto cleanup; 291 292 *dbdata = dbi; 293 return (ISC_R_SUCCESS); 294 295 cleanup: 296 sqlitedb_destroy(zone, driverdata, (void **)&dbi); 297 return (result); 298 } 299 300 301 /* 302 * Since the SQL database corresponds to a zone, the authority data should 303 * be returned by the lookup() function. Therefore the authority() function 304 * is NULL. 305 */ 306 static dns_sdbmethods_t sqlitedb_methods = { 307 sqlitedb_lookup, 308 NULL, /* authority */ 309 sqlitedb_allnodes, 310 sqlitedb_create, 311 sqlitedb_destroy, 312 NULL /* lookup2 */ 313 }; 314 315 316 /* 317 * Wrapper around dns_sdb_register(). 318 */ 319 isc_result_t 320 sqlitedb_init(void) 321 { 322 unsigned int flags; 323 flags = 0; 324 return (dns_sdb_register("sqlite", &sqlitedb_methods, NULL, flags, 325 ns_g_mctx, &sqlitedb)); 326 } 327 328 329 /* 330 * Wrapper around dns_sdb_unregister(). 331 */ 332 void 333 sqlitedb_clear(void) 334 { 335 if (sqlitedb != NULL) 336 dns_sdb_unregister(&sqlitedb); 337 } 338