1 /* $NetBSD: sdlz_helper.c,v 1.5 2014/12/10 04:37:55 christos Exp $ */
2
3 /*
4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
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
8 * above copyright notice and this permission notice appear in all
9 * copies.
10 *
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.
19 *
20 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21 * conceived and contributed by Rob Butler.
22 *
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
26 * copies.
27 *
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.
36 */
37
38 /*
39 * Copyright (C) 1999-2001 Internet Software Consortium.
40 *
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.
44 *
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.
53 */
54
55 #include <config.h>
56
57 #include <dns/log.h>
58 #include <dns/result.h>
59
60 #include <isc/mem.h>
61 #include <isc/result.h>
62 #include <isc/string.h>
63 #include <isc/util.h>
64
65 #include <dlz/sdlz_helper.h>
66
67 /*
68 * sdlz helper methods
69 */
70
71 /*%
72 * properly destroys a querylist by de-allocating the
73 * memory for each query segment, and then the list itself
74 */
75
76 static void
destroy_querylist(isc_mem_t * mctx,query_list_t ** querylist)77 destroy_querylist(isc_mem_t *mctx, query_list_t **querylist)
78 {
79 query_segment_t *tseg = NULL;
80 query_segment_t *nseg = NULL;
81
82 REQUIRE(mctx != NULL);
83
84 /* if query list is null, nothing to do */
85 if (*querylist == NULL)
86 return;
87
88 /* start at the top of the list */
89 nseg = ISC_LIST_HEAD(**querylist);
90 while (nseg != NULL) { /* loop, until end of list */
91 tseg = nseg;
92 /*
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%
96 */
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));
103 }
104 /* deallocate the query segment list */
105 isc_mem_put(mctx, *querylist, sizeof(query_list_t));
106 }
107
108 /*% constructs a query list by parsing a string into query segments */
109 static isc_result_t
build_querylist(isc_mem_t * mctx,const char * query_str,char ** zone,char ** record,char ** client,query_list_t ** querylist,unsigned int flags)110 build_querylist(isc_mem_t *mctx, const char *query_str, char **zone,
111 char **record, char **client, query_list_t **querylist,
112 unsigned int flags)
113 {
114 isc_result_t result;
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;
120 query_list_t *tql;
121 query_segment_t *tseg = NULL;
122
123 REQUIRE(querylist != NULL && *querylist == NULL);
124 REQUIRE(mctx != NULL);
125
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);
131 else
132 /* we did need it, PROBLEM!!! */
133 return (ISC_R_FAILURE);
134 }
135
136 /* allocate memory for query list */
137 tql = isc_mem_get(mctx, sizeof(query_list_t));
138 /* couldn't allocate memory. Problem!! */
139 if (tql == NULL)
140 return (ISC_R_NOMEMORY);
141
142 /* initialize the query segment list */
143 ISC_LIST_INIT(*tql);
144
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;
150 goto cleanup;
151 }
152
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;
159 goto cleanup;
160 }
161 tseg->sql = NULL;
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);
167
168 /*
169 * split string at the first "$". set query segment to
170 * left portion
171 */
172 tseg->sql = isc_mem_strdup(mctx,
173 isc_string_separate(&right_str,
174 "$"));
175 if (tseg->sql == NULL) {
176 /* no memory, clean everything up. */
177 result = ISC_R_NOMEMORY;
178 goto cleanup;
179 }
180 /* tseg->sql points directly to a string. */
181 tseg->direct = isc_boolean_true;
182 tseg->strlen = strlen(tseg->sql);
183
184 /* check if we encountered "$zone$" token */
185 if (strcasecmp(tseg->sql, "zone") == 0) {
186 /*
187 * we don't really need, or want the "zone"
188 * text, so get rid of it.
189 */
190 isc_mem_free(mctx, tseg->sql);
191 /* set tseg->sql to in-direct zone string */
192 tseg->sql = (char**) zone;
193 tseg->strlen = 0;
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) {
199 /*
200 * we don't really need, or want the "record"
201 * text, so get rid of it.
202 */
203 isc_mem_free(mctx, tseg->sql);
204 /* set tseg->sql to in-direct record string */
205 tseg->sql = (char**) record;
206 tseg->strlen = 0;
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) {
212 /*
213 * we don't really need, or want the "client"
214 * text, so get rid of it.
215 */
216 isc_mem_free(mctx, tseg->sql);
217 /* set tseg->sql to in-direct record string */
218 tseg->sql = (char**) client;
219 tseg->strlen = 0;
220 /* tseg->sql points in-directly poinsts to a string */
221 tseg->direct = isc_boolean_false;
222 foundclient = isc_boolean_true;
223 }
224 }
225
226 /* we don't need temp_str any more */
227 isc_mem_free(mctx, temp_str);
228 /*
229 * add checks later to verify zone and record are found if
230 * necessary.
231 */
232
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;
240 goto flag_fail;
241 }
242
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;
250 goto flag_fail;
251 }
252
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;
260 goto flag_fail;
261 }
262
263 /* pass back the query list */
264 *querylist = (query_list_t *) tql;
265
266 /* return success */
267 return (ISC_R_SUCCESS);
268
269 cleanup:
270 /* get rid of temp_str */
271 if (temp_str != NULL)
272 isc_mem_free(mctx, temp_str);
273
274 flag_fail:
275 /* get rid of what was build of the query list */
276 if (tql != NULL)
277 destroy_querylist(mctx, &tql);
278 return result;
279 }
280
281 /*%
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
285 */
286 char *
sdlzh_build_querystring(isc_mem_t * mctx,query_list_t * querylist)287 sdlzh_build_querystring(isc_mem_t *mctx, query_list_t *querylist)
288 {
289 query_segment_t *tseg = NULL;
290 unsigned int length = 0;
291 char *qs = NULL;
292
293 REQUIRE(mctx != NULL);
294 REQUIRE(querylist != NULL);
295
296 /* start at the top of the list */
297 tseg = ISC_LIST_HEAD(*querylist);
298 while (tseg != NULL) {
299 /*
300 * if this is a query segment, use the
301 * precalculated string length
302 */
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);
309 }
310
311 /* allocate memory for the string */
312 qs = isc_mem_allocate(mctx, length + 1);
313 /* couldn't allocate memory, We need more ram! */
314 if (qs == NULL)
315 return NULL;
316
317 *qs = 0;
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)
322 /* query segments */
323 strcat(qs, tseg->sql);
324 else
325 /* dynamic segments */
326 strcat(qs, * (char**) tseg->sql);
327 /* get the next segment */
328 tseg = ISC_LIST_NEXT(tseg, link);
329 }
330
331 return qs;
332 }
333
334 /*% constructs a sql dbinstance (DBI) */
335 isc_result_t
sdlzh_build_sqldbinstance(isc_mem_t * mctx,const char * allnodes_str,const char * allowxfr_str,const char * authority_str,const char * findzone_str,const char * lookup_str,const char * countzone_str,dbinstance_t ** 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)
340 {
341
342 isc_result_t result;
343 dbinstance_t *db = NULL;
344
345 REQUIRE(dbi != NULL && *dbi == NULL);
346 REQUIRE(mctx != NULL);
347
348 /* allocate and zero memory for driver structure */
349 db = isc_mem_get(mctx, sizeof(dbinstance_t));
350 if (db == NULL) {
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);
356 }
357 memset(db, 0, sizeof(dbinstance_t));
358 db->dbconn = NULL;
359 db->client = NULL;
360 db->record = NULL;
361 db->zone = NULL;
362 db->mctx = NULL;
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;
369 db->lookup_q = NULL;
370
371 /* attach to the memory context */
372 isc_mem_attach(mctx, &db->mctx);
373
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));
380 goto cleanup;
381 }
382
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");
392 goto cleanup;
393 }
394
395 /* build the allow zone transfer query list */
396 result = build_querylist(mctx, allowxfr_str, &db->zone,
397 &db->record, &db->client,
398 &db->allowxfr_q,
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");
405 goto cleanup;
406 }
407
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");
417 goto cleanup;
418 }
419
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");
429 goto cleanup;
430 }
431
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");
441 goto cleanup;
442 }
443
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");
453 goto cleanup;
454 }
455
456 /* pass back the db instance */
457 *dbi = (dbinstance_t *) db;
458
459 /* return success */
460 return (ISC_R_SUCCESS);
461
462 cleanup:
463 /* destroy whatever was build of the db instance */
464 destroy_sqldbinstance(db);
465 /* return failure */
466 return (ISC_R_FAILURE);
467 }
468
469 void
sdlzh_destroy_sqldbinstance(dbinstance_t * dbi)470 sdlzh_destroy_sqldbinstance(dbinstance_t *dbi)
471 {
472 isc_mem_t *mctx;
473
474 /* save mctx for later */
475 mctx = dbi->mctx;
476
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);
484
485 /* get rid of the mutex */
486 (void) isc_mutex_destroy(&dbi->instance_lock);
487
488 /* return, and detach the memory */
489 isc_mem_put(mctx, dbi, sizeof(dbinstance_t));
490 isc_mem_detach(&mctx);
491 }
492
493 char *
sdlzh_get_parameter_value(isc_mem_t * mctx,const char * input,const char * key)494 sdlzh_get_parameter_value(isc_mem_t *mctx, const char *input, const char* key)
495 {
496 int keylen;
497 char *keystart;
498 char value[255];
499 int i;
500
501 if (key == NULL || input == NULL || strlen(input) < 1)
502 return NULL;
503
504 keylen = strlen(key);
505
506 if (keylen < 1)
507 return NULL;
508
509 keystart = strstr(input, key);
510
511 if (keystart == NULL)
512 return NULL;
513
514 REQUIRE(mctx != NULL);
515
516 for (i = 0; i < 255; i++) {
517 value[i] = keystart[keylen + i];
518 if (value[i] == ' ' || value[i] == '\0') {
519 value[i] = '\0';
520 break;
521 }
522 }
523
524 return isc_mem_strdup(mctx, value);
525 }
526