xref: /minix3/external/bsd/bind/dist/contrib/dlz/drivers/dlz_ldap_driver.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1 /*	$NetBSD: dlz_ldap_driver.c,v 1.7 2014/12/10 04:37:55 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the
8  * above copyright notice and this permission notice appear in all
9  * copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18  * USE OR PERFORMANCE OF THIS SOFTWARE.
19  *
20  * The development of Dynamically Loadable Zones (DLZ) for BIND 9 was
21  * conceived and contributed by Rob Butler.
22  *
23  * Permission to use, copy, modify, and distribute this software for any
24  * purpose with or without fee is hereby granted, provided that the
25  * above copyright notice and this permission notice appear in all
26  * copies.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35  * USE OR PERFORMANCE OF THIS SOFTWARE.
36  */
37 
38 /*
39  * Copyright (C) 1999-2001  Internet Software Consortium.
40  *
41  * Permission to use, copy, modify, and distribute this software for any
42  * purpose with or without fee is hereby granted, provided that the above
43  * copyright notice and this permission notice appear in all copies.
44  *
45  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
46  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
49  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
50  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
51  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53  */
54 
55 #ifdef DLZ_LDAP
56 
57 #include <config.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <stdlib.h>
61 
62 #include <dns/log.h>
63 #include <dns/sdlz.h>
64 #include <dns/result.h>
65 
66 #include <isc/mem.h>
67 #include <isc/platform.h>
68 #include <isc/print.h>
69 #include <isc/result.h>
70 #include <isc/string.h>
71 #include <isc/util.h>
72 
73 #include <named/globals.h>
74 
75 #include <dlz/sdlz_helper.h>
76 #include <dlz/dlz_ldap_driver.h>
77 
78 /*
79  * Need older API functions from ldap.h.
80  */
81 #define LDAP_DEPRECATED 1
82 
83 #include <ldap.h>
84 
85 #define SIMPLE "simple"
86 #define KRB41 "krb41"
87 #define KRB42 "krb42"
88 #define V2 "v2"
89 #define V3 "v3"
90 
91 static dns_sdlzimplementation_t *dlz_ldap = NULL;
92 
93 #define dbc_search_limit 30
94 #define ALLNODES 1
95 #define ALLOWXFR 2
96 #define AUTHORITY 3
97 #define FINDZONE 4
98 #define LOOKUP 5
99 
100 /*%
101  * Structure to hold everthing needed by this "instance" of the LDAP
102  * driver remember, the driver code is only loaded once, but may have
103  * many separate instances.
104  */
105 
106 typedef struct {
107 #ifdef ISC_PLATFORM_USETHREADS
108 	db_list_t    *db; /*%< handle to a list of DB */
109 #else
110 	dbinstance_t *db; /*%< handle to db */
111 #endif
112 	int method;	/*%< security authentication method */
113 	char *user;	/*%< who is authenticating */
114 	char *cred;	/*%< password for simple authentication method */
115 	int protocol;	/*%< LDAP communication protocol version */
116 	char *hosts;	/*%< LDAP server hosts */
117 } ldap_instance_t;
118 
119 /* forward references */
120 
121 static isc_result_t
122 dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name,
123 		  dns_clientinfomethods_t *methods,
124 		  dns_clientinfo_t *clientinfo);
125 
126 static void
127 dlz_ldap_destroy(void *driverarg, void *dbdata);
128 
129 /*
130  * Private methods
131  */
132 
133 /*% checks that the LDAP URL parameters make sense */
134 static isc_result_t
dlz_ldap_checkURL(char * URL,int attrCnt,const char * msg)135 dlz_ldap_checkURL(char *URL, int attrCnt, const char *msg) {
136 	isc_result_t result = ISC_R_SUCCESS;
137 	int ldap_result;
138 	LDAPURLDesc *ldap_url = NULL;
139 
140 	if (!ldap_is_ldap_url(URL)) {
141 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
142 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
143 			      "%s query is not a valid LDAP URL", msg);
144 		result = ISC_R_FAILURE;
145 		goto cleanup;
146 	}
147 
148 	ldap_result = ldap_url_parse(URL, &ldap_url);
149 	if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
150 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
151 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
152 			      "parsing %s query failed", msg);
153 		result = ISC_R_FAILURE;
154 		goto cleanup;
155 	}
156 
157 	if (ldap_count_values(ldap_url->lud_attrs) < attrCnt) {
158 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
159 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
160 			      "%s query must specify at least "
161 			      "%d attributes to return",
162 			      msg, attrCnt);
163 		result = ISC_R_FAILURE;
164 		goto cleanup;
165 	}
166 
167 	if (ldap_url->lud_host != NULL) {
168 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
169 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
170 			      "%s query must not specify a host", msg);
171 		result = ISC_R_FAILURE;
172 		goto cleanup;
173 	}
174 
175 	if (ldap_url->lud_port != 389) {
176 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
177 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
178 			      "%s query must not specify a port", msg);
179 		result = ISC_R_FAILURE;
180 		goto cleanup;
181 	}
182 
183 	if (ldap_url->lud_dn == NULL || strlen (ldap_url->lud_dn) < 1) {
184 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
185 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
186 			      "%s query must specify a search base", msg);
187 		result = ISC_R_FAILURE;
188 		goto cleanup;
189 	}
190 
191 	if (ldap_url->lud_exts != NULL || ldap_url->lud_crit_exts != 0) {
192 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
193 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
194 			      "%s uses extensions. "
195 			      "The driver does not support LDAP extensions.",
196 			      msg);
197 		result = ISC_R_FAILURE;
198 		goto cleanup;
199 	}
200 
201  cleanup:
202 	if (ldap_url != NULL)
203 		ldap_free_urldesc(ldap_url);
204 
205 	return (result);
206 }
207 
208 /*% Connects / reconnects to LDAP server */
209 static isc_result_t
dlz_ldap_connect(ldap_instance_t * dbi,dbinstance_t * dbc)210 dlz_ldap_connect(ldap_instance_t *dbi, dbinstance_t *dbc) {
211 	isc_result_t result;
212 	int ldap_result;
213 
214 	/* if we have a connection, get ride of it. */
215 	if (dbc->dbconn != NULL) {
216 		ldap_unbind_s((LDAP *) dbc->dbconn);
217 		dbc->dbconn = NULL;
218 	}
219 
220 	/* now connect / reconnect. */
221 
222 	/* initialize. */
223 	dbc->dbconn = ldap_init(dbi->hosts, LDAP_PORT);
224 	if (dbc->dbconn == NULL)
225 		return (ISC_R_NOMEMORY);
226 
227 	/* set protocol version. */
228 	ldap_result = ldap_set_option((LDAP *) dbc->dbconn,
229 				      LDAP_OPT_PROTOCOL_VERSION,
230 				      &(dbi->protocol));
231 	if (ldap_result != LDAP_SUCCESS) {
232 		result = ISC_R_NOPERM;
233 		goto cleanup;
234 	}
235 
236 	/* "bind" to server.  i.e. send username / pass */
237 	ldap_result = ldap_bind_s((LDAP *) dbc->dbconn, dbi->user,
238 				  dbi->cred, dbi->method);
239 	if (ldap_result != LDAP_SUCCESS) {
240 		result = ISC_R_FAILURE;
241 		goto cleanup;
242 	}
243 
244 	return (ISC_R_SUCCESS);
245 
246  cleanup:
247 
248 	/* cleanup if failure. */
249 	if (dbc->dbconn != NULL) {
250 		ldap_unbind_s((LDAP *) dbc->dbconn);
251 		dbc->dbconn = NULL;
252 	}
253 
254 	return (result);
255 }
256 
257 #ifdef ISC_PLATFORM_USETHREADS
258 
259 
260 /*%
261  * Properly cleans up a list of database instances.
262  * This function is only used when the driver is compiled for
263  * multithreaded operation.
264  */
265 static void
ldap_destroy_dblist(db_list_t * dblist)266 ldap_destroy_dblist(db_list_t *dblist) {
267 	dbinstance_t *ndbi = NULL;
268 	dbinstance_t *dbi = NULL;
269 
270 	/* get the first DBI in the list */
271 	ndbi = ISC_LIST_HEAD(*dblist);
272 
273 	/* loop through the list */
274 	while (ndbi != NULL) {
275 		dbi = ndbi;
276 		/* get the next DBI in the list */
277 		ndbi = ISC_LIST_NEXT(dbi, link);
278 		/* release DB connection */
279 		if (dbi->dbconn != NULL)
280 			ldap_unbind_s((LDAP *) dbi->dbconn);
281 		/* release all memory that comprised a DBI */
282 		destroy_sqldbinstance(dbi);
283 	}
284 	/* release memory for the list structure */
285 	isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t));
286 }
287 
288 /*%
289  * Loops through the list of DB instances, attempting to lock
290  * on the mutex.  If successful, the DBI is reserved for use
291  * and the thread can perform queries against the database.
292  * If the lock fails, the next one in the list is tried.
293  * looping continues until a lock is obtained, or until
294  * the list has been searched dbc_search_limit times.
295  * This function is only used when the driver is compiled for
296  * multithreaded operation.
297  */
298 static dbinstance_t *
ldap_find_avail_conn(db_list_t * dblist)299 ldap_find_avail_conn(db_list_t *dblist) {
300 	dbinstance_t *dbi = NULL;
301 	dbinstance_t *head;
302 	int count = 0;
303 
304 	/* get top of list */
305 	head = dbi = ISC_LIST_HEAD(*dblist);
306 
307 	/* loop through list */
308 	while (count < dbc_search_limit) {
309 		/* try to lock on the mutex */
310 		if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
311 			return (dbi); /* success, return the DBI for use. */
312 
313 		/* not successful, keep trying */
314 		dbi = ISC_LIST_NEXT(dbi, link);
315 
316 		/* check to see if we have gone to the top of the list. */
317 		if (dbi == NULL) {
318 			count++;
319 			dbi = head;
320 		}
321 	}
322 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
323 		      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
324 		      "LDAP driver unable to find available connection "
325 		      "after searching %d times",
326 		      count);
327 	return (NULL);
328 }
329 #endif /* ISC_PLATFORM_USETHREADS */
330 
331 static isc_result_t
ldap_process_results(LDAP * dbc,LDAPMessage * msg,char ** attrs,void * ptr,isc_boolean_t allnodes)332 ldap_process_results(LDAP *dbc, LDAPMessage *msg, char ** attrs,
333 		     void *ptr, isc_boolean_t allnodes)
334 {
335 	isc_result_t result = ISC_R_SUCCESS;
336 	int i = 0;
337 	int j;
338 	int len;
339 	char *attribute = NULL;
340 	LDAPMessage *entry;
341 	char *endp = NULL;
342 	char *host = NULL;
343 	char *type = NULL;
344 	char *data = NULL;
345 	char **vals = NULL;
346 	int ttl;
347 
348 	/* make sure there are at least some attributes to process. */
349 	REQUIRE(attrs != NULL || attrs[0] != NULL);
350 
351 	/* get the first entry to process */
352 	entry = ldap_first_entry(dbc, msg);
353 	if (entry == NULL) {
354 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
355 			      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
356 			      "LDAP no entries to process.");
357 		return (ISC_R_FAILURE);
358 	}
359 
360 	/* loop through all entries returned */
361 	while (entry != NULL) {
362 		/* reset for this loop */
363 		ttl = 0;
364 		len = 0;
365 		i = 0;
366 		attribute = attrs[i];
367 
368 		/* determine how much space we need for data string */
369 		for (j = 0; attrs[j] != NULL; j++) {
370 			/* get the list of values for this attribute. */
371 			vals = ldap_get_values(dbc, entry, attrs[j]);
372 			/* skip empty attributes. */
373 			if (vals == NULL || ldap_count_values(vals) < 1)
374 				continue;
375 			/*
376 			 * we only use the first value.  this driver
377 			 * does not support multi-valued attributes.
378 			 */
379 			len = len + strlen(vals[0]) + 1;
380 			/* free vals for next loop */
381 			ldap_value_free(vals);
382 		} /* end for (j = 0; attrs[j] != NULL, j++) loop */
383 
384 		/* allocate memory for data string */
385 		data = isc_mem_allocate(ns_g_mctx, len + 1);
386 		if (data == NULL) {
387 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
388 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
389 				      "LDAP driver unable to allocate memory "
390 				      "while processing results");
391 			result = ISC_R_FAILURE;
392 			goto cleanup;
393 		}
394 
395 		/*
396 		 * Make sure data is null termed at the beginning so
397 		 * we can check if any data was stored to it later.
398 		 */
399 		data[0] = '\0';
400 
401 		/* reset j to re-use below */
402 		j = 0;
403 
404 		/* loop through the attributes in the order specified. */
405 		while (attribute != NULL) {
406 			/* get the list of values for this attribute. */
407 			vals = ldap_get_values(dbc, entry, attribute);
408 
409 			/* skip empty attributes. */
410 			if (vals == NULL || vals[0] == NULL) {
411 				/* increment attibute pointer */
412 				attribute = attrs[++i];
413 				/* start loop over */
414 				continue;
415 			}
416 
417 			/*
418 			 * j initially = 0.  Increment j each time we
419 			 * set a field that way next loop will set
420 			 * next field.
421 			 */
422 			switch(j) {
423 			case 0:
424 				j++;
425 				/*
426 				 * convert text to int, make sure it
427 				 * worked right
428 				 */
429 				ttl = strtol(vals[0], &endp, 10);
430 				if (*endp != '\0' || ttl < 0) {
431 					isc_log_write(dns_lctx,
432 						      DNS_LOGCATEGORY_DATABASE,
433 						      DNS_LOGMODULE_DLZ,
434 						      ISC_LOG_ERROR,
435 						      "LDAP driver ttl must "
436 						      "be a postive number");
437 					goto cleanup;
438 				}
439 				break;
440 			case 1:
441 				j++;
442 				type = isc_mem_strdup(ns_g_mctx, vals[0]);
443 				break;
444 			case 2:
445 				j++;
446 				if (allnodes)
447 					host = isc_mem_strdup(ns_g_mctx,
448 							      vals[0]);
449 				else
450 					strcpy(data, vals[0]);
451 				break;
452 			case 3:
453 				j++;
454 				if (allnodes)
455 					strcpy(data, vals[0]);
456 				else {
457 					strcat(data, " ");
458 					strcat(data, vals[0]);
459 				}
460 				break;
461 			default:
462 				strcat(data, " ");
463 				strcat(data, vals[0]);
464 				break;
465 			} /* end switch(j) */
466 
467 			/* free values */
468 			ldap_value_free(vals);
469 			vals = NULL;
470 
471 			/* increment attibute pointer */
472 			attribute = attrs[++i];
473 		}	/* end while (attribute != NULL) */
474 
475 		if (type == NULL) {
476 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
477 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
478 				      "LDAP driver unable "
479 				      "to retrieve DNS type");
480 			result = ISC_R_FAILURE;
481 			goto cleanup;
482 		}
483 
484 		if (strlen(data) < 1) {
485 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
486 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
487 				      "LDAP driver unable "
488 				      "to retrieve DNS data");
489 			result = ISC_R_FAILURE;
490 			goto cleanup;
491 		}
492 
493 		if (allnodes && host != NULL) {
494 			if (strcasecmp(host, "~") == 0)
495 				result = dns_sdlz_putnamedrr(
496 						(dns_sdlzallnodes_t *) ptr,
497 						"*", type, ttl, data);
498 			else
499 				result = dns_sdlz_putnamedrr(
500 						(dns_sdlzallnodes_t *) ptr,
501 						host, type, ttl, data);
502 			if (result != ISC_R_SUCCESS)
503 				isc_log_write(dns_lctx,
504 					DNS_LOGCATEGORY_DATABASE,
505 					DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
506 					"dlz-ldap: putnamedrr failed "
507 					"for \"%s %s %u %s\", %s",
508 					host, type, ttl, data,
509 					isc_result_totext(result));
510 		} else {
511 			result = dns_sdlz_putrr((dns_sdlzlookup_t *) ptr,
512 						type, ttl, data);
513 			if (result != ISC_R_SUCCESS)
514 				isc_log_write(dns_lctx,
515 					DNS_LOGCATEGORY_DATABASE,
516 					DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
517 					"dlz-ldap: putrr failed "
518 					"for \"%s %u %s\", %s",
519 					type, ttl, data,
520 					isc_result_totext(result));
521 		}
522 
523 		if (result != ISC_R_SUCCESS) {
524 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
525 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
526 				      "LDAP driver failed "
527 				      "while sending data to BIND.");
528 			goto cleanup;
529 		}
530 
531 		/* free memory for type, data and host for next loop */
532 		isc_mem_free(ns_g_mctx, type);
533 		isc_mem_free(ns_g_mctx, data);
534 		if (host != NULL)
535 			isc_mem_free(ns_g_mctx, host);
536 
537 		/* get the next entry to process */
538 		entry = ldap_next_entry(dbc, entry);
539 	} /* end while (entry != NULL) */
540 
541  cleanup:
542 	/* de-allocate memory */
543 	if (vals != NULL)
544 		ldap_value_free(vals);
545 	if (host != NULL)
546 		isc_mem_free(ns_g_mctx, host);
547 	if (type != NULL)
548 		isc_mem_free(ns_g_mctx, type);
549 	if (data != NULL)
550 		isc_mem_free(ns_g_mctx, data);
551 
552 	return (result);
553 }
554 
555 /*%
556  * This function is the real core of the driver.   Zone, record
557  * and client strings are passed in (or NULL is passed if the
558  * string is not available).  The type of query we want to run
559  * is indicated by the query flag, and the dbdata object is passed
560  * passed in to.  dbdata really holds either:
561  *		1) a list of database instances (in multithreaded mode) OR
562  *		2) a single database instance (in single threaded mode)
563  * The function will construct the query and obtain an available
564  * database instance (DBI).  It will then run the query and hopefully
565  * obtain a result set.
566  */
567 static isc_result_t
ldap_get_results(const char * zone,const char * record,const char * client,unsigned int query,void * dbdata,void * ptr)568 ldap_get_results(const char *zone, const char *record,
569 		 const char *client, unsigned int query,
570 		 void *dbdata, void *ptr)
571 {
572 	isc_result_t result;
573 	dbinstance_t *dbi = NULL;
574 	char *querystring = NULL;
575 	LDAPURLDesc *ldap_url = NULL;
576 	int ldap_result = 0;
577 	LDAPMessage *ldap_msg = NULL;
578 	int i;
579 	int entries;
580 
581 	/* get db instance / connection */
582 #ifdef ISC_PLATFORM_USETHREADS
583 
584 	/* find an available DBI from the list */
585 	dbi = ldap_find_avail_conn((db_list_t *)
586 				   ((ldap_instance_t *)dbdata)->db);
587 
588 #else /* ISC_PLATFORM_USETHREADS */
589 
590 	/*
591 	 * only 1 DBI - no need to lock instance lock either
592 	 * only 1 thread in the whole process, no possible contention.
593 	 */
594 	dbi =  (dbinstance_t *) ((ldap_instance_t *)dbdata)->db;
595 
596 #endif /* ISC_PLATFORM_USETHREADS */
597 
598 	/* if DBI is null, can't do anything else */
599 	if (dbi == NULL)
600 		return (ISC_R_FAILURE);
601 
602 	/* set fields */
603 	if (zone != NULL) {
604 		dbi->zone = isc_mem_strdup(ns_g_mctx, zone);
605 		if (dbi->zone == NULL) {
606 			result = ISC_R_NOMEMORY;
607 			goto cleanup;
608 		}
609 	} else {
610 		dbi->zone = NULL;
611 	}
612 	if (record != NULL) {
613 		dbi->record = isc_mem_strdup(ns_g_mctx, record);
614 		if (dbi->record == NULL) {
615 			result = ISC_R_NOMEMORY;
616 			goto cleanup;
617 		}
618 	} else {
619 		dbi->record = NULL;
620 	}
621 	if (client != NULL) {
622 		dbi->client = isc_mem_strdup(ns_g_mctx, client);
623 		if (dbi->client == NULL) {
624 			result = ISC_R_NOMEMORY;
625 			goto cleanup;
626 		}
627 	} else {
628 		dbi->client = NULL;
629 	}
630 
631 	/* what type of query are we going to run? */
632 	switch(query) {
633 	case ALLNODES:
634 		/*
635 		 * if the query was not passed in from the config file
636 		 * then we can't run it.  return not_implemented, so
637 		 * it's like the code for that operation was never
638 		 * built into the driver.... AHHH flexibility!!!
639 		 */
640 		if (dbi->allnodes_q == NULL) {
641 			result = ISC_R_NOTIMPLEMENTED;
642 			goto cleanup;
643 		} else {
644 			querystring = build_querystring(ns_g_mctx,
645 			dbi->allnodes_q);
646 		}
647 		break;
648 	case ALLOWXFR:
649 		/* same as comments as ALLNODES */
650 		if (dbi->allowxfr_q == NULL) {
651 			result = ISC_R_NOTIMPLEMENTED;
652 			goto cleanup;
653 		} else {
654 			querystring = build_querystring(ns_g_mctx,
655 			dbi->allowxfr_q);
656 		}
657 		break;
658 	case AUTHORITY:
659 		/* same as comments as ALLNODES */
660 		if (dbi->authority_q == NULL) {
661 			result = ISC_R_NOTIMPLEMENTED;
662 			goto cleanup;
663 		} else {
664 			querystring = build_querystring(ns_g_mctx,
665 			dbi->authority_q);
666 		}
667 		break;
668 	case FINDZONE:
669 		/* this is required.  It's the whole point of DLZ! */
670 		if (dbi->findzone_q == NULL) {
671 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
672 				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
673 				      "No query specified for findzone.  "
674 				      "Findzone requires a query");
675 			result = ISC_R_FAILURE;
676 			goto cleanup;
677 		} else {
678 			querystring = build_querystring(ns_g_mctx,
679 			dbi->findzone_q);
680 		}
681 		break;
682 	case LOOKUP:
683 		/* this is required.  It's also a major point of DLZ! */
684 		if (dbi->lookup_q == NULL) {
685 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
686 				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
687 				      "No query specified for lookup.  "
688 				      "Lookup requires a query");
689 			result = ISC_R_FAILURE;
690 			goto cleanup;
691 		} else {
692 			querystring = build_querystring(ns_g_mctx,
693 							dbi->lookup_q);
694 		}
695 		break;
696 	default:
697 		/*
698 		 * this should never happen.  If it does, the code is
699 		 * screwed up!
700 		 */
701 		UNEXPECTED_ERROR(__FILE__, __LINE__,
702 				 "Incorrect query flag passed to "
703 				 "ldap_get_results");
704 		result = ISC_R_UNEXPECTED;
705 		goto cleanup;
706 	}
707 
708 	/* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */
709 	if (querystring  == NULL) {
710 		result = ISC_R_NOMEMORY;
711 		goto cleanup;
712 	}
713 
714 	/*
715 	 * output the full query string during debug so we can see
716 	 * what lame error the query has.
717 	 */
718 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
719 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
720 		      "\nQuery String: %s\n", querystring);
721 
722         /* break URL down into it's component parts, if error cleanup */
723 	ldap_result = ldap_url_parse(querystring, &ldap_url);
724 	if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
725 		result = ISC_R_FAILURE;
726 		goto cleanup;
727 	}
728 
729 	for (i = 0; i < 3; i++) {
730 
731 		/*
732 		 * dbi->dbconn may be null if trying to reconnect on a
733 		 * previous query failed.
734 		 */
735 		if (dbi->dbconn == NULL) {
736 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
737 				      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
738 				      "LDAP driver attempting to re-connect");
739 
740 			result = dlz_ldap_connect((ldap_instance_t *) dbdata,
741 						  dbi);
742 			if (result != ISC_R_SUCCESS) {
743 				result = ISC_R_FAILURE;
744 				continue;
745 			}
746 		}
747 
748 		/* perform ldap search syncronously */
749 		ldap_result = ldap_search_s((LDAP *) dbi->dbconn,
750 					    ldap_url->lud_dn,
751 					    ldap_url->lud_scope,
752 					    ldap_url->lud_filter,
753 					    ldap_url->lud_attrs, 0, &ldap_msg);
754 
755 		/*
756 		 * check return code.  No such object is ok, just
757 		 * didn't find what we wanted
758 		 */
759 		switch(ldap_result) {
760 		case LDAP_NO_SUCH_OBJECT:
761     			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
762 				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
763 				      "No object found matching "
764 				      "query requirements");
765 			result = ISC_R_NOTFOUND;
766 			goto cleanup;
767 			break;
768 		case LDAP_SUCCESS:	/* on success do nothing */
769 			result = ISC_R_SUCCESS;
770 			i = 3;
771 			break;
772 		case LDAP_SERVER_DOWN:
773 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
774 				      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
775 				      "LDAP driver attempting to re-connect");
776 			result = dlz_ldap_connect((ldap_instance_t *) dbdata,
777 						  dbi);
778 			if (result != ISC_R_SUCCESS)
779 				result = ISC_R_FAILURE;
780 			break;
781 		default:
782 			/*
783 			 * other errors not ok.  Log error message and
784 			 * get out
785 			 */
786     			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
787 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
788 				      "LDAP error: %s",
789 				      ldap_err2string(ldap_result));
790 			result = ISC_R_FAILURE;
791 			goto cleanup;
792 			break;
793 		} /* close switch(ldap_result) */
794 	} /* end for (int i = 0 i < 3; i++) */
795 
796 	if (result != ISC_R_SUCCESS)
797 		goto cleanup;
798 
799 	switch(query) {
800 	case ALLNODES:
801 		result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
802 					      ldap_url->lud_attrs,
803 					      ptr, isc_boolean_true);
804 		break;
805 	case AUTHORITY:
806 	case LOOKUP:
807 		result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
808 					      ldap_url->lud_attrs,
809 					      ptr, isc_boolean_false);
810 		break;
811 	case ALLOWXFR:
812 		entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
813 		if (entries == 0)
814 			result = ISC_R_NOPERM;
815 		else if (entries > 0)
816 			result = ISC_R_SUCCESS;
817 		else
818 			result = ISC_R_FAILURE;
819 		break;
820 	case FINDZONE:
821 		entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
822 		if (entries == 0)
823 			result = ISC_R_NOTFOUND;
824 		else if (entries > 0)
825 			result = ISC_R_SUCCESS;
826 		else
827 			result = ISC_R_FAILURE;
828 		break;
829 	default:
830 		/*
831 		 * this should never happen.  If it does, the code is
832 		 * screwed up!
833 		 */
834 		UNEXPECTED_ERROR(__FILE__, __LINE__,
835 				 "Incorrect query flag passed to "
836 				 "ldap_get_results");
837 		result = ISC_R_UNEXPECTED;
838 	}
839 
840  cleanup:
841 	/* it's always good to cleanup after yourself */
842 
843         /* if we retrieved results, free them */
844 	if (ldap_msg != NULL)
845 		ldap_msgfree(ldap_msg);
846 
847 	if (ldap_url != NULL)
848 		ldap_free_urldesc(ldap_url);
849 
850 	/* cleanup */
851 	if (dbi->zone != NULL)
852 		isc_mem_free(ns_g_mctx, dbi->zone);
853 	if (dbi->record != NULL)
854 		isc_mem_free(ns_g_mctx, dbi->record);
855 	if (dbi->client != NULL)
856 		isc_mem_free(ns_g_mctx, dbi->client);
857 
858 #ifdef ISC_PLATFORM_USETHREADS
859 
860 	/* release the lock so another thread can use this dbi */
861 	isc_mutex_unlock(&dbi->instance_lock);
862 
863 #endif /* ISC_PLATFORM_USETHREADS */
864 
865         /* release query string */
866 	if (querystring  != NULL)
867 		isc_mem_free(ns_g_mctx, querystring );
868 
869 	/* return result */
870 	return (result);
871 }
872 
873 /*
874  * DLZ methods
875  */
876 static isc_result_t
dlz_ldap_allowzonexfr(void * driverarg,void * dbdata,const char * name,const char * client)877 dlz_ldap_allowzonexfr(void *driverarg, void *dbdata, const char *name,
878 		      const char *client)
879 {
880 	isc_result_t result;
881 
882 	UNUSED(driverarg);
883 
884 	/* check to see if we are authoritative for the zone first */
885 	result = dlz_ldap_findzone(driverarg, dbdata, name, NULL, NULL);
886 	if (result != ISC_R_SUCCESS) {
887 		return (result);
888 	}
889 
890         /* get all the zone data */
891 	result = ldap_get_results(name, NULL, client, ALLOWXFR, dbdata, NULL);
892 	return (result);
893 }
894 
895 static isc_result_t
dlz_ldap_allnodes(const char * zone,void * driverarg,void * dbdata,dns_sdlzallnodes_t * allnodes)896 dlz_ldap_allnodes(const char *zone, void *driverarg, void *dbdata,
897 		  dns_sdlzallnodes_t *allnodes)
898 {
899 	UNUSED(driverarg);
900 	return (ldap_get_results(zone, NULL, NULL, ALLNODES, dbdata, allnodes));
901 }
902 
903 static isc_result_t
dlz_ldap_authority(const char * zone,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup)904 dlz_ldap_authority(const char *zone, void *driverarg, void *dbdata,
905 		   dns_sdlzlookup_t *lookup)
906 {
907 	UNUSED(driverarg);
908 	return (ldap_get_results(zone, NULL, NULL, AUTHORITY, dbdata, lookup));
909 }
910 
911 static isc_result_t
dlz_ldap_findzone(void * driverarg,void * dbdata,const char * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)912 dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name,
913 		  dns_clientinfomethods_t *methods,
914 		  dns_clientinfo_t *clientinfo)
915 {
916 	UNUSED(driverarg);
917 	UNUSED(methods);
918 	UNUSED(clientinfo);
919 	return (ldap_get_results(name, NULL, NULL, FINDZONE, dbdata, NULL));
920 }
921 
922 static isc_result_t
dlz_ldap_lookup(const char * zone,const char * name,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)923 dlz_ldap_lookup(const char *zone, const char *name, void *driverarg,
924 		void *dbdata, dns_sdlzlookup_t *lookup,
925 		dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
926 {
927 	isc_result_t result;
928 
929 	UNUSED(driverarg);
930 	UNUSED(methods);
931 	UNUSED(clientinfo);
932 
933 	if (strcmp(name, "*") == 0)
934 		result = ldap_get_results(zone, "~", NULL, LOOKUP,
935 					  dbdata, lookup);
936 	else
937 		result = ldap_get_results(zone, name, NULL, LOOKUP,
938 					  dbdata, lookup);
939 	return (result);
940 }
941 
942 
943 static isc_result_t
dlz_ldap_create(const char * dlzname,unsigned int argc,char * argv[],void * driverarg,void ** dbdata)944 dlz_ldap_create(const char *dlzname, unsigned int argc, char *argv[],
945 		void *driverarg, void **dbdata)
946 {
947 	isc_result_t result;
948 	ldap_instance_t *ldap_inst = NULL;
949 	dbinstance_t *dbi = NULL;
950 	int protocol;
951 	int method;
952 
953 #ifdef ISC_PLATFORM_USETHREADS
954 	/* if multi-threaded, we need a few extra variables. */
955 	int dbcount;
956 	char *endp;
957 /* db_list_t *dblist = NULL; */
958 	int i;
959 
960 #endif /* ISC_PLATFORM_USETHREADS */
961 
962 	UNUSED(dlzname);
963 	UNUSED(driverarg);
964 
965 #ifdef ISC_PLATFORM_USETHREADS
966 	/* if debugging, let user know we are multithreaded. */
967 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
968 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
969 		      "LDAP driver running multithreaded");
970 #else /* ISC_PLATFORM_USETHREADS */
971 	/* if debugging, let user know we are single threaded. */
972 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
973 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
974 		      "LDAP driver running single threaded");
975 #endif /* ISC_PLATFORM_USETHREADS */
976 
977 	if (argc < 9) {
978 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
979 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
980 			      "LDAP driver requires at least "
981 			      "8 command line args.");
982 		return (ISC_R_FAILURE);
983 	}
984 
985 	/* no more than 13 arg's should be passed to the driver */
986 	if (argc > 12) {
987 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
988 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
989 			      "LDAP driver cannot accept more than "
990 			      "11 command line args.");
991 		return (ISC_R_FAILURE);
992 	}
993 
994 	/* determine protocol version. */
995 	if (strncasecmp(argv[2], V2, strlen(V2)) == 0) {
996 		protocol = 2;
997 	} else if (strncasecmp(argv[2], V3, strlen(V3)) == 0) {
998 		protocol = 3;
999 	} else {
1000 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1001 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1002 			      "LDAP driver protocol must be either %s or %s",
1003 			      V2, V3);
1004 		return (ISC_R_FAILURE);
1005 	}
1006 
1007 	/* determine connection method. */
1008 	if (strncasecmp(argv[3], SIMPLE, strlen(SIMPLE)) == 0) {
1009 		method = LDAP_AUTH_SIMPLE;
1010 	} else if (strncasecmp(argv[3], KRB41, strlen(KRB41)) == 0) {
1011 		method = LDAP_AUTH_KRBV41;
1012 	} else if (strncasecmp(argv[3], KRB42, strlen(KRB42)) == 0) {
1013 		method = LDAP_AUTH_KRBV42;
1014 	} else {
1015 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1016 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1017 			      "LDAP driver authentication method must be "
1018 			      "one of %s, %s or %s",
1019 			      SIMPLE, KRB41, KRB42);
1020 		return (ISC_R_FAILURE);
1021 	}
1022 
1023 	/* multithreaded build can have multiple DB connections */
1024 #ifdef ISC_PLATFORM_USETHREADS
1025 
1026 	/* check how many db connections we should create */
1027 	dbcount = strtol(argv[1], &endp, 10);
1028 	if (*endp != '\0' || dbcount < 0) {
1029 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1030 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1031 			      "LDAP driver database connection count "
1032 			      "must be positive.");
1033 		return (ISC_R_FAILURE);
1034 	}
1035 #endif
1036 
1037 	/* check that LDAP URL parameters make sense */
1038 	switch(argc) {
1039 	case 12:
1040 		result = dlz_ldap_checkURL(argv[11], 0, "allow zone transfer");
1041 		if (result != ISC_R_SUCCESS)
1042 			return (result);
1043 	case 11:
1044 		result = dlz_ldap_checkURL(argv[10], 3, "all nodes");
1045 		if (result != ISC_R_SUCCESS)
1046 			return (result);
1047 	case 10:
1048 		if (strlen(argv[9]) > 0) {
1049 			result = dlz_ldap_checkURL(argv[9], 3, "authority");
1050 			if (result != ISC_R_SUCCESS)
1051 				return (result);
1052 		}
1053 	case 9:
1054 		result = dlz_ldap_checkURL(argv[8], 3, "lookup");
1055 		if (result != ISC_R_SUCCESS)
1056 			return (result);
1057 		result = dlz_ldap_checkURL(argv[7], 0, "find zone");
1058 		if (result != ISC_R_SUCCESS)
1059 			return (result);
1060 		break;
1061 	default:
1062 		/* not really needed, should shut up compiler. */
1063 		result = ISC_R_FAILURE;
1064 	}
1065 
1066 	/* allocate memory for LDAP instance */
1067 	ldap_inst = isc_mem_get(ns_g_mctx, sizeof(ldap_instance_t));
1068 	if (ldap_inst == NULL)
1069 		return (ISC_R_NOMEMORY);
1070 	memset(ldap_inst, 0, sizeof(ldap_instance_t));
1071 
1072 	/* store info needed to automatically re-connect. */
1073 	ldap_inst->protocol = protocol;
1074 	ldap_inst->method = method;
1075 	ldap_inst->hosts = isc_mem_strdup(ns_g_mctx, argv[6]);
1076 	if (ldap_inst->hosts == NULL) {
1077 		result = ISC_R_NOMEMORY;
1078 		goto cleanup;
1079 	}
1080 	ldap_inst->user = isc_mem_strdup(ns_g_mctx, argv[4]);
1081 	if (ldap_inst->user == NULL) {
1082 		result = ISC_R_NOMEMORY;
1083 		goto cleanup;
1084 	}
1085 	ldap_inst->cred = isc_mem_strdup(ns_g_mctx, argv[5]);
1086 	if (ldap_inst->cred == NULL) {
1087 		result = ISC_R_NOMEMORY;
1088 		goto cleanup;
1089 	}
1090 
1091 #ifdef ISC_PLATFORM_USETHREADS
1092 	/* allocate memory for database connection list */
1093 	ldap_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
1094 	if (ldap_inst->db == NULL) {
1095 		result = ISC_R_NOMEMORY;
1096 		goto cleanup;
1097 	}
1098 
1099 	/* initialize DB connection list */
1100 	ISC_LIST_INIT(*(ldap_inst->db));
1101 
1102 	/*
1103 	 * create the appropriate number of database instances (DBI)
1104 	 * append each new DBI to the end of the list
1105 	 */
1106 	for (i = 0; i < dbcount; i++) {
1107 
1108 #endif /* ISC_PLATFORM_USETHREADS */
1109 
1110 		/* how many queries were passed in from config file? */
1111 		switch(argc) {
1112 		case 9:
1113 			result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
1114 						     NULL, argv[7], argv[8],
1115 						     NULL, &dbi);
1116 			break;
1117 		case 10:
1118 			result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
1119 						     argv[9], argv[7], argv[8],
1120 						     NULL, &dbi);
1121 			break;
1122 		case 11:
1123 			result = build_sqldbinstance(ns_g_mctx, argv[10], NULL,
1124 						     argv[9], argv[7], argv[8],
1125 						     NULL, &dbi);
1126 			break;
1127 		case 12:
1128 			result = build_sqldbinstance(ns_g_mctx, argv[10],
1129 						     argv[11], argv[9],
1130 						     argv[7], argv[8],
1131 						     NULL, &dbi);
1132 			break;
1133 		default:
1134 			/* not really needed, should shut up compiler. */
1135 			result = ISC_R_FAILURE;
1136 		}
1137 
1138 		if (result == ISC_R_SUCCESS) {
1139 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1140 				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1141 				      "LDAP driver created "
1142 				      "database instance object.");
1143 		} else { /* unsuccessful?, log err msg and cleanup. */
1144 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1145 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1146 				      "LDAP driver could not create "
1147 				      "database instance object.");
1148 			goto cleanup;
1149 		}
1150 
1151 #ifdef ISC_PLATFORM_USETHREADS
1152 		/* when multithreaded, build a list of DBI's */
1153 		ISC_LINK_INIT(dbi, link);
1154 		ISC_LIST_APPEND(*(ldap_inst->db), dbi, link);
1155 #else
1156 		/*
1157 		 * when single threaded, hold onto the one connection
1158 		 * instance.
1159 		 */
1160 		ldap_inst->db = dbi;
1161 
1162 #endif
1163 		/* attempt to connect */
1164 		result = dlz_ldap_connect(ldap_inst, dbi);
1165 
1166 		/*
1167 		 * if db connection cannot be created, log err msg and
1168 		 * cleanup.
1169 		 */
1170 		switch(result) {
1171 			/* success, do nothing */
1172 		case ISC_R_SUCCESS:
1173 			break;
1174 			/*
1175 			 * no memory means ldap_init could not
1176 			 * allocate memory
1177 			 */
1178 		case ISC_R_NOMEMORY:
1179 #ifdef ISC_PLATFORM_USETHREADS
1180 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1181 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1182 				      "LDAP driver could not allocate memory "
1183 				      "for connection number %u",
1184 				      i+1);
1185 #else
1186 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1187 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1188 				      "LDAP driver could not allocate memory "
1189 				      "for connection");
1190 #endif
1191 			goto cleanup;
1192 			break;
1193 			/*
1194 			 * no perm means ldap_set_option could not set
1195 			 * protocol version
1196 			 */
1197 		case ISC_R_NOPERM:
1198 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1199 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1200 				      "LDAP driver could not "
1201 				      "set protocol version.");
1202 			result = ISC_R_FAILURE;
1203 			goto cleanup;
1204 			break;
1205 			/* failure means couldn't connect to ldap server */
1206 		case ISC_R_FAILURE:
1207 #ifdef ISC_PLATFORM_USETHREADS
1208 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1209 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1210 				      "LDAP driver could not "
1211 				      "bind connection number %u to server.",
1212 				      i+1);
1213 #else
1214 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1215 				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1216 				      "LDAP driver could not "
1217 				      "bind connection to server.");
1218 #endif
1219 			goto cleanup;
1220 			break;
1221 			/*
1222 			 * default should never happen.  If it does,
1223 			 * major errors.
1224 			 */
1225 		default:
1226 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1227 					 "dlz_ldap_create() failed: %s",
1228 					 isc_result_totext(result));
1229 			result = ISC_R_UNEXPECTED;
1230 			goto cleanup;
1231 			break;
1232 		} /* end switch(result) */
1233 
1234 
1235 #ifdef ISC_PLATFORM_USETHREADS
1236 
1237 		/* set DBI = null for next loop through. */
1238 		dbi = NULL;
1239 	}	/* end for loop */
1240 
1241 #endif /* ISC_PLATFORM_USETHREADS */
1242 
1243 
1244 	/* set dbdata to the ldap_instance we created. */
1245 	*dbdata = ldap_inst;
1246 
1247 	/* hey, we got through all of that ok, return success. */
1248 	return(ISC_R_SUCCESS);
1249 
1250  cleanup:
1251 	dlz_ldap_destroy(NULL, ldap_inst);
1252 
1253 	return(ISC_R_FAILURE);
1254 }
1255 
1256 void
dlz_ldap_destroy(void * driverarg,void * dbdata)1257 dlz_ldap_destroy(void *driverarg, void *dbdata) {
1258 	UNUSED(driverarg);
1259 
1260 	if (dbdata != NULL) {
1261 #ifdef ISC_PLATFORM_USETHREADS
1262 		/* cleanup the list of DBI's */
1263 		ldap_destroy_dblist((db_list_t *)
1264 				    ((ldap_instance_t *)dbdata)->db);
1265 
1266 #else /* ISC_PLATFORM_USETHREADS */
1267 		if (((ldap_instance_t *)dbdata)->db->dbconn != NULL)
1268 			ldap_unbind_s((LDAP *)
1269 				      ((ldap_instance_t *)dbdata)->db->dbconn);
1270 
1271 		/* destroy single DB instance */
1272 		destroy_sqldbinstance(((ldap_instance_t *)dbdata)->db);
1273 #endif /* ISC_PLATFORM_USETHREADS */
1274 
1275 		if (((ldap_instance_t *)dbdata)->hosts != NULL)
1276 			isc_mem_free(ns_g_mctx,
1277 				     ((ldap_instance_t *)dbdata)->hosts);
1278 
1279 		if (((ldap_instance_t *)dbdata)->user != NULL)
1280 			isc_mem_free(ns_g_mctx,
1281 				     ((ldap_instance_t *)dbdata)->user);
1282 
1283 		if (((ldap_instance_t *)dbdata)->cred != NULL)
1284 			isc_mem_free(ns_g_mctx,
1285 				     ((ldap_instance_t *)dbdata)->cred);
1286 
1287 		isc_mem_put(ns_g_mctx, dbdata, sizeof(ldap_instance_t));
1288 	}
1289 }
1290 
1291 static dns_sdlzmethods_t dlz_ldap_methods = {
1292 	dlz_ldap_create,
1293 	dlz_ldap_destroy,
1294 	dlz_ldap_findzone,
1295 	dlz_ldap_lookup,
1296 	dlz_ldap_authority,
1297 	dlz_ldap_allnodes,
1298 	dlz_ldap_allowzonexfr,
1299 	NULL,
1300 	NULL,
1301 	NULL,
1302 	NULL,
1303 	NULL,
1304 	NULL,
1305 	NULL,
1306 };
1307 
1308 /*%
1309  * Wrapper around dns_sdlzregister().
1310  */
1311 isc_result_t
dlz_ldap_init(void)1312 dlz_ldap_init(void) {
1313 	isc_result_t result;
1314 
1315 	/*
1316 	 * Write debugging message to log
1317 	 */
1318 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1319 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1320 		      "Registering DLZ ldap driver.");
1321 
1322 	result = dns_sdlzregister("ldap", &dlz_ldap_methods, NULL,
1323 				  DNS_SDLZFLAG_RELATIVEOWNER |
1324 				  DNS_SDLZFLAG_RELATIVERDATA,
1325 				  ns_g_mctx, &dlz_ldap);
1326 	if (result != ISC_R_SUCCESS) {
1327 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1328 				 "dns_sdlzregister() failed: %s",
1329 				 isc_result_totext(result));
1330 		result = ISC_R_UNEXPECTED;
1331 	}
1332 
1333 	return (result);
1334 }
1335 
1336 /*%
1337  * Wrapper around dns_sdlzunregister().
1338  */
1339 void
dlz_ldap_clear(void)1340 dlz_ldap_clear(void) {
1341 	/*
1342 	 * Write debugging message to log
1343 	 */
1344 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1345 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1346 		      "Unregistering DLZ ldap driver.");
1347 
1348 	if (dlz_ldap != NULL)
1349 		dns_sdlzunregister(&dlz_ldap);
1350 }
1351 
1352 #endif
1353