1 /* $NetBSD: tcldb.c,v 1.4 2014/12/10 04:37:57 christos Exp $ */
4 * Copyright (C) 2004, 2007, 2011, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: tcldb.c,v 1.12 2011/10/11 23:46:45 tbox Exp */
23 * A simple database driver that calls a Tcl procedure to define
24 * the contents of the DNS namespace. The procedure is loaded
25 * from the file lookup.tcl; look at the comments there for
37 #include <isc/print.h>
38 #include <isc/result.h>
44 #include <named/globals.h>
52 if (result != ISC_R_SUCCESS) return (result); \
53 } while (/*CONSTCOND*/0)
55 typedef struct tcldb_driver
{
60 static tcldb_driver_t
*the_driver
= NULL
;
62 static dns_sdbimplementation_t
*tcldb
= NULL
;
65 tcldb_driver_create(isc_mem_t
*mctx
, tcldb_driver_t
**driverp
) {
67 isc_result_t result
= ISC_R_SUCCESS
;
68 tcldb_driver_t
*driver
= isc_mem_get(mctx
, sizeof(tcldb_driver_t
));
70 return (ISC_R_NOMEMORY
);
72 driver
->interp
= Tcl_CreateInterp();
74 tclres
= Tcl_EvalFile(driver
->interp
, (char *) "lookup.tcl");
75 if (tclres
!= TCL_OK
) {
76 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
77 DNS_LOGMODULE_SDB
, ISC_LOG_ERROR
,
78 "initializing tcldb: "
79 "loading 'lookup.tcl' failed: %s",
80 driver
->interp
->result
);
81 result
= ISC_R_FAILURE
;
85 return (ISC_R_SUCCESS
);
88 isc_mem_put(mctx
, driver
, sizeof(tcldb_driver_t
));
94 tcldb_driver_destroy(tcldb_driver_t
**driverp
) {
95 tcldb_driver_t
*driver
= *driverp
;
96 Tcl_DeleteInterp(driver
->interp
);
97 isc_mem_put(driver
->mctx
, driver
, sizeof(tcldb_driver_t
));
101 * Perform a lookup, by invoking the Tcl procedure "lookup".
103 #ifdef DNS_CLIENTINFO_VERSION
105 tcldb_lookup(const char *zone
, const char *name
, void *dbdata
,
106 dns_sdblookup_t
*lookup
, dns_clientinfomethods_t
*methods
,
107 dns_clientinfo_t
*clientinfo
)
110 tcldb_lookup(const char *zone
, const char *name
, void *dbdata
,
111 dns_sdblookup_t
*lookup
)
112 #endif /* DNS_CLIENTINFO_VERSION */
114 isc_result_t result
= ISC_R_SUCCESS
;
116 int rrc
; /* RR count */
117 char **rrv
; /* RR vector */
122 #ifdef DNS_CLIENTINFO_VERSION
125 #endif /* DNS_CLIENTINFO_VERSION */
127 tcldb_driver_t
*driver
= (tcldb_driver_t
*) dbdata
;
132 cmd
= Tcl_Merge(3, cmdv
);
133 tclres
= Tcl_Eval(driver
->interp
, cmd
);
136 if (tclres
!= TCL_OK
) {
137 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
138 DNS_LOGMODULE_SDB
, ISC_LOG_ERROR
,
139 "zone '%s': tcl lookup function failed: %s",
140 zone
, driver
->interp
->result
);
141 return (ISC_R_FAILURE
);
144 if (strcmp(driver
->interp
->result
, "NXDOMAIN") == 0) {
145 result
= ISC_R_NOTFOUND
;
149 tclres
= Tcl_SplitList(driver
->interp
, driver
->interp
->result
,
151 if (tclres
!= TCL_OK
)
154 for (i
= 0; i
< rrc
; i
++) {
156 int fieldc
; /* Field count */
157 char **fieldv
; /* Field vector */
158 tclres
= Tcl_SplitList(driver
->interp
, rrv
[i
],
160 if (tclres
!= TCL_OK
) {
161 tmpres
= ISC_R_FAILURE
;
166 tmpres
= dns_sdb_putrr(lookup
, fieldv
[0], atoi(fieldv
[1]),
168 Tcl_Free((char *) fieldv
);
170 if (tmpres
!= ISC_R_SUCCESS
)
173 Tcl_Free((char *) rrv
);
174 if (result
== ISC_R_SUCCESS
)
178 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
179 DNS_LOGMODULE_SDB
, ISC_LOG_ERROR
,
181 "malformed return value from tcl lookup function: %s",
182 zone
, driver
->interp
->result
);
183 result
= ISC_R_FAILURE
;
189 * Set up per-zone state. In our case, the database arguments of the
190 * zone are collected into a Tcl list and assigned to an element of
191 * the global array "dbargs".
194 tcldb_create(const char *zone
, int argc
, char **argv
,
195 void *driverdata
, void **dbdata
)
197 tcldb_driver_t
*driver
= (tcldb_driver_t
*) driverdata
;
199 char *list
= Tcl_Merge(argc
, argv
);
201 Tcl_SetVar2(driver
->interp
, (char *) "dbargs", (char *) zone
, list
, 0);
205 *dbdata
= driverdata
;
207 return (ISC_R_SUCCESS
);
211 * This driver does not support zone transfer, so allnodes() is NULL.
213 static dns_sdbmethods_t tcldb_methods
= {
215 NULL
, /* authority */
223 * Initialize the tcldb driver.
228 int flags
= DNS_SDBFLAG_RELATIVEOWNER
| DNS_SDBFLAG_RELATIVERDATA
;
230 result
= tcldb_driver_create(ns_g_mctx
, &the_driver
);
231 if (result
!= ISC_R_SUCCESS
)
234 return (dns_sdb_register("tcl", &tcldb_methods
, the_driver
, flags
,
239 * Wrapper around dns_sdb_unregister().
244 dns_sdb_unregister(&tcldb
);
245 if (the_driver
!= NULL
)
246 tcldb_driver_destroy(&the_driver
);