2
* Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
4
* Permission to use, copy, modify, and distribute this software for any
5
* purpose with or without fee is hereby granted, provided that the
6
* above copyright notice and this permission notice appear in all
9
* THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
10
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
11
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12
* STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
16
* USE OR PERFORMANCE OF THIS SOFTWARE.
18
* The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
19
* conceived and contributed by Rob Butler.
21
* Permission to use, copy, modify, and distribute this software for any
22
* purpose with or without fee is hereby granted, provided that the
23
* above copyright notice and this permission notice appear in all
26
* THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
27
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
28
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
29
* ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
30
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
32
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
33
* USE OR PERFORMANCE OF THIS SOFTWARE.
37
* Copyright (C) 1999-2001 Internet Software Consortium.
39
* Permission to use, copy, modify, and distribute this software for any
40
* purpose with or without fee is hereby granted, provided that the above
41
* copyright notice and this permission notice appear in all copies.
43
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
44
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
45
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
46
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
47
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
48
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
49
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
50
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
62
#include <dns/result.h>
65
#include <isc/platform.h>
66
#include <isc/print.h>
67
#include <isc/result.h>
68
#include <isc/string.h>
71
#include <named/globals.h>
73
#include <dlz/sdlz_helper.h>
74
#include <dlz/dlz_ldap_driver.h>
77
* Need older API functions from ldap.h.
79
#define LDAP_DEPRECATED 1
83
#define SIMPLE "simple"
89
static dns_sdlzimplementation_t *dlz_ldap = NULL;
91
#define dbc_search_limit 30
99
* Structure to hold everthing needed by this "instance" of the LDAP
100
* driver remember, the driver code is only loaded once, but may have
101
* many separate instances.
106
#ifdef ISC_PLATFORM_USETHREADS
107
db_list_t *db; /*%< handle to a list of DB */
109
dbinstance_t *db; /*%< handle to db */
111
int method; /*%< security authentication method */
112
char *user; /*%< who is authenticating */
113
char *cred; /*%< password for simple authentication method */
114
int protocol; /*%< LDAP communication protocol version */
115
char *hosts; /*%< LDAP server hosts */
119
/* forward references */
122
dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name);
125
dlz_ldap_destroy(void *driverarg, void *dbdata);
131
/*% checks that the LDAP URL parameters make sense */
134
dlz_ldap_checkURL(char *URL, int attrCnt, const char *msg) {
136
isc_result_t result = ISC_R_SUCCESS;
138
LDAPURLDesc *ldap_url = NULL;
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;
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;
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",
163
result = ISC_R_FAILURE;
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;
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;
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;
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.",
197
result = ISC_R_FAILURE;
203
if (ldap_url != NULL)
204
ldap_free_urldesc(ldap_url);
208
/*% Connects / reconnects to LDAP server */
211
dlz_ldap_connect(ldap_instance_t *dbi, dbinstance_t *dbc) {
216
/* if we have a connection, get ride of it. */
217
if (dbc->dbconn != NULL) {
218
ldap_unbind_s((LDAP *) dbc->dbconn);
222
/* now connect / reconnect. */
225
dbc->dbconn = ldap_init(dbi->hosts, LDAP_PORT);
226
if (dbc->dbconn == NULL)
227
return ISC_R_NOMEMORY;
229
/* set protocol version. */
230
ldap_result = ldap_set_option((LDAP *) dbc->dbconn,
231
LDAP_OPT_PROTOCOL_VERSION,
233
if (ldap_result != LDAP_SUCCESS) {
234
result = ISC_R_NOPERM;
238
/* "bind" to server. i.e. send username / pass */
239
ldap_result = ldap_bind_s((LDAP *) dbc->dbconn, dbi->user,
240
dbi->cred, dbi->method);
241
if (ldap_result != LDAP_SUCCESS) {
242
result = ISC_R_FAILURE;
246
return ISC_R_SUCCESS;
250
/* cleanup if failure. */
251
if (dbc->dbconn != NULL) {
252
ldap_unbind_s((LDAP *) dbc->dbconn);
259
#ifdef ISC_PLATFORM_USETHREADS
263
* Properly cleans up a list of database instances.
264
* This function is only used when the driver is compiled for
265
* multithreaded operation.
268
ldap_destroy_dblist(db_list_t *dblist)
271
dbinstance_t *ndbi = NULL;
272
dbinstance_t *dbi = NULL;
274
/* get the first DBI in the list */
275
ndbi = ISC_LIST_HEAD(*dblist);
277
/* loop through the list */
278
while (ndbi != NULL) {
280
/* get the next DBI in the list */
281
ndbi = ISC_LIST_NEXT(dbi, link);
282
/* release DB connection */
283
if (dbi->dbconn != NULL)
284
ldap_unbind_s((LDAP *) dbi->dbconn);
285
/* release all memory that comprised a DBI */
286
destroy_sqldbinstance(dbi);
288
/* release memory for the list structure */
289
isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t));
293
* Loops through the list of DB instances, attempting to lock
294
* on the mutex. If successful, the DBI is reserved for use
295
* and the thread can perform queries against the database.
296
* If the lock fails, the next one in the list is tried.
297
* looping continues until a lock is obtained, or until
298
* the list has been searched dbc_search_limit times.
299
* This function is only used when the driver is compiled for
300
* multithreaded operation.
303
static dbinstance_t *
304
ldap_find_avail_conn(db_list_t *dblist)
306
dbinstance_t *dbi = NULL;
310
/* get top of list */
311
head = dbi = ISC_LIST_HEAD(*dblist);
313
/* loop through list */
314
while (count < dbc_search_limit) {
315
/* try to lock on the mutex */
316
if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
317
return dbi; /* success, return the DBI for use. */
319
/* not successful, keep trying */
320
dbi = ISC_LIST_NEXT(dbi, link);
322
/* check to see if we have gone to the top of the list. */
328
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
329
DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
330
"LDAP driver unable to find available connection "
331
"after searching %d times",
336
#endif /* ISC_PLATFORM_USETHREADS */
339
ldap_process_results(LDAP *dbc, LDAPMessage *msg, char ** attrs,
340
void *ptr, isc_boolean_t allnodes)
342
isc_result_t result = ISC_R_SUCCESS;
346
char *attribute = NULL;
355
/* make sure there are at least some attributes to process. */
356
REQUIRE(attrs != NULL || attrs[0] != NULL);
358
/* get the first entry to process */
359
entry = ldap_first_entry(dbc, msg);
361
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
362
DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
363
"LDAP no entries to process.");
364
return ISC_R_FAILURE;
367
/* loop through all entries returned */
368
while (entry != NULL) {
370
/* reset for this loop */
374
attribute = attrs[i];
376
/* determine how much space we need for data string */
377
for (j=0; attrs[j] != NULL; j++) {
378
/* get the list of values for this attribute. */
379
vals = ldap_get_values(dbc, entry, attrs[j]);
380
/* skip empty attributes. */
381
if (vals == NULL || ldap_count_values(vals) < 1)
384
* we only use the first value. this driver
385
* does not support multi-valued attributes.
387
len = len + strlen(vals[0]) + 1;
388
/* free vals for next loop */
389
ldap_value_free(vals);
390
} /* end for (j=0; attrs[j] != NULL, j++) loop */
392
/* allocate memory for data string */
393
data = isc_mem_allocate(ns_g_mctx, len + 1);
395
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
396
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
397
"LDAP driver unable to allocate memory "
398
"while processing results");
399
result = ISC_R_FAILURE;
404
* Make sure data is null termed at the beginning so
405
* we can check if any data was stored to it later.
409
/* reset j to re-use below */
412
/* loop through the attributes in the order specified. */
413
while (attribute != NULL) {
415
/* get the list of values for this attribute. */
416
vals = ldap_get_values(dbc, entry, attribute);
418
/* skip empty attributes. */
419
if (vals == NULL || vals[0] == NULL) {
420
/* increment attibute pointer */
421
attribute = attrs[++i];
422
/* start loop over */
427
* j initially = 0. Increment j each time we
428
* set a field that way next loop will set
435
* convert text to int, make sure it
438
ttl = strtol(vals[0], &endp, 10);
439
if (*endp != '\0' || ttl < 0) {
440
isc_log_write(dns_lctx,
441
DNS_LOGCATEGORY_DATABASE,
444
"LDAP driver ttl must "
445
"be a postive number");
451
type = isc_mem_strdup(ns_g_mctx, vals[0]);
455
if (allnodes == isc_boolean_true) {
456
host = isc_mem_strdup(ns_g_mctx,
459
strcpy(data, vals[0]);
464
if (allnodes == isc_boolean_true) {
465
strcpy(data, vals[0]);
468
strcat(data, vals[0]);
473
strcat(data, vals[0]);
475
} /* end switch(j) */
478
ldap_value_free(vals);
481
/* increment attibute pointer */
482
attribute = attrs[++i];
483
} /* end while (attribute != NULL) */
486
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
487
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
488
"LDAP driver unable "
489
"to retrieve dns type");
490
result = ISC_R_FAILURE;
493
if (strlen(data) < 1) {
494
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
495
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
496
"LDAP driver unable "
497
"to retrieve dns data");
498
result = ISC_R_FAILURE;
501
if (allnodes == isc_boolean_true) {
502
if (strcasecmp(host, "~") == 0)
503
result = dns_sdlz_putnamedrr(
504
(dns_sdlzallnodes_t *) ptr,
505
"*", type, ttl, data);
507
result = dns_sdlz_putnamedrr(
508
(dns_sdlzallnodes_t *) ptr,
509
host, type, ttl, data);
512
result = dns_sdlz_putrr((dns_sdlzlookup_t *) ptr,
515
if (result != ISC_R_SUCCESS) {
516
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
517
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
518
"LDAP driver failed "
519
"while sending data to Bind.");
523
/* free memory for type, data and host for next loop */
524
isc_mem_free(ns_g_mctx, type);
525
isc_mem_free(ns_g_mctx, data);
527
isc_mem_free(ns_g_mctx, host);
529
/* get the next entry to process */
530
entry = ldap_next_entry(dbc, entry);
531
} /* end while (entry != NULL) */
535
/* de-allocate memory */
537
ldap_value_free(vals);
539
isc_mem_free(ns_g_mctx, host);
541
isc_mem_free(ns_g_mctx, type);
543
isc_mem_free(ns_g_mctx, data);
549
* This function is the real core of the driver. Zone, record
550
* and client strings are passed in (or NULL is passed if the
551
* string is not available). The type of query we want to run
552
* is indicated by the query flag, and the dbdata object is passed
553
* passed in to. dbdata really holds either:
554
* 1) a list of database instances (in multithreaded mode) OR
555
* 2) a single database instance (in single threaded mode)
556
* The function will construct the query and obtain an available
557
* database instance (DBI). It will then run the query and hopefully
558
* obtain a result set.
561
ldap_get_results(const char *zone, const char *record,
562
const char *client, unsigned int query,
563
void *dbdata, void *ptr)
566
dbinstance_t *dbi = NULL;
567
char *querystring = NULL;
568
LDAPURLDesc *ldap_url = NULL;
570
LDAPMessage *ldap_msg = NULL;
574
/* get db instance / connection */
575
#ifdef ISC_PLATFORM_USETHREADS
577
/* find an available DBI from the list */
578
dbi = ldap_find_avail_conn((db_list_t *)
579
((ldap_instance_t *)dbdata)->db);
581
#else /* ISC_PLATFORM_USETHREADS */
584
* only 1 DBI - no need to lock instance lock either
585
* only 1 thread in the whole process, no possible contention.
587
dbi = (dbinstance_t *) ((ldap_instance_t *)dbdata)->db;
589
#endif /* ISC_PLATFORM_USETHREADS */
591
/* if DBI is null, can't do anything else */
593
return ISC_R_FAILURE;
597
dbi->zone = isc_mem_strdup(ns_g_mctx, zone);
598
if (dbi->zone == NULL) {
599
result = ISC_R_NOMEMORY;
605
if (record != NULL) {
606
dbi->record = isc_mem_strdup(ns_g_mctx, record);
607
if (dbi->record == NULL) {
608
result = ISC_R_NOMEMORY;
614
if (client != NULL) {
615
dbi->client = isc_mem_strdup(ns_g_mctx, client);
616
if (dbi->client == NULL) {
617
result = ISC_R_NOMEMORY;
624
/* what type of query are we going to run? */
628
* if the query was not passed in from the config file
629
* then we can't run it. return not_implemented, so
630
* it's like the code for that operation was never
631
* built into the driver.... AHHH flexibility!!!
633
if (dbi->allnodes_q == NULL) {
634
result = ISC_R_NOTIMPLEMENTED;
637
querystring = build_querystring(ns_g_mctx,
642
/* same as comments as ALLNODES */
643
if (dbi->allowxfr_q == NULL) {
644
result = ISC_R_NOTIMPLEMENTED;
647
querystring = build_querystring(ns_g_mctx,
652
/* same as comments as ALLNODES */
653
if (dbi->authority_q == NULL) {
654
result = ISC_R_NOTIMPLEMENTED;
657
querystring = build_querystring(ns_g_mctx,
662
/* this is required. It's the whole point of DLZ! */
663
if (dbi->findzone_q == NULL) {
664
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
665
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
666
"No query specified for findzone. "
667
"Findzone requires a query");
668
result = ISC_R_FAILURE;
671
querystring = build_querystring(ns_g_mctx,
676
/* this is required. It's also a major point of DLZ! */
677
if (dbi->lookup_q == NULL) {
678
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
679
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
680
"No query specified for lookup. "
681
"Lookup requires a query");
682
result = ISC_R_FAILURE;
685
querystring = build_querystring(ns_g_mctx,
691
* this should never happen. If it does, the code is
694
UNEXPECTED_ERROR(__FILE__, __LINE__,
695
"Incorrect query flag passed to "
697
result = ISC_R_UNEXPECTED;
701
/* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
702
if (querystring == NULL) {
703
result = ISC_R_NOMEMORY;
708
* output the full query string during debug so we can see
709
* what lame error the query has.
711
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
712
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
713
"\nQuery String: %s\n", querystring);
715
/* break URL down into it's component parts, if error cleanup */
716
ldap_result = ldap_url_parse(querystring, &ldap_url);
717
if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
718
result = ISC_R_FAILURE;
722
for (i=0; i < 3; i++) {
725
* dbi->dbconn may be null if trying to reconnect on a
726
* previous query failed.
728
if (dbi->dbconn == NULL) {
729
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
730
DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
731
"LDAP driver attempting to re-connect");
733
result = dlz_ldap_connect((ldap_instance_t *) dbdata,
735
if (result != ISC_R_SUCCESS) {
736
result = ISC_R_FAILURE;
741
/* perform ldap search syncronously */
742
ldap_result = ldap_search_s((LDAP *) dbi->dbconn,
745
ldap_url->lud_filter,
746
ldap_url->lud_attrs, 0, &ldap_msg);
749
* check return code. No such object is ok, just
750
* didn't find what we wanted
752
switch(ldap_result) {
753
case LDAP_NO_SUCH_OBJECT:
754
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
755
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
756
"No object found matching "
757
"query requirements");
758
result = ISC_R_NOTFOUND;
761
case LDAP_SUCCESS: /* on success do nothing */
762
result = ISC_R_SUCCESS;
765
case LDAP_SERVER_DOWN:
766
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
767
DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
768
"LDAP driver attempting to re-connect");
769
result = dlz_ldap_connect((ldap_instance_t *) dbdata,
771
if (result != ISC_R_SUCCESS)
772
result = ISC_R_FAILURE;
776
* other errors not ok. Log error message and
779
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
780
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
782
ldap_err2string(ldap_result));
783
result = ISC_R_FAILURE;
786
} /* close switch(ldap_result) */
787
} /* end for (int i=0 i < 3; i++) */
789
if (result != ISC_R_SUCCESS)
794
result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
796
ptr, isc_boolean_true);
800
result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
802
ptr, isc_boolean_false);
805
entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
807
result = ISC_R_NOPERM;
808
else if (entries > 0)
809
result = ISC_R_SUCCESS;
811
result = ISC_R_FAILURE;
814
entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
816
result = ISC_R_NOTFOUND;
817
else if (entries > 0)
818
result = ISC_R_SUCCESS;
820
result = ISC_R_FAILURE;
824
* this should never happen. If it does, the code is
827
UNEXPECTED_ERROR(__FILE__, __LINE__,
828
"Incorrect query flag passed to "
830
result = ISC_R_UNEXPECTED;
835
/* it's always good to cleanup after yourself */
837
/* if we retrieved results, free them */
838
if (ldap_msg != NULL)
839
ldap_msgfree(ldap_msg);
841
if (ldap_url != NULL)
842
ldap_free_urldesc(ldap_url);
845
if (dbi->zone != NULL)
846
isc_mem_free(ns_g_mctx, dbi->zone);
847
if (dbi->record != NULL)
848
isc_mem_free(ns_g_mctx, dbi->record);
849
if (dbi->client != NULL)
850
isc_mem_free(ns_g_mctx, dbi->client);
852
#ifdef ISC_PLATFORM_USETHREADS
854
/* release the lock so another thread can use this dbi */
855
isc_mutex_unlock(&dbi->instance_lock);
857
#endif /* ISC_PLATFORM_USETHREADS */
859
/* release query string */
860
if (querystring != NULL)
861
isc_mem_free(ns_g_mctx, querystring );
872
dlz_ldap_allowzonexfr(void *driverarg, void *dbdata, const char *name,
879
/* check to see if we are authoritative for the zone first */
880
result = dlz_ldap_findzone(driverarg, dbdata, name);
881
if (result != ISC_R_SUCCESS) {
885
/* get all the zone data */
886
return ldap_get_results(name, NULL, client, ALLOWXFR, dbdata, NULL);
890
dlz_ldap_allnodes(const char *zone, void *driverarg, void *dbdata,
891
dns_sdlzallnodes_t *allnodes)
894
return ldap_get_results(zone, NULL, NULL, ALLNODES, dbdata, allnodes);
898
dlz_ldap_authority(const char *zone, void *driverarg, void *dbdata,
899
dns_sdlzlookup_t *lookup)
902
return ldap_get_results(zone, NULL, NULL, AUTHORITY, dbdata, lookup);
906
dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name)
909
return ldap_get_results(name, NULL, NULL, FINDZONE, dbdata, NULL);
913
dlz_ldap_lookup(const char *zone, const char *name, void *driverarg,
914
void *dbdata, dns_sdlzlookup_t *lookup)
917
if (strcmp(name, "*") == 0)
918
return ldap_get_results(zone, "~", NULL,
919
LOOKUP, dbdata, lookup);
921
return ldap_get_results(zone, name, NULL,
922
LOOKUP, dbdata, lookup);
927
dlz_ldap_create(const char *dlzname, unsigned int argc, char *argv[],
928
void *driverarg, void **dbdata)
932
ldap_instance_t *ldap_inst = NULL;
933
dbinstance_t *dbi = NULL;
937
#ifdef ISC_PLATFORM_USETHREADS
938
/* if multi-threaded, we need a few extra variables. */
941
/* db_list_t *dblist = NULL; */
944
#endif /* ISC_PLATFORM_USETHREADS */
949
#ifdef ISC_PLATFORM_USETHREADS
950
/* if debugging, let user know we are multithreaded. */
951
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
952
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
953
"LDAP driver running multithreaded");
954
#else /* ISC_PLATFORM_USETHREADS */
955
/* if debugging, let user know we are single threaded. */
956
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
957
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
958
"LDAP driver running single threaded");
959
#endif /* ISC_PLATFORM_USETHREADS */
962
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
963
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
964
"LDAP driver requires at least "
965
"8 command line args.");
966
return (ISC_R_FAILURE);
969
/* no more than 13 arg's should be passed to the driver */
971
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
972
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
973
"LDAP driver cannot accept more than "
974
"11 command line args.");
975
return (ISC_R_FAILURE);
978
/* determine protocol version. */
979
if (strncasecmp(argv[2], V2, strlen(V2)) == 0) {
981
} else if (strncasecmp(argv[2], V3, strlen(V3)) == 0) {
984
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
985
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
986
"LDAP driver protocol must be either %s or %s",
988
return (ISC_R_FAILURE);
991
/* determine connection method. */
992
if (strncasecmp(argv[3], SIMPLE, strlen(SIMPLE)) == 0) {
993
method = LDAP_AUTH_SIMPLE;
994
} else if (strncasecmp(argv[3], KRB41, strlen(KRB41)) == 0) {
995
method = LDAP_AUTH_KRBV41;
996
} else if (strncasecmp(argv[3], KRB42, strlen(KRB42)) == 0) {
997
method = LDAP_AUTH_KRBV42;
999
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1000
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1001
"LDAP driver authentication method must be "
1002
"one of %s, %s or %s",
1003
SIMPLE, KRB41, KRB42);
1004
return (ISC_R_FAILURE);
1007
/* multithreaded build can have multiple DB connections */
1008
#ifdef ISC_PLATFORM_USETHREADS
1010
/* check how many db connections we should create */
1011
dbcount = strtol(argv[1], &endp, 10);
1012
if (*endp != '\0' || dbcount < 0) {
1013
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1014
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1015
"LDAP driver database connection count "
1016
"must be positive.");
1017
return (ISC_R_FAILURE);
1021
/* check that LDAP URL parameters make sense */
1024
result = dlz_ldap_checkURL(argv[11], 0, "allow zone transfer");
1025
if (result != ISC_R_SUCCESS)
1028
result = dlz_ldap_checkURL(argv[10], 3, "all nodes");
1029
if (result != ISC_R_SUCCESS)
1032
if (strlen(argv[9]) > 0) {
1033
result = dlz_ldap_checkURL(argv[9], 3, "authority");
1034
if (result != ISC_R_SUCCESS)
1038
result = dlz_ldap_checkURL(argv[8], 3, "lookup");
1039
if (result != ISC_R_SUCCESS)
1041
result = dlz_ldap_checkURL(argv[7], 0, "find zone");
1042
if (result != ISC_R_SUCCESS)
1046
/* not really needed, should shut up compiler. */
1047
result = ISC_R_FAILURE;
1050
/* allocate memory for LDAP instance */
1051
ldap_inst = isc_mem_get(ns_g_mctx, sizeof(ldap_instance_t));
1052
if (ldap_inst == NULL)
1053
return (ISC_R_NOMEMORY);
1054
memset(ldap_inst, 0, sizeof(ldap_instance_t));
1056
/* store info needed to automatically re-connect. */
1057
ldap_inst->protocol = protocol;
1058
ldap_inst->method = method;
1059
ldap_inst->hosts = isc_mem_strdup(ns_g_mctx, argv[6]);
1060
if (ldap_inst->hosts == NULL) {
1061
result = ISC_R_NOMEMORY;
1064
ldap_inst->user = isc_mem_strdup(ns_g_mctx, argv[4]);
1065
if (ldap_inst->user == NULL) {
1066
result = ISC_R_NOMEMORY;
1069
ldap_inst->cred = isc_mem_strdup(ns_g_mctx, argv[5]);
1070
if (ldap_inst->cred == NULL) {
1071
result = ISC_R_NOMEMORY;
1075
#ifdef ISC_PLATFORM_USETHREADS
1076
/* allocate memory for database connection list */
1077
ldap_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
1078
if (ldap_inst->db == NULL) {
1079
result = ISC_R_NOMEMORY;
1083
/* initialize DB connection list */
1084
ISC_LIST_INIT(*(ldap_inst->db));
1087
* create the appropriate number of database instances (DBI)
1088
* append each new DBI to the end of the list
1090
for (i = 0; i < dbcount; i++) {
1092
#endif /* ISC_PLATFORM_USETHREADS */
1094
/* how many queries were passed in from config file? */
1097
result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
1098
NULL, argv[7], argv[8],
1102
result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
1103
argv[9], argv[7], argv[8],
1107
result = build_sqldbinstance(ns_g_mctx, argv[10], NULL,
1108
argv[9], argv[7], argv[8],
1112
result = build_sqldbinstance(ns_g_mctx, argv[10],
1118
/* not really needed, should shut up compiler. */
1119
result = ISC_R_FAILURE;
1122
if (result == ISC_R_SUCCESS) {
1123
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1124
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1125
"LDAP driver created "
1126
"database instance object.");
1127
} else { /* unsuccessful?, log err msg and cleanup. */
1128
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1129
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1130
"LDAP driver could not create "
1131
"database instance object.");
1135
#ifdef ISC_PLATFORM_USETHREADS
1136
/* when multithreaded, build a list of DBI's */
1137
ISC_LINK_INIT(dbi, link);
1138
ISC_LIST_APPEND(*(ldap_inst->db), dbi, link);
1141
* when single threaded, hold onto the one connection
1144
ldap_inst->db = dbi;
1147
/* attempt to connect */
1148
result = dlz_ldap_connect(ldap_inst, dbi);
1151
* if db connection cannot be created, log err msg and
1155
/* success, do nothing */
1159
* no memory means ldap_init could not
1162
case ISC_R_NOMEMORY:
1163
#ifdef ISC_PLATFORM_USETHREADS
1164
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1165
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1166
"LDAP driver could not allocate memory "
1167
"for connection number %u",
1170
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1171
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1172
"LDAP driver could not allocate memory "
1178
* no perm means ldap_set_option could not set
1182
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1183
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1184
"LDAP driver could not "
1185
"set protocol version.");
1186
result = ISC_R_FAILURE;
1189
/* failure means couldn't connect to ldap server */
1191
#ifdef ISC_PLATFORM_USETHREADS
1192
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1193
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1194
"LDAP driver could not "
1195
"bind connection number %u to server.",
1198
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1199
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1200
"LDAP driver could not "
1201
"bind connection to server.");
1206
* default should never happen. If it does,
1210
UNEXPECTED_ERROR(__FILE__, __LINE__,
1211
"dlz_ldap_create() failed: %s",
1212
isc_result_totext(result));
1213
result = ISC_R_UNEXPECTED;
1216
} /* end switch(result) */
1219
#ifdef ISC_PLATFORM_USETHREADS
1221
/* set DBI = null for next loop through. */
1223
} /* end for loop */
1225
#endif /* ISC_PLATFORM_USETHREADS */
1228
/* set dbdata to the ldap_instance we created. */
1229
*dbdata = ldap_inst;
1231
/* hey, we got through all of that ok, return success. */
1232
return(ISC_R_SUCCESS);
1236
dlz_ldap_destroy(NULL, ldap_inst);
1238
return(ISC_R_FAILURE);
1242
dlz_ldap_destroy(void *driverarg, void *dbdata)
1247
if (dbdata != NULL) {
1249
#ifdef ISC_PLATFORM_USETHREADS
1251
/* cleanup the list of DBI's */
1252
ldap_destroy_dblist((db_list_t *)
1253
((ldap_instance_t *)dbdata)->db);
1255
#else /* ISC_PLATFORM_USETHREADS */
1257
/* release connection */
1258
if (((ldap_instance_t *)dbdata)->db->dbconn != NULL)
1259
ldap_unbind_s((LDAP *)
1260
((ldap_instance_t *)dbdata)->db->dbconn);
1262
/* destroy single DB instance */
1263
destroy_sqldbinstance(((ldap_instance_t *)dbdata)->db);
1265
#endif /* ISC_PLATFORM_USETHREADS */
1267
if (((ldap_instance_t *)dbdata)->hosts != NULL)
1268
isc_mem_free(ns_g_mctx,
1269
((ldap_instance_t *)dbdata)->hosts);
1271
if (((ldap_instance_t *)dbdata)->user != NULL)
1272
isc_mem_free(ns_g_mctx,
1273
((ldap_instance_t *)dbdata)->user);
1275
if (((ldap_instance_t *)dbdata)->cred != NULL)
1276
isc_mem_free(ns_g_mctx,
1277
((ldap_instance_t *)dbdata)->cred);
1279
isc_mem_put(ns_g_mctx, dbdata, sizeof(ldap_instance_t));
1283
static dns_sdlzmethods_t dlz_ldap_methods = {
1290
dlz_ldap_allowzonexfr
1294
* Wrapper around dns_sdlzregister().
1297
dlz_ldap_init(void) {
1298
isc_result_t result;
1301
* Write debugging message to log
1303
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1304
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1305
"Registering DLZ ldap driver.");
1307
result = dns_sdlzregister("ldap", &dlz_ldap_methods, NULL,
1308
DNS_SDLZFLAG_RELATIVEOWNER |
1309
DNS_SDLZFLAG_RELATIVERDATA,
1310
ns_g_mctx, &dlz_ldap);
1311
if (result != ISC_R_SUCCESS) {
1312
UNEXPECTED_ERROR(__FILE__, __LINE__,
1313
"dns_sdlzregister() failed: %s",
1314
isc_result_totext(result));
1315
result = ISC_R_UNEXPECTED;
1323
* Wrapper around dns_sdlzunregister().
1326
dlz_ldap_clear(void) {
1329
* Write debugging message to log
1331
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1332
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1333
"Unregistering DLZ ldap driver.");
1335
if (dlz_ldap != NULL)
1336
dns_sdlzunregister(&dlz_ldap);