1 /* $NetBSD: dlz_dbi.c,v 1.1.1.4 2014/12/10 03:34:31 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) 2013 Internet Systems Consortium, Inc. ("ISC")
40 * Copyright (C) 1999-2001 Internet Software Consortium.
42 * Permission to use, copy, modify, and/or 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.
46 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
47 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
48 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
49 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
50 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
51 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
52 * PERFORMANCE OF THIS SOFTWARE.
62 #include <sys/errno.h>
64 #include <dlz_minimal.h>
67 #include <dlz_pthread.h>
70 * properly destroys a querylist by de-allocating the
71 * memory for each query segment, and then the list itself
75 destroy_querylist(query_list_t
**querylist
) {
76 query_segment_t
*tseg
= NULL
;
77 query_segment_t
*nseg
= NULL
;
79 /* if query list is null, nothing to do */
80 if (*querylist
== NULL
)
83 /* start at the top of the list */
84 nseg
= DLZ_LIST_HEAD(**querylist
);
85 while (nseg
!= NULL
) { /* loop, until end of list */
88 * free the query segment's text string but only if it
89 * was really a query segment, and not a pointer to
90 * %zone%, or %record%, or %client%
92 if (tseg
->cmd
!= NULL
&& tseg
->direct
== ISC_TRUE
)
94 /* get the next query segment, before we destroy this one. */
95 nseg
= DLZ_LIST_NEXT(nseg
, link
);
96 /* deallocate this query segment. */
99 /* deallocate the query segment list */
103 /*% constructs a query list by parsing a string into query segments */
105 build_querylist(const char *query_str
, char **zone
, char **record
,
106 char **client
, query_list_t
**querylist
, unsigned int flags
,
110 isc_boolean_t foundzone
= ISC_FALSE
;
111 isc_boolean_t foundrecord
= ISC_FALSE
;
112 isc_boolean_t foundclient
= ISC_FALSE
;
113 char *temp_str
= NULL
;
114 char *right_str
= NULL
;
116 query_segment_t
*tseg
= NULL
;
118 /* if query string is null, or zero length */
119 if (query_str
== NULL
|| strlen(query_str
) < 1) {
120 if ((flags
& REQUIRE_QUERY
) == 0)
121 /* we don't need it were ok. */
122 return (ISC_R_SUCCESS
);
124 /* we did need it, PROBLEM!!! */
125 return (ISC_R_FAILURE
);
128 /* allocate memory for query list */
129 tql
= calloc(1, sizeof(query_list_t
));
130 /* couldn't allocate memory. Problem!! */
132 return (ISC_R_NOMEMORY
);
134 /* initialize the query segment list */
137 /* make a copy of query_str so we can chop it up */
138 temp_str
= right_str
= strdup(query_str
);
139 /* couldn't make a copy, problem!! */
140 if (right_str
== NULL
) {
141 result
= ISC_R_NOMEMORY
;
145 /* loop through the string and chop it up */
146 while (right_str
!= NULL
) {
147 /* allocate memory for tseg */
148 tseg
= calloc(1, sizeof(query_segment_t
));
149 if (tseg
== NULL
) { /* no memory, clean everything up. */
150 result
= ISC_R_NOMEMORY
;
154 tseg
->direct
= ISC_FALSE
;
155 /* initialize the query segment link */
156 DLZ_LINK_INIT(tseg
, link
);
157 /* append the query segment to the list */
158 DLZ_LIST_APPEND(*tql
, tseg
, link
);
161 * split string at the first "$". set query segment to
164 tseg
->cmd
= strdup(strsep(&right_str
, "$"));
165 if (tseg
->cmd
== NULL
) {
166 /* no memory, clean everything up. */
167 result
= ISC_R_NOMEMORY
;
170 /* tseg->cmd points directly to a string. */
171 tseg
->direct
= ISC_TRUE
;
172 tseg
->strlen
= strlen(tseg
->cmd
);
174 /* check if we encountered "$zone$" token */
175 if (strcasecmp(tseg
->cmd
, "zone") == 0) {
177 * we don't really need, or want the "zone"
178 * text, so get rid of it.
181 /* set tseg->cmd to in-direct zone string */
182 tseg
->cmd
= (char**) zone
;
184 /* tseg->cmd points in-directly to a string */
185 tseg
->direct
= ISC_FALSE
;
186 foundzone
= ISC_TRUE
;
187 /* check if we encountered "$record$" token */
188 } else if (strcasecmp(tseg
->cmd
, "record") == 0) {
190 * we don't really need, or want the "record"
191 * text, so get rid of it.
194 /* set tseg->cmd to in-direct record string */
195 tseg
->cmd
= (char**) record
;
197 /* tseg->cmd points in-directly poinsts to a string */
198 tseg
->direct
= ISC_FALSE
;
199 foundrecord
= ISC_TRUE
;
200 /* check if we encountered "$client$" token */
201 } else if (strcasecmp(tseg
->cmd
, "client") == 0) {
203 * we don't really need, or want the "client"
204 * text, so get rid of it.
207 /* set tseg->cmd to in-direct record string */
208 tseg
->cmd
= (char**) client
;
210 /* tseg->cmd points in-directly poinsts to a string */
211 tseg
->direct
= ISC_FALSE
;
212 foundclient
= ISC_TRUE
;
216 /* we don't need temp_str any more */
219 * add checks later to verify zone and record are found if
223 /* if this query requires %client%, make sure we found it */
224 if (((flags
& REQUIRE_CLIENT
) != 0) && (!foundclient
) ) {
225 /* Write error message to log */
228 "Required token $client$ not found.");
229 result
= ISC_R_FAILURE
;
233 /* if this query requires %record%, make sure we found it */
234 if (((flags
& REQUIRE_RECORD
) != 0) && (!foundrecord
) ) {
235 /* Write error message to log */
238 "Required token $record$ not found.");
239 result
= ISC_R_FAILURE
;
243 /* if this query requires %zone%, make sure we found it */
244 if (((flags
& REQUIRE_ZONE
) != 0) && (!foundzone
) ) {
245 /* Write error message to log */
247 log(ISC_LOG_ERROR
, "Required token $zone$ not found.");
248 result
= ISC_R_FAILURE
;
252 /* pass back the query list */
253 *querylist
= (query_list_t
*) tql
;
256 return (ISC_R_SUCCESS
);
259 /* get rid of temp_str */
260 if (temp_str
!= NULL
)
264 /* get rid of what was build of the query list */
266 destroy_querylist(&tql
);
271 * build a query string from query segments, and dynamic segments
272 * dynamic segments replace where the tokens %zone%, %record%, %client%
273 * used to be in our queries from named.conf
276 build_querystring(query_list_t
*querylist
) {
277 query_segment_t
*tseg
= NULL
;
278 unsigned int length
= 0;
281 /* start at the top of the list */
282 tseg
= DLZ_LIST_HEAD(*querylist
);
283 while (tseg
!= NULL
) {
285 * if this is a query segment, use the
286 * precalculated string length
288 if (tseg
->direct
== ISC_TRUE
)
289 length
+= tseg
->strlen
;
290 else /* calculate string length for dynamic segments. */
291 length
+= strlen(* (char**) tseg
->cmd
);
292 /* get the next segment */
293 tseg
= DLZ_LIST_NEXT(tseg
, link
);
296 qs
= malloc(length
+ 1);
301 /* start at the top of the list again */
302 tseg
= DLZ_LIST_HEAD(*querylist
);
303 while (tseg
!= NULL
) {
304 if (tseg
->direct
== ISC_TRUE
)
306 strcat(qs
, tseg
->cmd
);
308 /* dynamic segments */
309 strcat(qs
, * (char**) tseg
->cmd
);
310 /* get the next segment */
311 tseg
= DLZ_LIST_NEXT(tseg
, link
);
317 /*% constructs a dbinstance (DBI) */
319 build_dbinstance(const char *allnodes_str
, const char *allowxfr_str
,
320 const char *authority_str
, const char *findzone_str
,
321 const char *lookup_str
, const char *countzone_str
,
322 dbinstance_t
**dbi
, log_t log
)
326 dbinstance_t
*db
= NULL
;
329 /* allocate and zero memory for driver structure */
330 db
= calloc(1, sizeof(dbinstance_t
));
334 "Could not allocate memory for "
335 "database instance object.");
336 return (ISC_R_NOMEMORY
);
338 memset(db
, 0, sizeof(dbinstance_t
));
343 db
->query_buf
= NULL
;
344 db
->allnodes_q
= NULL
;
345 db
->allowxfr_q
= NULL
;
346 db
->authority_q
= NULL
;
347 db
->findzone_q
= NULL
;
348 db
->countzone_q
= NULL
;
351 /* initialize the reference count mutex */
352 err
= dlz_mutex_init(&db
->lock
, NULL
);
354 result
= ISC_R_NOMEMORY
;
356 } else if (err
!= 0) {
357 result
= ISC_R_UNEXPECTED
;
361 /* build the all nodes query list */
362 result
= build_querylist(allnodes_str
, &db
->zone
, &db
->record
,
363 &db
->client
, &db
->allnodes_q
,
365 /* if unsuccessful, log err msg and cleanup */
366 if (result
!= ISC_R_SUCCESS
) {
369 "Could not build all nodes query list");
373 /* build the allow zone transfer query list */
374 result
= build_querylist(allowxfr_str
, &db
->zone
, &db
->record
,
375 &db
->client
, &db
->allowxfr_q
,
376 REQUIRE_ZONE
| REQUIRE_CLIENT
,
378 /* if unsuccessful, log err msg and cleanup */
379 if (result
!= ISC_R_SUCCESS
) {
382 "Could not build allow xfr query list");
386 /* build the authority query, query list */
387 result
= build_querylist(authority_str
, &db
->zone
, &db
->record
,
388 &db
->client
, &db
->authority_q
,
390 /* if unsuccessful, log err msg and cleanup */
391 if (result
!= ISC_R_SUCCESS
) {
394 "Could not build authority query list");
398 /* build findzone query, query list */
399 result
= build_querylist(findzone_str
, &db
->zone
, &db
->record
,
400 &db
->client
, &db
->findzone_q
,
402 /* if unsuccessful, log err msg and cleanup */
403 if (result
!= ISC_R_SUCCESS
) {
406 "Could not build find zone query list");
410 /* build countzone query, query list */
411 result
= build_querylist(countzone_str
, &db
->zone
, &db
->record
,
412 &db
->client
, &db
->countzone_q
,
414 /* if unsuccessful, log err msg and cleanup */
415 if (result
!= ISC_R_SUCCESS
) {
418 "Could not build count zone query list");
422 /* build lookup query, query list */
423 result
= build_querylist(lookup_str
, &db
->zone
, &db
->record
,
424 &db
->client
, &db
->lookup_q
,
425 REQUIRE_RECORD
, log
);
426 /* if unsuccessful, log err msg and cleanup */
427 if (result
!= ISC_R_SUCCESS
) {
430 "Could not build lookup query list");
434 /* pass back the db instance */
435 *dbi
= (dbinstance_t
*) db
;
438 return (ISC_R_SUCCESS
);
441 /* destroy whatever was build of the db instance */
442 destroy_dbinstance(db
);
444 return (ISC_R_FAILURE
);
448 destroy_dbinstance(dbinstance_t
*dbi
) {
449 /* destroy any query lists we created */
450 destroy_querylist(&dbi
->allnodes_q
);
451 destroy_querylist(&dbi
->allowxfr_q
);
452 destroy_querylist(&dbi
->authority_q
);
453 destroy_querylist(&dbi
->findzone_q
);
454 destroy_querylist(&dbi
->countzone_q
);
455 destroy_querylist(&dbi
->lookup_q
);
457 /* get rid of the mutex */
458 (void) dlz_mutex_destroy(&dbi
->lock
);
460 /* return, and detach the memory */
465 get_parameter_value(const char *input
, const char* key
) {
471 if (key
== NULL
|| input
== NULL
|| *input
== '\0')
474 keylen
= strlen(key
);
479 keystart
= strstr(input
, key
);
481 if (keystart
== NULL
)
484 for (i
= 0; i
< 255; i
++) {
485 value
[i
] = keystart
[keylen
+ i
];
486 if (isspace(value
[i
]) || value
[i
] == '\0') {
492 return (strdup(value
));