xref: /minix3/external/bsd/bind/dist/contrib/sdb/tcl/tcldb.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: tcldb.c,v 1.4 2014/12/10 04:37:57 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004, 2007, 2011, 2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 2000, 2001  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id: tcldb.c,v 1.12 2011/10/11 23:46:45 tbox Exp  */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*
23*00b67f09SDavid van Moolenbroek  * A simple database driver that calls a Tcl procedure to define
24*00b67f09SDavid van Moolenbroek  * the contents of the DNS namespace.  The procedure is loaded
25*00b67f09SDavid van Moolenbroek  * from the file lookup.tcl; look at the comments there for
26*00b67f09SDavid van Moolenbroek  * more information.
27*00b67f09SDavid van Moolenbroek  */
28*00b67f09SDavid van Moolenbroek 
29*00b67f09SDavid van Moolenbroek #include <config.h>
30*00b67f09SDavid van Moolenbroek 
31*00b67f09SDavid van Moolenbroek #include <string.h>
32*00b67f09SDavid van Moolenbroek #include <stdlib.h>
33*00b67f09SDavid van Moolenbroek #include <unistd.h>
34*00b67f09SDavid van Moolenbroek #include <sys/stat.h>
35*00b67f09SDavid van Moolenbroek 
36*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
37*00b67f09SDavid van Moolenbroek #include <isc/print.h>
38*00b67f09SDavid van Moolenbroek #include <isc/result.h>
39*00b67f09SDavid van Moolenbroek #include <isc/util.h>
40*00b67f09SDavid van Moolenbroek 
41*00b67f09SDavid van Moolenbroek #include <dns/log.h>
42*00b67f09SDavid van Moolenbroek #include <dns/sdb.h>
43*00b67f09SDavid van Moolenbroek 
44*00b67f09SDavid van Moolenbroek #include <named/globals.h>
45*00b67f09SDavid van Moolenbroek 
46*00b67f09SDavid van Moolenbroek #include <tcl.h>
47*00b67f09SDavid van Moolenbroek 
48*00b67f09SDavid van Moolenbroek #include <tcldb.h>
49*00b67f09SDavid van Moolenbroek 
50*00b67f09SDavid van Moolenbroek #define CHECK(op)						\
51*00b67f09SDavid van Moolenbroek 	do { result = (op);					\
52*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) return (result);	\
53*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
54*00b67f09SDavid van Moolenbroek 
55*00b67f09SDavid van Moolenbroek typedef struct tcldb_driver {
56*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
57*00b67f09SDavid van Moolenbroek 	Tcl_Interp *interp;
58*00b67f09SDavid van Moolenbroek } tcldb_driver_t;
59*00b67f09SDavid van Moolenbroek 
60*00b67f09SDavid van Moolenbroek static tcldb_driver_t *the_driver = NULL;
61*00b67f09SDavid van Moolenbroek 
62*00b67f09SDavid van Moolenbroek static dns_sdbimplementation_t *tcldb = NULL;
63*00b67f09SDavid van Moolenbroek 
64*00b67f09SDavid van Moolenbroek static isc_result_t
tcldb_driver_create(isc_mem_t * mctx,tcldb_driver_t ** driverp)65*00b67f09SDavid van Moolenbroek tcldb_driver_create(isc_mem_t *mctx, tcldb_driver_t **driverp) {
66*00b67f09SDavid van Moolenbroek 	int tclres;
67*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
68*00b67f09SDavid van Moolenbroek 	tcldb_driver_t *driver = isc_mem_get(mctx, sizeof(tcldb_driver_t));
69*00b67f09SDavid van Moolenbroek 	if (driver == NULL)
70*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
71*00b67f09SDavid van Moolenbroek 	driver->mctx = mctx;
72*00b67f09SDavid van Moolenbroek 	driver->interp = Tcl_CreateInterp();
73*00b67f09SDavid van Moolenbroek 
74*00b67f09SDavid van Moolenbroek 	tclres = Tcl_EvalFile(driver->interp, (char *) "lookup.tcl");
75*00b67f09SDavid van Moolenbroek 	if (tclres != TCL_OK) {
76*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
77*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
78*00b67f09SDavid van Moolenbroek 			      "initializing tcldb: "
79*00b67f09SDavid van Moolenbroek 			      "loading 'lookup.tcl' failed: %s",
80*00b67f09SDavid van Moolenbroek 			      driver->interp->result);
81*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
82*00b67f09SDavid van Moolenbroek 		goto cleanup;
83*00b67f09SDavid van Moolenbroek 	}
84*00b67f09SDavid van Moolenbroek 	*driverp = driver;
85*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
86*00b67f09SDavid van Moolenbroek 
87*00b67f09SDavid van Moolenbroek  cleanup:
88*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, driver, sizeof(tcldb_driver_t));
89*00b67f09SDavid van Moolenbroek 	return (result);
90*00b67f09SDavid van Moolenbroek 
91*00b67f09SDavid van Moolenbroek }
92*00b67f09SDavid van Moolenbroek 
93*00b67f09SDavid van Moolenbroek static void
tcldb_driver_destroy(tcldb_driver_t ** driverp)94*00b67f09SDavid van Moolenbroek tcldb_driver_destroy(tcldb_driver_t **driverp) {
95*00b67f09SDavid van Moolenbroek 	tcldb_driver_t *driver = *driverp;
96*00b67f09SDavid van Moolenbroek 	Tcl_DeleteInterp(driver->interp);
97*00b67f09SDavid van Moolenbroek 	isc_mem_put(driver->mctx, driver, sizeof(tcldb_driver_t));
98*00b67f09SDavid van Moolenbroek }
99*00b67f09SDavid van Moolenbroek 
100*00b67f09SDavid van Moolenbroek /*
101*00b67f09SDavid van Moolenbroek  * Perform a lookup, by invoking the Tcl procedure "lookup".
102*00b67f09SDavid van Moolenbroek  */
103*00b67f09SDavid van Moolenbroek #ifdef DNS_CLIENTINFO_VERSION
104*00b67f09SDavid van Moolenbroek static isc_result_t
tcldb_lookup(const char * zone,const char * name,void * dbdata,dns_sdblookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)105*00b67f09SDavid van Moolenbroek tcldb_lookup(const char *zone, const char *name, void *dbdata,
106*00b67f09SDavid van Moolenbroek 	      dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
107*00b67f09SDavid van Moolenbroek 	      dns_clientinfo_t *clientinfo)
108*00b67f09SDavid van Moolenbroek #else
109*00b67f09SDavid van Moolenbroek static isc_result_t
110*00b67f09SDavid van Moolenbroek tcldb_lookup(const char *zone, const char *name, void *dbdata,
111*00b67f09SDavid van Moolenbroek 	      dns_sdblookup_t *lookup)
112*00b67f09SDavid van Moolenbroek #endif /* DNS_CLIENTINFO_VERSION */
113*00b67f09SDavid van Moolenbroek {
114*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
115*00b67f09SDavid van Moolenbroek 	int tclres;
116*00b67f09SDavid van Moolenbroek 	int rrc;	/* RR count */
117*00b67f09SDavid van Moolenbroek 	char **rrv;	/* RR vector */
118*00b67f09SDavid van Moolenbroek 	int i;
119*00b67f09SDavid van Moolenbroek 	char *cmdv[3];
120*00b67f09SDavid van Moolenbroek 	char *cmd;
121*00b67f09SDavid van Moolenbroek 
122*00b67f09SDavid van Moolenbroek #ifdef DNS_CLIENTINFO_VERSION
123*00b67f09SDavid van Moolenbroek 	UNUSED(methods);
124*00b67f09SDavid van Moolenbroek 	UNUSED(clientinfo);
125*00b67f09SDavid van Moolenbroek #endif /* DNS_CLIENTINFO_VERSION */
126*00b67f09SDavid van Moolenbroek 
127*00b67f09SDavid van Moolenbroek 	tcldb_driver_t *driver = (tcldb_driver_t *) dbdata;
128*00b67f09SDavid van Moolenbroek 
129*00b67f09SDavid van Moolenbroek 	cmdv[0] = "lookup";
130*00b67f09SDavid van Moolenbroek 	cmdv[1] = zone;
131*00b67f09SDavid van Moolenbroek 	cmdv[2] = name;
132*00b67f09SDavid van Moolenbroek 	cmd = Tcl_Merge(3, cmdv);
133*00b67f09SDavid van Moolenbroek 	tclres = Tcl_Eval(driver->interp, cmd);
134*00b67f09SDavid van Moolenbroek 	Tcl_Free(cmd);
135*00b67f09SDavid van Moolenbroek 
136*00b67f09SDavid van Moolenbroek 	if (tclres != TCL_OK) {
137*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
138*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
139*00b67f09SDavid van Moolenbroek 			      "zone '%s': tcl lookup function failed: %s",
140*00b67f09SDavid van Moolenbroek 			      zone, driver->interp->result);
141*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
142*00b67f09SDavid van Moolenbroek 	}
143*00b67f09SDavid van Moolenbroek 
144*00b67f09SDavid van Moolenbroek 	if (strcmp(driver->interp->result, "NXDOMAIN") == 0) {
145*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOTFOUND;
146*00b67f09SDavid van Moolenbroek 		goto fail;
147*00b67f09SDavid van Moolenbroek 	}
148*00b67f09SDavid van Moolenbroek 
149*00b67f09SDavid van Moolenbroek 	tclres = Tcl_SplitList(driver->interp, driver->interp->result,
150*00b67f09SDavid van Moolenbroek 			       &rrc, &rrv);
151*00b67f09SDavid van Moolenbroek 	if (tclres != TCL_OK)
152*00b67f09SDavid van Moolenbroek 		goto malformed;
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek 	for (i = 0; i < rrc; i++) {
155*00b67f09SDavid van Moolenbroek 		isc_result_t tmpres;
156*00b67f09SDavid van Moolenbroek 		int fieldc;	/* Field count */
157*00b67f09SDavid van Moolenbroek 		char **fieldv;	/* Field vector */
158*00b67f09SDavid van Moolenbroek 		tclres = Tcl_SplitList(driver->interp, rrv[i],
159*00b67f09SDavid van Moolenbroek 				       &fieldc, &fieldv);
160*00b67f09SDavid van Moolenbroek 		if (tclres != TCL_OK) {
161*00b67f09SDavid van Moolenbroek 			tmpres = ISC_R_FAILURE;
162*00b67f09SDavid van Moolenbroek 			goto failrr;
163*00b67f09SDavid van Moolenbroek 		}
164*00b67f09SDavid van Moolenbroek 		if (fieldc != 3)
165*00b67f09SDavid van Moolenbroek 			goto malformed;
166*00b67f09SDavid van Moolenbroek 		tmpres = dns_sdb_putrr(lookup, fieldv[0], atoi(fieldv[1]),
167*00b67f09SDavid van Moolenbroek 				       fieldv[2]);
168*00b67f09SDavid van Moolenbroek 		Tcl_Free((char *) fieldv);
169*00b67f09SDavid van Moolenbroek 	failrr:
170*00b67f09SDavid van Moolenbroek 		if (tmpres != ISC_R_SUCCESS)
171*00b67f09SDavid van Moolenbroek 			result = tmpres;
172*00b67f09SDavid van Moolenbroek 	}
173*00b67f09SDavid van Moolenbroek 	Tcl_Free((char *) rrv);
174*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS)
175*00b67f09SDavid van Moolenbroek 		return (result);
176*00b67f09SDavid van Moolenbroek 
177*00b67f09SDavid van Moolenbroek  malformed:
178*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
179*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
180*00b67f09SDavid van Moolenbroek 		      "zone '%s': "
181*00b67f09SDavid van Moolenbroek 		      "malformed return value from tcl lookup function: %s",
182*00b67f09SDavid van Moolenbroek 		      zone, driver->interp->result);
183*00b67f09SDavid van Moolenbroek 	result = ISC_R_FAILURE;
184*00b67f09SDavid van Moolenbroek  fail:
185*00b67f09SDavid van Moolenbroek 	return (result);
186*00b67f09SDavid van Moolenbroek }
187*00b67f09SDavid van Moolenbroek 
188*00b67f09SDavid van Moolenbroek /*
189*00b67f09SDavid van Moolenbroek  * Set up per-zone state.  In our case, the database arguments of the
190*00b67f09SDavid van Moolenbroek  * zone are collected into a Tcl list and assigned to an element of
191*00b67f09SDavid van Moolenbroek  * the global array "dbargs".
192*00b67f09SDavid van Moolenbroek  */
193*00b67f09SDavid van Moolenbroek static isc_result_t
tcldb_create(const char * zone,int argc,char ** argv,void * driverdata,void ** dbdata)194*00b67f09SDavid van Moolenbroek tcldb_create(const char *zone, int argc, char **argv,
195*00b67f09SDavid van Moolenbroek 	     void *driverdata, void **dbdata)
196*00b67f09SDavid van Moolenbroek {
197*00b67f09SDavid van Moolenbroek 	tcldb_driver_t *driver = (tcldb_driver_t *) driverdata;
198*00b67f09SDavid van Moolenbroek 
199*00b67f09SDavid van Moolenbroek 	char *list = Tcl_Merge(argc, argv);
200*00b67f09SDavid van Moolenbroek 
201*00b67f09SDavid van Moolenbroek 	Tcl_SetVar2(driver->interp, (char *) "dbargs", (char *) zone, list, 0);
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek 	Tcl_Free(list);
204*00b67f09SDavid van Moolenbroek 
205*00b67f09SDavid van Moolenbroek 	*dbdata = driverdata;
206*00b67f09SDavid van Moolenbroek 
207*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
208*00b67f09SDavid van Moolenbroek }
209*00b67f09SDavid van Moolenbroek 
210*00b67f09SDavid van Moolenbroek /*
211*00b67f09SDavid van Moolenbroek  * This driver does not support zone transfer, so allnodes() is NULL.
212*00b67f09SDavid van Moolenbroek  */
213*00b67f09SDavid van Moolenbroek static dns_sdbmethods_t tcldb_methods = {
214*00b67f09SDavid van Moolenbroek 	tcldb_lookup,
215*00b67f09SDavid van Moolenbroek 	NULL, /* authority */
216*00b67f09SDavid van Moolenbroek 	NULL, /* allnodes */
217*00b67f09SDavid van Moolenbroek 	tcldb_create,
218*00b67f09SDavid van Moolenbroek 	NULL, /* destroy */
219*00b67f09SDavid van Moolenbroek 	NULL /* lookup2 */
220*00b67f09SDavid van Moolenbroek };
221*00b67f09SDavid van Moolenbroek 
222*00b67f09SDavid van Moolenbroek /*
223*00b67f09SDavid van Moolenbroek  * Initialize the tcldb driver.
224*00b67f09SDavid van Moolenbroek  */
225*00b67f09SDavid van Moolenbroek isc_result_t
tcldb_init(void)226*00b67f09SDavid van Moolenbroek tcldb_init(void) {
227*00b67f09SDavid van Moolenbroek 	isc_result_t result;
228*00b67f09SDavid van Moolenbroek 	int flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA;
229*00b67f09SDavid van Moolenbroek 
230*00b67f09SDavid van Moolenbroek 	result = tcldb_driver_create(ns_g_mctx, &the_driver);
231*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
232*00b67f09SDavid van Moolenbroek 		return (result);
233*00b67f09SDavid van Moolenbroek 
234*00b67f09SDavid van Moolenbroek 	return (dns_sdb_register("tcl", &tcldb_methods, the_driver, flags,
235*00b67f09SDavid van Moolenbroek 				 ns_g_mctx, &tcldb));
236*00b67f09SDavid van Moolenbroek }
237*00b67f09SDavid van Moolenbroek 
238*00b67f09SDavid van Moolenbroek /*
239*00b67f09SDavid van Moolenbroek  * Wrapper around dns_sdb_unregister().
240*00b67f09SDavid van Moolenbroek  */
241*00b67f09SDavid van Moolenbroek void
tcldb_clear(void)242*00b67f09SDavid van Moolenbroek tcldb_clear(void) {
243*00b67f09SDavid van Moolenbroek 	if (tcldb != NULL)
244*00b67f09SDavid van Moolenbroek 		dns_sdb_unregister(&tcldb);
245*00b67f09SDavid van Moolenbroek 	if (the_driver != NULL)
246*00b67f09SDavid van Moolenbroek 		tcldb_driver_destroy(&the_driver);
247*00b67f09SDavid van Moolenbroek }
248