etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / contrib / dlz / drivers / dlz_filesystem_driver.c
blob334e6eda7e478652ea45dfb58396299498b6fc2f
1 /* $NetBSD: dlz_filesystem_driver.c,v 1.6 2014/12/10 04:37:55 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) 1999-2001 Internet Software Consortium.
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.
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.
55 #ifdef DLZ_FILESYSTEM
57 #include <config.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <stdlib.h>
62 #include <sys/stat.h>
64 #include <dns/log.h>
65 #include <dns/sdlz.h>
66 #include <dns/result.h>
68 #include <isc/dir.h>
69 #include <isc/mem.h>
70 #include <isc/platform.h>
71 #include <isc/print.h>
72 #include <isc/result.h>
73 #include <isc/util.h>
75 #include <named/globals.h>
77 #include <dlz/dlz_filesystem_driver.h>
79 static dns_sdlzimplementation_t *dlz_fs = NULL;
81 typedef struct config_data {
82 char *basedir;
83 int basedirsize;
84 char *datadir;
85 int datadirsize;
86 char *xfrdir;
87 int xfrdirsize;
88 int splitcnt;
89 char separator;
90 char pathsep;
91 isc_mem_t *mctx;
92 } config_data_t;
94 typedef struct dir_entry dir_entry_t;
96 struct dir_entry {
97 char dirpath[ISC_DIR_PATHMAX];
98 ISC_LINK(dir_entry_t) link;
101 typedef ISC_LIST(dir_entry_t) dlist_t;
103 /* forward reference */
105 static void
106 fs_destroy(void *driverarg, void *dbdata);
109 * Private methods
112 static isc_boolean_t
113 is_safe(const char *input) {
114 unsigned int i;
115 unsigned int len = strlen(input);
117 /* check that only allowed characters are in the domain name */
118 for (i=0; i < len; i++) {
119 /* '.' is allowed, but has special requirements */
120 if (input[i] == '.') {
121 /* '.' is not allowed as first char */
122 if (i == 0)
123 return (ISC_FALSE);
124 /* '..', two dots together is not allowed. */
125 else if (input[i-1] == '.')
126 return (ISC_FALSE);
127 /* '.' is not allowed as last char */
128 if (i == len)
129 return (ISC_FALSE);
130 /* only 1 dot in ok location, continue at next char */
131 continue;
133 /* '-' is allowed, continue at next char */
134 if (input[i] == '-')
135 continue;
136 /* 0-9 is allowed, continue at next char */
137 if (input[i] >= '0' && input[i] <= '9')
138 continue;
139 /* A-Z uppercase is allowed, continue at next char */
140 if (input[i] >= 'A' && input[i] <= 'Z')
141 continue;
142 /* a-z lowercase is allowed, continue at next char */
143 if (input[i] >= 'a' && input[i] <= 'z')
144 continue;
147 * colon needs to be allowed for IPV6 client
148 * addresses. Not dangerous in domain names, as not a
149 * special char.
151 if (input[i] == ':')
152 continue;
155 * '@' needs to be allowed for in zone data. Not
156 * dangerous in domain names, as not a special char.
158 if (input[i] == '@')
159 continue;
162 * if we reach this point we have encountered a
163 * disallowed char!
165 return (ISC_FALSE);
167 /* everything ok. */
168 return (ISC_TRUE);
171 static isc_result_t
172 create_path_helper(char *out, const char *in, config_data_t *cd) {
173 char *tmpString;
174 char *tmpPtr;
175 int i;
177 tmpString = isc_mem_strdup(ns_g_mctx, in);
178 if (tmpString == NULL)
179 return (ISC_R_NOMEMORY);
182 * don't forget is_safe guarantees '.' will NOT be the
183 * first/last char
185 while ((tmpPtr = strrchr(tmpString, '.')) != NULL) {
186 i = 0;
187 while (tmpPtr[i+1] != '\0') {
188 if (cd->splitcnt < 1)
189 strcat(out, (char *) &tmpPtr[i+1]);
190 else
191 strncat(out, (char *) &tmpPtr[i+1],
192 cd->splitcnt);
193 strncat(out, (char *) &cd->pathsep, 1);
194 if (cd->splitcnt == 0)
195 break;
196 if (strlen((char *) &tmpPtr[i+1]) <=
197 (unsigned int) cd->splitcnt)
198 break;
199 i += cd->splitcnt;
201 tmpPtr[0] = '\0';
204 /* handle the "first" label properly */
205 i=0;
206 tmpPtr = tmpString;
207 while (tmpPtr[i] != '\0') {
208 if (cd->splitcnt < 1)
209 strcat(out, (char *) &tmpPtr[i]);
210 else
211 strncat(out, (char *) &tmpPtr[i], cd->splitcnt);
212 strncat(out, (char *) &cd->pathsep, 1);
213 if (cd->splitcnt == 0)
214 break;
215 if (strlen((char *) &tmpPtr[i]) <=
216 (unsigned int) cd->splitcnt)
217 break;
218 i += cd->splitcnt;
221 isc_mem_free(ns_g_mctx, tmpString);
222 return (ISC_R_SUCCESS);
226 * Checks to make sure zone and host are safe. If safe, then
227 * hashes zone and host strings to build a path. If zone / host
228 * are not safe an error is returned.
231 static isc_result_t
232 create_path(const char *zone, const char *host, const char *client,
233 config_data_t *cd, char **path)
236 char *tmpPath;
237 int pathsize;
238 int len;
239 isc_result_t result;
240 isc_boolean_t isroot = ISC_FALSE;
242 /* we require a zone & cd parameter */
243 REQUIRE(zone != NULL);
244 REQUIRE(cd != NULL);
245 /* require path to be a pointer to NULL */
246 REQUIRE(path != NULL && *path == NULL);
248 * client and host may both be NULL, but they can't both be
249 * NON-NULL
251 REQUIRE( (host == NULL && client == NULL) ||
252 (host != NULL && client == NULL) ||
253 (host == NULL && client != NULL) );
255 /* special case for root zone */
256 if (strcmp(zone, ".") == 0)
257 isroot = ISC_TRUE;
259 /* if the requested zone is "unsafe", return error */
260 if (!isroot && !is_safe(zone))
261 return (ISC_R_FAILURE);
263 /* if host was passed, verify that it is safe */
264 if (host != NULL && !is_safe(host))
265 return (ISC_R_FAILURE);
267 /* if client was passed, verify that it is safe */
268 if (client != NULL && !is_safe(client))
269 return (ISC_R_FAILURE);
271 /* Determine how much memory the split up string will require */
272 if (host != NULL)
273 len = strlen(zone) + strlen(host);
274 else if (client != NULL)
275 len = strlen(zone) + strlen(client);
276 else
277 len = strlen(zone);
280 * even though datadir and xfrdir will never be in the same
281 * string we only waste a few bytes by allocating for both,
282 * and then we are safe from buffer overruns.
284 pathsize = len + cd->basedirsize +
285 cd->datadirsize + cd->xfrdirsize + 4;
287 /* if we are splitting names, we will need extra space. */
288 if (cd->splitcnt > 0)
289 pathsize += len/cd->splitcnt;
291 tmpPath = isc_mem_allocate(ns_g_mctx , pathsize * sizeof(char));
292 if (tmpPath == NULL) {
293 /* write error message */
294 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
295 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
296 "Filesystem driver unable to "
297 "allocate memory in create_path().");
298 result = ISC_R_NOMEMORY;
299 goto cleanup_mem;
303 * build path string.
304 * start out with base directory.
306 strcpy(tmpPath, cd->basedir);
308 /* add zone name - parsed properly */
309 if (!isroot) {
310 result = create_path_helper(tmpPath, zone, cd);
311 if (result != ISC_R_SUCCESS)
312 goto cleanup_mem;
316 * When neither client or host is passed we are building a
317 * path to see if a zone is supported. We require that a zone
318 * path have the "data dir" directory contained within it so
319 * that we know this zone is really supported. Otherwise,
320 * this zone may not really be supported because we are
321 * supporting a delagated sub zone.
323 * Example:
325 * We are supporting long.domain.com and using a splitcnt of
326 * 0. the base dir is "/base-dir/" and the data dir is
327 * "/.datadir" We want to see if we are authoritative for
328 * domain.com. Path /base-dir/com/domain/.datadir since
329 * /base-dir/com/domain/.datadir does not exist, we are not
330 * authoritative for the domain "domain.com". However we are
331 * authoritative for the domain "long.domain.com" because the
332 * path /base-dir/com/domain/long/.datadir does exist!
335 /* if client is passed append xfr dir, otherwise append data dir */
336 if (client != NULL) {
337 strcat(tmpPath, cd->xfrdir);
338 strncat(tmpPath, (char *) &cd->pathsep, 1);
339 strcat(tmpPath, client);
340 } else {
341 strcat(tmpPath, cd->datadir);
344 /* if host not null, add it. */
345 if (host != NULL) {
346 strncat(tmpPath, (char *) &cd->pathsep, 1);
347 if ((result = create_path_helper(tmpPath, host,
348 cd)) != ISC_R_SUCCESS)
349 goto cleanup_mem;
352 /* return the path we built. */
353 *path = tmpPath;
355 /* return success */
356 result = ISC_R_SUCCESS;
358 cleanup_mem:
359 /* cleanup memory */
361 /* free tmpPath memory */
362 if (tmpPath != NULL && result != ISC_R_SUCCESS)
363 isc_mem_free(ns_g_mctx, tmpPath);
365 /* free tmpPath memory */
366 return (result);
369 static isc_result_t
370 process_dir(isc_dir_t *dir, void *passback, config_data_t *cd,
371 dlist_t *dir_list, unsigned int basedirlen)
374 char tmp[ISC_DIR_PATHMAX + ISC_DIR_NAMEMAX];
375 int astPos;
376 struct stat sb;
377 isc_result_t result = ISC_R_FAILURE;
378 char *endp;
379 char *type;
380 char *ttlStr;
381 char *data;
382 char host[ISC_DIR_NAMEMAX];
383 char *tmpString;
384 char *tmpPtr;
385 int ttl;
386 int i;
387 int len;
388 dir_entry_t *direntry;
389 isc_boolean_t foundHost;
391 tmp[0] = '\0'; /* set 1st byte to '\0' so strcpy works right. */
392 host[0] = '\0';
393 foundHost = ISC_FALSE;
395 /* copy base directory name to tmp. */
396 strcpy(tmp, dir->dirname);
398 /* dir->dirname will always have '*' as the last char. */
399 astPos = strlen(dir->dirname) - 1;
401 /* if dir_list != NULL, were are performing a zone xfr */
402 if (dir_list != NULL) {
403 /* if splitcnt == 0, determine host from path. */
404 if (cd->splitcnt == 0) {
405 if (strlen(tmp) - 3 > basedirlen) {
406 tmp[astPos-1] = '\0';
407 tmpString = (char *) &tmp[basedirlen+1];
408 /* handle filesystem's special wildcard "-" */
409 if (strcmp(tmpString, "-") == 0) {
410 strcpy(host, "*");
411 } else {
413 * not special wildcard -- normal name
415 while ((tmpPtr = strrchr(tmpString,
416 cd->pathsep))
417 != NULL)
419 if ((strlen(host) +
420 strlen(tmpPtr + 1) + 2)
421 > ISC_DIR_NAMEMAX)
422 continue;
423 strcat(host, tmpPtr + 1);
424 strcat(host, ".");
425 tmpPtr[0] = '\0';
427 if ((strlen(host) +
428 strlen(tmpString) + 1)
429 <= ISC_DIR_NAMEMAX)
430 strcat(host, tmpString);
433 foundHost = ISC_TRUE;
434 /* set tmp again for use later */
435 strcpy(tmp, dir->dirname);
437 } else {
439 * if splitcnt != 0 determine host from
440 * ".host" directory entry
442 while (isc_dir_read(dir) == ISC_R_SUCCESS) {
443 if (strncasecmp(".host",
444 dir->entry.name, 5) == 0) {
446 * handle filesystem's special
447 * wildcard "-"
449 if (strcmp((char *) &dir->entry.name[6],
450 "-") == 0)
451 strcpy(host, "*");
452 else {
453 strncpy(host,
454 (char *) &dir->entry.name[6],
455 sizeof(host) - 1);
456 host[255] = '\0';
458 foundHost = ISC_TRUE;
459 break;
462 /* reset dir list for use later */
463 isc_dir_reset(dir);
464 } /* end of else */
467 while (isc_dir_read(dir) == ISC_R_SUCCESS) {
469 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
470 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
471 "Filesystem driver Dir name:"
472 " '%s' Dir entry: '%s'\n",
473 dir->dirname, dir->entry.name);
475 /* skip any entries starting with "." */
476 if (dir->entry.name[0] == '.')
477 continue;
480 * get rid of '*', set to NULL. Effectively trims
481 * string from previous loop to base directory only
482 * while still leaving memory for concat to be
483 * performed next.
486 tmp[astPos] = '\0';
488 /* add name to base directory name. */
489 strcat(tmp, dir->entry.name);
491 /* make sure we can stat entry */
492 if (stat(tmp, &sb) == 0 ) {
493 /* if entry is a directory */
494 if ((sb.st_mode & S_IFDIR) != 0) {
496 * if dir list is NOT NULL, add dir to
497 * dir list
499 if (dir_list != NULL) {
500 direntry =
501 isc_mem_get(ns_g_mctx,
502 sizeof(dir_entry_t));
503 if (direntry == NULL)
504 return (ISC_R_NOMEMORY);
505 strcpy(direntry->dirpath, tmp);
506 ISC_LINK_INIT(direntry, link);
507 ISC_LIST_APPEND(*dir_list, direntry,
508 link);
509 result = ISC_R_SUCCESS;
511 continue;
514 * if entry is a file be sure we do
515 * not add entry to DNS results if we
516 * are performing a zone xfr and we
517 * could not find a host entry.
520 } else if (dir_list != NULL &&
521 foundHost == ISC_FALSE) {
522 continue;
524 } else /* if we cannot stat entry, skip it. */
525 continue;
527 type = dir->entry.name;
528 ttlStr = strchr(type, cd->separator);
529 if (ttlStr == NULL) {
530 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
531 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
532 "Filesystem driver: "
533 "%s could not be parsed properly",
534 tmp);
535 return (ISC_R_FAILURE);
538 /* replace separator char with NULL to split string */
539 ttlStr[0] = '\0';
540 /* start string after NULL of previous string */
541 ttlStr = (char *) &ttlStr[1];
543 data = strchr(ttlStr, cd->separator);
544 if (data == NULL) {
545 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
546 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
547 "Filesystem driver: "
548 "%s could not be parsed properly",
549 tmp);
550 return (ISC_R_FAILURE);
553 /* replace separator char with NULL to split string */
554 data[0] = '\0';
556 /* start string after NULL of previous string */
557 data = (char *) &data[1];
559 /* replace all cd->separator chars with a space. */
560 len = strlen(data);
562 for (i=0; i < len; i++) {
563 if (data[i] == cd->separator)
564 data[i] = ' ';
567 /* convert text to int, make sure it worked right */
568 ttl = strtol(ttlStr, &endp, 10);
569 if (*endp != '\0' || ttl < 0) {
570 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
571 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
572 "Filesystem driver "
573 "ttl must be a postive number");
576 /* pass data back to Bind */
577 if (dir_list == NULL)
578 result = dns_sdlz_putrr((dns_sdlzlookup_t *) passback,
579 type, ttl, data);
580 else
581 result = dns_sdlz_putnamedrr((dns_sdlzallnodes_t *)
582 passback,
583 (char *) host,
584 type, ttl, data);
586 /* if error, return error right away */
587 if (result != ISC_R_SUCCESS)
588 return (result);
589 } /* end of while loop */
591 return (result);
595 * SDLZ interface methods
598 static isc_result_t
599 fs_allowzonexfr(void *driverarg, void *dbdata, const char *name,
600 const char *client)
603 isc_result_t result;
604 char *path;
605 struct stat sb;
606 config_data_t *cd;
607 path = NULL;
609 UNUSED(driverarg);
611 cd = (config_data_t *) dbdata;
613 if (create_path(name, NULL, client, cd, &path) != ISC_R_SUCCESS) {
614 return (ISC_R_NOTFOUND);
617 if (stat(path, &sb) != 0) {
618 result = ISC_R_NOTFOUND;
619 goto complete_AXFR;
622 if ((sb.st_mode & S_IFREG) != 0) {
623 result = ISC_R_SUCCESS;
624 goto complete_AXFR;
627 result = ISC_R_NOTFOUND;
629 complete_AXFR:
630 isc_mem_free(ns_g_mctx, path);
631 return (result);
634 static isc_result_t
635 fs_allnodes(const char *zone, void *driverarg, void *dbdata,
636 dns_sdlzallnodes_t *allnodes)
639 isc_result_t result;
640 dlist_t *dir_list;
641 config_data_t *cd;
642 char *basepath;
643 unsigned int basepathlen;
644 struct stat sb;
645 isc_dir_t dir;
646 dir_entry_t *dir_entry;
647 dir_entry_t *next_de;
649 basepath = NULL;
650 dir_list = NULL;
652 UNUSED(driverarg);
653 UNUSED(allnodes);
655 cd = (config_data_t *) dbdata;
657 /* allocate memory for list */
658 dir_list = isc_mem_get(ns_g_mctx, sizeof(dlist_t));
659 if (dir_list == NULL) {
660 result = ISC_R_NOTFOUND;
661 goto complete_allnds;
664 /* initialize list */
665 ISC_LIST_INIT(*dir_list);
667 if (create_path(zone, NULL, NULL, cd, &basepath) != ISC_R_SUCCESS) {
668 return (ISC_R_NOTFOUND);
671 /* remove path separator at end of path so stat works properly */
672 basepathlen = strlen(basepath);
674 if (stat(basepath, &sb) != 0) {
675 result = ISC_R_NOTFOUND;
676 goto complete_allnds;
679 if ((sb.st_mode & S_IFDIR) == 0) {
680 result = ISC_R_NOTFOUND;
681 goto complete_allnds;
684 /* initialize and open directory */
685 isc_dir_init(&dir);
686 result = isc_dir_open(&dir, basepath);
688 /* if directory open failed, return error. */
689 if (result != ISC_R_SUCCESS) {
690 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
691 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
692 "Unable to open %s directory to read entries.",
693 basepath);
694 result = ISC_R_FAILURE;
695 goto complete_allnds;
698 /* process the directory */
699 result = process_dir(&dir, allnodes, cd, dir_list, basepathlen);
701 /* close the directory */
702 isc_dir_close(&dir);
704 if (result != ISC_R_SUCCESS)
705 goto complete_allnds;
707 /* get first dir entry from list. */
708 dir_entry = ISC_LIST_HEAD(*dir_list);
709 while (dir_entry != NULL) {
711 result = isc_dir_open(&dir, dir_entry->dirpath);
712 /* if directory open failed, return error. */
713 if (result != ISC_R_SUCCESS) {
714 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
715 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
716 "Unable to open %s "
717 "directory to read entries.",
718 basepath);
719 result = ISC_R_FAILURE;
720 goto complete_allnds;
723 /* process the directory */
724 result = process_dir(&dir, allnodes, cd, dir_list, basepathlen);
726 /* close the directory */
727 isc_dir_close(&dir);
729 if (result != ISC_R_SUCCESS)
730 goto complete_allnds;
732 dir_entry = ISC_LIST_NEXT(dir_entry, link);
733 } /* end while */
735 complete_allnds:
736 if (dir_list != NULL) {
737 /* clean up entries from list. */
738 dir_entry = ISC_LIST_HEAD(*dir_list);
739 while (dir_entry != NULL) {
740 next_de = ISC_LIST_NEXT(dir_entry, link);
741 isc_mem_put(ns_g_mctx, dir_entry, sizeof(dir_entry_t));
742 dir_entry = next_de;
743 } /* end while */
744 isc_mem_put(ns_g_mctx, dir_list, sizeof(dlist_t));
747 if (basepath != NULL)
748 isc_mem_free(ns_g_mctx, basepath);
750 return (result);
753 static isc_result_t
754 fs_findzone(void *driverarg, void *dbdata, const char *name,
755 dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
758 isc_result_t result;
759 char *path;
760 struct stat sb;
761 path = NULL;
763 UNUSED(driverarg);
764 UNUSED(methods);
765 UNUSED(clientinfo);
767 if (create_path(name, NULL, NULL, (config_data_t *) dbdata,
768 &path) != ISC_R_SUCCESS) {
769 return (ISC_R_NOTFOUND);
772 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
773 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
774 "Filesystem driver Findzone() Checking for path: '%s'\n",
775 path);
777 if (stat(path, &sb) != 0) {
778 result = ISC_R_NOTFOUND;
779 goto complete_FZ;
782 if ((sb.st_mode & S_IFDIR) != 0) {
783 result = ISC_R_SUCCESS;
784 goto complete_FZ;
787 result = ISC_R_NOTFOUND;
789 complete_FZ:
791 isc_mem_free(ns_g_mctx, path);
792 return (result);
795 static isc_result_t
796 fs_lookup(const char *zone, const char *name, void *driverarg,
797 void *dbdata, dns_sdlzlookup_t *lookup,
798 dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
800 isc_result_t result;
801 char *path;
802 struct stat sb;
803 isc_dir_t dir;
804 path = NULL;
806 UNUSED(driverarg);
807 UNUSED(lookup);
808 UNUSED(methods);
809 UNUSED(clientinfo);
811 if (strcmp(name, "*") == 0)
813 * handle filesystem's special wildcard "-"
815 result = create_path(zone, "-", NULL,
816 (config_data_t *) dbdata, &path);
817 else
818 result = create_path(zone, name, NULL,
819 (config_data_t *) dbdata, &path);
821 if ( result != ISC_R_SUCCESS) {
822 return (ISC_R_NOTFOUND);
825 /* remove path separator at end of path so stat works properly */
826 path[strlen(path)-1] = '\0';
828 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
829 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
830 "Filesystem driver lookup() Checking for path: '%s'\n",
831 path);
834 if (stat(path, &sb) != 0) {
835 result = ISC_R_NOTFOUND;
836 goto complete_lkup;
839 if ((sb.st_mode & S_IFDIR) == 0) {
840 result = ISC_R_NOTFOUND;
841 goto complete_lkup;
844 /* initialize and open directory */
845 isc_dir_init(&dir);
846 result = isc_dir_open(&dir, path);
848 /* if directory open failed, return error. */
849 if (result != ISC_R_SUCCESS) {
850 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
851 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
852 "Unable to open %s directory to read entries.",
853 path);
854 result = ISC_R_FAILURE;
855 goto complete_lkup;
858 /* process any records in the directory */
859 result = process_dir(&dir, lookup, (config_data_t *) dbdata, NULL, 0);
861 /* close the directory */
862 isc_dir_close(&dir);
864 complete_lkup:
866 isc_mem_free(ns_g_mctx, path);
867 return (result);
870 static isc_result_t
871 fs_create(const char *dlzname, unsigned int argc, char *argv[],
872 void *driverarg, void **dbdata)
874 config_data_t *cd;
875 char *endp;
876 int len;
877 char pathsep;
879 UNUSED(driverarg);
880 UNUSED(dlzname);
882 /* we require 5 command line args. */
883 if (argc != 6) {
884 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
885 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
886 "Filesystem driver requires "
887 "6 command line args.");
888 return (ISC_R_FAILURE);
891 if (strlen(argv[5]) > 1) {
892 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
893 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
894 "Filesystem driver can only "
895 "accept a single character for separator.");
896 return (ISC_R_FAILURE);
899 /* verify base dir ends with '/' or '\' */
900 len = strlen(argv[1]);
901 if (argv[1][len-1] != '\\' && argv[1][len-1] != '/') {
902 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
903 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
904 "Base dir parameter for filesystem driver "
905 "should end with %s",
906 "either '/' or '\\' ");
907 return (ISC_R_FAILURE);
910 /* determine and save path separator for later */
911 if (argv[1][len-1] == '\\')
912 pathsep = '\\';
913 else
914 pathsep = '/';
916 /* allocate memory for our config data */
917 cd = isc_mem_get(ns_g_mctx, sizeof(config_data_t));
918 if (cd == NULL)
919 goto no_mem;
921 /* zero the memory */
922 memset(cd, 0, sizeof(config_data_t));
924 cd->pathsep = pathsep;
926 /* get and store our base directory */
927 cd->basedir = isc_mem_strdup(ns_g_mctx, argv[1]);
928 if (cd->basedir == NULL)
929 goto no_mem;
930 cd->basedirsize = strlen(cd->basedir);
932 /* get and store our data sub-dir */
933 cd->datadir = isc_mem_strdup(ns_g_mctx, argv[2]);
934 if (cd->datadir == NULL)
935 goto no_mem;
936 cd->datadirsize = strlen(cd->datadir);
938 /* get and store our zone xfr sub-dir */
939 cd->xfrdir = isc_mem_strdup(ns_g_mctx, argv[3]);
940 if (cd->xfrdir == NULL)
941 goto no_mem;
942 cd->xfrdirsize = strlen(cd->xfrdir);
944 /* get and store our directory split count */
945 cd->splitcnt = strtol(argv[4], &endp, 10);
946 if (*endp != '\0' || cd->splitcnt < 0) {
947 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
948 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
949 "Directory split count must be zero (0) "
950 "or a postive number");
953 /* get and store our separator character */
954 cd->separator = *argv[5];
956 /* attach config data to memory context */
957 isc_mem_attach(ns_g_mctx, &cd->mctx);
959 /* pass back config data */
960 *dbdata = cd;
962 /* return success */
963 return (ISC_R_SUCCESS);
965 /* handle no memory error */
966 no_mem:
968 /* if we allocated a config data object clean it up */
969 if (cd != NULL)
970 fs_destroy(NULL, cd);
972 /* write error message */
973 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
974 DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
975 "Filesystem driver unable to "
976 "allocate memory for config data.");
978 /* return error */
979 return (ISC_R_NOMEMORY);
982 static void
983 fs_destroy(void *driverarg, void *dbdata)
985 isc_mem_t *mctx;
986 config_data_t *cd;
988 UNUSED(driverarg);
990 cd = (config_data_t *) dbdata;
993 * free memory for each section of config data that was
994 * allocated
996 if (cd->basedir != NULL)
997 isc_mem_free(ns_g_mctx, cd->basedir);
999 if (cd->datadir != NULL)
1000 isc_mem_free(ns_g_mctx, cd->datadir);
1002 if (cd->xfrdir != NULL)
1003 isc_mem_free(ns_g_mctx, cd->xfrdir);
1005 /* hold memory context to use later */
1006 mctx = cd->mctx;
1008 /* free config data memory */
1009 isc_mem_put(mctx, cd, sizeof(config_data_t));
1011 /* detach memory from context */
1012 isc_mem_detach(&mctx);
1015 static dns_sdlzmethods_t dlz_fs_methods = {
1016 fs_create,
1017 fs_destroy,
1018 fs_findzone,
1019 fs_lookup,
1020 NULL,
1021 fs_allnodes,
1022 fs_allowzonexfr,
1023 NULL,
1024 NULL,
1025 NULL,
1026 NULL,
1027 NULL,
1028 NULL,
1029 NULL,
1033 * Wrapper around dns_sdlzregister().
1035 isc_result_t
1036 dlz_fs_init(void)
1038 isc_result_t result;
1041 * Write debugging message to log
1043 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1044 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1045 "Registering DLZ filesystem driver.");
1047 result = dns_sdlzregister("filesystem", &dlz_fs_methods, NULL,
1048 DNS_SDLZFLAG_RELATIVEOWNER |
1049 DNS_SDLZFLAG_RELATIVERDATA,
1050 ns_g_mctx, &dlz_fs);
1051 if (result != ISC_R_SUCCESS) {
1052 UNEXPECTED_ERROR(__FILE__, __LINE__,
1053 "dns_sdlzregister() failed: %s",
1054 isc_result_totext(result));
1055 result = ISC_R_UNEXPECTED;
1058 return (result);
1062 * Wrapper around dns_sdlzunregister().
1064 void
1065 dlz_fs_clear(void) {
1068 * Write debugging message to log
1070 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1071 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1072 "Unregistering DLZ filesystem driver.");
1074 if (dlz_fs != NULL)
1075 dns_sdlzunregister(&dlz_fs);
1078 #endif