2
* Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
4
* Permission to use, copy, modify, and distribute this software for any
5
* purpose with or without fee is hereby granted, provided that the
6
* above copyright notice and this permission notice appear in all
9
* THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
10
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
11
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12
* STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
16
* USE OR PERFORMANCE OF THIS SOFTWARE.
18
* The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
19
* conceived and contributed by Rob Butler.
21
* Permission to use, copy, modify, and distribute this software for any
22
* purpose with or without fee is hereby granted, provided that the
23
* above copyright notice and this permission notice appear in all
26
* THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
27
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
28
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
29
* ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
30
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
32
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
33
* USE OR PERFORMANCE OF THIS SOFTWARE.
37
* Copyright (C) 1999-2001 Internet Software Consortium.
39
* Permission to use, copy, modify, and distribute this software for any
40
* purpose with or without fee is hereby granted, provided that the above
41
* copyright notice and this permission notice appear in all copies.
43
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
44
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
45
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
46
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
47
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
48
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
49
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
50
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
58
#include <dns/result.h>
61
#include <isc/result.h>
62
#include <isc/string.h>
65
#include <dlz/sdlz_helper.h>
72
* properly destroys a querylist by de-allocating the
73
* memory for each query segment, and then the list itself
77
destroy_querylist(isc_mem_t *mctx, query_list_t **querylist)
79
query_segment_t *tseg = NULL;
80
query_segment_t *nseg = NULL;
82
REQUIRE(mctx != NULL);
84
/* if query list is null, nothing to do */
85
if (*querylist == NULL)
88
/* start at the top of the list */
89
nseg = ISC_LIST_HEAD(**querylist);
90
while (nseg != NULL) { /* loop, until end of list */
93
* free the query segment's text string but only if it
94
* was really a query segment, and not a pointer to
95
* %zone%, or %record%, or %client%
97
if (tseg->sql != NULL && tseg->direct == isc_boolean_true)
98
isc_mem_free(mctx, tseg->sql);
99
/* get the next query segment, before we destroy this one. */
100
nseg = ISC_LIST_NEXT(nseg, link);
101
/* deallocate this query segment. */
102
isc_mem_put(mctx, tseg, sizeof(query_segment_t));
104
/* deallocate the query segment list */
105
isc_mem_put(mctx, *querylist, sizeof(query_list_t));
108
/*% constructs a query list by parsing a string into query segments */
110
build_querylist(isc_mem_t *mctx, const char *query_str, char **zone,
111
char **record, char **client, query_list_t **querylist,
115
isc_boolean_t foundzone = isc_boolean_false;
116
isc_boolean_t foundrecord = isc_boolean_false;
117
isc_boolean_t foundclient = isc_boolean_false;
118
char *temp_str = NULL;
119
char *right_str = NULL;
121
query_segment_t *tseg = NULL;
123
REQUIRE(querylist != NULL && *querylist == NULL);
124
REQUIRE(mctx != NULL);
126
/* if query string is null, or zero length */
127
if (query_str == NULL || strlen(query_str) < 1) {
128
if ((flags & SDLZH_REQUIRE_QUERY) == 0)
129
/* we don't need it were ok. */
130
return (ISC_R_SUCCESS);
132
/* we did need it, PROBLEM!!! */
133
return (ISC_R_FAILURE);
136
/* allocate memory for query list */
137
tql = isc_mem_get(mctx, sizeof(query_list_t));
138
/* couldn't allocate memory. Problem!! */
140
return (ISC_R_NOMEMORY);
142
/* initialize the query segment list */
145
/* make a copy of query_str so we can chop it up */
146
temp_str = right_str = isc_mem_strdup(mctx, query_str);
147
/* couldn't make a copy, problem!! */
148
if (right_str == NULL) {
149
result = ISC_R_NOMEMORY;
153
/* loop through the string and chop it up */
154
while (right_str != NULL) {
155
/* allocate memory for tseg */
156
tseg = isc_mem_get(mctx, sizeof(query_segment_t));
157
if (tseg == NULL) { /* no memory, clean everything up. */
158
result = ISC_R_NOMEMORY;
162
tseg->direct = isc_boolean_false;
163
/* initialize the query segment link */
164
ISC_LINK_INIT(tseg, link);
165
/* append the query segment to the list */
166
ISC_LIST_APPEND(*tql, tseg, link);
169
* split string at the first "%". set query segment to
172
tseg->sql = isc_mem_strdup(mctx,
173
isc_string_separate(&right_str,
175
if (tseg->sql == NULL) {
176
/* no memory, clean everything up. */
177
result = ISC_R_NOMEMORY;
180
/* tseg->sql points directly to a string. */
181
tseg->direct = isc_boolean_true;
182
tseg->strlen = strlen(tseg->sql);
184
/* check if we encountered "%zone%" token */
185
if (strcasecmp(tseg->sql, "zone") == 0) {
187
* we don't really need, or want the "zone"
188
* text, so get rid of it.
190
isc_mem_free(mctx, tseg->sql);
191
/* set tseg->sql to in-direct zone string */
192
tseg->sql = (char**) zone;
194
/* tseg->sql points in-directly to a string */
195
tseg->direct = isc_boolean_false;
196
foundzone = isc_boolean_true;
197
/* check if we encountered "%record%" token */
198
} else if (strcasecmp(tseg->sql, "record") == 0) {
200
* we don't really need, or want the "record"
201
* text, so get rid of it.
203
isc_mem_free(mctx, tseg->sql);
204
/* set tseg->sql to in-direct record string */
205
tseg->sql = (char**) record;
207
/* tseg->sql points in-directly poinsts to a string */
208
tseg->direct = isc_boolean_false;
209
foundrecord = isc_boolean_true;
210
/* check if we encountered "%client%" token */
211
} else if (strcasecmp(tseg->sql, "client") == 0) {
213
* we don't really need, or want the "client"
214
* text, so get rid of it.
216
isc_mem_free(mctx, tseg->sql);
217
/* set tseg->sql to in-direct record string */
218
tseg->sql = (char**) client;
220
/* tseg->sql points in-directly poinsts to a string */
221
tseg->direct = isc_boolean_false;
222
foundclient = isc_boolean_true;
226
/* we don't need temp_str any more */
227
isc_mem_free(mctx, temp_str);
229
* add checks later to verify zone and record are found if
233
/* if this query requires %client%, make sure we found it */
234
if (((flags & SDLZH_REQUIRE_CLIENT) != 0) && (!foundclient) ) {
235
/* Write error message to log */
236
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
237
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
238
"Required token %%client%% not found.");
239
result = ISC_R_FAILURE;
243
/* if this query requires %record%, make sure we found it */
244
if (((flags & SDLZH_REQUIRE_RECORD) != 0) && (!foundrecord) ) {
245
/* Write error message to log */
246
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
247
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
248
"Required token %%record%% not found.");
249
result = ISC_R_FAILURE;
253
/* if this query requires %zone%, make sure we found it */
254
if (((flags & SDLZH_REQUIRE_ZONE) != 0) && (!foundzone) ) {
255
/* Write error message to log */
256
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
257
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
258
"Required token %%zone%% not found.");
259
result = ISC_R_FAILURE;
263
/* pass back the query list */
264
*querylist = (query_list_t *) tql;
267
return (ISC_R_SUCCESS);
270
/* get rid of temp_str */
271
if (temp_str != NULL)
272
isc_mem_free(mctx, temp_str);
275
/* get rid of what was build of the query list */
277
destroy_querylist(mctx, &tql);
282
* build a query string from query segments, and dynamic segments
283
* dynamic segments replace where the tokens %zone%, %record%, %client%
284
* used to be in our queries from named.conf
287
sdlzh_build_querystring(isc_mem_t *mctx, query_list_t *querylist)
289
query_segment_t *tseg = NULL;
290
unsigned int length = 0;
293
REQUIRE(mctx != NULL);
294
REQUIRE(querylist != NULL);
296
/* start at the top of the list */
297
tseg = ISC_LIST_HEAD(*querylist);
298
while (tseg != NULL) {
300
* if this is a query segment, use the
301
* precalculated string length
303
if (tseg->direct == isc_boolean_true)
304
length += tseg->strlen;
305
else /* calculate string length for dynamic segments. */
306
length += strlen(* (char**) tseg->sql);
307
/* get the next segment */
308
tseg = ISC_LIST_NEXT(tseg, link);
311
/* allocate memory for the string */
312
qs = isc_mem_allocate(mctx, length + 1);
313
/* couldn't allocate memory, We need more ram! */
317
/* start at the top of the list again */
318
tseg = ISC_LIST_HEAD(*querylist);
319
/* copy the first item in the list to the query string */
320
if (tseg->direct == isc_boolean_true) /* query segment */
321
strcpy(qs, tseg->sql);
323
strcpy(qs, * (char**) tseg->sql); /* dynamic segment */
325
/* concatonate the rest of the segments */
326
while ((tseg = ISC_LIST_NEXT(tseg, link)) != NULL) {
327
if (tseg->direct == isc_boolean_true)
329
strcat(qs, tseg->sql);
331
/* dynamic segments */
332
strcat(qs, * (char**) tseg->sql);
338
/*% constructs a sql dbinstance (DBI) */
340
sdlzh_build_sqldbinstance(isc_mem_t *mctx, const char *allnodes_str,
341
const char *allowxfr_str, const char *authority_str,
342
const char *findzone_str, const char *lookup_str,
343
const char *countzone_str, dbinstance_t **dbi)
347
dbinstance_t *db = NULL;
349
REQUIRE(dbi != NULL && *dbi == NULL);
350
REQUIRE(mctx != NULL);
352
/* allocate and zero memory for driver structure */
353
db = isc_mem_get(mctx, sizeof(dbinstance_t));
355
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
356
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
357
"Could not allocate memory for "
358
"database instance object.");
359
return (ISC_R_NOMEMORY);
361
memset(db, 0, sizeof(dbinstance_t));
367
db->query_buf = NULL;
368
db->allnodes_q = NULL;
369
db->allowxfr_q = NULL;
370
db->authority_q = NULL;
371
db->findzone_q = NULL;
372
db->countzone_q = NULL;
375
/* attach to the memory context */
376
isc_mem_attach(mctx, &db->mctx);
378
/* initialize the reference count mutex */
379
result = isc_mutex_init(&db->instance_lock);
380
if (result != ISC_R_SUCCESS) {
381
UNEXPECTED_ERROR(__FILE__, __LINE__,
382
"isc_mutex_init() failed: %s",
383
isc_result_totext(result));
387
/* build the all nodes query list */
388
result = build_querylist(mctx, allnodes_str, &db->zone,
389
&db->record, &db->client,
390
&db->allnodes_q, SDLZH_REQUIRE_ZONE);
391
/* if unsuccessful, log err msg and cleanup */
392
if (result != ISC_R_SUCCESS) {
393
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
394
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
395
"Could not build all nodes query list");
399
/* build the allow zone transfer query list */
400
result = build_querylist(mctx, allowxfr_str, &db->zone,
401
&db->record, &db->client,
403
SDLZH_REQUIRE_ZONE | SDLZH_REQUIRE_CLIENT);
404
/* if unsuccessful, log err msg and cleanup */
405
if (result != ISC_R_SUCCESS) {
406
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
407
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
408
"Could not build allow xfr query list");
412
/* build the authority query, query list */
413
result = build_querylist(mctx, authority_str, &db->zone,
414
&db->record, &db->client,
415
&db->authority_q, SDLZH_REQUIRE_ZONE);
416
/* if unsuccessful, log err msg and cleanup */
417
if (result != ISC_R_SUCCESS) {
418
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
419
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
420
"Could not build authority query list");
424
/* build findzone query, query list */
425
result = build_querylist(mctx, findzone_str, &db->zone,
426
&db->record, &db->client,
427
&db->findzone_q, SDLZH_REQUIRE_ZONE);
428
/* if unsuccessful, log err msg and cleanup */
429
if (result != ISC_R_SUCCESS) {
430
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
431
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
432
"Could not build find zone query list");
436
/* build countzone query, query list */
437
result = build_querylist(mctx, countzone_str, &db->zone,
438
&db->record, &db->client,
439
&db->countzone_q, SDLZH_REQUIRE_ZONE);
440
/* if unsuccessful, log err msg and cleanup */
441
if (result != ISC_R_SUCCESS) {
442
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
443
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
444
"Could not build count zone query list");
448
/* build lookup query, query list */
449
result = build_querylist(mctx, lookup_str, &db->zone,
450
&db->record, &db->client,
451
&db->lookup_q, SDLZH_REQUIRE_RECORD);
452
/* if unsuccessful, log err msg and cleanup */
453
if (result != ISC_R_SUCCESS) {
454
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
455
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
456
"Could not build lookup query list");
460
/* pass back the db instance */
461
*dbi = (dbinstance_t *) db;
464
return (ISC_R_SUCCESS);
467
/* destroy whatever was build of the db instance */
468
destroy_sqldbinstance(db);
470
return (ISC_R_FAILURE);
474
sdlzh_destroy_sqldbinstance(dbinstance_t *dbi)
478
/* save mctx for later */
481
/* destroy any query lists we created */
482
destroy_querylist(mctx, &dbi->allnodes_q);
483
destroy_querylist(mctx, &dbi->allowxfr_q);
484
destroy_querylist(mctx, &dbi->authority_q);
485
destroy_querylist(mctx, &dbi->findzone_q);
486
destroy_querylist(mctx, &dbi->countzone_q);
487
destroy_querylist(mctx, &dbi->lookup_q);
489
/* get rid of the mutex */
490
isc_mutex_destroy(&dbi->instance_lock);
492
/* return, and detach the memory */
493
isc_mem_put(mctx, dbi, sizeof(dbinstance_t));
494
isc_mem_detach(&mctx);
498
sdlzh_get_parameter_value(isc_mem_t *mctx, const char *input, const char* key)
505
if (key == NULL || input == NULL || strlen(input) < 1)
508
keylen = strlen(key);
513
keystart = strstr(input, key);
515
if (keystart == NULL)
518
REQUIRE(mctx != NULL);
520
for (i = 0; i < 255; i++) {
521
value[i] = keystart[keylen + i];
522
if (value[i] == ' ' || value[i] == '\0') {
528
return isc_mem_strdup(mctx, value);