4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the
8 * above copyright notice and this permission notice appear in all
11 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18 * USE OR PERFORMANCE OF THIS SOFTWARE.
20 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21 * conceived and contributed by Rob Butler.
23 * Permission to use, copy, modify, and distribute this software for any
24 * purpose with or without fee is hereby granted, provided that the
25 * above copyright notice and this permission notice appear in all
28 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35 * USE OR PERFORMANCE OF THIS SOFTWARE.
39 * Copyright (C) 1999-2001 Internet Software Consortium.
41 * Permission to use, copy, modify, and distribute this software for any
42 * purpose with or without fee is hereby granted, provided that the above
43 * copyright notice and this permission notice appear in all copies.
45 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
46 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
49 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
50 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
51 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
64 #include <dns/result.h>
67 #include <isc/platform.h>
68 #include <isc/print.h>
69 #include <isc/result.h>
70 #include <isc/string.h>
73 #include <named/globals.h>
75 #include <dlz/sdlz_helper.h>
76 #include <dlz/dlz_ldap_driver.h>
79 * Need older API functions from ldap.h.
81 #define LDAP_DEPRECATED 1
85 #define SIMPLE "simple"
91 static dns_sdlzimplementation_t
*dlz_ldap
= NULL
;
93 #define dbc_search_limit 30
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.
108 #ifdef ISC_PLATFORM_USETHREADS
109 db_list_t
*db
; /*%< handle to a list of DB */
111 dbinstance_t
*db
; /*%< handle to db */
113 int method
; /*%< security authentication method */
114 char *user
; /*%< who is authenticating */
115 char *cred
; /*%< password for simple authentication method */
116 int protocol
; /*%< LDAP communication protocol version */
117 char *hosts
; /*%< LDAP server hosts */
121 /* forward references */
124 dlz_ldap_findzone(void *driverarg
, void *dbdata
, const char *name
);
127 dlz_ldap_destroy(void *driverarg
, void *dbdata
);
133 /*% checks that the LDAP URL parameters make sense */
136 dlz_ldap_checkURL(char *URL
, int attrCnt
, const char *msg
) {
138 isc_result_t result
= ISC_R_SUCCESS
;
140 LDAPURLDesc
*ldap_url
= NULL
;
142 if (!ldap_is_ldap_url(URL
)) {
143 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
144 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
145 "%s query is not a valid LDAP URL", msg
);
146 result
= ISC_R_FAILURE
;
150 ldap_result
= ldap_url_parse(URL
, &ldap_url
);
151 if (ldap_result
!= LDAP_SUCCESS
|| ldap_url
== NULL
) {
152 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
153 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
154 "parsing %s query failed", msg
);
155 result
= ISC_R_FAILURE
;
159 if (ldap_count_values(ldap_url
->lud_attrs
) < attrCnt
) {
160 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
161 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
162 "%s query must specify at least "
163 "%d attributes to return",
165 result
= ISC_R_FAILURE
;
169 if (ldap_url
->lud_host
!= NULL
) {
170 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
171 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
172 "%s query must not specify a host", msg
);
173 result
= ISC_R_FAILURE
;
177 if (ldap_url
->lud_port
!= 389) {
178 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
179 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
180 "%s query must not specify a port", msg
);
181 result
= ISC_R_FAILURE
;
185 if (ldap_url
->lud_dn
== NULL
|| strlen (ldap_url
->lud_dn
) < 1) {
186 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
187 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
188 "%s query must specify a search base", msg
);
189 result
= ISC_R_FAILURE
;
193 if (ldap_url
->lud_exts
!= NULL
|| ldap_url
->lud_crit_exts
!= 0) {
194 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
195 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
196 "%s uses extensions. "
197 "The driver does not support LDAP extensions.",
199 result
= ISC_R_FAILURE
;
205 if (ldap_url
!= NULL
)
206 ldap_free_urldesc(ldap_url
);
210 /*% Connects / reconnects to LDAP server */
213 dlz_ldap_connect(ldap_instance_t
*dbi
, dbinstance_t
*dbc
) {
218 /* if we have a connection, get ride of it. */
219 if (dbc
->dbconn
!= NULL
) {
220 ldap_unbind_s((LDAP
*) dbc
->dbconn
);
224 /* now connect / reconnect. */
227 dbc
->dbconn
= ldap_init(dbi
->hosts
, LDAP_PORT
);
228 if (dbc
->dbconn
== NULL
)
229 return ISC_R_NOMEMORY
;
231 /* set protocol version. */
232 ldap_result
= ldap_set_option((LDAP
*) dbc
->dbconn
,
233 LDAP_OPT_PROTOCOL_VERSION
,
235 if (ldap_result
!= LDAP_SUCCESS
) {
236 result
= ISC_R_NOPERM
;
240 /* "bind" to server. i.e. send username / pass */
241 ldap_result
= ldap_bind_s((LDAP
*) dbc
->dbconn
, dbi
->user
,
242 dbi
->cred
, dbi
->method
);
243 if (ldap_result
!= LDAP_SUCCESS
) {
244 result
= ISC_R_FAILURE
;
248 return ISC_R_SUCCESS
;
252 /* cleanup if failure. */
253 if (dbc
->dbconn
!= NULL
) {
254 ldap_unbind_s((LDAP
*) dbc
->dbconn
);
261 #ifdef ISC_PLATFORM_USETHREADS
265 * Properly cleans up a list of database instances.
266 * This function is only used when the driver is compiled for
267 * multithreaded operation.
270 ldap_destroy_dblist(db_list_t
*dblist
)
273 dbinstance_t
*ndbi
= NULL
;
274 dbinstance_t
*dbi
= NULL
;
276 /* get the first DBI in the list */
277 ndbi
= ISC_LIST_HEAD(*dblist
);
279 /* loop through the list */
280 while (ndbi
!= NULL
) {
282 /* get the next DBI in the list */
283 ndbi
= ISC_LIST_NEXT(dbi
, link
);
284 /* release DB connection */
285 if (dbi
->dbconn
!= NULL
)
286 ldap_unbind_s((LDAP
*) dbi
->dbconn
);
287 /* release all memory that comprised a DBI */
288 destroy_sqldbinstance(dbi
);
290 /* release memory for the list structure */
291 isc_mem_put(ns_g_mctx
, dblist
, sizeof(db_list_t
));
295 * Loops through the list of DB instances, attempting to lock
296 * on the mutex. If successful, the DBI is reserved for use
297 * and the thread can perform queries against the database.
298 * If the lock fails, the next one in the list is tried.
299 * looping continues until a lock is obtained, or until
300 * the list has been searched dbc_search_limit times.
301 * This function is only used when the driver is compiled for
302 * multithreaded operation.
305 static dbinstance_t
*
306 ldap_find_avail_conn(db_list_t
*dblist
)
308 dbinstance_t
*dbi
= NULL
;
312 /* get top of list */
313 head
= dbi
= ISC_LIST_HEAD(*dblist
);
315 /* loop through list */
316 while (count
< dbc_search_limit
) {
317 /* try to lock on the mutex */
318 if (isc_mutex_trylock(&dbi
->instance_lock
) == ISC_R_SUCCESS
)
319 return dbi
; /* success, return the DBI for use. */
321 /* not successful, keep trying */
322 dbi
= ISC_LIST_NEXT(dbi
, link
);
324 /* check to see if we have gone to the top of the list. */
330 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
331 DNS_LOGMODULE_DLZ
, ISC_LOG_INFO
,
332 "LDAP driver unable to find available connection "
333 "after searching %d times",
338 #endif /* ISC_PLATFORM_USETHREADS */
341 ldap_process_results(LDAP
*dbc
, LDAPMessage
*msg
, char ** attrs
,
342 void *ptr
, isc_boolean_t allnodes
)
344 isc_result_t result
= ISC_R_SUCCESS
;
348 char *attribute
= NULL
;
357 /* make sure there are at least some attributes to process. */
358 REQUIRE(attrs
!= NULL
|| attrs
[0] != NULL
);
360 /* get the first entry to process */
361 entry
= ldap_first_entry(dbc
, msg
);
363 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
364 DNS_LOGMODULE_DLZ
, ISC_LOG_INFO
,
365 "LDAP no entries to process.");
366 return ISC_R_FAILURE
;
369 /* loop through all entries returned */
370 while (entry
!= NULL
) {
372 /* reset for this loop */
376 attribute
= attrs
[i
];
378 /* determine how much space we need for data string */
379 for (j
=0; attrs
[j
] != NULL
; j
++) {
380 /* get the list of values for this attribute. */
381 vals
= ldap_get_values(dbc
, entry
, attrs
[j
]);
382 /* skip empty attributes. */
383 if (vals
== NULL
|| ldap_count_values(vals
) < 1)
386 * we only use the first value. this driver
387 * does not support multi-valued attributes.
389 len
= len
+ strlen(vals
[0]) + 1;
390 /* free vals for next loop */
391 ldap_value_free(vals
);
392 } /* end for (j=0; attrs[j] != NULL, j++) loop */
394 /* allocate memory for data string */
395 data
= isc_mem_allocate(ns_g_mctx
, len
+ 1);
397 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
398 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
399 "LDAP driver unable to allocate memory "
400 "while processing results");
401 result
= ISC_R_FAILURE
;
406 * Make sure data is null termed at the beginning so
407 * we can check if any data was stored to it later.
411 /* reset j to re-use below */
414 /* loop through the attributes in the order specified. */
415 while (attribute
!= NULL
) {
417 /* get the list of values for this attribute. */
418 vals
= ldap_get_values(dbc
, entry
, attribute
);
420 /* skip empty attributes. */
421 if (vals
== NULL
|| vals
[0] == NULL
) {
422 /* increment attibute pointer */
423 attribute
= attrs
[++i
];
424 /* start loop over */
429 * j initially = 0. Increment j each time we
430 * set a field that way next loop will set
437 * convert text to int, make sure it
440 ttl
= strtol(vals
[0], &endp
, 10);
441 if (*endp
!= '\0' || ttl
< 0) {
442 isc_log_write(dns_lctx
,
443 DNS_LOGCATEGORY_DATABASE
,
446 "LDAP driver ttl must "
447 "be a postive number");
453 type
= isc_mem_strdup(ns_g_mctx
, vals
[0]);
457 if (allnodes
== isc_boolean_true
) {
458 host
= isc_mem_strdup(ns_g_mctx
,
461 strcpy(data
, vals
[0]);
466 if (allnodes
== isc_boolean_true
) {
467 strcpy(data
, vals
[0]);
470 strcat(data
, vals
[0]);
475 strcat(data
, vals
[0]);
477 } /* end switch(j) */
480 ldap_value_free(vals
);
483 /* increment attibute pointer */
484 attribute
= attrs
[++i
];
485 } /* end while (attribute != NULL) */
488 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
489 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
490 "LDAP driver unable "
491 "to retrieve dns type");
492 result
= ISC_R_FAILURE
;
495 if (strlen(data
) < 1) {
496 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
497 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
498 "LDAP driver unable "
499 "to retrieve dns data");
500 result
= ISC_R_FAILURE
;
503 if (allnodes
== isc_boolean_true
) {
504 if (strcasecmp(host
, "~") == 0)
505 result
= dns_sdlz_putnamedrr(
506 (dns_sdlzallnodes_t
*) ptr
,
507 "*", type
, ttl
, data
);
509 result
= dns_sdlz_putnamedrr(
510 (dns_sdlzallnodes_t
*) ptr
,
511 host
, type
, ttl
, data
);
514 result
= dns_sdlz_putrr((dns_sdlzlookup_t
*) ptr
,
517 if (result
!= ISC_R_SUCCESS
) {
518 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
519 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
520 "LDAP driver failed "
521 "while sending data to Bind.");
525 /* free memory for type, data and host for next loop */
526 isc_mem_free(ns_g_mctx
, type
);
527 isc_mem_free(ns_g_mctx
, data
);
529 isc_mem_free(ns_g_mctx
, host
);
531 /* get the next entry to process */
532 entry
= ldap_next_entry(dbc
, entry
);
533 } /* end while (entry != NULL) */
537 /* de-allocate memory */
539 ldap_value_free(vals
);
541 isc_mem_free(ns_g_mctx
, host
);
543 isc_mem_free(ns_g_mctx
, type
);
545 isc_mem_free(ns_g_mctx
, data
);
551 * This function is the real core of the driver. Zone, record
552 * and client strings are passed in (or NULL is passed if the
553 * string is not available). The type of query we want to run
554 * is indicated by the query flag, and the dbdata object is passed
555 * passed in to. dbdata really holds either:
556 * 1) a list of database instances (in multithreaded mode) OR
557 * 2) a single database instance (in single threaded mode)
558 * The function will construct the query and obtain an available
559 * database instance (DBI). It will then run the query and hopefully
560 * obtain a result set.
563 ldap_get_results(const char *zone
, const char *record
,
564 const char *client
, unsigned int query
,
565 void *dbdata
, void *ptr
)
568 dbinstance_t
*dbi
= NULL
;
569 char *querystring
= NULL
;
570 LDAPURLDesc
*ldap_url
= NULL
;
572 LDAPMessage
*ldap_msg
= NULL
;
576 /* get db instance / connection */
577 #ifdef ISC_PLATFORM_USETHREADS
579 /* find an available DBI from the list */
580 dbi
= ldap_find_avail_conn((db_list_t
*)
581 ((ldap_instance_t
*)dbdata
)->db
);
583 #else /* ISC_PLATFORM_USETHREADS */
586 * only 1 DBI - no need to lock instance lock either
587 * only 1 thread in the whole process, no possible contention.
589 dbi
= (dbinstance_t
*) ((ldap_instance_t
*)dbdata
)->db
;
591 #endif /* ISC_PLATFORM_USETHREADS */
593 /* if DBI is null, can't do anything else */
595 return ISC_R_FAILURE
;
599 dbi
->zone
= isc_mem_strdup(ns_g_mctx
, zone
);
600 if (dbi
->zone
== NULL
) {
601 result
= ISC_R_NOMEMORY
;
607 if (record
!= NULL
) {
608 dbi
->record
= isc_mem_strdup(ns_g_mctx
, record
);
609 if (dbi
->record
== NULL
) {
610 result
= ISC_R_NOMEMORY
;
616 if (client
!= NULL
) {
617 dbi
->client
= isc_mem_strdup(ns_g_mctx
, client
);
618 if (dbi
->client
== NULL
) {
619 result
= ISC_R_NOMEMORY
;
626 /* what type of query are we going to run? */
630 * if the query was not passed in from the config file
631 * then we can't run it. return not_implemented, so
632 * it's like the code for that operation was never
633 * built into the driver.... AHHH flexibility!!!
635 if (dbi
->allnodes_q
== NULL
) {
636 result
= ISC_R_NOTIMPLEMENTED
;
639 querystring
= build_querystring(ns_g_mctx
,
644 /* same as comments as ALLNODES */
645 if (dbi
->allowxfr_q
== NULL
) {
646 result
= ISC_R_NOTIMPLEMENTED
;
649 querystring
= build_querystring(ns_g_mctx
,
654 /* same as comments as ALLNODES */
655 if (dbi
->authority_q
== NULL
) {
656 result
= ISC_R_NOTIMPLEMENTED
;
659 querystring
= build_querystring(ns_g_mctx
,
664 /* this is required. It's the whole point of DLZ! */
665 if (dbi
->findzone_q
== NULL
) {
666 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
667 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
668 "No query specified for findzone. "
669 "Findzone requires a query");
670 result
= ISC_R_FAILURE
;
673 querystring
= build_querystring(ns_g_mctx
,
678 /* this is required. It's also a major point of DLZ! */
679 if (dbi
->lookup_q
== NULL
) {
680 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
681 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
682 "No query specified for lookup. "
683 "Lookup requires a query");
684 result
= ISC_R_FAILURE
;
687 querystring
= build_querystring(ns_g_mctx
,
693 * this should never happen. If it does, the code is
696 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
697 "Incorrect query flag passed to "
699 result
= ISC_R_UNEXPECTED
;
703 /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
704 if (querystring
== NULL
) {
705 result
= ISC_R_NOMEMORY
;
710 * output the full query string during debug so we can see
711 * what lame error the query has.
713 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
714 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(1),
715 "\nQuery String: %s\n", querystring
);
717 /* break URL down into it's component parts, if error cleanup */
718 ldap_result
= ldap_url_parse(querystring
, &ldap_url
);
719 if (ldap_result
!= LDAP_SUCCESS
|| ldap_url
== NULL
) {
720 result
= ISC_R_FAILURE
;
724 for (i
=0; i
< 3; i
++) {
727 * dbi->dbconn may be null if trying to reconnect on a
728 * previous query failed.
730 if (dbi
->dbconn
== NULL
) {
731 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
732 DNS_LOGMODULE_DLZ
, ISC_LOG_INFO
,
733 "LDAP driver attempting to re-connect");
735 result
= dlz_ldap_connect((ldap_instance_t
*) dbdata
,
737 if (result
!= ISC_R_SUCCESS
) {
738 result
= ISC_R_FAILURE
;
743 /* perform ldap search syncronously */
744 ldap_result
= ldap_search_s((LDAP
*) dbi
->dbconn
,
747 ldap_url
->lud_filter
,
748 ldap_url
->lud_attrs
, 0, &ldap_msg
);
751 * check return code. No such object is ok, just
752 * didn't find what we wanted
754 switch(ldap_result
) {
755 case LDAP_NO_SUCH_OBJECT
:
756 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
757 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(1),
758 "No object found matching "
759 "query requirements");
760 result
= ISC_R_NOTFOUND
;
763 case LDAP_SUCCESS
: /* on success do nothing */
764 result
= ISC_R_SUCCESS
;
767 case LDAP_SERVER_DOWN
:
768 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
769 DNS_LOGMODULE_DLZ
, ISC_LOG_INFO
,
770 "LDAP driver attempting to re-connect");
771 result
= dlz_ldap_connect((ldap_instance_t
*) dbdata
,
773 if (result
!= ISC_R_SUCCESS
)
774 result
= ISC_R_FAILURE
;
778 * other errors not ok. Log error message and
781 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
782 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
784 ldap_err2string(ldap_result
));
785 result
= ISC_R_FAILURE
;
788 } /* close switch(ldap_result) */
789 } /* end for (int i=0 i < 3; i++) */
791 if (result
!= ISC_R_SUCCESS
)
796 result
= ldap_process_results((LDAP
*) dbi
->dbconn
, ldap_msg
,
798 ptr
, isc_boolean_true
);
802 result
= ldap_process_results((LDAP
*) dbi
->dbconn
, ldap_msg
,
804 ptr
, isc_boolean_false
);
807 entries
= ldap_count_entries((LDAP
*) dbi
->dbconn
, ldap_msg
);
809 result
= ISC_R_NOPERM
;
810 else if (entries
> 0)
811 result
= ISC_R_SUCCESS
;
813 result
= ISC_R_FAILURE
;
816 entries
= ldap_count_entries((LDAP
*) dbi
->dbconn
, ldap_msg
);
818 result
= ISC_R_NOTFOUND
;
819 else if (entries
> 0)
820 result
= ISC_R_SUCCESS
;
822 result
= ISC_R_FAILURE
;
826 * this should never happen. If it does, the code is
829 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
830 "Incorrect query flag passed to "
832 result
= ISC_R_UNEXPECTED
;
837 /* it's always good to cleanup after yourself */
839 /* if we retrieved results, free them */
840 if (ldap_msg
!= NULL
)
841 ldap_msgfree(ldap_msg
);
843 if (ldap_url
!= NULL
)
844 ldap_free_urldesc(ldap_url
);
847 if (dbi
->zone
!= NULL
)
848 isc_mem_free(ns_g_mctx
, dbi
->zone
);
849 if (dbi
->record
!= NULL
)
850 isc_mem_free(ns_g_mctx
, dbi
->record
);
851 if (dbi
->client
!= NULL
)
852 isc_mem_free(ns_g_mctx
, dbi
->client
);
854 #ifdef ISC_PLATFORM_USETHREADS
856 /* release the lock so another thread can use this dbi */
857 isc_mutex_unlock(&dbi
->instance_lock
);
859 #endif /* ISC_PLATFORM_USETHREADS */
861 /* release query string */
862 if (querystring
!= NULL
)
863 isc_mem_free(ns_g_mctx
, querystring
);
874 dlz_ldap_allowzonexfr(void *driverarg
, void *dbdata
, const char *name
,
881 /* check to see if we are authoritative for the zone first */
882 result
= dlz_ldap_findzone(driverarg
, dbdata
, name
);
883 if (result
!= ISC_R_SUCCESS
) {
887 /* get all the zone data */
888 return ldap_get_results(name
, NULL
, client
, ALLOWXFR
, dbdata
, NULL
);
892 dlz_ldap_allnodes(const char *zone
, void *driverarg
, void *dbdata
,
893 dns_sdlzallnodes_t
*allnodes
)
896 return ldap_get_results(zone
, NULL
, NULL
, ALLNODES
, dbdata
, allnodes
);
900 dlz_ldap_authority(const char *zone
, void *driverarg
, void *dbdata
,
901 dns_sdlzlookup_t
*lookup
)
904 return ldap_get_results(zone
, NULL
, NULL
, AUTHORITY
, dbdata
, lookup
);
908 dlz_ldap_findzone(void *driverarg
, void *dbdata
, const char *name
)
911 return ldap_get_results(name
, NULL
, NULL
, FINDZONE
, dbdata
, NULL
);
915 dlz_ldap_lookup(const char *zone
, const char *name
, void *driverarg
,
916 void *dbdata
, dns_sdlzlookup_t
*lookup
)
919 if (strcmp(name
, "*") == 0)
920 return ldap_get_results(zone
, "~", NULL
,
921 LOOKUP
, dbdata
, lookup
);
923 return ldap_get_results(zone
, name
, NULL
,
924 LOOKUP
, dbdata
, lookup
);
929 dlz_ldap_create(const char *dlzname
, unsigned int argc
, char *argv
[],
930 void *driverarg
, void **dbdata
)
934 ldap_instance_t
*ldap_inst
= NULL
;
935 dbinstance_t
*dbi
= NULL
;
939 #ifdef ISC_PLATFORM_USETHREADS
940 /* if multi-threaded, we need a few extra variables. */
943 /* db_list_t *dblist = NULL; */
946 #endif /* ISC_PLATFORM_USETHREADS */
951 #ifdef ISC_PLATFORM_USETHREADS
952 /* if debugging, let user know we are multithreaded. */
953 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
954 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(1),
955 "LDAP driver running multithreaded");
956 #else /* ISC_PLATFORM_USETHREADS */
957 /* if debugging, let user know we are single threaded. */
958 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
959 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(1),
960 "LDAP driver running single threaded");
961 #endif /* ISC_PLATFORM_USETHREADS */
964 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
965 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
966 "LDAP driver requires at least "
967 "8 command line args.");
968 return (ISC_R_FAILURE
);
971 /* no more than 13 arg's should be passed to the driver */
973 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
974 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
975 "LDAP driver cannot accept more than "
976 "11 command line args.");
977 return (ISC_R_FAILURE
);
980 /* determine protocol version. */
981 if (strncasecmp(argv
[2], V2
, strlen(V2
)) == 0) {
983 } else if (strncasecmp(argv
[2], V3
, strlen(V3
)) == 0) {
986 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
987 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
988 "LDAP driver protocol must be either %s or %s",
990 return (ISC_R_FAILURE
);
993 /* determine connection method. */
994 if (strncasecmp(argv
[3], SIMPLE
, strlen(SIMPLE
)) == 0) {
995 method
= LDAP_AUTH_SIMPLE
;
996 } else if (strncasecmp(argv
[3], KRB41
, strlen(KRB41
)) == 0) {
997 method
= LDAP_AUTH_KRBV41
;
998 } else if (strncasecmp(argv
[3], KRB42
, strlen(KRB42
)) == 0) {
999 method
= LDAP_AUTH_KRBV42
;
1001 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1002 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1003 "LDAP driver authentication method must be "
1004 "one of %s, %s or %s",
1005 SIMPLE
, KRB41
, KRB42
);
1006 return (ISC_R_FAILURE
);
1009 /* multithreaded build can have multiple DB connections */
1010 #ifdef ISC_PLATFORM_USETHREADS
1012 /* check how many db connections we should create */
1013 dbcount
= strtol(argv
[1], &endp
, 10);
1014 if (*endp
!= '\0' || dbcount
< 0) {
1015 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1016 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1017 "LDAP driver database connection count "
1018 "must be positive.");
1019 return (ISC_R_FAILURE
);
1023 /* check that LDAP URL parameters make sense */
1026 result
= dlz_ldap_checkURL(argv
[11], 0, "allow zone transfer");
1027 if (result
!= ISC_R_SUCCESS
)
1030 result
= dlz_ldap_checkURL(argv
[10], 3, "all nodes");
1031 if (result
!= ISC_R_SUCCESS
)
1034 if (strlen(argv
[9]) > 0) {
1035 result
= dlz_ldap_checkURL(argv
[9], 3, "authority");
1036 if (result
!= ISC_R_SUCCESS
)
1040 result
= dlz_ldap_checkURL(argv
[8], 3, "lookup");
1041 if (result
!= ISC_R_SUCCESS
)
1043 result
= dlz_ldap_checkURL(argv
[7], 0, "find zone");
1044 if (result
!= ISC_R_SUCCESS
)
1048 /* not really needed, should shut up compiler. */
1049 result
= ISC_R_FAILURE
;
1052 /* allocate memory for LDAP instance */
1053 ldap_inst
= isc_mem_get(ns_g_mctx
, sizeof(ldap_instance_t
));
1054 if (ldap_inst
== NULL
)
1055 return (ISC_R_NOMEMORY
);
1056 memset(ldap_inst
, 0, sizeof(ldap_instance_t
));
1058 /* store info needed to automatically re-connect. */
1059 ldap_inst
->protocol
= protocol
;
1060 ldap_inst
->method
= method
;
1061 ldap_inst
->hosts
= isc_mem_strdup(ns_g_mctx
, argv
[6]);
1062 if (ldap_inst
->hosts
== NULL
) {
1063 result
= ISC_R_NOMEMORY
;
1066 ldap_inst
->user
= isc_mem_strdup(ns_g_mctx
, argv
[4]);
1067 if (ldap_inst
->user
== NULL
) {
1068 result
= ISC_R_NOMEMORY
;
1071 ldap_inst
->cred
= isc_mem_strdup(ns_g_mctx
, argv
[5]);
1072 if (ldap_inst
->cred
== NULL
) {
1073 result
= ISC_R_NOMEMORY
;
1077 #ifdef ISC_PLATFORM_USETHREADS
1078 /* allocate memory for database connection list */
1079 ldap_inst
->db
= isc_mem_get(ns_g_mctx
, sizeof(db_list_t
));
1080 if (ldap_inst
->db
== NULL
) {
1081 result
= ISC_R_NOMEMORY
;
1085 /* initialize DB connection list */
1086 ISC_LIST_INIT(*(ldap_inst
->db
));
1089 * create the appropriate number of database instances (DBI)
1090 * append each new DBI to the end of the list
1092 for (i
= 0; i
< dbcount
; i
++) {
1094 #endif /* ISC_PLATFORM_USETHREADS */
1096 /* how many queries were passed in from config file? */
1099 result
= build_sqldbinstance(ns_g_mctx
, NULL
, NULL
,
1100 NULL
, argv
[7], argv
[8],
1104 result
= build_sqldbinstance(ns_g_mctx
, NULL
, NULL
,
1105 argv
[9], argv
[7], argv
[8],
1109 result
= build_sqldbinstance(ns_g_mctx
, argv
[10], NULL
,
1110 argv
[9], argv
[7], argv
[8],
1114 result
= build_sqldbinstance(ns_g_mctx
, argv
[10],
1120 /* not really needed, should shut up compiler. */
1121 result
= ISC_R_FAILURE
;
1124 if (result
== ISC_R_SUCCESS
) {
1125 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1126 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
1127 "LDAP driver created "
1128 "database instance object.");
1129 } else { /* unsuccessful?, log err msg and cleanup. */
1130 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1131 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1132 "LDAP driver could not create "
1133 "database instance object.");
1137 #ifdef ISC_PLATFORM_USETHREADS
1138 /* when multithreaded, build a list of DBI's */
1139 ISC_LINK_INIT(dbi
, link
);
1140 ISC_LIST_APPEND(*(ldap_inst
->db
), dbi
, link
);
1143 * when single threaded, hold onto the one connection
1146 ldap_inst
->db
= dbi
;
1149 /* attempt to connect */
1150 result
= dlz_ldap_connect(ldap_inst
, dbi
);
1153 * if db connection cannot be created, log err msg and
1157 /* success, do nothing */
1161 * no memory means ldap_init could not
1164 case ISC_R_NOMEMORY
:
1165 #ifdef ISC_PLATFORM_USETHREADS
1166 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1167 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1168 "LDAP driver could not allocate memory "
1169 "for connection number %u",
1172 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1173 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1174 "LDAP driver could not allocate memory "
1180 * no perm means ldap_set_option could not set
1184 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1185 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1186 "LDAP driver could not "
1187 "set protocol version.");
1188 result
= ISC_R_FAILURE
;
1191 /* failure means couldn't connect to ldap server */
1193 #ifdef ISC_PLATFORM_USETHREADS
1194 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1195 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1196 "LDAP driver could not "
1197 "bind connection number %u to server.",
1200 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1201 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
1202 "LDAP driver could not "
1203 "bind connection to server.");
1208 * default should never happen. If it does,
1212 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1213 "dlz_ldap_create() failed: %s",
1214 isc_result_totext(result
));
1215 result
= ISC_R_UNEXPECTED
;
1218 } /* end switch(result) */
1221 #ifdef ISC_PLATFORM_USETHREADS
1223 /* set DBI = null for next loop through. */
1225 } /* end for loop */
1227 #endif /* ISC_PLATFORM_USETHREADS */
1230 /* set dbdata to the ldap_instance we created. */
1231 *dbdata
= ldap_inst
;
1233 /* hey, we got through all of that ok, return success. */
1234 return(ISC_R_SUCCESS
);
1238 dlz_ldap_destroy(NULL
, ldap_inst
);
1240 return(ISC_R_FAILURE
);
1244 dlz_ldap_destroy(void *driverarg
, void *dbdata
)
1249 if (dbdata
!= NULL
) {
1251 #ifdef ISC_PLATFORM_USETHREADS
1253 /* cleanup the list of DBI's */
1254 ldap_destroy_dblist((db_list_t
*)
1255 ((ldap_instance_t
*)dbdata
)->db
);
1257 #else /* ISC_PLATFORM_USETHREADS */
1259 /* release connection */
1260 if (((ldap_instance_t
*)dbdata
)->db
->dbconn
!= NULL
)
1261 ldap_unbind_s((LDAP
*)
1262 ((ldap_instance_t
*)dbdata
)->db
->dbconn
);
1264 /* destroy single DB instance */
1265 destroy_sqldbinstance(((ldap_instance_t
*)dbdata
)->db
);
1267 #endif /* ISC_PLATFORM_USETHREADS */
1269 if (((ldap_instance_t
*)dbdata
)->hosts
!= NULL
)
1270 isc_mem_free(ns_g_mctx
,
1271 ((ldap_instance_t
*)dbdata
)->hosts
);
1273 if (((ldap_instance_t
*)dbdata
)->user
!= NULL
)
1274 isc_mem_free(ns_g_mctx
,
1275 ((ldap_instance_t
*)dbdata
)->user
);
1277 if (((ldap_instance_t
*)dbdata
)->cred
!= NULL
)
1278 isc_mem_free(ns_g_mctx
,
1279 ((ldap_instance_t
*)dbdata
)->cred
);
1281 isc_mem_put(ns_g_mctx
, dbdata
, sizeof(ldap_instance_t
));
1285 static dns_sdlzmethods_t dlz_ldap_methods
= {
1292 dlz_ldap_allowzonexfr
1296 * Wrapper around dns_sdlzregister().
1299 dlz_ldap_init(void) {
1300 isc_result_t result
;
1303 * Write debugging message to log
1305 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1306 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
1307 "Registering DLZ ldap driver.");
1309 result
= dns_sdlzregister("ldap", &dlz_ldap_methods
, NULL
,
1310 DNS_SDLZFLAG_RELATIVEOWNER
|
1311 DNS_SDLZFLAG_RELATIVERDATA
,
1312 ns_g_mctx
, &dlz_ldap
);
1313 if (result
!= ISC_R_SUCCESS
) {
1314 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1315 "dns_sdlzregister() failed: %s",
1316 isc_result_totext(result
));
1317 result
= ISC_R_UNEXPECTED
;
1325 * Wrapper around dns_sdlzunregister().
1328 dlz_ldap_clear(void) {
1331 * Write debugging message to log
1333 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
1334 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
1335 "Unregistering DLZ ldap driver.");
1337 if (dlz_ldap
!= NULL
)
1338 dns_sdlzunregister(&dlz_ldap
);