diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 07:24:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 07:24:22 +0000 |
commit | 45d6379135504814ab723b57f0eb8be23393a51d (patch) | |
tree | d4f2ec4acca824a8446387a758b0ce4238a4dffa /contrib/dlz/drivers/dlz_filesystem_driver.c | |
parent | Initial commit. (diff) | |
download | bind9-564253c724404fc788d27ab128f285c1070fe23c.tar.xz bind9-564253c724404fc788d27ab128f285c1070fe23c.zip |
Adding upstream version 1:9.16.44.upstream/1%9.16.44upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/dlz/drivers/dlz_filesystem_driver.c')
-rw-r--r-- | contrib/dlz/drivers/dlz_filesystem_driver.c | 1000 |
1 files changed, 1000 insertions, 0 deletions
diff --git a/contrib/dlz/drivers/dlz_filesystem_driver.c b/contrib/dlz/drivers/dlz_filesystem_driver.c new file mode 100644 index 0000000..c097411 --- /dev/null +++ b/contrib/dlz/drivers/dlz_filesystem_driver.c @@ -0,0 +1,1000 @@ +/* + * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * 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/. + */ + +#ifdef DLZ_FILESYSTEM +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include <isc/dir.h> +#include <isc/mem.h> +#include <isc/platform.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dns/log.h> +#include <dns/result.h> +#include <dns/sdlz.h> + +#include <dlz/dlz_filesystem_driver.h> +#include <named/globals.h> + +static dns_sdlzimplementation_t *dlz_fs = NULL; + +typedef struct config_data { + char *basedir; + int basedirsize; + char *datadir; + int datadirsize; + char *xfrdir; + int xfrdirsize; + int splitcnt; + char separator; + char pathsep; + isc_mem_t *mctx; +} config_data_t; + +typedef struct dir_entry dir_entry_t; + +struct dir_entry { + char dirpath[PATH_MAX]; + ISC_LINK(dir_entry_t) link; +}; + +typedef ISC_LIST(dir_entry_t) dlist_t; + +/* forward reference */ + +static void +fs_destroy(void *driverarg, void *dbdata); + +/* + * Private methods + */ + +static bool +is_safe(const char *input) { + unsigned int i; + unsigned int len = strlen(input); + + /* check that only allowed characters are in the domain name */ + for (i = 0; i < len; i++) { + /* '.' is allowed, but has special requirements */ + if (input[i] == '.') { + /* '.' is not allowed as first char */ + if (i == 0) { + return (false); + } + /* '..', two dots together is not allowed. */ + if (input[i - 1] == '.') { + return (false); + } + /* '.' is not allowed as last char */ + if (i == len - 1) { + return (false); + } + /* only 1 dot in ok location, continue at next char */ + continue; + } + /* '-' is allowed, continue at next char */ + if (input[i] == '-') { + continue; + } + /* 0-9 is allowed, continue at next char */ + if (input[i] >= '0' && input[i] <= '9') { + continue; + } + /* A-Z uppercase is allowed, continue at next char */ + if (input[i] >= 'A' && input[i] <= 'Z') { + continue; + } + /* a-z lowercase is allowed, continue at next char */ + if (input[i] >= 'a' && input[i] <= 'z') { + continue; + } + + /* + * colon needs to be allowed for IPV6 client + * addresses. Not dangerous in domain names, as not a + * special char. + */ + if (input[i] == ':') { + continue; + } + + /* + * '@' needs to be allowed for in zone data. Not + * dangerous in domain names, as not a special char. + */ + if (input[i] == '@') { + continue; + } + + /* + * if we reach this point we have encountered a + * disallowed char! + */ + return (false); + } + /* everything ok. */ + return (true); +} + +static void +create_path_helper(char *out, const char *in, config_data_t *cd) { + char *tmpString; + char *tmpPtr; + int i; + + tmpString = isc_mem_strdup(named_g_mctx, in); + + /* + * don't forget is_safe guarantees '.' will NOT be the + * first/last char + */ + while ((tmpPtr = strrchr(tmpString, '.')) != NULL) { + i = 0; + while (tmpPtr[i + 1] != '\0') { + if (cd->splitcnt < 1) { + strcat(out, (char *)&tmpPtr[i + 1]); + } else { + strncat(out, (char *)&tmpPtr[i + 1], + cd->splitcnt); + } + strncat(out, (char *)&cd->pathsep, 1); + if (cd->splitcnt == 0) { + break; + } + if (strlen((char *)&tmpPtr[i + 1]) <= + (unsigned int)cd->splitcnt) + { + break; + } + i += cd->splitcnt; + } + tmpPtr[0] = '\0'; + } + + /* handle the "first" label properly */ + i = 0; + tmpPtr = tmpString; + while (tmpPtr[i] != '\0') { + if (cd->splitcnt < 1) { + strcat(out, (char *)&tmpPtr[i]); + } else { + strncat(out, (char *)&tmpPtr[i], cd->splitcnt); + } + strncat(out, (char *)&cd->pathsep, 1); + if (cd->splitcnt == 0) { + break; + } + if (strlen((char *)&tmpPtr[i]) <= (unsigned int)cd->splitcnt) { + break; + } + i += cd->splitcnt; + } + + isc_mem_free(named_g_mctx, tmpString); +} + +/*% + * Checks to make sure zone and host are safe. If safe, then + * hashes zone and host strings to build a path. If zone / host + * are not safe an error is returned. + */ + +static isc_result_t +create_path(const char *zone, const char *host, const char *client, + config_data_t *cd, char **path) { + char *tmpPath; + int pathsize; + int len; + bool isroot = false; + + /* we require a zone & cd parameter */ + REQUIRE(zone != NULL); + REQUIRE(cd != NULL); + /* require path to be a pointer to NULL */ + REQUIRE(path != NULL && *path == NULL); + /* + * client and host may both be NULL, but they can't both be + * NON-NULL + */ + REQUIRE((host == NULL && client == NULL) || + (host != NULL && client == NULL) || + (host == NULL && client != NULL)); + + /* special case for root zone */ + if (strcmp(zone, ".") == 0) { + isroot = true; + } + + /* if the requested zone is "unsafe", return error */ + if (!isroot && !is_safe(zone)) { + return (ISC_R_FAILURE); + } + + /* if host was passed, verify that it is safe */ + if (host != NULL && !is_safe(host)) { + return (ISC_R_FAILURE); + } + + /* if client was passed, verify that it is safe */ + if (client != NULL && !is_safe(client)) { + return (ISC_R_FAILURE); + } + + /* Determine how much memory the split up string will require */ + if (host != NULL) { + len = strlen(zone) + strlen(host); + } else if (client != NULL) { + len = strlen(zone) + strlen(client); + } else { + len = strlen(zone); + } + + /* + * even though datadir and xfrdir will never be in the same + * string we only waste a few bytes by allocating for both, + * and then we are safe from buffer overruns. + */ + pathsize = len + cd->basedirsize + cd->datadirsize + cd->xfrdirsize + 4; + + /* if we are splitting names, we will need extra space. */ + if (cd->splitcnt > 0) { + pathsize += len / cd->splitcnt; + } + + tmpPath = isc_mem_allocate(named_g_mctx, pathsize * sizeof(char)); + + /* + * build path string. + * start out with base directory. + */ + strcpy(tmpPath, cd->basedir); + + /* add zone name - parsed properly */ + if (!isroot) { + create_path_helper(tmpPath, zone, cd); + } + + /* + * When neither client or host is passed we are building a + * path to see if a zone is supported. We require that a zone + * path have the "data dir" directory contained within it so + * that we know this zone is really supported. Otherwise, + * this zone may not really be supported because we are + * supporting a delagated sub zone. + * + * Example: + * + * We are supporting long.domain.com and using a splitcnt of + * 0. the base dir is "/base-dir/" and the data dir is + * "/.datadir" We want to see if we are authoritative for + * domain.com. Path /base-dir/com/domain/.datadir since + * /base-dir/com/domain/.datadir does not exist, we are not + * authoritative for the domain "domain.com". However we are + * authoritative for the domain "long.domain.com" because the + * path /base-dir/com/domain/long/.datadir does exist! + */ + + /* if client is passed append xfr dir, otherwise append data dir */ + if (client != NULL) { + strcat(tmpPath, cd->xfrdir); + strncat(tmpPath, (char *)&cd->pathsep, 1); + strcat(tmpPath, client); + } else { + strcat(tmpPath, cd->datadir); + } + + /* if host not null, add it. */ + if (host != NULL) { + strncat(tmpPath, (char *)&cd->pathsep, 1); + create_path_helper(tmpPath, host, cd); + } + + /* return the path we built. */ + *path = tmpPath; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +process_dir(isc_dir_t *dir, void *passback, config_data_t *cd, + dlist_t *dir_list, unsigned int basedirlen) { + char tmp[PATH_MAX + NAME_MAX]; + int astPos; + struct stat sb; + isc_result_t result = ISC_R_FAILURE; + char *endp; + char *type; + char *ttlStr; + char *data; + char host[NAME_MAX]; + char *tmpString; + char *tmpPtr; + int ttl; + int i; + int len; + dir_entry_t *direntry; + bool foundHost; + + tmp[0] = '\0'; /* set 1st byte to '\0' so strcpy works right. */ + host[0] = '\0'; + foundHost = false; + + /* copy base directory name to tmp. */ + strcpy(tmp, dir->dirname); + + /* dir->dirname will always have '*' as the last char. */ + astPos = strlen(dir->dirname) - 1; + + /* if dir_list != NULL, were are performing a zone xfr */ + if (dir_list != NULL) { + /* if splitcnt == 0, determine host from path. */ + if (cd->splitcnt == 0) { + if (strlen(tmp) - 3 > basedirlen) { + tmp[astPos - 1] = '\0'; + tmpString = (char *)&tmp[basedirlen + 1]; + /* handle filesystem's special wildcard "-" */ + if (strcmp(tmpString, "-") == 0) { + strcpy(host, "*"); + } else { + /* + * not special wildcard -- normal name + */ + while ((tmpPtr = strrchr( + tmpString, + cd->pathsep)) != NULL) + { + if ((strlen(host) + + strlen(tmpPtr + 1) + 2) > + NAME_MAX) + { + continue; + } + strcat(host, tmpPtr + 1); + strcat(host, "."); + tmpPtr[0] = '\0'; + } + if ((strlen(host) + strlen(tmpString) + + 1) <= NAME_MAX) + { + strcat(host, tmpString); + } + } + + foundHost = true; + /* set tmp again for use later */ + strcpy(tmp, dir->dirname); + } + } else { + /* + * if splitcnt != 0 determine host from + * ".host" directory entry + */ + while (isc_dir_read(dir) == ISC_R_SUCCESS) { + if (strncasecmp(".host", dir->entry.name, 5) == + 0) + { + /* + * handle filesystem's special + * wildcard "-" + */ + if (strcmp((char *)&dir->entry.name[6], + "-") == 0) + { + strlcpy(host, "*", + sizeof(host)); + } else { + strlcpy(host, + (char *)&dir->entry + .name[6], + sizeof(host)); + } + foundHost = true; + break; + } + } + /* reset dir list for use later */ + isc_dir_reset(dir); + } /* end of else */ + } + + while (isc_dir_read(dir) == ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), + "Filesystem driver Dir name:" + " '%s' Dir entry: '%s'\n", + dir->dirname, dir->entry.name); + + /* skip any entries starting with "." */ + if (dir->entry.name[0] == '.') { + continue; + } + + /* + * get rid of '*', set to NULL. Effectively trims + * string from previous loop to base directory only + * while still leaving memory for concat to be + * performed next. + */ + + tmp[astPos] = '\0'; + + /* add name to base directory name. */ + strcat(tmp, dir->entry.name); + + /* make sure we can stat entry */ + if (stat(tmp, &sb) == 0) { + /* if entry is a directory */ + if ((sb.st_mode & S_IFDIR) != 0) { + /* + * if dir list is NOT NULL, add dir to + * dir list + */ + if (dir_list != NULL) { + direntry = isc_mem_get( + named_g_mctx, + sizeof(dir_entry_t)); + strcpy(direntry->dirpath, tmp); + ISC_LINK_INIT(direntry, link); + ISC_LIST_APPEND(*dir_list, direntry, + link); + result = ISC_R_SUCCESS; + } + continue; + + /* + * if entry is a file be sure we do + * not add entry to DNS results if we + * are performing a zone xfr and we + * could not find a host entry. + */ + } else if (dir_list != NULL && !foundHost) { + continue; + } + } else { /* if we cannot stat entry, skip it. */ + continue; + } + + type = dir->entry.name; + ttlStr = strchr(type, cd->separator); + if (ttlStr == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Filesystem driver: " + "%s could not be parsed properly", + tmp); + return (ISC_R_FAILURE); + } + + /* replace separator char with NULL to split string */ + ttlStr[0] = '\0'; + /* start string after NULL of previous string */ + ttlStr = (char *)&ttlStr[1]; + + data = strchr(ttlStr, cd->separator); + if (data == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Filesystem driver: " + "%s could not be parsed properly", + tmp); + return (ISC_R_FAILURE); + } + + /* replace separator char with NULL to split string */ + data[0] = '\0'; + + /* start string after NULL of previous string */ + data = (char *)&data[1]; + + /* replace all cd->separator chars with a space. */ + len = strlen(data); + + for (i = 0; i < len; i++) { + if (data[i] == cd->separator) { + data[i] = ' '; + } + } + + /* convert text to int, make sure it worked right */ + ttl = strtol(ttlStr, &endp, 10); + if (*endp != '\0' || ttl < 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Filesystem driver " + "ttl must be a positive number"); + } + + /* pass data back to Bind */ + if (dir_list == NULL) { + result = dns_sdlz_putrr((dns_sdlzlookup_t *)passback, + type, ttl, data); + } else { + result = dns_sdlz_putnamedrr( + (dns_sdlzallnodes_t *)passback, (char *)host, + type, ttl, data); + } + + /* if error, return error right away */ + if (result != ISC_R_SUCCESS) { + return (result); + } + } /* end of while loop */ + + return (result); +} + +/* + * SDLZ interface methods + */ + +static isc_result_t +fs_allowzonexfr(void *driverarg, void *dbdata, const char *name, + const char *client) { + isc_result_t result; + char *path; + struct stat sb; + config_data_t *cd; + path = NULL; + + UNUSED(driverarg); + + cd = (config_data_t *)dbdata; + + if (create_path(name, NULL, client, cd, &path) != ISC_R_SUCCESS) { + return (ISC_R_NOTFOUND); + } + + if (stat(path, &sb) != 0) { + result = ISC_R_NOTFOUND; + goto complete_AXFR; + } + + if ((sb.st_mode & S_IFREG) != 0) { + result = ISC_R_SUCCESS; + goto complete_AXFR; + } + + result = ISC_R_NOTFOUND; + +complete_AXFR: + isc_mem_free(named_g_mctx, path); + return (result); +} + +static isc_result_t +fs_allnodes(const char *zone, void *driverarg, void *dbdata, + dns_sdlzallnodes_t *allnodes) { + isc_result_t result; + dlist_t *dir_list; + config_data_t *cd; + char *basepath; + unsigned int basepathlen; + struct stat sb; + isc_dir_t dir; + dir_entry_t *dir_entry; + dir_entry_t *next_de; + + basepath = NULL; + dir_list = NULL; + + UNUSED(driverarg); + UNUSED(allnodes); + + cd = (config_data_t *)dbdata; + + /* allocate memory for list */ + dir_list = isc_mem_get(named_g_mctx, sizeof(dlist_t)); + + /* initialize list */ + ISC_LIST_INIT(*dir_list); + + if (create_path(zone, NULL, NULL, cd, &basepath) != ISC_R_SUCCESS) { + result = ISC_R_NOTFOUND; + goto complete_allnds; + } + + /* remove path separator at end of path so stat works properly */ + basepathlen = strlen(basepath); + + if (stat(basepath, &sb) != 0) { + result = ISC_R_NOTFOUND; + goto complete_allnds; + } + + if ((sb.st_mode & S_IFDIR) == 0) { + result = ISC_R_NOTFOUND; + goto complete_allnds; + } + + /* initialize and open directory */ + isc_dir_init(&dir); + result = isc_dir_open(&dir, basepath); + + /* if directory open failed, return error. */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Unable to open %s directory to read entries.", + basepath); + result = ISC_R_FAILURE; + goto complete_allnds; + } + + /* process the directory */ + result = process_dir(&dir, allnodes, cd, dir_list, basepathlen); + + /* close the directory */ + isc_dir_close(&dir); + + if (result != ISC_R_SUCCESS) { + goto complete_allnds; + } + + /* get first dir entry from list. */ + dir_entry = ISC_LIST_HEAD(*dir_list); + while (dir_entry != NULL) { + result = isc_dir_open(&dir, dir_entry->dirpath); + /* if directory open failed, return error. */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Unable to open %s " + "directory to read entries.", + basepath); + result = ISC_R_FAILURE; + goto complete_allnds; + } + + /* process the directory */ + result = process_dir(&dir, allnodes, cd, dir_list, basepathlen); + + /* close the directory */ + isc_dir_close(&dir); + + if (result != ISC_R_SUCCESS) { + goto complete_allnds; + } + + dir_entry = ISC_LIST_NEXT(dir_entry, link); + } /* end while */ + +complete_allnds: + /* clean up entries from list. */ + dir_entry = ISC_LIST_HEAD(*dir_list); + while (dir_entry != NULL) { + next_de = ISC_LIST_NEXT(dir_entry, link); + isc_mem_put(named_g_mctx, dir_entry, sizeof(dir_entry_t)); + dir_entry = next_de; + } /* end while */ + isc_mem_put(named_g_mctx, dir_list, sizeof(dlist_t)); + + if (basepath != NULL) { + isc_mem_free(named_g_mctx, basepath); + } + + return (result); +} + +static isc_result_t +fs_findzone(void *driverarg, void *dbdata, const char *name, + dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo) { + isc_result_t result; + char *path; + struct stat sb; + path = NULL; + + UNUSED(driverarg); + UNUSED(methods); + UNUSED(clientinfo); + + if (create_path(name, NULL, NULL, (config_data_t *)dbdata, &path) != + ISC_R_SUCCESS) + { + return (ISC_R_NOTFOUND); + } + + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, + ISC_LOG_DEBUG(1), + "Filesystem driver Findzone() Checking for path: '%s'\n", + path); + + if (stat(path, &sb) != 0) { + result = ISC_R_NOTFOUND; + goto complete_FZ; + } + + if ((sb.st_mode & S_IFDIR) != 0) { + result = ISC_R_SUCCESS; + goto complete_FZ; + } + + result = ISC_R_NOTFOUND; + +complete_FZ: + + isc_mem_free(named_g_mctx, path); + return (result); +} + +static isc_result_t +fs_lookup(const char *zone, const char *name, void *driverarg, void *dbdata, + dns_sdlzlookup_t *lookup, dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) { + isc_result_t result; + char *path; + struct stat sb; + isc_dir_t dir; + path = NULL; + + UNUSED(driverarg); + UNUSED(lookup); + UNUSED(methods); + UNUSED(clientinfo); + + if (strcmp(name, "*") == 0) { + /* + * handle filesystem's special wildcard "-" + */ + result = create_path(zone, "-", NULL, (config_data_t *)dbdata, + &path); + } else { + result = create_path(zone, name, NULL, (config_data_t *)dbdata, + &path); + } + + if (result != ISC_R_SUCCESS) { + return (ISC_R_NOTFOUND); + } + + /* remove path separator at end of path so stat works properly */ + path[strlen(path) - 1] = '\0'; + + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, + ISC_LOG_DEBUG(1), + "Filesystem driver lookup() Checking for path: '%s'\n", + path); + + if (stat(path, &sb) != 0) { + result = ISC_R_NOTFOUND; + goto complete_lkup; + } + + if ((sb.st_mode & S_IFDIR) == 0) { + result = ISC_R_NOTFOUND; + goto complete_lkup; + } + + /* initialize and open directory */ + isc_dir_init(&dir); + result = isc_dir_open(&dir, path); + + /* if directory open failed, return error. */ + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Unable to open %s directory to read entries.", + path); + result = ISC_R_FAILURE; + goto complete_lkup; + } + + /* process any records in the directory */ + result = process_dir(&dir, lookup, (config_data_t *)dbdata, NULL, 0); + + /* close the directory */ + isc_dir_close(&dir); + +complete_lkup: + + isc_mem_free(named_g_mctx, path); + return (result); +} + +static isc_result_t +fs_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, + void **dbdata) { + config_data_t *cd; + char *endp; + int len; + char pathsep; + + UNUSED(driverarg); + UNUSED(dlzname); + + /* we require 5 command line args. */ + if (argc != 6) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Filesystem driver requires " + "6 command line args."); + return (ISC_R_FAILURE); + } + + if (strlen(argv[5]) > 1) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Filesystem driver can only " + "accept a single character for separator."); + return (ISC_R_FAILURE); + } + + /* verify base dir ends with '/' or '\' */ + len = strlen(argv[1]); + if (argv[1][len - 1] != '\\' && argv[1][len - 1] != '/') { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Base dir parameter for filesystem driver " + "should end with %s", + "either '/' or '\\' "); + return (ISC_R_FAILURE); + } + + /* determine and save path separator for later */ + if (argv[1][len - 1] == '\\') { + pathsep = '\\'; + } else { + pathsep = '/'; + } + + /* allocate memory for our config data */ + cd = isc_mem_get(named_g_mctx, sizeof(config_data_t)); + + /* zero the memory */ + memset(cd, 0, sizeof(config_data_t)); + + cd->pathsep = pathsep; + + /* get and store our base directory */ + cd->basedir = isc_mem_strdup(named_g_mctx, argv[1]); + cd->basedirsize = strlen(cd->basedir); + + /* get and store our data sub-dir */ + cd->datadir = isc_mem_strdup(named_g_mctx, argv[2]); + cd->datadirsize = strlen(cd->datadir); + + /* get and store our zone xfr sub-dir */ + cd->xfrdir = isc_mem_strdup(named_g_mctx, argv[3]); + cd->xfrdirsize = strlen(cd->xfrdir); + + /* get and store our directory split count */ + cd->splitcnt = strtol(argv[4], &endp, 10); + if (*endp != '\0' || cd->splitcnt < 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Directory split count must be zero (0) " + "or a positive number"); + } + + /* get and store our separator character */ + cd->separator = *argv[5]; + + /* attach config data to memory context */ + isc_mem_attach(named_g_mctx, &cd->mctx); + + /* pass back config data */ + *dbdata = cd; + + /* return success */ + return (ISC_R_SUCCESS); +} + +static void +fs_destroy(void *driverarg, void *dbdata) { + isc_mem_t *mctx; + config_data_t *cd; + + UNUSED(driverarg); + + cd = (config_data_t *)dbdata; + + /* + * free memory for each section of config data that was + * allocated + */ + if (cd->basedir != NULL) { + isc_mem_free(named_g_mctx, cd->basedir); + } + + if (cd->datadir != NULL) { + isc_mem_free(named_g_mctx, cd->datadir); + } + + if (cd->xfrdir != NULL) { + isc_mem_free(named_g_mctx, cd->xfrdir); + } + + /* hold memory context to use later */ + mctx = cd->mctx; + + /* free config data memory */ + isc_mem_putanddetach(&mctx, cd, sizeof(config_data_t)); +} + +static dns_sdlzmethods_t dlz_fs_methods = { + fs_create, + fs_destroy, + fs_findzone, + fs_lookup, + NULL, + fs_allnodes, + fs_allowzonexfr, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +/*% + * Wrapper around dns_sdlzregister(). + */ +isc_result_t +dlz_fs_init(void) { + isc_result_t result; + + /* + * Write debugging message to log + */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, + ISC_LOG_DEBUG(2), "Registering DLZ filesystem driver."); + + result = dns_sdlzregister("filesystem", &dlz_fs_methods, NULL, + DNS_SDLZFLAG_RELATIVEOWNER | + DNS_SDLZFLAG_RELATIVERDATA, + named_g_mctx, &dlz_fs); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "dns_sdlzregister() failed: %s", + isc_result_totext(result)); + result = ISC_R_UNEXPECTED; + } + + return (result); +} + +/*% + * Wrapper around dns_sdlzunregister(). + */ +void +dlz_fs_clear(void) { + /* + * Write debugging message to log + */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, + ISC_LOG_DEBUG(2), "Unregistering DLZ filesystem driver."); + + if (dlz_fs != NULL) { + dns_sdlzunregister(&dlz_fs); + } +} + +#endif /* ifdef DLZ_FILESYSTEM */ |