diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 18:37:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 18:37:14 +0000 |
commit | ea648e70a989cca190cd7403fe892fd2dcc290b4 (patch) | |
tree | e2b6b1c647da68b0d4d66082835e256eb30970e8 /contrib/dlz/drivers/sdlz_helper.c | |
parent | Initial commit. (diff) | |
download | bind9-ea648e70a989cca190cd7403fe892fd2dcc290b4.tar.xz bind9-ea648e70a989cca190cd7403fe892fd2dcc290b4.zip |
Adding upstream version 1:9.11.5.P4+dfsg.upstream/1%9.11.5.P4+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/dlz/drivers/sdlz_helper.c')
-rw-r--r-- | contrib/dlz/drivers/sdlz_helper.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/contrib/dlz/drivers/sdlz_helper.c b/contrib/dlz/drivers/sdlz_helper.c new file mode 100644 index 0000000..979488a --- /dev/null +++ b/contrib/dlz/drivers/sdlz_helper.c @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + * + * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was + * conceived and contributed by Rob Butler. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copyright (C) 1999-2001, 2016 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <config.h> + +#include <dns/log.h> +#include <dns/result.h> + +#include <isc/mem.h> +#include <isc/result.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dlz/sdlz_helper.h> + +/* + * sdlz helper methods + */ + +/*% + * properly destroys a querylist by de-allocating the + * memory for each query segment, and then the list itself + */ + +static void +destroy_querylist(isc_mem_t *mctx, query_list_t **querylist) +{ + query_segment_t *tseg = NULL; + query_segment_t *nseg = NULL; + + REQUIRE(mctx != NULL); + + /* if query list is null, nothing to do */ + if (*querylist == NULL) + return; + + /* start at the top of the list */ + nseg = ISC_LIST_HEAD(**querylist); + while (nseg != NULL) { /* loop, until end of list */ + tseg = nseg; + /* + * free the query segment's text string but only if it + * was really a query segment, and not a pointer to + * %zone%, or %record%, or %client% + */ + if (tseg->sql != NULL && tseg->direct == true) + isc_mem_free(mctx, tseg->sql); + /* get the next query segment, before we destroy this one. */ + nseg = ISC_LIST_NEXT(nseg, link); + /* deallocate this query segment. */ + isc_mem_put(mctx, tseg, sizeof(query_segment_t)); + } + /* deallocate the query segment list */ + isc_mem_put(mctx, *querylist, sizeof(query_list_t)); +} + +/*% constructs a query list by parsing a string into query segments */ +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) +{ + isc_result_t result; + bool foundzone = false; + bool foundrecord = false; + bool foundclient = false; + char *temp_str = NULL; + char *right_str = NULL; + query_list_t *tql; + query_segment_t *tseg = NULL; + + REQUIRE(querylist != NULL && *querylist == NULL); + REQUIRE(mctx != NULL); + + /* if query string is null, or zero length */ + if (query_str == NULL || strlen(query_str) < 1) { + if ((flags & SDLZH_REQUIRE_QUERY) == 0) + /* we don't need it were ok. */ + return (ISC_R_SUCCESS); + else + /* we did need it, PROBLEM!!! */ + return (ISC_R_FAILURE); + } + + /* allocate memory for query list */ + tql = isc_mem_get(mctx, sizeof(query_list_t)); + /* couldn't allocate memory. Problem!! */ + if (tql == NULL) + return (ISC_R_NOMEMORY); + + /* initialize the query segment list */ + ISC_LIST_INIT(*tql); + + /* make a copy of query_str so we can chop it up */ + temp_str = right_str = isc_mem_strdup(mctx, query_str); + /* couldn't make a copy, problem!! */ + if (right_str == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + /* loop through the string and chop it up */ + while (right_str != NULL) { + /* allocate memory for tseg */ + tseg = isc_mem_get(mctx, sizeof(query_segment_t)); + if (tseg == NULL) { /* no memory, clean everything up. */ + result = ISC_R_NOMEMORY; + goto cleanup; + } + tseg->sql = NULL; + tseg->direct = false; + /* initialize the query segment link */ + ISC_LINK_INIT(tseg, link); + /* append the query segment to the list */ + ISC_LIST_APPEND(*tql, tseg, link); + + /* + * split string at the first "$". set query segment to + * left portion + */ + tseg->sql = isc_mem_strdup(mctx, + isc_string_separate(&right_str, + "$")); + if (tseg->sql == NULL) { + /* no memory, clean everything up. */ + result = ISC_R_NOMEMORY; + goto cleanup; + } + /* tseg->sql points directly to a string. */ + tseg->direct = true; + tseg->strlen = strlen(tseg->sql); + + /* check if we encountered "$zone$" token */ + if (strcasecmp(tseg->sql, "zone") == 0) { + /* + * we don't really need, or want the "zone" + * text, so get rid of it. + */ + isc_mem_free(mctx, tseg->sql); + /* set tseg->sql to in-direct zone string */ + tseg->sql = (char**) zone; + tseg->strlen = 0; + /* tseg->sql points in-directly to a string */ + tseg->direct = false; + foundzone = true; + /* check if we encountered "$record$" token */ + } else if (strcasecmp(tseg->sql, "record") == 0) { + /* + * we don't really need, or want the "record" + * text, so get rid of it. + */ + isc_mem_free(mctx, tseg->sql); + /* set tseg->sql to in-direct record string */ + tseg->sql = (char**) record; + tseg->strlen = 0; + /* tseg->sql points in-directly poinsts to a string */ + tseg->direct = false; + foundrecord = true; + /* check if we encountered "$client$" token */ + } else if (strcasecmp(tseg->sql, "client") == 0) { + /* + * we don't really need, or want the "client" + * text, so get rid of it. + */ + isc_mem_free(mctx, tseg->sql); + /* set tseg->sql to in-direct record string */ + tseg->sql = (char**) client; + tseg->strlen = 0; + /* tseg->sql points in-directly poinsts to a string */ + tseg->direct = false; + foundclient = true; + } + } + + /* we don't need temp_str any more */ + isc_mem_free(mctx, temp_str); + /* + * add checks later to verify zone and record are found if + * necessary. + */ + + /* if this query requires %client%, make sure we found it */ + if (((flags & SDLZH_REQUIRE_CLIENT) != 0) && (!foundclient) ) { + /* Write error message to log */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Required token $client$ not found."); + result = ISC_R_FAILURE; + goto flag_fail; + } + + /* if this query requires %record%, make sure we found it */ + if (((flags & SDLZH_REQUIRE_RECORD) != 0) && (!foundrecord) ) { + /* Write error message to log */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Required token $record$ not found."); + result = ISC_R_FAILURE; + goto flag_fail; + } + + /* if this query requires %zone%, make sure we found it */ + if (((flags & SDLZH_REQUIRE_ZONE) != 0) && (!foundzone) ) { + /* Write error message to log */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Required token $zone$ not found."); + result = ISC_R_FAILURE; + goto flag_fail; + } + + /* pass back the query list */ + *querylist = (query_list_t *) tql; + + /* return success */ + return (ISC_R_SUCCESS); + + cleanup: + /* get rid of temp_str */ + if (temp_str != NULL) + isc_mem_free(mctx, temp_str); + + flag_fail: + /* get rid of what was build of the query list */ + if (tql != NULL) + destroy_querylist(mctx, &tql); + return result; +} + +/*% + * build a query string from query segments, and dynamic segments + * dynamic segments replace where the tokens %zone%, %record%, %client% + * used to be in our queries from named.conf + */ +char * +sdlzh_build_querystring(isc_mem_t *mctx, query_list_t *querylist) +{ + query_segment_t *tseg = NULL; + unsigned int length = 0; + char *qs = NULL; + + REQUIRE(mctx != NULL); + REQUIRE(querylist != NULL); + + /* start at the top of the list */ + tseg = ISC_LIST_HEAD(*querylist); + while (tseg != NULL) { + /* + * if this is a query segment, use the + * precalculated string length + */ + if (tseg->direct == true) + length += tseg->strlen; + else /* calculate string length for dynamic segments. */ + length += strlen(* (char**) tseg->sql); + /* get the next segment */ + tseg = ISC_LIST_NEXT(tseg, link); + } + + /* allocate memory for the string */ + qs = isc_mem_allocate(mctx, length + 1); + /* couldn't allocate memory, We need more ram! */ + if (qs == NULL) + return NULL; + + *qs = 0; + /* start at the top of the list again */ + tseg = ISC_LIST_HEAD(*querylist); + while (tseg != NULL) { + if (tseg->direct == true) + /* query segments */ + strcat(qs, tseg->sql); + else + /* dynamic segments */ + strcat(qs, * (char**) tseg->sql); + /* get the next segment */ + tseg = ISC_LIST_NEXT(tseg, link); + } + + return qs; +} + +/*% constructs a sql dbinstance (DBI) */ +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) +{ + + isc_result_t result; + dbinstance_t *db = NULL; + + REQUIRE(dbi != NULL && *dbi == NULL); + REQUIRE(mctx != NULL); + + /* allocate and zero memory for driver structure */ + db = isc_mem_get(mctx, sizeof(dbinstance_t)); + if (db == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not allocate memory for " + "database instance object."); + return (ISC_R_NOMEMORY); + } + memset(db, 0, sizeof(dbinstance_t)); + db->dbconn = NULL; + db->client = NULL; + db->record = NULL; + db->zone = NULL; + db->mctx = NULL; + db->query_buf = NULL; + db->allnodes_q = NULL; + db->allowxfr_q = NULL; + db->authority_q = NULL; + db->findzone_q = NULL; + db->countzone_q = NULL; + db->lookup_q = NULL; + + /* attach to the memory context */ + isc_mem_attach(mctx, &db->mctx); + + /* initialize the reference count mutex */ + result = isc_mutex_init(&db->instance_lock); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_mutex_init() failed: %s", + isc_result_totext(result)); + goto cleanup; + } + + /* build the all nodes query list */ + result = build_querylist(mctx, allnodes_str, &db->zone, + &db->record, &db->client, + &db->allnodes_q, SDLZH_REQUIRE_ZONE); + /* if unsuccessful, log err msg and cleanup */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not build all nodes query list"); + goto cleanup; + } + + /* build the allow zone transfer query list */ + result = build_querylist(mctx, allowxfr_str, &db->zone, + &db->record, &db->client, + &db->allowxfr_q, + SDLZH_REQUIRE_ZONE | SDLZH_REQUIRE_CLIENT); + /* if unsuccessful, log err msg and cleanup */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not build allow xfr query list"); + goto cleanup; + } + + /* build the authority query, query list */ + result = build_querylist(mctx, authority_str, &db->zone, + &db->record, &db->client, + &db->authority_q, SDLZH_REQUIRE_ZONE); + /* if unsuccessful, log err msg and cleanup */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not build authority query list"); + goto cleanup; + } + + /* build findzone query, query list */ + result = build_querylist(mctx, findzone_str, &db->zone, + &db->record, &db->client, + &db->findzone_q, SDLZH_REQUIRE_ZONE); + /* if unsuccessful, log err msg and cleanup */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not build find zone query list"); + goto cleanup; + } + + /* build countzone query, query list */ + result = build_querylist(mctx, countzone_str, &db->zone, + &db->record, &db->client, + &db->countzone_q, SDLZH_REQUIRE_ZONE); + /* if unsuccessful, log err msg and cleanup */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not build count zone query list"); + goto cleanup; + } + + /* build lookup query, query list */ + result = build_querylist(mctx, lookup_str, &db->zone, + &db->record, &db->client, + &db->lookup_q, SDLZH_REQUIRE_RECORD); + /* if unsuccessful, log err msg and cleanup */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not build lookup query list"); + goto cleanup; + } + + /* pass back the db instance */ + *dbi = (dbinstance_t *) db; + + /* return success */ + return (ISC_R_SUCCESS); + + cleanup: + /* destroy whatever was build of the db instance */ + destroy_sqldbinstance(db); + /* return failure */ + return (ISC_R_FAILURE); +} + +void +sdlzh_destroy_sqldbinstance(dbinstance_t *dbi) +{ + isc_mem_t *mctx; + + /* save mctx for later */ + mctx = dbi->mctx; + + /* destroy any query lists we created */ + destroy_querylist(mctx, &dbi->allnodes_q); + destroy_querylist(mctx, &dbi->allowxfr_q); + destroy_querylist(mctx, &dbi->authority_q); + destroy_querylist(mctx, &dbi->findzone_q); + destroy_querylist(mctx, &dbi->countzone_q); + destroy_querylist(mctx, &dbi->lookup_q); + + /* get rid of the mutex */ + (void) isc_mutex_destroy(&dbi->instance_lock); + + /* return, and detach the memory */ + isc_mem_put(mctx, dbi, sizeof(dbinstance_t)); + isc_mem_detach(&mctx); +} + +char * +sdlzh_get_parameter_value(isc_mem_t *mctx, const char *input, const char* key) +{ + int keylen; + char *keystart; + char value[255]; + int i; + + if (key == NULL || input == NULL || strlen(input) < 1) + return NULL; + + keylen = strlen(key); + + if (keylen < 1) + return NULL; + + keystart = strstr(input, key); + + if (keystart == NULL) + return NULL; + + REQUIRE(mctx != NULL); + + for (i = 0; i < 255; i++) { + value[i] = keystart[keylen + i]; + if (value[i] == ' ' || value[i] == '\0') { + value[i] = '\0'; + break; + } + } + + return isc_mem_strdup(mctx, value); +} |