xref: /minix3/external/bsd/bind/dist/contrib/dlz/drivers/dlz_odbc_driver.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: dlz_odbc_driver.c,v 1.5 2014/12/10 04:37:55 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the
8*00b67f09SDavid van Moolenbroek  * above copyright notice and this permission notice appear in all
9*00b67f09SDavid van Moolenbroek  * copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12*00b67f09SDavid van Moolenbroek  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13*00b67f09SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14*00b67f09SDavid van Moolenbroek  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15*00b67f09SDavid van Moolenbroek  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16*00b67f09SDavid van Moolenbroek  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18*00b67f09SDavid van Moolenbroek  * USE OR PERFORMANCE OF THIS SOFTWARE.
19*00b67f09SDavid van Moolenbroek  *
20*00b67f09SDavid van Moolenbroek  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21*00b67f09SDavid van Moolenbroek  * conceived and contributed by Rob Butler.
22*00b67f09SDavid van Moolenbroek  *
23*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
24*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the
25*00b67f09SDavid van Moolenbroek  * above copyright notice and this permission notice appear in all
26*00b67f09SDavid van Moolenbroek  * copies.
27*00b67f09SDavid van Moolenbroek  *
28*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29*00b67f09SDavid van Moolenbroek  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30*00b67f09SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31*00b67f09SDavid van Moolenbroek  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32*00b67f09SDavid van Moolenbroek  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33*00b67f09SDavid van Moolenbroek  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35*00b67f09SDavid van Moolenbroek  * USE OR PERFORMANCE OF THIS SOFTWARE.
36*00b67f09SDavid van Moolenbroek  */
37*00b67f09SDavid van Moolenbroek 
38*00b67f09SDavid van Moolenbroek /*
39*00b67f09SDavid van Moolenbroek  * Copyright (C) 1999-2001  Internet Software Consortium.
40*00b67f09SDavid van Moolenbroek  *
41*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
42*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
43*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
44*00b67f09SDavid van Moolenbroek  *
45*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
46*00b67f09SDavid van Moolenbroek  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47*00b67f09SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48*00b67f09SDavid van Moolenbroek  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
49*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
50*00b67f09SDavid van Moolenbroek  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
51*00b67f09SDavid van Moolenbroek  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52*00b67f09SDavid van Moolenbroek  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53*00b67f09SDavid van Moolenbroek  */
54*00b67f09SDavid van Moolenbroek 
55*00b67f09SDavid van Moolenbroek #ifdef DLZ_ODBC
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek #include <config.h>
58*00b67f09SDavid van Moolenbroek #include <stdio.h>
59*00b67f09SDavid van Moolenbroek #include <string.h>
60*00b67f09SDavid van Moolenbroek #include <stdlib.h>
61*00b67f09SDavid van Moolenbroek 
62*00b67f09SDavid van Moolenbroek #include <dns/log.h>
63*00b67f09SDavid van Moolenbroek #include <dns/sdlz.h>
64*00b67f09SDavid van Moolenbroek #include <dns/result.h>
65*00b67f09SDavid van Moolenbroek 
66*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
67*00b67f09SDavid van Moolenbroek #include <isc/platform.h>
68*00b67f09SDavid van Moolenbroek #include <isc/print.h>
69*00b67f09SDavid van Moolenbroek #include <isc/result.h>
70*00b67f09SDavid van Moolenbroek #include <isc/string.h>
71*00b67f09SDavid van Moolenbroek #include <isc/util.h>
72*00b67f09SDavid van Moolenbroek 
73*00b67f09SDavid van Moolenbroek #include <named/globals.h>
74*00b67f09SDavid van Moolenbroek 
75*00b67f09SDavid van Moolenbroek #include <dlz/sdlz_helper.h>
76*00b67f09SDavid van Moolenbroek #include <dlz/dlz_odbc_driver.h>
77*00b67f09SDavid van Moolenbroek 
78*00b67f09SDavid van Moolenbroek #include <sql.h>
79*00b67f09SDavid van Moolenbroek #include <sqlext.h>
80*00b67f09SDavid van Moolenbroek #include <sqltypes.h>
81*00b67f09SDavid van Moolenbroek 
82*00b67f09SDavid van Moolenbroek static dns_sdlzimplementation_t *dlz_odbc = NULL;
83*00b67f09SDavid van Moolenbroek 
84*00b67f09SDavid van Moolenbroek #define dbc_search_limit 30
85*00b67f09SDavid van Moolenbroek #define ALLNODES 1
86*00b67f09SDavid van Moolenbroek #define ALLOWXFR 2
87*00b67f09SDavid van Moolenbroek #define AUTHORITY 3
88*00b67f09SDavid van Moolenbroek #define FINDZONE 4
89*00b67f09SDavid van Moolenbroek #define LOOKUP 5
90*00b67f09SDavid van Moolenbroek 
91*00b67f09SDavid van Moolenbroek #define sqlOK(a) ((a == SQL_SUCCESS || a == SQL_SUCCESS_WITH_INFO) ? -1 : 0)
92*00b67f09SDavid van Moolenbroek 
93*00b67f09SDavid van Moolenbroek /*
94*00b67f09SDavid van Moolenbroek  * Private Structures
95*00b67f09SDavid van Moolenbroek  */
96*00b67f09SDavid van Moolenbroek 
97*00b67f09SDavid van Moolenbroek /*
98*00b67f09SDavid van Moolenbroek  * structure to hold ODBC connection & statement
99*00b67f09SDavid van Moolenbroek  */
100*00b67f09SDavid van Moolenbroek 
101*00b67f09SDavid van Moolenbroek typedef struct{
102*00b67f09SDavid van Moolenbroek 	SQLHDBC   dbc;
103*00b67f09SDavid van Moolenbroek 	SQLHSTMT  stmnt;
104*00b67f09SDavid van Moolenbroek } odbc_db_t;
105*00b67f09SDavid van Moolenbroek 
106*00b67f09SDavid van Moolenbroek /*
107*00b67f09SDavid van Moolenbroek  * Structure to hold everthing needed by this "instance" of the odbc driver
108*00b67f09SDavid van Moolenbroek  * remember, the driver code is only loaded once, but may have many separate
109*00b67f09SDavid van Moolenbroek  * instances
110*00b67f09SDavid van Moolenbroek  */
111*00b67f09SDavid van Moolenbroek 
112*00b67f09SDavid van Moolenbroek typedef struct {
113*00b67f09SDavid van Moolenbroek 
114*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
115*00b67f09SDavid van Moolenbroek 
116*00b67f09SDavid van Moolenbroek     db_list_t    *db;       /* handle to a list of DB */
117*00b67f09SDavid van Moolenbroek 
118*00b67f09SDavid van Moolenbroek #else
119*00b67f09SDavid van Moolenbroek 
120*00b67f09SDavid van Moolenbroek     dbinstance_t *db;       /* handle to db */
121*00b67f09SDavid van Moolenbroek 
122*00b67f09SDavid van Moolenbroek #endif
123*00b67f09SDavid van Moolenbroek 
124*00b67f09SDavid van Moolenbroek     SQLHENV      sql_env;  /* handle to SQL environment */
125*00b67f09SDavid van Moolenbroek     SQLCHAR      *dsn;
126*00b67f09SDavid van Moolenbroek     SQLCHAR      *user;
127*00b67f09SDavid van Moolenbroek     SQLCHAR      *pass;
128*00b67f09SDavid van Moolenbroek } odbc_instance_t;
129*00b67f09SDavid van Moolenbroek 
130*00b67f09SDavid van Moolenbroek /* forward reference */
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek static size_t
133*00b67f09SDavid van Moolenbroek odbc_makesafe(char *to, const char *from, size_t length);
134*00b67f09SDavid van Moolenbroek 
135*00b67f09SDavid van Moolenbroek /*
136*00b67f09SDavid van Moolenbroek  * Private methods
137*00b67f09SDavid van Moolenbroek  */
138*00b67f09SDavid van Moolenbroek 
139*00b67f09SDavid van Moolenbroek static SQLSMALLINT
safeLen(void * a)140*00b67f09SDavid van Moolenbroek safeLen(void *a) {
141*00b67f09SDavid van Moolenbroek 	if (a == NULL)
142*00b67f09SDavid van Moolenbroek 		return 0;
143*00b67f09SDavid van Moolenbroek 	return strlen((char *) a);
144*00b67f09SDavid van Moolenbroek }
145*00b67f09SDavid van Moolenbroek 
146*00b67f09SDavid van Moolenbroek /*% propertly cleans up an odbc_instance_t */
147*00b67f09SDavid van Moolenbroek 
148*00b67f09SDavid van Moolenbroek static void
destroy_odbc_instance(odbc_instance_t * odbc_inst)149*00b67f09SDavid van Moolenbroek destroy_odbc_instance(odbc_instance_t *odbc_inst) {
150*00b67f09SDavid van Moolenbroek 
151*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
152*00b67f09SDavid van Moolenbroek 
153*00b67f09SDavid van Moolenbroek 	dbinstance_t *ndbi = NULL;
154*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
155*00b67f09SDavid van Moolenbroek 
156*00b67f09SDavid van Moolenbroek 	/* get the first DBI in the list */
157*00b67f09SDavid van Moolenbroek 	ndbi = ISC_LIST_HEAD(*odbc_inst->db);
158*00b67f09SDavid van Moolenbroek 
159*00b67f09SDavid van Moolenbroek 	/* loop through the list */
160*00b67f09SDavid van Moolenbroek 	while (ndbi != NULL) {
161*00b67f09SDavid van Moolenbroek 		dbi = ndbi;
162*00b67f09SDavid van Moolenbroek 		/* get the next DBI in the list */
163*00b67f09SDavid van Moolenbroek 		ndbi = ISC_LIST_NEXT(dbi, link);
164*00b67f09SDavid van Moolenbroek 
165*00b67f09SDavid van Moolenbroek 		/* if we have a connection / statement object in memory */
166*00b67f09SDavid van Moolenbroek 		if (dbi->dbconn != NULL) {
167*00b67f09SDavid van Moolenbroek 			/* free statement handle */
168*00b67f09SDavid van Moolenbroek 			if (((odbc_db_t *) (dbi->dbconn))->stmnt != NULL) {
169*00b67f09SDavid van Moolenbroek 				SQLFreeHandle(SQL_HANDLE_STMT,
170*00b67f09SDavid van Moolenbroek 					      ((odbc_db_t *)
171*00b67f09SDavid van Moolenbroek 					       (dbi->dbconn))->stmnt);
172*00b67f09SDavid van Moolenbroek 				((odbc_db_t *) (dbi->dbconn))->stmnt = NULL;
173*00b67f09SDavid van Moolenbroek 			}
174*00b67f09SDavid van Moolenbroek 
175*00b67f09SDavid van Moolenbroek 			/* disconnect from database & free connection handle */
176*00b67f09SDavid van Moolenbroek 			if (((odbc_db_t *) (dbi->dbconn))->dbc != NULL) {
177*00b67f09SDavid van Moolenbroek 				SQLDisconnect(((odbc_db_t *)
178*00b67f09SDavid van Moolenbroek 					       dbi->dbconn)->dbc);
179*00b67f09SDavid van Moolenbroek 				SQLFreeHandle(SQL_HANDLE_DBC,
180*00b67f09SDavid van Moolenbroek 					      ((odbc_db_t *)
181*00b67f09SDavid van Moolenbroek 					       (dbi->dbconn))->dbc);
182*00b67f09SDavid van Moolenbroek 				((odbc_db_t *) (dbi->dbconn))->dbc = NULL;
183*00b67f09SDavid van Moolenbroek 			}
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek 			/* free memory that held connection & statement. */
186*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, dbi->dbconn);
187*00b67f09SDavid van Moolenbroek 		}
188*00b67f09SDavid van Moolenbroek 		/* release all memory that comprised a DBI */
189*00b67f09SDavid van Moolenbroek 		destroy_sqldbinstance(dbi);
190*00b67f09SDavid van Moolenbroek 	}
191*00b67f09SDavid van Moolenbroek 	/* release memory for the list structure */
192*00b67f09SDavid van Moolenbroek 	isc_mem_put(ns_g_mctx, odbc_inst->db, sizeof(db_list_t));
193*00b67f09SDavid van Moolenbroek 
194*00b67f09SDavid van Moolenbroek #else /* ISC_PLATFORM_USETHREADS */
195*00b67f09SDavid van Moolenbroek 
196*00b67f09SDavid van Moolenbroek 	/* free statement handle */
197*00b67f09SDavid van Moolenbroek 	if (((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt != NULL) {
198*00b67f09SDavid van Moolenbroek 		SQLFreeHandle(SQL_HANDLE_STMT,
199*00b67f09SDavid van Moolenbroek 			      ((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt);
200*00b67f09SDavid van Moolenbroek 		((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt = NULL;
201*00b67f09SDavid van Moolenbroek 	}
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek 	/* disconnect from database, free connection handle */
204*00b67f09SDavid van Moolenbroek 	if (((odbc_db_t *) (odbc_inst->db->dbconn))->dbc != NULL) {
205*00b67f09SDavid van Moolenbroek 		SQLDisconnect(((odbc_db_t *) (odbc_inst->db->dbconn))->dbc);
206*00b67f09SDavid van Moolenbroek 		SQLFreeHandle(SQL_HANDLE_DBC,
207*00b67f09SDavid van Moolenbroek 			      ((odbc_db_t *) (odbc_inst->db->dbconn))->dbc);
208*00b67f09SDavid van Moolenbroek 		((odbc_db_t *) (odbc_inst->db->dbconn))->dbc = NULL;
209*00b67f09SDavid van Moolenbroek 	}
210*00b67f09SDavid van Moolenbroek 	/*	free mem for the odbc_db_t structure held in db */
211*00b67f09SDavid van Moolenbroek 	if (((odbc_db_t *) odbc_inst->db->dbconn) != NULL) {
212*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, odbc_inst->db->dbconn);
213*00b67f09SDavid van Moolenbroek 		odbc_inst->db->dbconn = NULL;
214*00b67f09SDavid van Moolenbroek 	}
215*00b67f09SDavid van Moolenbroek 
216*00b67f09SDavid van Moolenbroek 	if (odbc_inst->db != NULL)
217*00b67f09SDavid van Moolenbroek 		destroy_sqldbinstance(odbc_inst->db);
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
220*00b67f09SDavid van Moolenbroek 
221*00b67f09SDavid van Moolenbroek 
222*00b67f09SDavid van Moolenbroek 	/* free sql environment */
223*00b67f09SDavid van Moolenbroek 	if (odbc_inst->sql_env != NULL)
224*00b67f09SDavid van Moolenbroek 		SQLFreeHandle(SQL_HANDLE_ENV, odbc_inst->sql_env);
225*00b67f09SDavid van Moolenbroek 
226*00b67f09SDavid van Moolenbroek 	/* free ODBC instance strings */
227*00b67f09SDavid van Moolenbroek 	if (odbc_inst->dsn != NULL)
228*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, odbc_inst->dsn);
229*00b67f09SDavid van Moolenbroek 	if (odbc_inst->pass != NULL)
230*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, odbc_inst->pass);
231*00b67f09SDavid van Moolenbroek 	if (odbc_inst->user != NULL)
232*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, odbc_inst->user);
233*00b67f09SDavid van Moolenbroek 
234*00b67f09SDavid van Moolenbroek 	/* free memory for odbc_inst */
235*00b67f09SDavid van Moolenbroek 	if (odbc_inst != NULL)
236*00b67f09SDavid van Moolenbroek 		isc_mem_put(ns_g_mctx, odbc_inst, sizeof(odbc_instance_t));
237*00b67f09SDavid van Moolenbroek 
238*00b67f09SDavid van Moolenbroek }
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek /*% Connects to database, and creates ODBC statements */
241*00b67f09SDavid van Moolenbroek 
242*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_connect(odbc_instance_t * dbi,odbc_db_t ** dbc)243*00b67f09SDavid van Moolenbroek odbc_connect(odbc_instance_t *dbi, odbc_db_t **dbc) {
244*00b67f09SDavid van Moolenbroek 
245*00b67f09SDavid van Moolenbroek 	odbc_db_t *ndb = *dbc;
246*00b67f09SDavid van Moolenbroek 	SQLRETURN sqlRes;
247*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
248*00b67f09SDavid van Moolenbroek 
249*00b67f09SDavid van Moolenbroek 	if (ndb != NULL) {
250*00b67f09SDavid van Moolenbroek 		/*
251*00b67f09SDavid van Moolenbroek 		 * if db != null, we have to do some cleanup
252*00b67f09SDavid van Moolenbroek 		 * if statement handle != null free it
253*00b67f09SDavid van Moolenbroek 		 */
254*00b67f09SDavid van Moolenbroek 		if (ndb->stmnt != NULL) {
255*00b67f09SDavid van Moolenbroek 			SQLFreeHandle(SQL_HANDLE_STMT, ndb->stmnt);
256*00b67f09SDavid van Moolenbroek 			ndb->stmnt = NULL;
257*00b67f09SDavid van Moolenbroek 		}
258*00b67f09SDavid van Moolenbroek 
259*00b67f09SDavid van Moolenbroek 		/* if connection handle != null free it */
260*00b67f09SDavid van Moolenbroek 		if (ndb->dbc != NULL) {
261*00b67f09SDavid van Moolenbroek 			SQLFreeHandle(SQL_HANDLE_DBC, ndb->dbc);
262*00b67f09SDavid van Moolenbroek 			ndb->dbc = NULL;
263*00b67f09SDavid van Moolenbroek 		}
264*00b67f09SDavid van Moolenbroek 	} else {
265*00b67f09SDavid van Moolenbroek 		ndb = isc_mem_allocate(ns_g_mctx, sizeof(odbc_db_t));
266*00b67f09SDavid van Moolenbroek 		if (ndb == NULL) {
267*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
268*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
269*00b67f09SDavid van Moolenbroek 				      "Odbc driver unable to allocate memory");
270*00b67f09SDavid van Moolenbroek 			return ISC_R_NOMEMORY;
271*00b67f09SDavid van Moolenbroek 		}
272*00b67f09SDavid van Moolenbroek 		memset(ndb, 0, sizeof(odbc_db_t));
273*00b67f09SDavid van Moolenbroek 	}
274*00b67f09SDavid van Moolenbroek 
275*00b67f09SDavid van Moolenbroek 	sqlRes = SQLAllocHandle(SQL_HANDLE_DBC, dbi->sql_env, &(ndb->dbc));
276*00b67f09SDavid van Moolenbroek 	if (!sqlOK(sqlRes)) {
277*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
278*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
279*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to allocate memory");
280*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
281*00b67f09SDavid van Moolenbroek 		goto cleanup;
282*00b67f09SDavid van Moolenbroek 	}
283*00b67f09SDavid van Moolenbroek 
284*00b67f09SDavid van Moolenbroek 	sqlRes = SQLConnect(ndb->dbc, dbi->dsn, safeLen(dbi->dsn), dbi->user,
285*00b67f09SDavid van Moolenbroek 			    safeLen(dbi->user), dbi->pass, safeLen(dbi->pass));
286*00b67f09SDavid van Moolenbroek 	if (!sqlOK(sqlRes)) {
287*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
288*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
289*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to connect");
290*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
291*00b67f09SDavid van Moolenbroek 		goto cleanup;
292*00b67f09SDavid van Moolenbroek 	}
293*00b67f09SDavid van Moolenbroek 
294*00b67f09SDavid van Moolenbroek 	sqlRes = SQLAllocHandle(SQL_HANDLE_STMT, ndb->dbc, &(ndb->stmnt));
295*00b67f09SDavid van Moolenbroek 	if (!sqlOK(sqlRes)) {
296*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
297*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
298*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to allocate memory");
299*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
300*00b67f09SDavid van Moolenbroek 		goto cleanup;
301*00b67f09SDavid van Moolenbroek 	}
302*00b67f09SDavid van Moolenbroek 
303*00b67f09SDavid van Moolenbroek 	*dbc = ndb;
304*00b67f09SDavid van Moolenbroek 
305*00b67f09SDavid van Moolenbroek 	return ISC_R_SUCCESS;
306*00b67f09SDavid van Moolenbroek 
307*00b67f09SDavid van Moolenbroek  cleanup:
308*00b67f09SDavid van Moolenbroek 
309*00b67f09SDavid van Moolenbroek 	if (ndb != NULL) {
310*00b67f09SDavid van Moolenbroek 
311*00b67f09SDavid van Moolenbroek 		/* if statement handle != null free it */
312*00b67f09SDavid van Moolenbroek 		if (ndb->stmnt != NULL) {
313*00b67f09SDavid van Moolenbroek 			SQLFreeHandle(SQL_HANDLE_STMT, ndb->stmnt);
314*00b67f09SDavid van Moolenbroek 			ndb->stmnt = NULL;
315*00b67f09SDavid van Moolenbroek 		}
316*00b67f09SDavid van Moolenbroek 
317*00b67f09SDavid van Moolenbroek 		/* if connection handle != null free it */
318*00b67f09SDavid van Moolenbroek 		if (ndb->dbc != NULL) {
319*00b67f09SDavid van Moolenbroek 			SQLDisconnect(ndb->dbc);
320*00b67f09SDavid van Moolenbroek 			SQLFreeHandle(SQL_HANDLE_DBC, ndb->dbc);
321*00b67f09SDavid van Moolenbroek 			ndb->dbc = NULL;
322*00b67f09SDavid van Moolenbroek 		}
323*00b67f09SDavid van Moolenbroek 		/* free memory holding ndb */
324*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, ndb);
325*00b67f09SDavid van Moolenbroek 	}
326*00b67f09SDavid van Moolenbroek 
327*00b67f09SDavid van Moolenbroek 	return result;
328*00b67f09SDavid van Moolenbroek }
329*00b67f09SDavid van Moolenbroek 
330*00b67f09SDavid van Moolenbroek /*%
331*00b67f09SDavid van Moolenbroek  * Loops through the list of DB instances, attempting to lock
332*00b67f09SDavid van Moolenbroek  * on the mutex.  If successful, the DBI is reserved for use
333*00b67f09SDavid van Moolenbroek  * and the thread can perform queries against the database.
334*00b67f09SDavid van Moolenbroek  * If the lock fails, the next one in the list is tried.
335*00b67f09SDavid van Moolenbroek  * looping continues until a lock is obtained, or until
336*00b67f09SDavid van Moolenbroek  * the list has been searched dbc_search_limit times.
337*00b67f09SDavid van Moolenbroek  * This function is only used when the driver is compiled for
338*00b67f09SDavid van Moolenbroek  * multithreaded operation.
339*00b67f09SDavid van Moolenbroek  */
340*00b67f09SDavid van Moolenbroek 
341*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
342*00b67f09SDavid van Moolenbroek 
343*00b67f09SDavid van Moolenbroek static dbinstance_t *
odbc_find_avail_conn(db_list_t * dblist)344*00b67f09SDavid van Moolenbroek odbc_find_avail_conn(db_list_t *dblist)
345*00b67f09SDavid van Moolenbroek {
346*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
347*00b67f09SDavid van Moolenbroek 	dbinstance_t *head;
348*00b67f09SDavid van Moolenbroek 	int count = 0;
349*00b67f09SDavid van Moolenbroek 
350*00b67f09SDavid van Moolenbroek 	/* get top of list */
351*00b67f09SDavid van Moolenbroek 	head = dbi = ISC_LIST_HEAD(*dblist);
352*00b67f09SDavid van Moolenbroek 
353*00b67f09SDavid van Moolenbroek 	/* loop through list */
354*00b67f09SDavid van Moolenbroek 	while (count < dbc_search_limit) {
355*00b67f09SDavid van Moolenbroek 		/* try to lock on the mutex */
356*00b67f09SDavid van Moolenbroek 		if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
357*00b67f09SDavid van Moolenbroek 			return dbi; /* success, return the DBI for use. */
358*00b67f09SDavid van Moolenbroek 
359*00b67f09SDavid van Moolenbroek 		/* not successful, keep trying */
360*00b67f09SDavid van Moolenbroek 		dbi = ISC_LIST_NEXT(dbi, link);
361*00b67f09SDavid van Moolenbroek 
362*00b67f09SDavid van Moolenbroek 		/* check to see if we have gone to the top of the list. */
363*00b67f09SDavid van Moolenbroek 		if (dbi == NULL) {
364*00b67f09SDavid van Moolenbroek 			count++;
365*00b67f09SDavid van Moolenbroek 			dbi = head;
366*00b67f09SDavid van Moolenbroek 		}
367*00b67f09SDavid van Moolenbroek 	}
368*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
369*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
370*00b67f09SDavid van Moolenbroek 		      "Odbc driver unable to find available "
371*00b67f09SDavid van Moolenbroek 		      "connection after searching %d times",
372*00b67f09SDavid van Moolenbroek 		      count);
373*00b67f09SDavid van Moolenbroek 	return NULL;
374*00b67f09SDavid van Moolenbroek }
375*00b67f09SDavid van Moolenbroek 
376*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
377*00b67f09SDavid van Moolenbroek 
378*00b67f09SDavid van Moolenbroek /*% Allocates memory for a new string, and then constructs the new
379*00b67f09SDavid van Moolenbroek  * string by "escaping" the input string.  The new string is
380*00b67f09SDavid van Moolenbroek  * safe to be used in queries.  This is necessary because we cannot
381*00b67f09SDavid van Moolenbroek  * be sure of what types of strings are passed to us, and we don't
382*00b67f09SDavid van Moolenbroek  * want special characters in the string causing problems.
383*00b67f09SDavid van Moolenbroek  */
384*00b67f09SDavid van Moolenbroek 
385*00b67f09SDavid van Moolenbroek static char *
odbc_escape_string(const char * instr)386*00b67f09SDavid van Moolenbroek odbc_escape_string(const char *instr) {
387*00b67f09SDavid van Moolenbroek 
388*00b67f09SDavid van Moolenbroek 	char *outstr;
389*00b67f09SDavid van Moolenbroek 	unsigned int len;
390*00b67f09SDavid van Moolenbroek 
391*00b67f09SDavid van Moolenbroek 	if (instr == NULL)
392*00b67f09SDavid van Moolenbroek 		return NULL;
393*00b67f09SDavid van Moolenbroek 
394*00b67f09SDavid van Moolenbroek 	len = strlen(instr);
395*00b67f09SDavid van Moolenbroek 
396*00b67f09SDavid van Moolenbroek 	outstr = isc_mem_allocate(ns_g_mctx ,(2 * len * sizeof(char)) + 1);
397*00b67f09SDavid van Moolenbroek 	if (outstr == NULL)
398*00b67f09SDavid van Moolenbroek 		return NULL;
399*00b67f09SDavid van Moolenbroek 
400*00b67f09SDavid van Moolenbroek 	odbc_makesafe(outstr, instr, len);
401*00b67f09SDavid van Moolenbroek 
402*00b67f09SDavid van Moolenbroek 	return outstr;
403*00b67f09SDavid van Moolenbroek }
404*00b67f09SDavid van Moolenbroek 
405*00b67f09SDavid van Moolenbroek /* ---------------
406*00b67f09SDavid van Moolenbroek  * Escaping arbitrary strings to get valid SQL strings/identifiers.
407*00b67f09SDavid van Moolenbroek  *
408*00b67f09SDavid van Moolenbroek  * Replaces "\\" with "\\\\" and "'" with "''".
409*00b67f09SDavid van Moolenbroek  * length is the length of the buffer pointed to by
410*00b67f09SDavid van Moolenbroek  * from.  The buffer at to must be at least 2*length + 1 characters
411*00b67f09SDavid van Moolenbroek  * long.  A terminating NUL character is written.
412*00b67f09SDavid van Moolenbroek  *
413*00b67f09SDavid van Moolenbroek  * NOTICE!!!
414*00b67f09SDavid van Moolenbroek  * This function was borrowed directly from PostgreSQL's libpq.
415*00b67f09SDavid van Moolenbroek  *
416*00b67f09SDavid van Moolenbroek  * The copyright statements from the original file containing this
417*00b67f09SDavid van Moolenbroek  * function are included below:
418*00b67f09SDavid van Moolenbroek  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
419*00b67f09SDavid van Moolenbroek  * Portions Copyright (c) 1994, Regents of the University of California
420*00b67f09SDavid van Moolenbroek  * ---------------
421*00b67f09SDavid van Moolenbroek  */
422*00b67f09SDavid van Moolenbroek 
423*00b67f09SDavid van Moolenbroek static size_t
odbc_makesafe(char * to,const char * from,size_t length)424*00b67f09SDavid van Moolenbroek odbc_makesafe(char *to, const char *from, size_t length)
425*00b67f09SDavid van Moolenbroek {
426*00b67f09SDavid van Moolenbroek 	const char *source = from;
427*00b67f09SDavid van Moolenbroek 	char	   *target = to;
428*00b67f09SDavid van Moolenbroek 	unsigned int remaining = length;
429*00b67f09SDavid van Moolenbroek 
430*00b67f09SDavid van Moolenbroek 	while (remaining > 0)
431*00b67f09SDavid van Moolenbroek 	{
432*00b67f09SDavid van Moolenbroek 		switch (*source)
433*00b67f09SDavid van Moolenbroek 		{
434*00b67f09SDavid van Moolenbroek 			case '\\':
435*00b67f09SDavid van Moolenbroek 				*target = '\\';
436*00b67f09SDavid van Moolenbroek 				target++;
437*00b67f09SDavid van Moolenbroek 				*target = '\\';
438*00b67f09SDavid van Moolenbroek 				/* target and remaining are updated below. */
439*00b67f09SDavid van Moolenbroek 				break;
440*00b67f09SDavid van Moolenbroek 
441*00b67f09SDavid van Moolenbroek 			case '\'':
442*00b67f09SDavid van Moolenbroek 				*target = '\'';
443*00b67f09SDavid van Moolenbroek 				target++;
444*00b67f09SDavid van Moolenbroek 				*target = '\'';
445*00b67f09SDavid van Moolenbroek 				/* target and remaining are updated below. */
446*00b67f09SDavid van Moolenbroek 				break;
447*00b67f09SDavid van Moolenbroek 
448*00b67f09SDavid van Moolenbroek 			default:
449*00b67f09SDavid van Moolenbroek 				*target = *source;
450*00b67f09SDavid van Moolenbroek 				/* target and remaining are updated below. */
451*00b67f09SDavid van Moolenbroek 		}
452*00b67f09SDavid van Moolenbroek 		source++;
453*00b67f09SDavid van Moolenbroek 		target++;
454*00b67f09SDavid van Moolenbroek 		remaining--;
455*00b67f09SDavid van Moolenbroek 	}
456*00b67f09SDavid van Moolenbroek 
457*00b67f09SDavid van Moolenbroek 	/* Write the terminating NUL character. */
458*00b67f09SDavid van Moolenbroek 	*target = '\0';
459*00b67f09SDavid van Moolenbroek 
460*00b67f09SDavid van Moolenbroek 	return target - to;
461*00b67f09SDavid van Moolenbroek }
462*00b67f09SDavid van Moolenbroek 
463*00b67f09SDavid van Moolenbroek /*%
464*00b67f09SDavid van Moolenbroek  * This function is the real core of the driver.   Zone, record
465*00b67f09SDavid van Moolenbroek  * and client strings are passed in (or NULL is passed if the
466*00b67f09SDavid van Moolenbroek  * string is not available).  The type of query we want to run
467*00b67f09SDavid van Moolenbroek  * is indicated by the query flag, and the dbdata object is passed
468*00b67f09SDavid van Moolenbroek  * passed in to.  dbdata really holds either:
469*00b67f09SDavid van Moolenbroek  *		1) a list of database instances (in multithreaded mode) OR
470*00b67f09SDavid van Moolenbroek  *		2) a single database instance (in single threaded mode)
471*00b67f09SDavid van Moolenbroek  * The function will construct the query and obtain an available
472*00b67f09SDavid van Moolenbroek  * database instance (DBI).  It will then run the query and hopefully
473*00b67f09SDavid van Moolenbroek  * obtain a result set.  The data base instance that is used is returned
474*00b67f09SDavid van Moolenbroek  * to the caller so they can get the data from the result set from it.
475*00b67f09SDavid van Moolenbroek  * If successfull, it will be the responsibility of the caller to close
476*00b67f09SDavid van Moolenbroek  * the cursor, and unlock the mutex of the DBI when they are done with it.
477*00b67f09SDavid van Moolenbroek  * If not successfull, this function will perform all the cleanup.
478*00b67f09SDavid van Moolenbroek  */
479*00b67f09SDavid van Moolenbroek 
480*00b67f09SDavid van Moolenbroek 
481*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_get_resultset(const char * zone,const char * record,const char * client,unsigned int query,void * dbdata,dbinstance_t ** r_dbi)482*00b67f09SDavid van Moolenbroek odbc_get_resultset(const char *zone, const char *record,
483*00b67f09SDavid van Moolenbroek 		   const char *client, unsigned int query,
484*00b67f09SDavid van Moolenbroek 		   void *dbdata, dbinstance_t **r_dbi)
485*00b67f09SDavid van Moolenbroek {
486*00b67f09SDavid van Moolenbroek 
487*00b67f09SDavid van Moolenbroek 	isc_result_t result;
488*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
489*00b67f09SDavid van Moolenbroek 	char *querystring = NULL;
490*00b67f09SDavid van Moolenbroek 	unsigned int j = 0;
491*00b67f09SDavid van Moolenbroek 	SQLRETURN sqlRes;
492*00b67f09SDavid van Moolenbroek 
493*00b67f09SDavid van Moolenbroek 	REQUIRE(*r_dbi == NULL);
494*00b67f09SDavid van Moolenbroek 
495*00b67f09SDavid van Moolenbroek 	/* get db instance / connection */
496*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
497*00b67f09SDavid van Moolenbroek 
498*00b67f09SDavid van Moolenbroek 	/* find an available DBI from the list */
499*00b67f09SDavid van Moolenbroek 	dbi = odbc_find_avail_conn(((odbc_instance_t *) dbdata)->db);
500*00b67f09SDavid van Moolenbroek 
501*00b67f09SDavid van Moolenbroek #else /* ISC_PLATFORM_USETHREADS */
502*00b67f09SDavid van Moolenbroek 
503*00b67f09SDavid van Moolenbroek 	/*
504*00b67f09SDavid van Moolenbroek 	 * only 1 DBI - no need to lock instance lock either
505*00b67f09SDavid van Moolenbroek 	 * only 1 thread in the whole process, no possible contention.
506*00b67f09SDavid van Moolenbroek 	 */
507*00b67f09SDavid van Moolenbroek 	dbi =  (dbinstance_t *) ((odbc_instance_t *) dbdata)->db;
508*00b67f09SDavid van Moolenbroek 
509*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
510*00b67f09SDavid van Moolenbroek 
511*00b67f09SDavid van Moolenbroek 	/* if DBI is null, can't do anything else */
512*00b67f09SDavid van Moolenbroek 	if (dbi == NULL) {
513*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
514*00b67f09SDavid van Moolenbroek 		goto cleanup;
515*00b67f09SDavid van Moolenbroek 	}
516*00b67f09SDavid van Moolenbroek 
517*00b67f09SDavid van Moolenbroek 	/* what type of query are we going to run? */
518*00b67f09SDavid van Moolenbroek 	switch(query) {
519*00b67f09SDavid van Moolenbroek 	case ALLNODES:
520*00b67f09SDavid van Moolenbroek 		/*
521*00b67f09SDavid van Moolenbroek 		 * if the query was not passed in from the config file
522*00b67f09SDavid van Moolenbroek 		 * then we can't run it.  return not_implemented, so
523*00b67f09SDavid van Moolenbroek 		 * it's like the code for that operation was never
524*00b67f09SDavid van Moolenbroek 		 * built into the driver.... AHHH flexibility!!!
525*00b67f09SDavid van Moolenbroek 		 */
526*00b67f09SDavid van Moolenbroek 		if (dbi->allnodes_q == NULL) {
527*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOTIMPLEMENTED;
528*00b67f09SDavid van Moolenbroek 			goto cleanup;
529*00b67f09SDavid van Moolenbroek 		}
530*00b67f09SDavid van Moolenbroek 		break;
531*00b67f09SDavid van Moolenbroek 	case ALLOWXFR:
532*00b67f09SDavid van Moolenbroek 		/* same as comments as ALLNODES */
533*00b67f09SDavid van Moolenbroek 		if (dbi->allowxfr_q == NULL) {
534*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOTIMPLEMENTED;
535*00b67f09SDavid van Moolenbroek 			goto cleanup;
536*00b67f09SDavid van Moolenbroek 		}
537*00b67f09SDavid van Moolenbroek 		break;
538*00b67f09SDavid van Moolenbroek 	case AUTHORITY:
539*00b67f09SDavid van Moolenbroek 		/* same as comments as ALLNODES */
540*00b67f09SDavid van Moolenbroek 		if (dbi->authority_q == NULL) {
541*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOTIMPLEMENTED;
542*00b67f09SDavid van Moolenbroek 			goto cleanup;
543*00b67f09SDavid van Moolenbroek 		}
544*00b67f09SDavid van Moolenbroek 		break;
545*00b67f09SDavid van Moolenbroek 	case FINDZONE:
546*00b67f09SDavid van Moolenbroek 		/* this is required.  It's the whole point of DLZ! */
547*00b67f09SDavid van Moolenbroek 		if (dbi->findzone_q == NULL) {
548*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
549*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
550*00b67f09SDavid van Moolenbroek 				      "No query specified for findzone.  "
551*00b67f09SDavid van Moolenbroek 				      "Findzone requires a query");
552*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
553*00b67f09SDavid van Moolenbroek 			goto cleanup;
554*00b67f09SDavid van Moolenbroek 		}
555*00b67f09SDavid van Moolenbroek 		break;
556*00b67f09SDavid van Moolenbroek 	case LOOKUP:
557*00b67f09SDavid van Moolenbroek 		/* this is required.  It's also a major point of DLZ! */
558*00b67f09SDavid van Moolenbroek 		if (dbi->lookup_q == NULL) {
559*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
560*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
561*00b67f09SDavid van Moolenbroek 				      "No query specified for lookup.  "
562*00b67f09SDavid van Moolenbroek 				      "Lookup requires a query");
563*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
564*00b67f09SDavid van Moolenbroek 			goto cleanup;
565*00b67f09SDavid van Moolenbroek 		}
566*00b67f09SDavid van Moolenbroek 		break;
567*00b67f09SDavid van Moolenbroek 	default:
568*00b67f09SDavid van Moolenbroek 		/*
569*00b67f09SDavid van Moolenbroek 		 * this should never happen.  If it does, the code is
570*00b67f09SDavid van Moolenbroek 		 * screwed up!
571*00b67f09SDavid van Moolenbroek 		 */
572*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
573*00b67f09SDavid van Moolenbroek 				 "Incorrect query flag passed to "
574*00b67f09SDavid van Moolenbroek 				 "odbc_get_resultset");
575*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
576*00b67f09SDavid van Moolenbroek 		goto cleanup;
577*00b67f09SDavid van Moolenbroek 	}
578*00b67f09SDavid van Moolenbroek 
579*00b67f09SDavid van Moolenbroek 
580*00b67f09SDavid van Moolenbroek 	/*
581*00b67f09SDavid van Moolenbroek 	 * was a zone string passed?  If so, make it safe for use in
582*00b67f09SDavid van Moolenbroek 	 * queries.
583*00b67f09SDavid van Moolenbroek 	 */
584*00b67f09SDavid van Moolenbroek 	if (zone != NULL) {
585*00b67f09SDavid van Moolenbroek 		dbi->zone = odbc_escape_string(zone);
586*00b67f09SDavid van Moolenbroek 		if (dbi->zone == NULL) {
587*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
588*00b67f09SDavid van Moolenbroek 			goto cleanup;
589*00b67f09SDavid van Moolenbroek 		}
590*00b67f09SDavid van Moolenbroek 	} else {	/* no string passed, set the string pointer to NULL */
591*00b67f09SDavid van Moolenbroek 		dbi->zone = NULL;
592*00b67f09SDavid van Moolenbroek 	}
593*00b67f09SDavid van Moolenbroek 
594*00b67f09SDavid van Moolenbroek 	/*
595*00b67f09SDavid van Moolenbroek 	 * was a record string passed?  If so, make it safe for use in
596*00b67f09SDavid van Moolenbroek 	 * queries.
597*00b67f09SDavid van Moolenbroek 	 */
598*00b67f09SDavid van Moolenbroek 	if (record != NULL) {
599*00b67f09SDavid van Moolenbroek 		dbi->record = odbc_escape_string(record);
600*00b67f09SDavid van Moolenbroek 		if (dbi->record == NULL) {
601*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
602*00b67f09SDavid van Moolenbroek 			goto cleanup;
603*00b67f09SDavid van Moolenbroek 		}
604*00b67f09SDavid van Moolenbroek 	} else {	/* no string passed, set the string pointer to NULL */
605*00b67f09SDavid van Moolenbroek 		dbi->record = NULL;
606*00b67f09SDavid van Moolenbroek 	}
607*00b67f09SDavid van Moolenbroek 
608*00b67f09SDavid van Moolenbroek 	/*
609*00b67f09SDavid van Moolenbroek 	 * was a client string passed?  If so, make it safe for use in
610*00b67f09SDavid van Moolenbroek 	 * queries.
611*00b67f09SDavid van Moolenbroek 	 */
612*00b67f09SDavid van Moolenbroek 	if (client != NULL) {
613*00b67f09SDavid van Moolenbroek 		dbi->client = odbc_escape_string(client);
614*00b67f09SDavid van Moolenbroek 		if (dbi->client == NULL) {
615*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
616*00b67f09SDavid van Moolenbroek 			goto cleanup;
617*00b67f09SDavid van Moolenbroek 		}
618*00b67f09SDavid van Moolenbroek 	} else {	/* no string passed, set the string pointer to NULL */
619*00b67f09SDavid van Moolenbroek 		dbi->client = NULL;
620*00b67f09SDavid van Moolenbroek 	}
621*00b67f09SDavid van Moolenbroek 
622*00b67f09SDavid van Moolenbroek 	/*
623*00b67f09SDavid van Moolenbroek 	 * what type of query are we going to run?
624*00b67f09SDavid van Moolenbroek 	 * this time we build the actual query to run.
625*00b67f09SDavid van Moolenbroek 	 */
626*00b67f09SDavid van Moolenbroek 	switch(query) {
627*00b67f09SDavid van Moolenbroek 	case ALLNODES:
628*00b67f09SDavid van Moolenbroek 		querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
629*00b67f09SDavid van Moolenbroek 		break;
630*00b67f09SDavid van Moolenbroek 	case ALLOWXFR:
631*00b67f09SDavid van Moolenbroek 		querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
632*00b67f09SDavid van Moolenbroek 		break;
633*00b67f09SDavid van Moolenbroek 	case AUTHORITY:
634*00b67f09SDavid van Moolenbroek 		querystring = build_querystring(ns_g_mctx, dbi->authority_q);
635*00b67f09SDavid van Moolenbroek 		break;
636*00b67f09SDavid van Moolenbroek 	case FINDZONE:
637*00b67f09SDavid van Moolenbroek 		querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
638*00b67f09SDavid van Moolenbroek 		break;
639*00b67f09SDavid van Moolenbroek 	case LOOKUP:
640*00b67f09SDavid van Moolenbroek 		querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
641*00b67f09SDavid van Moolenbroek 		break;
642*00b67f09SDavid van Moolenbroek 	default:
643*00b67f09SDavid van Moolenbroek 		/*
644*00b67f09SDavid van Moolenbroek 		 * this should never happen.  If it does, the code is
645*00b67f09SDavid van Moolenbroek 		 * screwed up!
646*00b67f09SDavid van Moolenbroek 		 */
647*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
648*00b67f09SDavid van Moolenbroek 				 "Incorrect query flag passed to "
649*00b67f09SDavid van Moolenbroek 				 "odbc_get_resultset");
650*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
651*00b67f09SDavid van Moolenbroek 		goto cleanup;
652*00b67f09SDavid van Moolenbroek 	}
653*00b67f09SDavid van Moolenbroek 
654*00b67f09SDavid van Moolenbroek 	/* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */
655*00b67f09SDavid van Moolenbroek 	if (querystring  == NULL) {
656*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
657*00b67f09SDavid van Moolenbroek 		goto cleanup;
658*00b67f09SDavid van Moolenbroek 	}
659*00b67f09SDavid van Moolenbroek 
660*00b67f09SDavid van Moolenbroek 	/* output the full query string during debug so we can see */
661*00b67f09SDavid van Moolenbroek 	/* what lame error the query has. */
662*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
663*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
664*00b67f09SDavid van Moolenbroek 		      "\nQuery String: %s\n", querystring);
665*00b67f09SDavid van Moolenbroek 
666*00b67f09SDavid van Moolenbroek 	/* attempt query up to 3 times. */
667*00b67f09SDavid van Moolenbroek 	for (j=0; j < 3; j++) {
668*00b67f09SDavid van Moolenbroek 		/* try to get result set */
669*00b67f09SDavid van Moolenbroek 		sqlRes = SQLExecDirect(((odbc_db_t *) dbi->dbconn)->stmnt,
670*00b67f09SDavid van Moolenbroek 				       (SQLCHAR *) querystring,
671*00b67f09SDavid van Moolenbroek 				       (SQLINTEGER) strlen(querystring));
672*00b67f09SDavid van Moolenbroek 
673*00b67f09SDavid van Moolenbroek 		/* if error, reset DB connection */
674*00b67f09SDavid van Moolenbroek 		if (!sqlOK(sqlRes)) {
675*00b67f09SDavid van Moolenbroek 			/* close cursor */
676*00b67f09SDavid van Moolenbroek 			SQLCloseCursor(((odbc_db_t *) dbi->dbconn)->stmnt);
677*00b67f09SDavid van Moolenbroek 			/* attempt to reconnect */
678*00b67f09SDavid van Moolenbroek 			result = odbc_connect((odbc_instance_t *) dbdata,
679*00b67f09SDavid van Moolenbroek 					      (odbc_db_t **) &(dbi->dbconn));
680*00b67f09SDavid van Moolenbroek 			/* check if we reconnected */
681*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
682*00b67f09SDavid van Moolenbroek 				break;
683*00b67f09SDavid van Moolenbroek 			/* incase this is the last time through the loop */
684*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
685*00b67f09SDavid van Moolenbroek 		} else {
686*00b67f09SDavid van Moolenbroek 			result = ISC_R_SUCCESS;
687*00b67f09SDavid van Moolenbroek 			/* return dbi */
688*00b67f09SDavid van Moolenbroek 			*r_dbi = dbi;
689*00b67f09SDavid van Moolenbroek 			/* result set ok, break loop */
690*00b67f09SDavid van Moolenbroek 			break;
691*00b67f09SDavid van Moolenbroek 		}
692*00b67f09SDavid van Moolenbroek 	}	/* end for loop */
693*00b67f09SDavid van Moolenbroek 
694*00b67f09SDavid van Moolenbroek  cleanup:	/* it's always good to cleanup after yourself */
695*00b67f09SDavid van Moolenbroek 
696*00b67f09SDavid van Moolenbroek 		/* if we couldn't even allocate DBI, just return NULL */
697*00b67f09SDavid van Moolenbroek 	if (dbi == NULL)
698*00b67f09SDavid van Moolenbroek 		return ISC_R_FAILURE;
699*00b67f09SDavid van Moolenbroek 
700*00b67f09SDavid van Moolenbroek 	/* free dbi->zone string */
701*00b67f09SDavid van Moolenbroek 	if (dbi->zone != NULL)
702*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, dbi->zone);
703*00b67f09SDavid van Moolenbroek 
704*00b67f09SDavid van Moolenbroek 	/* free dbi->record string */
705*00b67f09SDavid van Moolenbroek 	if (dbi->record != NULL)
706*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, dbi->record);
707*00b67f09SDavid van Moolenbroek 
708*00b67f09SDavid van Moolenbroek 	/* free dbi->client string */
709*00b67f09SDavid van Moolenbroek 	if (dbi->client != NULL)
710*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, dbi->client);
711*00b67f09SDavid van Moolenbroek 
712*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
713*00b67f09SDavid van Moolenbroek 
714*00b67f09SDavid van Moolenbroek 	/* if we are done using this dbi, release the lock */
715*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
716*00b67f09SDavid van Moolenbroek 		isc_mutex_unlock(&dbi->instance_lock);
717*00b67f09SDavid van Moolenbroek 
718*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
719*00b67f09SDavid van Moolenbroek 
720*00b67f09SDavid van Moolenbroek 	/* release query string */
721*00b67f09SDavid van Moolenbroek 	if (querystring  != NULL)
722*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, querystring );
723*00b67f09SDavid van Moolenbroek 
724*00b67f09SDavid van Moolenbroek 	/* return result */
725*00b67f09SDavid van Moolenbroek 	return result;
726*00b67f09SDavid van Moolenbroek 
727*00b67f09SDavid van Moolenbroek }
728*00b67f09SDavid van Moolenbroek 
729*00b67f09SDavid van Moolenbroek /*%
730*00b67f09SDavid van Moolenbroek  * Gets a single field from the ODBC statement.  The memory for the
731*00b67f09SDavid van Moolenbroek  * returned data is dynamically allocated.  If this method is successful
732*00b67f09SDavid van Moolenbroek  * it is the reponsibility of the caller to free the memory using
733*00b67f09SDavid van Moolenbroek  * isc_mem_free(ns_g_mctx, *ptr);
734*00b67f09SDavid van Moolenbroek  */
735*00b67f09SDavid van Moolenbroek 
736*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_getField(SQLHSTMT * stmnt,SQLSMALLINT field,char ** data)737*00b67f09SDavid van Moolenbroek odbc_getField(SQLHSTMT *stmnt, SQLSMALLINT field, char **data) {
738*00b67f09SDavid van Moolenbroek 
739*00b67f09SDavid van Moolenbroek 	SQLLEN size;
740*00b67f09SDavid van Moolenbroek 
741*00b67f09SDavid van Moolenbroek 	REQUIRE(data != NULL && *data == NULL);
742*00b67f09SDavid van Moolenbroek 
743*00b67f09SDavid van Moolenbroek 	if (sqlOK(SQLColAttribute(stmnt, field, SQL_DESC_DISPLAY_SIZE,
744*00b67f09SDavid van Moolenbroek 				  NULL, 0, NULL, &size)) && size > 0) {
745*00b67f09SDavid van Moolenbroek 		*data = isc_mem_allocate(ns_g_mctx, size + 1);
746*00b67f09SDavid van Moolenbroek 		if (data != NULL) {
747*00b67f09SDavid van Moolenbroek 			if (sqlOK(SQLGetData(stmnt, field, SQL_C_CHAR,
748*00b67f09SDavid van Moolenbroek 					     *data, size + 1,&size)))
749*00b67f09SDavid van Moolenbroek 				return ISC_R_SUCCESS;
750*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, *data);
751*00b67f09SDavid van Moolenbroek 		}
752*00b67f09SDavid van Moolenbroek 	}
753*00b67f09SDavid van Moolenbroek 	return ISC_R_FAILURE;
754*00b67f09SDavid van Moolenbroek }
755*00b67f09SDavid van Moolenbroek 
756*00b67f09SDavid van Moolenbroek /*%
757*00b67f09SDavid van Moolenbroek  * Gets multiple fields from the ODBC statement.  The memory for the
758*00b67f09SDavid van Moolenbroek  * returned data is dynamically allocated.  If this method is successful
759*00b67f09SDavid van Moolenbroek  * it is the reponsibility of the caller to free the memory using
760*00b67f09SDavid van Moolenbroek  * isc_mem_free(ns_g_mctx, *ptr);
761*00b67f09SDavid van Moolenbroek  */
762*00b67f09SDavid van Moolenbroek 
763*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_getManyFields(SQLHSTMT * stmnt,SQLSMALLINT startField,SQLSMALLINT endField,char ** retData)764*00b67f09SDavid van Moolenbroek odbc_getManyFields(SQLHSTMT *stmnt, SQLSMALLINT startField,
765*00b67f09SDavid van Moolenbroek 		   SQLSMALLINT endField, char **retData) {
766*00b67f09SDavid van Moolenbroek 
767*00b67f09SDavid van Moolenbroek 	isc_result_t result;
768*00b67f09SDavid van Moolenbroek 	SQLLEN size;
769*00b67f09SDavid van Moolenbroek 	int totSize = 0;
770*00b67f09SDavid van Moolenbroek 	SQLSMALLINT i;
771*00b67f09SDavid van Moolenbroek 	int j = 0;
772*00b67f09SDavid van Moolenbroek 	char *data;
773*00b67f09SDavid van Moolenbroek 
774*00b67f09SDavid van Moolenbroek 	REQUIRE(retData != NULL && *retData == NULL);
775*00b67f09SDavid van Moolenbroek 	REQUIRE(startField > 0 && startField <= endField);
776*00b67f09SDavid van Moolenbroek 
777*00b67f09SDavid van Moolenbroek 	/* determine how large the data is */
778*00b67f09SDavid van Moolenbroek 	for (i=startField; i <= endField; i++)
779*00b67f09SDavid van Moolenbroek 		if (sqlOK(SQLColAttribute(stmnt, i, SQL_DESC_DISPLAY_SIZE,
780*00b67f09SDavid van Moolenbroek 					  NULL, 0, NULL, &size)) && size > 0) {
781*00b67f09SDavid van Moolenbroek 			/* always allow for a " " (space) character */
782*00b67f09SDavid van Moolenbroek 			totSize += (size + 1);
783*00b67f09SDavid van Moolenbroek 			/* after the data item */
784*00b67f09SDavid van Moolenbroek 		}
785*00b67f09SDavid van Moolenbroek 
786*00b67f09SDavid van Moolenbroek 	if (totSize < 1)
787*00b67f09SDavid van Moolenbroek 		return ISC_R_FAILURE;
788*00b67f09SDavid van Moolenbroek 
789*00b67f09SDavid van Moolenbroek 	/* allow for a "\n" at the end of the string/ */
790*00b67f09SDavid van Moolenbroek 	data = isc_mem_allocate(ns_g_mctx, ++totSize);
791*00b67f09SDavid van Moolenbroek 	if (data == NULL)
792*00b67f09SDavid van Moolenbroek 		return ISC_R_NOMEMORY;
793*00b67f09SDavid van Moolenbroek 
794*00b67f09SDavid van Moolenbroek 	result = ISC_R_FAILURE;
795*00b67f09SDavid van Moolenbroek 
796*00b67f09SDavid van Moolenbroek 	/* get the data and concat all fields into a large string */
797*00b67f09SDavid van Moolenbroek 	for (i=startField; i <= endField; i++) {
798*00b67f09SDavid van Moolenbroek 		if (sqlOK(SQLGetData(stmnt, i, SQL_C_CHAR, &(data[j]),
799*00b67f09SDavid van Moolenbroek 				     totSize - j, &size))) {
800*00b67f09SDavid van Moolenbroek 			if (size > 0) {
801*00b67f09SDavid van Moolenbroek 				j += size;
802*00b67f09SDavid van Moolenbroek 				data[j++] = ' ';
803*00b67f09SDavid van Moolenbroek 				data[j] = '\0';
804*00b67f09SDavid van Moolenbroek 				result = ISC_R_SUCCESS;
805*00b67f09SDavid van Moolenbroek 			}
806*00b67f09SDavid van Moolenbroek 		} else {
807*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, data);
808*00b67f09SDavid van Moolenbroek 			return ISC_R_FAILURE;
809*00b67f09SDavid van Moolenbroek 		}
810*00b67f09SDavid van Moolenbroek 	}
811*00b67f09SDavid van Moolenbroek 
812*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
813*00b67f09SDavid van Moolenbroek 		isc_mem_free(ns_g_mctx, data);
814*00b67f09SDavid van Moolenbroek 		return result;
815*00b67f09SDavid van Moolenbroek 	}
816*00b67f09SDavid van Moolenbroek 
817*00b67f09SDavid van Moolenbroek 	*retData = data;
818*00b67f09SDavid van Moolenbroek 	return ISC_R_SUCCESS;
819*00b67f09SDavid van Moolenbroek 
820*00b67f09SDavid van Moolenbroek }
821*00b67f09SDavid van Moolenbroek 
822*00b67f09SDavid van Moolenbroek /*%
823*00b67f09SDavid van Moolenbroek  * The processing of result sets for lookup and authority are
824*00b67f09SDavid van Moolenbroek  * exactly the same.  So that functionality has been moved
825*00b67f09SDavid van Moolenbroek  * into this function to minimize code.
826*00b67f09SDavid van Moolenbroek  */
827*00b67f09SDavid van Moolenbroek 
828*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_process_rs(dns_sdlzlookup_t * lookup,dbinstance_t * dbi)829*00b67f09SDavid van Moolenbroek odbc_process_rs(dns_sdlzlookup_t *lookup, dbinstance_t *dbi)
830*00b67f09SDavid van Moolenbroek {
831*00b67f09SDavid van Moolenbroek 
832*00b67f09SDavid van Moolenbroek 
833*00b67f09SDavid van Moolenbroek 	isc_result_t result;
834*00b67f09SDavid van Moolenbroek 	SQLSMALLINT fields;
835*00b67f09SDavid van Moolenbroek 	SQLHSTMT  *stmnt;
836*00b67f09SDavid van Moolenbroek 	char *ttl_s;
837*00b67f09SDavid van Moolenbroek 	char *type;
838*00b67f09SDavid van Moolenbroek 	char *data;
839*00b67f09SDavid van Moolenbroek 	char *endp;
840*00b67f09SDavid van Moolenbroek 	int ttl;
841*00b67f09SDavid van Moolenbroek 
842*00b67f09SDavid van Moolenbroek 	REQUIRE(dbi != NULL);
843*00b67f09SDavid van Moolenbroek 
844*00b67f09SDavid van Moolenbroek 	stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt;
845*00b67f09SDavid van Moolenbroek 
846*00b67f09SDavid van Moolenbroek 	/* get number of columns */
847*00b67f09SDavid van Moolenbroek 	if (!sqlOK(SQLNumResultCols(stmnt, &fields))) {
848*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
849*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
850*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to process result set");
851*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
852*00b67f09SDavid van Moolenbroek 		goto process_rs_cleanup;
853*00b67f09SDavid van Moolenbroek 	}
854*00b67f09SDavid van Moolenbroek 
855*00b67f09SDavid van Moolenbroek 	/* get things ready for processing */
856*00b67f09SDavid van Moolenbroek 	result = ISC_R_FAILURE;
857*00b67f09SDavid van Moolenbroek 
858*00b67f09SDavid van Moolenbroek 	while (sqlOK(SQLFetch(stmnt))) {
859*00b67f09SDavid van Moolenbroek 
860*00b67f09SDavid van Moolenbroek 		/* set to null for next pass through */
861*00b67f09SDavid van Moolenbroek 		data = type = ttl_s = NULL;
862*00b67f09SDavid van Moolenbroek 
863*00b67f09SDavid van Moolenbroek 		switch(fields) {
864*00b67f09SDavid van Moolenbroek 		case 1:
865*00b67f09SDavid van Moolenbroek 			/*
866*00b67f09SDavid van Moolenbroek 			 * one column in rs, it's the data field.  use
867*00b67f09SDavid van Moolenbroek 			 * default type of A record, and default TTL
868*00b67f09SDavid van Moolenbroek 			 * of 86400.  attempt to get data, & tell bind
869*00b67f09SDavid van Moolenbroek 			 * about it.
870*00b67f09SDavid van Moolenbroek 			 */
871*00b67f09SDavid van Moolenbroek 			if ((result = odbc_getField(stmnt, 1,
872*00b67f09SDavid van Moolenbroek 						    &data)) == ISC_R_SUCCESS) {
873*00b67f09SDavid van Moolenbroek 				result = dns_sdlz_putrr(lookup, "a",
874*00b67f09SDavid van Moolenbroek 							86400, data);
875*00b67f09SDavid van Moolenbroek 			}
876*00b67f09SDavid van Moolenbroek 			break;
877*00b67f09SDavid van Moolenbroek 		case 2:
878*00b67f09SDavid van Moolenbroek 			/*
879*00b67f09SDavid van Moolenbroek 			 * two columns, data field, and data type.
880*00b67f09SDavid van Moolenbroek 			 * use default TTL of 86400.  attempt to get
881*00b67f09SDavid van Moolenbroek 			 * DNS type & data, then tell bind about it.
882*00b67f09SDavid van Moolenbroek 			 */
883*00b67f09SDavid van Moolenbroek 			if ((result = odbc_getField(stmnt, 1,
884*00b67f09SDavid van Moolenbroek 						    &type)) == ISC_R_SUCCESS &&
885*00b67f09SDavid van Moolenbroek 			    (result = odbc_getField(stmnt, 2,
886*00b67f09SDavid van Moolenbroek 						    &data)) == ISC_R_SUCCESS) {
887*00b67f09SDavid van Moolenbroek 				result = dns_sdlz_putrr(lookup, type,
888*00b67f09SDavid van Moolenbroek 							86400, data);
889*00b67f09SDavid van Moolenbroek 			}
890*00b67f09SDavid van Moolenbroek 			break;
891*00b67f09SDavid van Moolenbroek 		default:
892*00b67f09SDavid van Moolenbroek 			/*
893*00b67f09SDavid van Moolenbroek 			 * 3 fields or more, concatenate the last ones
894*00b67f09SDavid van Moolenbroek 			 * together.  attempt to get DNS ttl, type,
895*00b67f09SDavid van Moolenbroek 			 * data then tell Bind about them.
896*00b67f09SDavid van Moolenbroek 			 */
897*00b67f09SDavid van Moolenbroek 			if ((result = odbc_getField(stmnt, 1, &ttl_s))
898*00b67f09SDavid van Moolenbroek 				== ISC_R_SUCCESS &&
899*00b67f09SDavid van Moolenbroek 			    (result = odbc_getField(stmnt, 2, &type))
900*00b67f09SDavid van Moolenbroek 				== ISC_R_SUCCESS &&
901*00b67f09SDavid van Moolenbroek 			    (result = odbc_getManyFields(stmnt, 3,
902*00b67f09SDavid van Moolenbroek 							 fields, &data))
903*00b67f09SDavid van Moolenbroek 				== ISC_R_SUCCESS) {
904*00b67f09SDavid van Moolenbroek 				/* try to convert ttl string to int */
905*00b67f09SDavid van Moolenbroek 				ttl = strtol(ttl_s, &endp, 10);
906*00b67f09SDavid van Moolenbroek 				/* failure converting ttl. */
907*00b67f09SDavid van Moolenbroek 				if (*endp != '\0' || ttl < 0) {
908*00b67f09SDavid van Moolenbroek 					isc_log_write(dns_lctx,
909*00b67f09SDavid van Moolenbroek 						      DNS_LOGCATEGORY_DATABASE,
910*00b67f09SDavid van Moolenbroek 						      DNS_LOGMODULE_DLZ,
911*00b67f09SDavid van Moolenbroek 						      ISC_LOG_ERROR,
912*00b67f09SDavid van Moolenbroek 						      "Odbc driver ttl must "
913*00b67f09SDavid van Moolenbroek 						      "be a postive number");
914*00b67f09SDavid van Moolenbroek 					result = ISC_R_FAILURE;
915*00b67f09SDavid van Moolenbroek 				} else {
916*00b67f09SDavid van Moolenbroek 					/*
917*00b67f09SDavid van Moolenbroek 					 * successful converting TTL,
918*00b67f09SDavid van Moolenbroek 					 * tell Bind everything
919*00b67f09SDavid van Moolenbroek 					 */
920*00b67f09SDavid van Moolenbroek 					result = dns_sdlz_putrr(lookup, type,
921*00b67f09SDavid van Moolenbroek 								ttl, data);
922*00b67f09SDavid van Moolenbroek 				}
923*00b67f09SDavid van Moolenbroek 			} /* closes bid if () */
924*00b67f09SDavid van Moolenbroek 		} /* closes switch(fields) */
925*00b67f09SDavid van Moolenbroek 
926*00b67f09SDavid van Moolenbroek 		/* clean up mem */
927*00b67f09SDavid van Moolenbroek 		if (ttl_s != NULL)
928*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, ttl_s);
929*00b67f09SDavid van Moolenbroek 		if (type != NULL)
930*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, type);
931*00b67f09SDavid van Moolenbroek 		if (data != NULL)
932*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, data);
933*00b67f09SDavid van Moolenbroek 
934*00b67f09SDavid van Moolenbroek 		/* I sure hope we were successful */
935*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
936*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
937*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
938*00b67f09SDavid van Moolenbroek 				      "dns_sdlz_putrr returned error. "
939*00b67f09SDavid van Moolenbroek 				      "Error code was: %s",
940*00b67f09SDavid van Moolenbroek 				      isc_result_totext(result));
941*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
942*00b67f09SDavid van Moolenbroek 			goto process_rs_cleanup;
943*00b67f09SDavid van Moolenbroek 		}
944*00b67f09SDavid van Moolenbroek 	} /* closes while loop */
945*00b67f09SDavid van Moolenbroek 
946*00b67f09SDavid van Moolenbroek  process_rs_cleanup:
947*00b67f09SDavid van Moolenbroek 
948*00b67f09SDavid van Moolenbroek 	/* close cursor */
949*00b67f09SDavid van Moolenbroek 	SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
950*00b67f09SDavid van Moolenbroek 
951*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
952*00b67f09SDavid van Moolenbroek 
953*00b67f09SDavid van Moolenbroek 	/* free lock on dbi so someone else can use it. */
954*00b67f09SDavid van Moolenbroek 	isc_mutex_unlock(&dbi->instance_lock);
955*00b67f09SDavid van Moolenbroek 
956*00b67f09SDavid van Moolenbroek #endif
957*00b67f09SDavid van Moolenbroek 
958*00b67f09SDavid van Moolenbroek 	return result;
959*00b67f09SDavid van Moolenbroek }
960*00b67f09SDavid van Moolenbroek 
961*00b67f09SDavid van Moolenbroek /*
962*00b67f09SDavid van Moolenbroek  * SDLZ interface methods
963*00b67f09SDavid van Moolenbroek  */
964*00b67f09SDavid van Moolenbroek 
965*00b67f09SDavid van Moolenbroek /*% determine if the zone is supported by (in) the database */
966*00b67f09SDavid van Moolenbroek 
967*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_findzone(void * driverarg,void * dbdata,const char * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)968*00b67f09SDavid van Moolenbroek odbc_findzone(void *driverarg, void *dbdata, const char *name,
969*00b67f09SDavid van Moolenbroek 	      dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
970*00b67f09SDavid van Moolenbroek {
971*00b67f09SDavid van Moolenbroek 
972*00b67f09SDavid van Moolenbroek 	isc_result_t result;
973*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
974*00b67f09SDavid van Moolenbroek 
975*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
976*00b67f09SDavid van Moolenbroek 	UNUSED(methods);
977*00b67f09SDavid van Moolenbroek 	UNUSED(clientinfo);
978*00b67f09SDavid van Moolenbroek 
979*00b67f09SDavid van Moolenbroek 	/* run the query and get the result set from the database. */
980*00b67f09SDavid van Moolenbroek 	/* if result != ISC_R_SUCCESS cursor and mutex already cleaned up. */
981*00b67f09SDavid van Moolenbroek 	/* so we don't have to do it here. */
982*00b67f09SDavid van Moolenbroek 	result = odbc_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &dbi);
983*00b67f09SDavid van Moolenbroek 
984*00b67f09SDavid van Moolenbroek 	/* Check that we got a result set with data */
985*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS &&
986*00b67f09SDavid van Moolenbroek 	    !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {
987*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOTFOUND;
988*00b67f09SDavid van Moolenbroek 	}
989*00b67f09SDavid van Moolenbroek 
990*00b67f09SDavid van Moolenbroek 	if (dbi != NULL) {
991*00b67f09SDavid van Moolenbroek 		/* get rid of result set, we are done with it. */
992*00b67f09SDavid van Moolenbroek 		SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
993*00b67f09SDavid van Moolenbroek 
994*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
995*00b67f09SDavid van Moolenbroek 
996*00b67f09SDavid van Moolenbroek 		/* free lock on dbi so someone else can use it. */
997*00b67f09SDavid van Moolenbroek 		isc_mutex_unlock(&dbi->instance_lock);
998*00b67f09SDavid van Moolenbroek #endif
999*00b67f09SDavid van Moolenbroek 	}
1000*00b67f09SDavid van Moolenbroek 
1001*00b67f09SDavid van Moolenbroek 	return result;
1002*00b67f09SDavid van Moolenbroek }
1003*00b67f09SDavid van Moolenbroek 
1004*00b67f09SDavid van Moolenbroek /*% Determine if the client is allowed to perform a zone transfer */
1005*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_allowzonexfr(void * driverarg,void * dbdata,const char * name,const char * client)1006*00b67f09SDavid van Moolenbroek odbc_allowzonexfr(void *driverarg, void *dbdata, const char *name,
1007*00b67f09SDavid van Moolenbroek 		  const char *client)
1008*00b67f09SDavid van Moolenbroek {
1009*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1010*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
1011*00b67f09SDavid van Moolenbroek 
1012*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
1013*00b67f09SDavid van Moolenbroek 
1014*00b67f09SDavid van Moolenbroek 	/* first check if the zone is supported by the database. */
1015*00b67f09SDavid van Moolenbroek 	result = odbc_findzone(driverarg, dbdata, name, NULL, NULL);
1016*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1017*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTFOUND);
1018*00b67f09SDavid van Moolenbroek 
1019*00b67f09SDavid van Moolenbroek 	/*
1020*00b67f09SDavid van Moolenbroek 	 * if we get to this point we know the zone is supported by
1021*00b67f09SDavid van Moolenbroek 	 * the database.  the only questions now are is the zone
1022*00b67f09SDavid van Moolenbroek 	 * transfer is allowed for this client and did the config file
1023*00b67f09SDavid van Moolenbroek 	 * have an allow zone xfr query
1024*00b67f09SDavid van Moolenbroek 	 *
1025*00b67f09SDavid van Moolenbroek 	 * Run our query, and get a result set from the database.  if
1026*00b67f09SDavid van Moolenbroek 	 * result != ISC_R_SUCCESS cursor and mutex already cleaned
1027*00b67f09SDavid van Moolenbroek 	 * up, so we don't have to do it here.
1028*00b67f09SDavid van Moolenbroek 	 */
1029*00b67f09SDavid van Moolenbroek 	result = odbc_get_resultset(name, NULL, client, ALLOWXFR,
1030*00b67f09SDavid van Moolenbroek 				    dbdata, &dbi);
1031*00b67f09SDavid van Moolenbroek 
1032*00b67f09SDavid van Moolenbroek 	/* if we get "not implemented", send it along. */
1033*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTIMPLEMENTED)
1034*00b67f09SDavid van Moolenbroek 		return result;
1035*00b67f09SDavid van Moolenbroek 
1036*00b67f09SDavid van Moolenbroek 	/* Check that we got a result set with data */
1037*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS &&
1038*00b67f09SDavid van Moolenbroek 	    !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {
1039*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOPERM;
1040*00b67f09SDavid van Moolenbroek 	}
1041*00b67f09SDavid van Moolenbroek 
1042*00b67f09SDavid van Moolenbroek 	if (dbi != NULL) {
1043*00b67f09SDavid van Moolenbroek 		/* get rid of result set, we are done with it. */
1044*00b67f09SDavid van Moolenbroek 		SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
1045*00b67f09SDavid van Moolenbroek 
1046*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1047*00b67f09SDavid van Moolenbroek 
1048*00b67f09SDavid van Moolenbroek 		/* free lock on dbi so someone else can use it. */
1049*00b67f09SDavid van Moolenbroek 		isc_mutex_unlock(&dbi->instance_lock);
1050*00b67f09SDavid van Moolenbroek #endif
1051*00b67f09SDavid van Moolenbroek 
1052*00b67f09SDavid van Moolenbroek 	}
1053*00b67f09SDavid van Moolenbroek 
1054*00b67f09SDavid van Moolenbroek 	return result;
1055*00b67f09SDavid van Moolenbroek }
1056*00b67f09SDavid van Moolenbroek 
1057*00b67f09SDavid van Moolenbroek /*%
1058*00b67f09SDavid van Moolenbroek  * If the client is allowed to perform a zone transfer, the next order of
1059*00b67f09SDavid van Moolenbroek  * business is to get all the nodes in the zone, so bind can respond to the
1060*00b67f09SDavid van Moolenbroek  * query.
1061*00b67f09SDavid van Moolenbroek  */
1062*00b67f09SDavid van Moolenbroek 
1063*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_allnodes(const char * zone,void * driverarg,void * dbdata,dns_sdlzallnodes_t * allnodes)1064*00b67f09SDavid van Moolenbroek odbc_allnodes(const char *zone, void *driverarg, void *dbdata,
1065*00b67f09SDavid van Moolenbroek 	      dns_sdlzallnodes_t *allnodes)
1066*00b67f09SDavid van Moolenbroek {
1067*00b67f09SDavid van Moolenbroek 
1068*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1069*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
1070*00b67f09SDavid van Moolenbroek 	SQLHSTMT  *stmnt;
1071*00b67f09SDavid van Moolenbroek 	SQLSMALLINT fields;
1072*00b67f09SDavid van Moolenbroek 	char *data;
1073*00b67f09SDavid van Moolenbroek 	char *type;
1074*00b67f09SDavid van Moolenbroek 	char *ttl_s;
1075*00b67f09SDavid van Moolenbroek 	int ttl;
1076*00b67f09SDavid van Moolenbroek 	char *host;
1077*00b67f09SDavid van Moolenbroek 	char *endp;
1078*00b67f09SDavid van Moolenbroek 
1079*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
1080*00b67f09SDavid van Moolenbroek 
1081*00b67f09SDavid van Moolenbroek 	/* run the query and get the result set from the database. */
1082*00b67f09SDavid van Moolenbroek 	result = odbc_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &dbi);
1083*00b67f09SDavid van Moolenbroek 
1084*00b67f09SDavid van Moolenbroek 	/* if we get "not implemented", send it along */
1085*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTIMPLEMENTED)
1086*00b67f09SDavid van Moolenbroek 		return result;
1087*00b67f09SDavid van Moolenbroek 
1088*00b67f09SDavid van Moolenbroek 	/* if we didn't get a result set, log an err msg. */
1089*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1090*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1091*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1092*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to return "
1093*00b67f09SDavid van Moolenbroek 			      "result set for all nodes query");
1094*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
1095*00b67f09SDavid van Moolenbroek 	}
1096*00b67f09SDavid van Moolenbroek 
1097*00b67f09SDavid van Moolenbroek 	stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt;
1098*00b67f09SDavid van Moolenbroek 
1099*00b67f09SDavid van Moolenbroek 	/* get number of columns */
1100*00b67f09SDavid van Moolenbroek 	if (!sqlOK(SQLNumResultCols(stmnt, &fields))) {
1101*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1102*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1103*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to process result set");
1104*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
1105*00b67f09SDavid van Moolenbroek 		goto allnodes_cleanup;
1106*00b67f09SDavid van Moolenbroek 	}
1107*00b67f09SDavid van Moolenbroek 
1108*00b67f09SDavid van Moolenbroek 	if (fields < 4) {	/* gotta have at least 4 columns */
1109*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1110*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1111*00b67f09SDavid van Moolenbroek 			      "Odbc driver too few fields returned by "
1112*00b67f09SDavid van Moolenbroek 			      "all nodes query");
1113*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
1114*00b67f09SDavid van Moolenbroek 		goto allnodes_cleanup;
1115*00b67f09SDavid van Moolenbroek 	}
1116*00b67f09SDavid van Moolenbroek 
1117*00b67f09SDavid van Moolenbroek 	/* get things ready for processing */
1118*00b67f09SDavid van Moolenbroek 	result = ISC_R_FAILURE;
1119*00b67f09SDavid van Moolenbroek 
1120*00b67f09SDavid van Moolenbroek 	while (sqlOK(SQLFetch(stmnt))) {
1121*00b67f09SDavid van Moolenbroek 
1122*00b67f09SDavid van Moolenbroek 		/* set to null for next pass through */
1123*00b67f09SDavid van Moolenbroek 		data = host = type = ttl_s = NULL;
1124*00b67f09SDavid van Moolenbroek 
1125*00b67f09SDavid van Moolenbroek 		/*
1126*00b67f09SDavid van Moolenbroek 		 * attempt to get DNS ttl, type, host, data then tell
1127*00b67f09SDavid van Moolenbroek 		 * Bind about them
1128*00b67f09SDavid van Moolenbroek 		 */
1129*00b67f09SDavid van Moolenbroek 		if ((result = odbc_getField(stmnt, 1,
1130*00b67f09SDavid van Moolenbroek 					    &ttl_s)) == ISC_R_SUCCESS &&
1131*00b67f09SDavid van Moolenbroek 		    (result = odbc_getField(stmnt, 2,
1132*00b67f09SDavid van Moolenbroek 					    &type)) == ISC_R_SUCCESS &&
1133*00b67f09SDavid van Moolenbroek 		    (result = odbc_getField(stmnt, 3,
1134*00b67f09SDavid van Moolenbroek 					    &host)) == ISC_R_SUCCESS &&
1135*00b67f09SDavid van Moolenbroek 		    (result = odbc_getManyFields(stmnt, 4, fields,
1136*00b67f09SDavid van Moolenbroek 						 &data)) == ISC_R_SUCCESS) {
1137*00b67f09SDavid van Moolenbroek 			/* convert ttl string to int */
1138*00b67f09SDavid van Moolenbroek 			ttl = strtol(ttl_s, &endp, 10);
1139*00b67f09SDavid van Moolenbroek 			/* failure converting ttl. */
1140*00b67f09SDavid van Moolenbroek 			if (*endp != '\0' || ttl < 0) {
1141*00b67f09SDavid van Moolenbroek 				isc_log_write(dns_lctx,
1142*00b67f09SDavid van Moolenbroek 					      DNS_LOGCATEGORY_DATABASE,
1143*00b67f09SDavid van Moolenbroek 					      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1144*00b67f09SDavid van Moolenbroek 					      "Odbc driver ttl must be "
1145*00b67f09SDavid van Moolenbroek 					      "a postive number");
1146*00b67f09SDavid van Moolenbroek 				result = ISC_R_FAILURE;
1147*00b67f09SDavid van Moolenbroek 			} else {
1148*00b67f09SDavid van Moolenbroek 				/* successful converting TTL, tell Bind  */
1149*00b67f09SDavid van Moolenbroek 				result = dns_sdlz_putnamedrr(allnodes, host,
1150*00b67f09SDavid van Moolenbroek 							     type, ttl, data);
1151*00b67f09SDavid van Moolenbroek 			}
1152*00b67f09SDavid van Moolenbroek 		} /* closes big if () */
1153*00b67f09SDavid van Moolenbroek 
1154*00b67f09SDavid van Moolenbroek 		/* clean up mem */
1155*00b67f09SDavid van Moolenbroek 		if (ttl_s != NULL)
1156*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, ttl_s);
1157*00b67f09SDavid van Moolenbroek 		if (type != NULL)
1158*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, type);
1159*00b67f09SDavid van Moolenbroek 		if (host != NULL)
1160*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, host);
1161*00b67f09SDavid van Moolenbroek 		if (data != NULL)
1162*00b67f09SDavid van Moolenbroek 			isc_mem_free(ns_g_mctx, data);
1163*00b67f09SDavid van Moolenbroek 
1164*00b67f09SDavid van Moolenbroek 		/* if we weren't successful, log err msg */
1165*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1166*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1167*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1168*00b67f09SDavid van Moolenbroek 				      "dns_sdlz_putnamedrr returned error. "
1169*00b67f09SDavid van Moolenbroek 				      "Error code was: %s",
1170*00b67f09SDavid van Moolenbroek 				      isc_result_totext(result));
1171*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
1172*00b67f09SDavid van Moolenbroek 			goto allnodes_cleanup;
1173*00b67f09SDavid van Moolenbroek 		}
1174*00b67f09SDavid van Moolenbroek 	} /* closes while loop */
1175*00b67f09SDavid van Moolenbroek 
1176*00b67f09SDavid van Moolenbroek  allnodes_cleanup:
1177*00b67f09SDavid van Moolenbroek 
1178*00b67f09SDavid van Moolenbroek 	/* close cursor */
1179*00b67f09SDavid van Moolenbroek 	SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
1180*00b67f09SDavid van Moolenbroek 
1181*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1182*00b67f09SDavid van Moolenbroek 
1183*00b67f09SDavid van Moolenbroek 	/* free lock on dbi so someone else can use it. */
1184*00b67f09SDavid van Moolenbroek 	isc_mutex_unlock(&dbi->instance_lock);
1185*00b67f09SDavid van Moolenbroek 
1186*00b67f09SDavid van Moolenbroek #endif
1187*00b67f09SDavid van Moolenbroek 
1188*00b67f09SDavid van Moolenbroek 	return result;
1189*00b67f09SDavid van Moolenbroek }
1190*00b67f09SDavid van Moolenbroek 
1191*00b67f09SDavid van Moolenbroek /*%
1192*00b67f09SDavid van Moolenbroek  * if the lookup function does not return SOA or NS records for the zone,
1193*00b67f09SDavid van Moolenbroek  * use this function to get that information for Bind.
1194*00b67f09SDavid van Moolenbroek  */
1195*00b67f09SDavid van Moolenbroek 
1196*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_authority(const char * zone,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup)1197*00b67f09SDavid van Moolenbroek odbc_authority(const char *zone, void *driverarg, void *dbdata,
1198*00b67f09SDavid van Moolenbroek 	       dns_sdlzlookup_t *lookup)
1199*00b67f09SDavid van Moolenbroek {
1200*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1201*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
1202*00b67f09SDavid van Moolenbroek 
1203*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
1204*00b67f09SDavid van Moolenbroek 
1205*00b67f09SDavid van Moolenbroek 	/* run the query and get the result set from the database. */
1206*00b67f09SDavid van Moolenbroek 	result = odbc_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &dbi);
1207*00b67f09SDavid van Moolenbroek 	/* if we get "not implemented", send it along */
1208*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTIMPLEMENTED)
1209*00b67f09SDavid van Moolenbroek 		return result;
1210*00b67f09SDavid van Moolenbroek 	/* if we didn't get a result set, log an err msg. */
1211*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1212*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1213*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1214*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to return "
1215*00b67f09SDavid van Moolenbroek 			      "result set for authority query");
1216*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
1217*00b67f09SDavid van Moolenbroek 	}
1218*00b67f09SDavid van Moolenbroek 	/* lookup and authority result sets are processed in the same manner */
1219*00b67f09SDavid van Moolenbroek 	/* odbc_process_rs does the job for both functions. */
1220*00b67f09SDavid van Moolenbroek 	return odbc_process_rs(lookup, dbi);
1221*00b67f09SDavid van Moolenbroek }
1222*00b67f09SDavid van Moolenbroek 
1223*00b67f09SDavid van Moolenbroek /*% if zone is supported, lookup up a (or multiple) record(s) in it */
1224*00b67f09SDavid van Moolenbroek 
1225*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_lookup(const char * zone,const char * name,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)1226*00b67f09SDavid van Moolenbroek odbc_lookup(const char *zone, const char *name, void *driverarg,
1227*00b67f09SDavid van Moolenbroek 	    void *dbdata, dns_sdlzlookup_t *lookup,
1228*00b67f09SDavid van Moolenbroek 	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
1229*00b67f09SDavid van Moolenbroek {
1230*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1231*00b67f09SDavid van Moolenbroek 	dbinstance_t *dbi = NULL;
1232*00b67f09SDavid van Moolenbroek 
1233*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
1234*00b67f09SDavid van Moolenbroek 	UNUSED(methods);
1235*00b67f09SDavid van Moolenbroek 	UNUSED(clientinfo);
1236*00b67f09SDavid van Moolenbroek 
1237*00b67f09SDavid van Moolenbroek 	/* run the query and get the result set from the database. */
1238*00b67f09SDavid van Moolenbroek 	result = odbc_get_resultset(zone, name, NULL, LOOKUP, dbdata, &dbi);
1239*00b67f09SDavid van Moolenbroek 	/* if we didn't get a result set, log an err msg. */
1240*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1241*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1242*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1243*00b67f09SDavid van Moolenbroek 			      "Odbc driver unable to return "
1244*00b67f09SDavid van Moolenbroek 			      "result set for lookup query");
1245*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
1246*00b67f09SDavid van Moolenbroek 	}
1247*00b67f09SDavid van Moolenbroek 	/* lookup and authority result sets are processed in the same manner */
1248*00b67f09SDavid van Moolenbroek 	/* odbc_process_rs does the job for both functions. */
1249*00b67f09SDavid van Moolenbroek 	return odbc_process_rs(lookup, dbi);
1250*00b67f09SDavid van Moolenbroek }
1251*00b67f09SDavid van Moolenbroek 
1252*00b67f09SDavid van Moolenbroek /*%
1253*00b67f09SDavid van Moolenbroek  * create an instance of the driver.  Remember, only 1 copy of the driver's
1254*00b67f09SDavid van Moolenbroek  * code is ever loaded, the driver has to remember which context it's
1255*00b67f09SDavid van Moolenbroek  * operating in.  This is done via use of the dbdata argument which is
1256*00b67f09SDavid van Moolenbroek  * passed into all query functions.
1257*00b67f09SDavid van Moolenbroek  */
1258*00b67f09SDavid van Moolenbroek static isc_result_t
odbc_create(const char * dlzname,unsigned int argc,char * argv[],void * driverarg,void ** dbdata)1259*00b67f09SDavid van Moolenbroek odbc_create(const char *dlzname, unsigned int argc, char *argv[],
1260*00b67f09SDavid van Moolenbroek 	    void *driverarg, void **dbdata)
1261*00b67f09SDavid van Moolenbroek {
1262*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1263*00b67f09SDavid van Moolenbroek 	odbc_instance_t *odbc_inst = NULL;
1264*00b67f09SDavid van Moolenbroek 	dbinstance_t *db = NULL;
1265*00b67f09SDavid van Moolenbroek 	SQLRETURN sqlRes;
1266*00b67f09SDavid van Moolenbroek 
1267*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1268*00b67f09SDavid van Moolenbroek 	/* if multi-threaded, we need a few extra variables. */
1269*00b67f09SDavid van Moolenbroek 	int dbcount;
1270*00b67f09SDavid van Moolenbroek 	int i;
1271*00b67f09SDavid van Moolenbroek 	char *endp;
1272*00b67f09SDavid van Moolenbroek 
1273*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
1274*00b67f09SDavid van Moolenbroek 
1275*00b67f09SDavid van Moolenbroek 	UNUSED(dlzname);
1276*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
1277*00b67f09SDavid van Moolenbroek 
1278*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1279*00b67f09SDavid van Moolenbroek 	/* if debugging, let user know we are multithreaded. */
1280*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1281*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
1282*00b67f09SDavid van Moolenbroek 		      "Odbc driver running multithreaded");
1283*00b67f09SDavid van Moolenbroek #else /* ISC_PLATFORM_USETHREADS */
1284*00b67f09SDavid van Moolenbroek 	/* if debugging, let user know we are single threaded. */
1285*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1286*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
1287*00b67f09SDavid van Moolenbroek 		      "Odbc driver running single threaded");
1288*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
1289*00b67f09SDavid van Moolenbroek 
1290*00b67f09SDavid van Moolenbroek 	/* verify we have at least 5 arg's passed to the driver */
1291*00b67f09SDavid van Moolenbroek 	if (argc < 5) {
1292*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1293*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1294*00b67f09SDavid van Moolenbroek 			      "Odbc driver requires at least "
1295*00b67f09SDavid van Moolenbroek 			      "4 command line args.");
1296*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
1297*00b67f09SDavid van Moolenbroek 	}
1298*00b67f09SDavid van Moolenbroek 
1299*00b67f09SDavid van Moolenbroek 	/* no more than 8 arg's should be passed to the driver */
1300*00b67f09SDavid van Moolenbroek 	if (argc > 8) {
1301*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1302*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1303*00b67f09SDavid van Moolenbroek 			      "Odbc driver cannot accept more than "
1304*00b67f09SDavid van Moolenbroek 			      "7 command line args.");
1305*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
1306*00b67f09SDavid van Moolenbroek 	}
1307*00b67f09SDavid van Moolenbroek 
1308*00b67f09SDavid van Moolenbroek 	/* multithreaded build can have multiple DB connections */
1309*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1310*00b67f09SDavid van Moolenbroek 
1311*00b67f09SDavid van Moolenbroek 	/* check how many db connections we should create */
1312*00b67f09SDavid van Moolenbroek 	dbcount = strtol(argv[1], &endp, 10);
1313*00b67f09SDavid van Moolenbroek 	if (*endp != '\0' || dbcount < 0) {
1314*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1315*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1316*00b67f09SDavid van Moolenbroek 			      "Odbc driver database connection count "
1317*00b67f09SDavid van Moolenbroek 			      "must be positive.");
1318*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
1319*00b67f09SDavid van Moolenbroek 	}
1320*00b67f09SDavid van Moolenbroek 
1321*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
1322*00b67f09SDavid van Moolenbroek 
1323*00b67f09SDavid van Moolenbroek 	/* allocate memory for odbc instance */
1324*00b67f09SDavid van Moolenbroek 	odbc_inst = isc_mem_get(ns_g_mctx, sizeof(odbc_instance_t));
1325*00b67f09SDavid van Moolenbroek 	if (odbc_inst == NULL)
1326*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
1327*00b67f09SDavid van Moolenbroek 	memset(odbc_inst, 0, sizeof(odbc_instance_t));
1328*00b67f09SDavid van Moolenbroek 
1329*00b67f09SDavid van Moolenbroek 	/* parse connection string and get paramters. */
1330*00b67f09SDavid van Moolenbroek 
1331*00b67f09SDavid van Moolenbroek 	/* get odbc database dsn - required */
1332*00b67f09SDavid van Moolenbroek 	odbc_inst->dsn = (SQLCHAR *) getParameterValue(argv[2],
1333*00b67f09SDavid van Moolenbroek 						       "dsn=");
1334*00b67f09SDavid van Moolenbroek 	if (odbc_inst->dsn == NULL) {
1335*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1336*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1337*00b67f09SDavid van Moolenbroek 			      "odbc driver requires a dns parameter.");
1338*00b67f09SDavid van Moolenbroek 		result = ISC_R_FAILURE;
1339*00b67f09SDavid van Moolenbroek 		goto cleanup;
1340*00b67f09SDavid van Moolenbroek 	}
1341*00b67f09SDavid van Moolenbroek 	/* get odbc database username */
1342*00b67f09SDavid van Moolenbroek 	/* if no username was passed, set odbc_inst.user = NULL; */
1343*00b67f09SDavid van Moolenbroek 	odbc_inst->user = (SQLCHAR *) getParameterValue(argv[2],
1344*00b67f09SDavid van Moolenbroek 							"user=");
1345*00b67f09SDavid van Moolenbroek 
1346*00b67f09SDavid van Moolenbroek 	/* get odbc database password */
1347*00b67f09SDavid van Moolenbroek 	/* if no password was passed, set odbc_inst.pass = NULL; */
1348*00b67f09SDavid van Moolenbroek 	odbc_inst->pass = (SQLCHAR *) getParameterValue(argv[2], "pass=");
1349*00b67f09SDavid van Moolenbroek 
1350*00b67f09SDavid van Moolenbroek 	/* create odbc environment & set environment to ODBC V3 */
1351*00b67f09SDavid van Moolenbroek 	if (odbc_inst->sql_env == NULL) {
1352*00b67f09SDavid van Moolenbroek 		/* create environment handle */
1353*00b67f09SDavid van Moolenbroek 		sqlRes = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
1354*00b67f09SDavid van Moolenbroek 					&(odbc_inst->sql_env));
1355*00b67f09SDavid van Moolenbroek 		if (!sqlOK(sqlRes)) {
1356*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1357*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
1358*00b67f09SDavid van Moolenbroek 				      "Odbc driver unable to allocate memory");
1359*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
1360*00b67f09SDavid van Moolenbroek 			goto cleanup;
1361*00b67f09SDavid van Moolenbroek 		}
1362*00b67f09SDavid van Moolenbroek 		/*set ODBC version = 3 */
1363*00b67f09SDavid van Moolenbroek 		sqlRes = SQLSetEnvAttr(odbc_inst->sql_env,
1364*00b67f09SDavid van Moolenbroek 				       SQL_ATTR_ODBC_VERSION,
1365*00b67f09SDavid van Moolenbroek 				       (void *) SQL_OV_ODBC3, 0);
1366*00b67f09SDavid van Moolenbroek 		if (!sqlOK(sqlRes)) {
1367*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1368*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
1369*00b67f09SDavid van Moolenbroek 				      "Unable to configure ODBC environment");
1370*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
1371*00b67f09SDavid van Moolenbroek 			goto cleanup;
1372*00b67f09SDavid van Moolenbroek 		}
1373*00b67f09SDavid van Moolenbroek 	}
1374*00b67f09SDavid van Moolenbroek 
1375*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1376*00b67f09SDavid van Moolenbroek 
1377*00b67f09SDavid van Moolenbroek 	/* allocate memory for database connection list */
1378*00b67f09SDavid van Moolenbroek 	odbc_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
1379*00b67f09SDavid van Moolenbroek 	if (odbc_inst->db == NULL) {
1380*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1381*00b67f09SDavid van Moolenbroek 		goto cleanup;
1382*00b67f09SDavid van Moolenbroek 	}
1383*00b67f09SDavid van Moolenbroek 
1384*00b67f09SDavid van Moolenbroek 
1385*00b67f09SDavid van Moolenbroek 	/* initialize DB connection list */
1386*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(*odbc_inst->db);
1387*00b67f09SDavid van Moolenbroek 
1388*00b67f09SDavid van Moolenbroek 	/* create the appropriate number of database instances (DBI) */
1389*00b67f09SDavid van Moolenbroek 	/* append each new DBI to the end of the list */
1390*00b67f09SDavid van Moolenbroek 	for (i=0; i < dbcount; i++) {
1391*00b67f09SDavid van Moolenbroek 
1392*00b67f09SDavid van Moolenbroek #endif /* ISC_PLATFORM_USETHREADS */
1393*00b67f09SDavid van Moolenbroek 
1394*00b67f09SDavid van Moolenbroek 		/* how many queries were passed in from config file? */
1395*00b67f09SDavid van Moolenbroek 		switch(argc) {
1396*00b67f09SDavid van Moolenbroek 		case 5:
1397*00b67f09SDavid van Moolenbroek 			result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
1398*00b67f09SDavid van Moolenbroek 						     NULL, argv[3], argv[4],
1399*00b67f09SDavid van Moolenbroek 						     NULL, &db);
1400*00b67f09SDavid van Moolenbroek 			break;
1401*00b67f09SDavid van Moolenbroek 		case 6:
1402*00b67f09SDavid van Moolenbroek 			result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
1403*00b67f09SDavid van Moolenbroek 						     argv[5], argv[3], argv[4],
1404*00b67f09SDavid van Moolenbroek 						     NULL, &db);
1405*00b67f09SDavid van Moolenbroek 			break;
1406*00b67f09SDavid van Moolenbroek 		case 7:
1407*00b67f09SDavid van Moolenbroek 			result = build_sqldbinstance(ns_g_mctx, argv[6], NULL,
1408*00b67f09SDavid van Moolenbroek 						     argv[5], argv[3], argv[4],
1409*00b67f09SDavid van Moolenbroek 						     NULL, &db);
1410*00b67f09SDavid van Moolenbroek 			break;
1411*00b67f09SDavid van Moolenbroek 		case 8:
1412*00b67f09SDavid van Moolenbroek 			result = build_sqldbinstance(ns_g_mctx, argv[6],
1413*00b67f09SDavid van Moolenbroek 						     argv[7], argv[5], argv[3],
1414*00b67f09SDavid van Moolenbroek 						     argv[4], NULL, &db);
1415*00b67f09SDavid van Moolenbroek 			break;
1416*00b67f09SDavid van Moolenbroek 		default:
1417*00b67f09SDavid van Moolenbroek 			/* not really needed, should shut up compiler. */
1418*00b67f09SDavid van Moolenbroek 			result = ISC_R_FAILURE;
1419*00b67f09SDavid van Moolenbroek 		}
1420*00b67f09SDavid van Moolenbroek 
1421*00b67f09SDavid van Moolenbroek 		/* unsuccessful?, log err msg and cleanup. */
1422*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1423*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1424*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1425*00b67f09SDavid van Moolenbroek 				      "Odbc driver could not create "
1426*00b67f09SDavid van Moolenbroek 				      "database instance object.");
1427*00b67f09SDavid van Moolenbroek 			goto cleanup;
1428*00b67f09SDavid van Moolenbroek 		}
1429*00b67f09SDavid van Moolenbroek 
1430*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1431*00b67f09SDavid van Moolenbroek 
1432*00b67f09SDavid van Moolenbroek 		/* when multithreaded, build a list of DBI's */
1433*00b67f09SDavid van Moolenbroek 		ISC_LINK_INIT(db, link);
1434*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(*odbc_inst->db, db, link);
1435*00b67f09SDavid van Moolenbroek 
1436*00b67f09SDavid van Moolenbroek #endif
1437*00b67f09SDavid van Moolenbroek 
1438*00b67f09SDavid van Moolenbroek 		result = odbc_connect(odbc_inst, (odbc_db_t **) &(db->dbconn));
1439*00b67f09SDavid van Moolenbroek 
1440*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1441*00b67f09SDavid van Moolenbroek 
1442*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1443*00b67f09SDavid van Moolenbroek 
1444*00b67f09SDavid van Moolenbroek 			/*
1445*00b67f09SDavid van Moolenbroek 			 * if multi threaded, let user know which
1446*00b67f09SDavid van Moolenbroek 			 * connection failed.  user could be
1447*00b67f09SDavid van Moolenbroek 			 * attempting to create 10 db connections and
1448*00b67f09SDavid van Moolenbroek 			 * for some reason the db backend only allows
1449*00b67f09SDavid van Moolenbroek 			 * 9.
1450*00b67f09SDavid van Moolenbroek 			 */
1451*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1452*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1453*00b67f09SDavid van Moolenbroek 				      "Odbc driver failed to create database "
1454*00b67f09SDavid van Moolenbroek 				      "connection number %u after 3 attempts",
1455*00b67f09SDavid van Moolenbroek 				      i+1);
1456*00b67f09SDavid van Moolenbroek #else
1457*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1458*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1459*00b67f09SDavid van Moolenbroek 				      "Odbc driver failed to create database "
1460*00b67f09SDavid van Moolenbroek 				      "connection after 3 attempts");
1461*00b67f09SDavid van Moolenbroek #endif
1462*00b67f09SDavid van Moolenbroek 			goto cleanup;
1463*00b67f09SDavid van Moolenbroek 		}
1464*00b67f09SDavid van Moolenbroek 
1465*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USETHREADS
1466*00b67f09SDavid van Moolenbroek 
1467*00b67f09SDavid van Moolenbroek 		/* set DB = null for next loop through. */
1468*00b67f09SDavid van Moolenbroek 		db = NULL;
1469*00b67f09SDavid van Moolenbroek 
1470*00b67f09SDavid van Moolenbroek 	}	/* end for loop */
1471*00b67f09SDavid van Moolenbroek 
1472*00b67f09SDavid van Moolenbroek #else
1473*00b67f09SDavid van Moolenbroek 	/* tell odbc_inst about the db connection we just created. */
1474*00b67f09SDavid van Moolenbroek 	odbc_inst->db = db;
1475*00b67f09SDavid van Moolenbroek 
1476*00b67f09SDavid van Moolenbroek #endif
1477*00b67f09SDavid van Moolenbroek 
1478*00b67f09SDavid van Moolenbroek 	/* set dbdata to the odbc_instance we created. */
1479*00b67f09SDavid van Moolenbroek 	*dbdata = odbc_inst;
1480*00b67f09SDavid van Moolenbroek 
1481*00b67f09SDavid van Moolenbroek 	/* hey, we got through all of that ok, return success. */
1482*00b67f09SDavid van Moolenbroek 	return(ISC_R_SUCCESS);
1483*00b67f09SDavid van Moolenbroek 
1484*00b67f09SDavid van Moolenbroek  cleanup:
1485*00b67f09SDavid van Moolenbroek 
1486*00b67f09SDavid van Moolenbroek 	destroy_odbc_instance(odbc_inst);
1487*00b67f09SDavid van Moolenbroek 
1488*00b67f09SDavid van Moolenbroek 	return result;
1489*00b67f09SDavid van Moolenbroek }
1490*00b67f09SDavid van Moolenbroek 
1491*00b67f09SDavid van Moolenbroek /*%
1492*00b67f09SDavid van Moolenbroek  * destroy an instance of the driver.  Remember, only 1 copy of the driver's
1493*00b67f09SDavid van Moolenbroek  * code is ever loaded, the driver has to remember which context it's
1494*00b67f09SDavid van Moolenbroek  * operating in.  This is done via use of the dbdata argument.
1495*00b67f09SDavid van Moolenbroek  * so we really only need to clean it up since we are not using driverarg.
1496*00b67f09SDavid van Moolenbroek  */
1497*00b67f09SDavid van Moolenbroek 
1498*00b67f09SDavid van Moolenbroek static void
odbc_destroy(void * driverarg,void * dbdata)1499*00b67f09SDavid van Moolenbroek odbc_destroy(void *driverarg, void *dbdata)
1500*00b67f09SDavid van Moolenbroek {
1501*00b67f09SDavid van Moolenbroek 	UNUSED(driverarg);
1502*00b67f09SDavid van Moolenbroek 
1503*00b67f09SDavid van Moolenbroek 	destroy_odbc_instance((odbc_instance_t *) dbdata);
1504*00b67f09SDavid van Moolenbroek }
1505*00b67f09SDavid van Moolenbroek 
1506*00b67f09SDavid van Moolenbroek 
1507*00b67f09SDavid van Moolenbroek /* pointers to all our runtime methods. */
1508*00b67f09SDavid van Moolenbroek /* this is used during driver registration */
1509*00b67f09SDavid van Moolenbroek /* i.e. in dlz_odbc_init below. */
1510*00b67f09SDavid van Moolenbroek static dns_sdlzmethods_t dlz_odbc_methods = {
1511*00b67f09SDavid van Moolenbroek 	odbc_create,
1512*00b67f09SDavid van Moolenbroek 	odbc_destroy,
1513*00b67f09SDavid van Moolenbroek 	odbc_findzone,
1514*00b67f09SDavid van Moolenbroek 	odbc_lookup,
1515*00b67f09SDavid van Moolenbroek 	odbc_authority,
1516*00b67f09SDavid van Moolenbroek 	odbc_allnodes,
1517*00b67f09SDavid van Moolenbroek 	odbc_allowzonexfr,
1518*00b67f09SDavid van Moolenbroek 	NULL,
1519*00b67f09SDavid van Moolenbroek 	NULL,
1520*00b67f09SDavid van Moolenbroek 	NULL,
1521*00b67f09SDavid van Moolenbroek 	NULL,
1522*00b67f09SDavid van Moolenbroek 	NULL,
1523*00b67f09SDavid van Moolenbroek 	NULL,
1524*00b67f09SDavid van Moolenbroek 	NULL,
1525*00b67f09SDavid van Moolenbroek };
1526*00b67f09SDavid van Moolenbroek 
1527*00b67f09SDavid van Moolenbroek /*%
1528*00b67f09SDavid van Moolenbroek  * Wrapper around dns_sdlzregister().
1529*00b67f09SDavid van Moolenbroek  */
1530*00b67f09SDavid van Moolenbroek isc_result_t
dlz_odbc_init(void)1531*00b67f09SDavid van Moolenbroek dlz_odbc_init(void) {
1532*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1533*00b67f09SDavid van Moolenbroek 
1534*00b67f09SDavid van Moolenbroek 	/*
1535*00b67f09SDavid van Moolenbroek 	 * Write debugging message to log
1536*00b67f09SDavid van Moolenbroek 	 */
1537*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1538*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1539*00b67f09SDavid van Moolenbroek 		      "Registering DLZ odbc driver.");
1540*00b67f09SDavid van Moolenbroek 
1541*00b67f09SDavid van Moolenbroek 	/*
1542*00b67f09SDavid van Moolenbroek 	 * Driver is always threadsafe.  When multithreaded all
1543*00b67f09SDavid van Moolenbroek 	 * functions use multithreaded code.  When not multithreaded,
1544*00b67f09SDavid van Moolenbroek 	 * all functions can only be entered once, but only 1 thread
1545*00b67f09SDavid van Moolenbroek 	 * of operation is available in Bind.  So everything is still
1546*00b67f09SDavid van Moolenbroek 	 * threadsafe.
1547*00b67f09SDavid van Moolenbroek 	 */
1548*00b67f09SDavid van Moolenbroek 	result = dns_sdlzregister("odbc", &dlz_odbc_methods, NULL,
1549*00b67f09SDavid van Moolenbroek 				  DNS_SDLZFLAG_RELATIVEOWNER |
1550*00b67f09SDavid van Moolenbroek 				  DNS_SDLZFLAG_RELATIVERDATA |
1551*00b67f09SDavid van Moolenbroek 				  DNS_SDLZFLAG_THREADSAFE,
1552*00b67f09SDavid van Moolenbroek 				  ns_g_mctx, &dlz_odbc);
1553*00b67f09SDavid van Moolenbroek 	/* if we can't register the driver, there are big problems. */
1554*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1555*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1556*00b67f09SDavid van Moolenbroek 				 "dns_sdlzregister() failed: %s",
1557*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
1558*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
1559*00b67f09SDavid van Moolenbroek 	}
1560*00b67f09SDavid van Moolenbroek 
1561*00b67f09SDavid van Moolenbroek 
1562*00b67f09SDavid van Moolenbroek 	return result;
1563*00b67f09SDavid van Moolenbroek }
1564*00b67f09SDavid van Moolenbroek 
1565*00b67f09SDavid van Moolenbroek /*%
1566*00b67f09SDavid van Moolenbroek  * Wrapper around dns_sdlzunregister().
1567*00b67f09SDavid van Moolenbroek  */
1568*00b67f09SDavid van Moolenbroek void
dlz_odbc_clear(void)1569*00b67f09SDavid van Moolenbroek dlz_odbc_clear(void) {
1570*00b67f09SDavid van Moolenbroek 
1571*00b67f09SDavid van Moolenbroek 	/*
1572*00b67f09SDavid van Moolenbroek 	 * Write debugging message to log
1573*00b67f09SDavid van Moolenbroek 	 */
1574*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1575*00b67f09SDavid van Moolenbroek 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1576*00b67f09SDavid van Moolenbroek 		      "Unregistering DLZ odbc driver.");
1577*00b67f09SDavid van Moolenbroek 
1578*00b67f09SDavid van Moolenbroek 	/* unregister the driver. */
1579*00b67f09SDavid van Moolenbroek 	if (dlz_odbc != NULL)
1580*00b67f09SDavid van Moolenbroek 		dns_sdlzunregister(&dlz_odbc);
1581*00b67f09SDavid van Moolenbroek }
1582*00b67f09SDavid van Moolenbroek 
1583*00b67f09SDavid van Moolenbroek #endif
1584