1 /* $NetBSD: sdlz_helper.c,v 1.5 2014/12/10 04:37:55 christos Exp $ */
4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
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
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.
20 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21 * conceived and contributed by Rob Butler.
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
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.
39 * Copyright (C) 1999-2001 Internet Software Consortium.
41 * Permission to use, copy, modify, and distribute this software for any
42 * purpose with or without fee is hereby granted, provided that the above
43 * copyright notice and this permission notice appear in all copies.
45 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
46 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
49 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
50 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
51 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52 * 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! */
318 /* start at the top of the list again */
319 tseg
= ISC_LIST_HEAD(*querylist
);
320 while (tseg
!= NULL
) {
321 if (tseg
->direct
== isc_boolean_true
)
323 strcat(qs
, tseg
->sql
);
325 /* dynamic segments */
326 strcat(qs
, * (char**) tseg
->sql
);
327 /* get the next segment */
328 tseg
= ISC_LIST_NEXT(tseg
, link
);
334 /*% constructs a sql dbinstance (DBI) */
336 sdlzh_build_sqldbinstance(isc_mem_t
*mctx
, const char *allnodes_str
,
337 const char *allowxfr_str
, const char *authority_str
,
338 const char *findzone_str
, const char *lookup_str
,
339 const char *countzone_str
, dbinstance_t
**dbi
)
343 dbinstance_t
*db
= NULL
;
345 REQUIRE(dbi
!= NULL
&& *dbi
== NULL
);
346 REQUIRE(mctx
!= NULL
);
348 /* allocate and zero memory for driver structure */
349 db
= isc_mem_get(mctx
, sizeof(dbinstance_t
));
351 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
352 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
353 "Could not allocate memory for "
354 "database instance object.");
355 return (ISC_R_NOMEMORY
);
357 memset(db
, 0, sizeof(dbinstance_t
));
363 db
->query_buf
= NULL
;
364 db
->allnodes_q
= NULL
;
365 db
->allowxfr_q
= NULL
;
366 db
->authority_q
= NULL
;
367 db
->findzone_q
= NULL
;
368 db
->countzone_q
= NULL
;
371 /* attach to the memory context */
372 isc_mem_attach(mctx
, &db
->mctx
);
374 /* initialize the reference count mutex */
375 result
= isc_mutex_init(&db
->instance_lock
);
376 if (result
!= ISC_R_SUCCESS
) {
377 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
378 "isc_mutex_init() failed: %s",
379 isc_result_totext(result
));
383 /* build the all nodes query list */
384 result
= build_querylist(mctx
, allnodes_str
, &db
->zone
,
385 &db
->record
, &db
->client
,
386 &db
->allnodes_q
, SDLZH_REQUIRE_ZONE
);
387 /* if unsuccessful, log err msg and cleanup */
388 if (result
!= ISC_R_SUCCESS
) {
389 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
390 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
391 "Could not build all nodes query list");
395 /* build the allow zone transfer query list */
396 result
= build_querylist(mctx
, allowxfr_str
, &db
->zone
,
397 &db
->record
, &db
->client
,
399 SDLZH_REQUIRE_ZONE
| SDLZH_REQUIRE_CLIENT
);
400 /* if unsuccessful, log err msg and cleanup */
401 if (result
!= ISC_R_SUCCESS
) {
402 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
403 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
404 "Could not build allow xfr query list");
408 /* build the authority query, query list */
409 result
= build_querylist(mctx
, authority_str
, &db
->zone
,
410 &db
->record
, &db
->client
,
411 &db
->authority_q
, SDLZH_REQUIRE_ZONE
);
412 /* if unsuccessful, log err msg and cleanup */
413 if (result
!= ISC_R_SUCCESS
) {
414 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
415 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
416 "Could not build authority query list");
420 /* build findzone query, query list */
421 result
= build_querylist(mctx
, findzone_str
, &db
->zone
,
422 &db
->record
, &db
->client
,
423 &db
->findzone_q
, SDLZH_REQUIRE_ZONE
);
424 /* if unsuccessful, log err msg and cleanup */
425 if (result
!= ISC_R_SUCCESS
) {
426 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
427 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
428 "Could not build find zone query list");
432 /* build countzone query, query list */
433 result
= build_querylist(mctx
, countzone_str
, &db
->zone
,
434 &db
->record
, &db
->client
,
435 &db
->countzone_q
, SDLZH_REQUIRE_ZONE
);
436 /* if unsuccessful, log err msg and cleanup */
437 if (result
!= ISC_R_SUCCESS
) {
438 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
439 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
440 "Could not build count zone query list");
444 /* build lookup query, query list */
445 result
= build_querylist(mctx
, lookup_str
, &db
->zone
,
446 &db
->record
, &db
->client
,
447 &db
->lookup_q
, SDLZH_REQUIRE_RECORD
);
448 /* if unsuccessful, log err msg and cleanup */
449 if (result
!= ISC_R_SUCCESS
) {
450 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
451 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
452 "Could not build lookup query list");
456 /* pass back the db instance */
457 *dbi
= (dbinstance_t
*) db
;
460 return (ISC_R_SUCCESS
);
463 /* destroy whatever was build of the db instance */
464 destroy_sqldbinstance(db
);
466 return (ISC_R_FAILURE
);
470 sdlzh_destroy_sqldbinstance(dbinstance_t
*dbi
)
474 /* save mctx for later */
477 /* destroy any query lists we created */
478 destroy_querylist(mctx
, &dbi
->allnodes_q
);
479 destroy_querylist(mctx
, &dbi
->allowxfr_q
);
480 destroy_querylist(mctx
, &dbi
->authority_q
);
481 destroy_querylist(mctx
, &dbi
->findzone_q
);
482 destroy_querylist(mctx
, &dbi
->countzone_q
);
483 destroy_querylist(mctx
, &dbi
->lookup_q
);
485 /* get rid of the mutex */
486 (void) isc_mutex_destroy(&dbi
->instance_lock
);
488 /* return, and detach the memory */
489 isc_mem_put(mctx
, dbi
, sizeof(dbinstance_t
));
490 isc_mem_detach(&mctx
);
494 sdlzh_get_parameter_value(isc_mem_t
*mctx
, const char *input
, const char* key
)
501 if (key
== NULL
|| input
== NULL
|| strlen(input
) < 1)
504 keylen
= strlen(key
);
509 keystart
= strstr(input
, key
);
511 if (keystart
== NULL
)
514 REQUIRE(mctx
!= NULL
);
516 for (i
= 0; i
< 255; i
++) {
517 value
[i
] = keystart
[keylen
+ i
];
518 if (value
[i
] == ' ' || value
[i
] == '\0') {
524 return isc_mem_strdup(mctx
, value
);