Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / contrib / dlz / modules / filesystem / dlz_filesystem_dynamic.c
blob48e2d012759ed15d8d5f46b2257229cea9ed1ab9
1 /* $NetBSD: dlz_filesystem_dynamic.c,v 1.1.1.3 2014/12/10 03:34:31 christos Exp $ */
3 /*
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
9 * copies.
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
26 * copies.
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.
56 * This provides the externally loadable filesystem DLZ module, without
57 * update support
60 #include <stdio.h>
61 #include <string.h>
62 #include <stdarg.h>
63 #include <stdint.h>
64 #include <stdlib.h>
66 #include <sys/stat.h>
68 #include "dlz_minimal.h"
69 #include "dlz_list.h"
70 #include "dir.h"
72 typedef struct config_data {
73 char *basedir;
74 int basedirsize;
75 char *datadir;
76 int datadirsize;
77 char *xfrdir;
78 int xfrdirsize;
79 int splitcnt;
80 char separator;
81 char pathsep;
83 /* Helper functions from the dlz_dlopen driver */
84 log_t *log;
85 dns_sdlz_putrr_t *putrr;
86 dns_sdlz_putnamedrr_t *putnamedrr;
87 dns_dlz_writeablezone_t *writeable_zone;
88 } config_data_t;
90 typedef struct dir_entry dir_entry_t;
92 struct dir_entry {
93 char dirpath[DIR_PATHMAX];
94 DLZ_LINK(dir_entry_t) link;
97 typedef DLZ_LIST(dir_entry_t) dlist_t;
99 /* forward reference */
101 static void
102 b9_add_helper(struct config_data *cd, const char *helper_name, void *ptr);
105 * Private methods
107 static isc_boolean_t
108 is_safe(const char *input) {
109 unsigned int i;
110 unsigned int len = strlen(input);
112 /* check that only allowed characters are in the domain name */
113 for (i = 0; i < len; i++) {
114 /* '.' is allowed, but has special requirements */
115 if (input[i] == '.') {
116 /* '.' is not allowed as first char */
117 if (i == 0)
118 return (ISC_FALSE);
119 /* '..', two dots together is not allowed. */
120 else if (input[i-1] == '.')
121 return (ISC_FALSE);
122 /* '.' is not allowed as last char */
123 if (i == len)
124 return (ISC_FALSE);
125 /* only 1 dot in ok location, continue at next char */
126 continue;
128 /* '-' is allowed, continue at next char */
129 if (input[i] == '-')
130 continue;
131 /* 0-9 is allowed, continue at next char */
132 if (input[i] >= '0' && input[i] <= '9')
133 continue;
134 /* A-Z uppercase is allowed, continue at next char */
135 if (input[i] >= 'A' && input[i] <= 'Z')
136 continue;
137 /* a-z lowercase is allowed, continue at next char */
138 if (input[i] >= 'a' && input[i] <= 'z')
139 continue;
142 * colon needs to be allowed for IPV6 client
143 * addresses. Not dangerous in domain names, as not a
144 * special char.
146 if (input[i] == ':')
147 continue;
150 * '@' needs to be allowed for in zone data. Not
151 * dangerous in domain names, as not a special char.
153 if (input[i] == '@')
154 continue;
157 * if we reach this point we have encountered a
158 * disallowed char!
160 return (ISC_FALSE);
162 /* everything ok. */
163 return (ISC_TRUE);
166 static isc_result_t
167 create_path_helper(char *out, const char *in, config_data_t *cd) {
168 char *tmpString;
169 char *tmpPtr;
170 int i;
172 tmpString = strdup(in);
173 if (tmpString == NULL)
174 return (ISC_R_NOMEMORY);
177 * don't forget is_safe guarantees '.' will NOT be the
178 * first/last char
180 while ((tmpPtr = strrchr(tmpString, '.')) != NULL) {
181 i = 0;
182 while (tmpPtr[i+1] != '\0') {
183 if (cd->splitcnt < 1)
184 strcat(out, (char *) &tmpPtr[i+1]);
185 else
186 strncat(out, (char *) &tmpPtr[i+1],
187 cd->splitcnt);
188 strncat(out, (char *) &cd->pathsep, 1);
189 if (cd->splitcnt == 0)
190 break;
191 if (strlen((char *) &tmpPtr[i+1]) <=
192 (unsigned int) cd->splitcnt)
193 break;
194 i += cd->splitcnt;
196 tmpPtr[0] = '\0';
199 /* handle the "first" label properly */
200 i=0;
201 tmpPtr = tmpString;
202 while (tmpPtr[i] != '\0') {
203 if (cd->splitcnt < 1)
204 strcat(out, (char *) &tmpPtr[i]);
205 else
206 strncat(out, (char *) &tmpPtr[i], cd->splitcnt);
207 strncat(out, (char *) &cd->pathsep, 1);
208 if (cd->splitcnt == 0)
209 break;
210 if (strlen((char *) &tmpPtr[i]) <=
211 (unsigned int) cd->splitcnt)
212 break;
213 i += cd->splitcnt;
216 free(tmpString);
217 return (ISC_R_SUCCESS);
221 * Checks to make sure zone and host are safe. If safe, then
222 * hashes zone and host strings to build a path. If zone / host
223 * are not safe an error is returned.
226 static isc_result_t
227 create_path(const char *zone, const char *host, const char *client,
228 config_data_t *cd, char **path)
231 char *tmpPath;
232 int pathsize;
233 int len;
234 isc_result_t result;
235 isc_boolean_t isroot = ISC_FALSE;
237 /* special case for root zone */
238 if (strcmp(zone, ".") == 0)
239 isroot = ISC_TRUE;
241 /* if the requested zone is "unsafe", return error */
242 if (!isroot && !is_safe(zone))
243 return (ISC_R_FAILURE);
245 /* if host was passed, verify that it is safe */
246 if (host != NULL && !is_safe(host))
247 return (ISC_R_FAILURE);
249 /* if client was passed, verify that it is safe */
250 if (client != NULL && !is_safe(client))
251 return (ISC_R_FAILURE);
253 /* Determine how much memory the split up string will require */
254 if (host != NULL)
255 len = strlen(zone) + strlen(host);
256 else if (client != NULL)
257 len = strlen(zone) + strlen(client);
258 else
259 len = strlen(zone);
262 * even though datadir and xfrdir will never be in the same
263 * string we only waste a few bytes by allocating for both,
264 * and then we are safe from buffer overruns.
266 pathsize = len + cd->basedirsize +
267 cd->datadirsize + cd->xfrdirsize + 4;
269 /* if we are splitting names, we will need extra space. */
270 if (cd->splitcnt > 0)
271 pathsize += len/cd->splitcnt;
273 tmpPath = malloc(pathsize * sizeof(char));
274 if (tmpPath == NULL) {
275 /* write error message */
276 cd->log(ISC_LOG_ERROR,
277 "Filesystem driver unable to "
278 "allocate memory in create_path().");
279 result = ISC_R_NOMEMORY;
280 goto cleanup_mem;
284 * build path string.
285 * start out with base directory.
287 strcpy(tmpPath, cd->basedir);
289 /* add zone name - parsed properly */
290 if (!isroot) {
291 result = create_path_helper(tmpPath, zone, cd);
292 if (result != ISC_R_SUCCESS)
293 goto cleanup_mem;
297 * When neither client or host is passed we are building a
298 * path to see if a zone is supported. We require that a zone
299 * path have the "data dir" directory contained within it so
300 * that we know this zone is really supported. Otherwise,
301 * this zone may not really be supported because we are
302 * supporting a delagated sub zone.
304 * Example:
306 * We are supporting long.domain.com and using a splitcnt of
307 * 0. the base dir is "/base-dir/" and the data dir is
308 * "/.datadir" We want to see if we are authoritative for
309 * domain.com. Path /base-dir/com/domain/.datadir since
310 * /base-dir/com/domain/.datadir does not exist, we are not
311 * authoritative for the domain "domain.com". However we are
312 * authoritative for the domain "long.domain.com" because the
313 * path /base-dir/com/domain/long/.datadir does exist!
316 /* if client is passed append xfr dir, otherwise append data dir */
317 if (client != NULL) {
318 strcat(tmpPath, cd->xfrdir);
319 strncat(tmpPath, (char *) &cd->pathsep, 1);
320 strcat(tmpPath, client);
321 } else
322 strcat(tmpPath, cd->datadir);
324 /* if host not null, add it. */
325 if (host != NULL) {
326 strncat(tmpPath, (char *) &cd->pathsep, 1);
327 result = create_path_helper(tmpPath, host, cd);
328 if (result != ISC_R_SUCCESS)
329 goto cleanup_mem;
332 /* return the path we built. */
333 *path = tmpPath;
335 /* return success */
336 result = ISC_R_SUCCESS;
338 cleanup_mem:
339 /* cleanup memory */
341 /* free tmpPath memory */
342 if (tmpPath != NULL && result != ISC_R_SUCCESS)
343 free(tmpPath);
345 return (result);
348 static isc_result_t
349 process_dir(dir_t *dir, void *passback, config_data_t *cd,
350 dlist_t *dir_list, unsigned int basedirlen)
353 char tmp[DIR_PATHMAX + DIR_NAMEMAX];
354 int astPos;
355 struct stat sb;
356 isc_result_t result = ISC_R_FAILURE;
357 char *endp;
358 char *type;
359 char *ttlStr;
360 char *data;
361 char host[DIR_NAMEMAX];
362 char *tmpString;
363 char *tmpPtr;
364 int ttl;
365 int i;
366 int len;
367 dir_entry_t *direntry;
368 isc_boolean_t foundHost;
370 tmp[0] = '\0'; /* set 1st byte to '\0' so strcpy works right. */
371 host[0] = '\0';
372 foundHost = ISC_FALSE;
374 /* copy base directory name to tmp. */
375 strcpy(tmp, dir->dirname);
377 /* dir->dirname will always have '*' as the last char. */
378 astPos = strlen(dir->dirname) - 1;
380 /* if dir_list != NULL, were are performing a zone xfr */
381 if (dir_list != NULL) {
382 /* if splitcnt == 0, determine host from path. */
383 if (cd->splitcnt == 0) {
384 if (strlen(tmp) - 3 > basedirlen) {
385 tmp[astPos-1] = '\0';
386 tmpString = (char *) &tmp[basedirlen+1];
387 /* handle filesystem's special wildcard "-" */
388 if (strcmp(tmpString, "-") == 0) {
389 strcpy(host, "*");
390 } else {
392 * not special wildcard -- normal name
394 while ((tmpPtr = strrchr(tmpString,
395 cd->pathsep))
396 != NULL)
398 if ((strlen(host) +
399 strlen(tmpPtr + 1) + 2)
400 > DIR_NAMEMAX)
401 continue;
402 strcat(host, tmpPtr + 1);
403 strcat(host, ".");
404 tmpPtr[0] = '\0';
406 if ((strlen(host) +
407 strlen(tmpString) + 1)
408 <= DIR_NAMEMAX)
409 strcat(host, tmpString);
412 foundHost = ISC_TRUE;
413 /* set tmp again for use later */
414 strcpy(tmp, dir->dirname);
416 } else {
418 * if splitcnt != 0 determine host from
419 * ".host" directory entry
421 while (dir_read(dir) == ISC_R_SUCCESS) {
422 if (strncasecmp(".host",
423 dir->entry.name, 5) == 0) {
425 * handle filesystem's special
426 * wildcard "-"
428 if (strcmp((char *) &dir->entry.name[6],
429 "-") == 0)
430 strcpy(host, "*");
431 else {
432 strncpy(host,
433 (char *) &dir->entry.name[6],
434 sizeof(host) - 1);
435 host[255] = '\0';
437 foundHost = ISC_TRUE;
438 break;
441 /* reset dir list for use later */
442 dir_reset(dir);
443 } /* end of else */
446 while (dir_read(dir) == ISC_R_SUCCESS) {
447 cd->log(ISC_LOG_DEBUG(1),
448 "Filesystem driver Dir name:"
449 " '%s' Dir entry: '%s'\n",
450 dir->dirname, dir->entry.name);
452 /* skip any entries starting with "." */
453 if (dir->entry.name[0] == '.')
454 continue;
457 * get rid of '*', set to NULL. Effectively trims
458 * string from previous loop to base directory only
459 * while still leaving memory for concat to be
460 * performed next.
463 tmp[astPos] = '\0';
465 /* add name to base directory name. */
466 strcat(tmp, dir->entry.name);
468 /* make sure we can stat entry */
469 if (stat(tmp, &sb) == 0 ) {
470 /* if entry is a directory */
471 if ((sb.st_mode & S_IFDIR) != 0) {
473 * if dir list is NOT NULL, add dir to
474 * dir list
476 if (dir_list != NULL) {
477 direntry = malloc(sizeof(dir_entry_t));
478 if (direntry == NULL)
479 return (ISC_R_NOMEMORY);
480 strcpy(direntry->dirpath, tmp);
481 DLZ_LINK_INIT(direntry, link);
482 DLZ_LIST_APPEND(*dir_list, direntry,
483 link);
484 result = ISC_R_SUCCESS;
486 continue;
489 * if entry is a file be sure we do
490 * not add entry to DNS results if we
491 * are performing a zone xfr and we
492 * could not find a host entry.
495 } else if (dir_list != NULL &&
496 foundHost == ISC_FALSE) {
497 continue;
499 } else /* if we cannot stat entry, skip it. */
500 continue;
502 type = dir->entry.name;
503 ttlStr = strchr(type, cd->separator);
504 if (ttlStr == NULL) {
505 cd->log(ISC_LOG_ERROR,
506 "Filesystem driver: "
507 "%s could not be parsed properly", tmp);
508 return (ISC_R_FAILURE);
511 /* replace separator char with NULL to split string */
512 ttlStr[0] = '\0';
513 /* start string after NULL of previous string */
514 ttlStr = (char *) &ttlStr[1];
516 data = strchr(ttlStr, cd->separator);
517 if (data == NULL) {
518 cd->log(ISC_LOG_ERROR,
519 "Filesystem driver: "
520 "%s could not be parsed properly", tmp);
521 return (ISC_R_FAILURE);
524 /* replace separator char with NULL to split string */
525 data[0] = '\0';
527 /* start string after NULL of previous string */
528 data = (char *) &data[1];
530 /* replace all cd->separator chars with a space. */
531 len = strlen(data);
533 for (i=0; i < len; i++) {
534 if (data[i] == cd->separator)
535 data[i] = ' ';
538 /* convert text to int, make sure it worked right */
539 ttl = strtol(ttlStr, &endp, 10);
540 if (*endp != '\0' || ttl < 0)
541 cd->log(ISC_LOG_ERROR,
542 "Filesystem driver "
543 "ttl must be a postive number");
545 /* pass data back to Bind */
546 if (dir_list == NULL)
547 result = cd->putrr((dns_sdlzlookup_t *) passback,
548 type, ttl, data);
549 else
550 result = cd->putnamedrr((dns_sdlzallnodes_t *) passback,
551 (char *) host,
552 type, ttl, data);
554 /* if error, return error right away */
555 if (result != ISC_R_SUCCESS)
556 return (result);
557 } /* end of while loop */
559 return (result);
563 * DLZ methods
565 isc_result_t
566 dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
567 isc_result_t result;
568 char *path;
569 struct stat sb;
570 config_data_t *cd;
571 path = NULL;
573 cd = (config_data_t *) dbdata;
575 if (create_path(name, NULL, client, cd, &path) != ISC_R_SUCCESS) {
576 return (ISC_R_NOTFOUND);
579 if (stat(path, &sb) != 0) {
580 result = ISC_R_NOTFOUND;
581 goto complete_AXFR;
584 if ((sb.st_mode & S_IFREG) != 0) {
585 result = ISC_R_SUCCESS;
586 goto complete_AXFR;
589 result = ISC_R_NOTFOUND;
591 complete_AXFR:
592 free(path);
593 return (result);
596 isc_result_t
597 dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) {
598 isc_result_t result;
599 dlist_t *dir_list;
600 config_data_t *cd = (config_data_t *) dbdata;
601 char *basepath;
602 unsigned int basepathlen;
603 struct stat sb;
604 dir_t dir;
605 dir_entry_t *dir_entry;
606 dir_entry_t *next_de;
608 basepath = NULL;
609 dir_list = NULL;
611 /* allocate memory for list */
612 dir_list = malloc(sizeof(dlist_t));
613 if (dir_list == NULL) {
614 result = ISC_R_NOTFOUND;
615 goto complete_allnds;
618 /* initialize list */
619 DLZ_LIST_INIT(*dir_list);
621 if (create_path(zone, NULL, NULL, cd, &basepath) != ISC_R_SUCCESS) {
622 return (ISC_R_NOTFOUND);
625 /* remove path separator at end of path so stat works properly */
626 basepathlen = strlen(basepath);
628 if (stat(basepath, &sb) != 0) {
629 result = ISC_R_NOTFOUND;
630 goto complete_allnds;
633 if ((sb.st_mode & S_IFDIR) == 0) {
634 result = ISC_R_NOTFOUND;
635 goto complete_allnds;
638 /* initialize and open directory */
639 dir_init(&dir);
640 result = dir_open(&dir, basepath);
642 /* if directory open failed, return error. */
643 if (result != ISC_R_SUCCESS) {
644 cd->log(ISC_LOG_ERROR,
645 "Unable to open %s directory to read entries.",
646 basepath);
647 result = ISC_R_FAILURE;
648 goto complete_allnds;
651 /* process the directory */
652 result = process_dir(&dir, allnodes, cd, dir_list, basepathlen);
654 /* close the directory */
655 dir_close(&dir);
657 if (result != ISC_R_SUCCESS)
658 goto complete_allnds;
660 /* get first dir entry from list. */
661 dir_entry = DLZ_LIST_HEAD(*dir_list);
662 while (dir_entry != NULL) {
663 result = dir_open(&dir, dir_entry->dirpath);
664 /* if directory open failed, return error. */
665 if (result != ISC_R_SUCCESS) {
666 cd->log(ISC_LOG_ERROR,
667 "Unable to open %s "
668 "directory to read entries.", basepath);
669 result = ISC_R_FAILURE;
670 goto complete_allnds;
673 /* process the directory */
674 result = process_dir(&dir, allnodes, cd, dir_list, basepathlen);
676 /* close the directory */
677 dir_close(&dir);
679 if (result != ISC_R_SUCCESS)
680 goto complete_allnds;
682 dir_entry = DLZ_LIST_NEXT(dir_entry, link);
683 } /* end while */
685 complete_allnds:
686 if (dir_list != NULL) {
687 /* clean up entries from list. */
688 dir_entry = DLZ_LIST_HEAD(*dir_list);
689 while (dir_entry != NULL) {
690 next_de = DLZ_LIST_NEXT(dir_entry, link);
691 free(dir_entry);
692 dir_entry = next_de;
693 } /* end while */
694 free(dir_list);
697 if (basepath != NULL)
698 free(basepath);
700 return (result);
703 #if DLZ_DLOPEN_VERSION < 3
704 isc_result_t
705 dlz_findzonedb(void *dbdata, const char *name)
706 #else
707 isc_result_t
708 dlz_findzonedb(void *dbdata, const char *name,
709 dns_clientinfomethods_t *methods,
710 dns_clientinfo_t *clientinfo)
711 #endif
714 isc_result_t result;
715 config_data_t *cd = (config_data_t *) dbdata;
716 char *path;
717 struct stat sb;
718 path = NULL;
720 #if DLZ_DLOPEN_VERSION >= 3
721 UNUSED(methods);
722 UNUSED(clientinfo);
723 #endif
725 if (create_path(name, NULL, NULL, cd, &path) != ISC_R_SUCCESS)
726 return (ISC_R_NOTFOUND);
728 cd->log(ISC_LOG_DEBUG(1),
729 "Filesystem driver Findzone() Checking for path: '%s'\n", path);
731 if (stat(path, &sb) != 0) {
732 result = ISC_R_NOTFOUND;
733 goto complete_FZ;
736 if ((sb.st_mode & S_IFDIR) != 0) {
737 result = ISC_R_SUCCESS;
738 goto complete_FZ;
741 result = ISC_R_NOTFOUND;
743 complete_FZ:
745 free(path);
746 return (result);
749 #if DLZ_DLOPEN_VERSION == 1
750 isc_result_t
751 dlz_lookup(const char *zone, const char *name,
752 void *dbdata, dns_sdlzlookup_t *lookup)
753 #else
754 isc_result_t
755 dlz_lookup(const char *zone, const char *name,
756 void *dbdata, dns_sdlzlookup_t *lookup,
757 dns_clientinfomethods_t *methods,
758 dns_clientinfo_t *clientinfo)
759 #endif
761 isc_result_t result = ISC_R_NOTFOUND;
762 config_data_t *cd = (config_data_t *) dbdata;
763 char *path;
764 struct stat sb;
765 dir_t dir;
766 path = NULL;
768 UNUSED(lookup);
769 #if DLZ_DLOPEN_VERSION >= 2
770 UNUSED(methods);
771 UNUSED(clientinfo);
772 #endif
774 if (strcmp(name, "*") == 0)
776 * handle filesystem's special wildcard "-"
778 result = create_path(zone, "-", NULL, cd, &path);
779 else
780 result = create_path(zone, name, NULL, cd, &path);
782 if (result != ISC_R_SUCCESS)
783 return (ISC_R_NOTFOUND);
785 /* remove path separator at end of path so stat works properly */
786 path[strlen(path)-1] = '\0';
788 cd->log(ISC_LOG_DEBUG(1),
789 "Filesystem driver lookup() Checking for path: '%s'\n", path);
791 if (stat(path, &sb) != 0) {
792 result = ISC_R_NOTFOUND;
793 goto complete_lkup;
796 if ((sb.st_mode & S_IFDIR) == 0) {
797 result = ISC_R_NOTFOUND;
798 goto complete_lkup;
801 /* initialize and open directory */
802 dir_init(&dir);
803 result = dir_open(&dir, path);
805 /* if directory open failed, return error. */
806 if (result != ISC_R_SUCCESS) {
807 cd->log(ISC_LOG_ERROR,
808 "Unable to open %s directory to read entries.", path);
809 result = ISC_R_FAILURE;
810 goto complete_lkup;
813 /* process any records in the directory */
814 result = process_dir(&dir, lookup, cd, NULL, 0);
816 /* close the directory */
817 dir_close(&dir);
819 complete_lkup:
821 free(path);
822 return (result);
825 isc_result_t
826 dlz_create(const char *dlzname, unsigned int argc, char *argv[],
827 void **dbdata, ...)
829 config_data_t *cd;
830 char *endp;
831 int len;
832 char pathsep;
833 const char *helper_name;
834 va_list ap;
836 UNUSED(dlzname);
838 /* allocate memory for our config data and helper functions */
839 cd = calloc(1, sizeof(config_data_t));
840 if (cd == NULL)
841 goto no_mem;
843 /* zero the memory */
844 memset(cd, 0, sizeof(config_data_t));
846 /* Fill in the helper functions */
847 va_start(ap, dbdata);
848 while ((helper_name = va_arg(ap, const char*)) != NULL)
849 b9_add_helper(cd, helper_name, va_arg(ap, void*));
850 va_end(ap);
852 /* we require 5 command line args. */
853 if (argc != 6) {
854 cd->log(ISC_LOG_ERROR,
855 "Filesystem driver requires "
856 "6 command line args.");
857 return (ISC_R_FAILURE);
860 if (strlen(argv[5]) > 1) {
861 cd->log(ISC_LOG_ERROR,
862 "Filesystem driver can only "
863 "accept a single character for separator.");
864 return (ISC_R_FAILURE);
867 /* verify base dir ends with '/' or '\' */
868 len = strlen(argv[1]);
869 if (argv[1][len-1] != '\\' && argv[1][len-1] != '/') {
870 cd->log(ISC_LOG_ERROR,
871 "Base dir parameter for filesystem driver "
872 "should end with %s",
873 "either '/' or '\\' ");
874 return (ISC_R_FAILURE);
877 /* determine and save path separator for later */
878 if (argv[1][len-1] == '\\')
879 pathsep = '\\';
880 else
881 pathsep = '/';
883 cd->pathsep = pathsep;
885 /* get and store our base directory */
886 cd->basedir = strdup(argv[1]);
887 if (cd->basedir == NULL)
888 goto no_mem;
889 cd->basedirsize = strlen(cd->basedir);
891 /* get and store our data sub-dir */
892 cd->datadir = strdup(argv[2]);
893 if (cd->datadir == NULL)
894 goto no_mem;
895 cd->datadirsize = strlen(cd->datadir);
897 /* get and store our zone xfr sub-dir */
898 cd->xfrdir = strdup(argv[3]);
899 if (cd->xfrdir == NULL)
900 goto no_mem;
901 cd->xfrdirsize = strlen(cd->xfrdir);
903 /* get and store our directory split count */
904 cd->splitcnt = strtol(argv[4], &endp, 10);
905 if (*endp != '\0' || cd->splitcnt < 0)
906 cd->log(ISC_LOG_ERROR,
907 "Directory split count must be zero (0) "
908 "or a postive number");
910 /* get and store our separator character */
911 cd->separator = *argv[5];
913 /* pass back config data */
914 *dbdata = cd;
916 /* return success */
917 return (ISC_R_SUCCESS);
919 /* handle no memory error */
920 no_mem:
922 /* write error message */
923 if (cd != NULL && cd->log != NULL)
924 cd->log(ISC_LOG_ERROR,
925 "filesystem_dynamic: Filesystem driver unable to "
926 "allocate memory for config data.");
928 /* if we allocated a config data object clean it up */
929 if (cd != NULL)
930 dlz_destroy(cd);
932 /* return error */
933 return (ISC_R_NOMEMORY);
936 void
937 dlz_destroy(void *dbdata) {
938 config_data_t *cd;
940 cd = (config_data_t *) dbdata;
943 * free memory for each section of config data that was
944 * allocated
946 if (cd->basedir != NULL)
947 free(cd->basedir);
949 if (cd->datadir != NULL)
950 free(cd->datadir);
952 if (cd->xfrdir != NULL)
953 free(cd->xfrdir);
955 /* free config data memory */
956 free(cd);
960 * Return the version of the API
963 dlz_version(unsigned int *flags) {
964 UNUSED(flags);
965 return (DLZ_DLOPEN_VERSION);
969 * Register a helper function from the bind9 dlz_dlopen driver
971 static void
972 b9_add_helper(struct config_data *cd, const char *helper_name, void *ptr) {
973 if (strcmp(helper_name, "log") == 0)
974 cd->log = (log_t *)ptr;
975 if (strcmp(helper_name, "putrr") == 0)
976 cd->putrr = (dns_sdlz_putrr_t *)ptr;
977 if (strcmp(helper_name, "putnamedrr") == 0)
978 cd->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr;
979 if (strcmp(helper_name, "writeable_zone") == 0)
980 cd->writeable_zone = (dns_dlz_writeablezone_t *)ptr;