openldap: initialize StartTLS option to it's default value
[collectd.git] / src / openldap.c
1 /**
2  * collectd - src/openldap.c
3  * Copyright (C) 2011       Kimo Rosenbaum
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Kimo Rosenbaum <kimor79 at yahoo.com>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "configfile.h"
26
27 #include <lber.h>
28 #include <ldap.h>
29
30 struct ldap_s /* {{{ */
31 {
32         char *name;
33
34         char *cacert;
35         char *host;
36         int   state;
37         int   starttls;
38         int   timeout;
39         char *url;
40         int   verifyhost;
41         int   version;
42
43         LDAP *ld;
44         char *dn;
45 };
46 typedef struct ldap_s ldap_t; /* }}} */
47
48 static void ldap_free (ldap_t *st) /* {{{ */
49 {
50         if (st == NULL)
51                 return;
52
53         sfree (st->cacert);
54         sfree (st->host);
55         sfree (st->name);
56         sfree (st->url);
57         if (st->ld)
58                 ldap_memfree (st->ld);
59         sfree (st);
60 } /* }}} void ldap_free */
61
62 /* initialize ldap for each host */
63 static int ldap_init_host (ldap_t *st) /* {{{ */
64 {
65         LDAP *ld;
66         int rc;
67         rc = ldap_initialize (&ld, st->url);
68         if (rc != LDAP_SUCCESS)
69         {
70                 ERROR ("openldap plugin: ldap_initialize failed: %s",
71                         ldap_err2string (rc));
72                 st->state = 0;
73                 return (-1);
74         }
75
76         st->ld = ld;
77
78         ldap_set_option (st->ld, LDAP_OPT_PROTOCOL_VERSION, &st->version);
79
80         ldap_set_option (st->ld, LDAP_OPT_TIMEOUT,
81                 &(const struct timeval){st->timeout, 0});
82
83         if (st->cacert != NULL)
84                 ldap_set_option (st->ld, LDAP_OPT_X_TLS_CACERTFILE, st->cacert);
85
86         if (st->verifyhost == 0)
87         {
88                 int never = LDAP_OPT_X_TLS_NEVER;
89                 ldap_set_option (st->ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &never);
90         }
91
92         if (st->starttls != 0)
93         {
94                 rc = ldap_start_tls_s (ld, NULL, NULL);
95                 if (rc != LDAP_SUCCESS)
96                 {
97                         ERROR ("openldap plugin: Failed to start tls on %s: %s",
98                                         st->url, ldap_err2string (rc));
99                         st->state = 0;
100                         ldap_unbind_ext_s (st->ld, NULL, NULL);
101                         return (-1);
102                 }
103         }
104
105         struct berval cred;
106         cred.bv_val = "";
107         cred.bv_len = 0;
108
109         rc = ldap_sasl_bind_s (st->ld, NULL, NULL, &cred, NULL, NULL, NULL);
110         if (rc != LDAP_SUCCESS)
111         {
112                 ERROR ("openldap plugin: Failed to bind to %s: %s",
113                                 st->url, ldap_err2string (rc));
114                 st->state = 0;
115                 ldap_unbind_ext_s (st->ld, NULL, NULL);
116                 return (-1);
117         }
118         else
119         {
120                 DEBUG ("openldap plugin: Successfully connected to %s",
121                                 st->url);
122                 st->state = 1;
123                 return (0);
124         }
125 } /* }}} static ldap_init_host */
126
127 static void ldap_submit_value (const char *type, const char *type_instance, /* {{{ */
128                 value_t value, ldap_t *st)
129 {
130         value_list_t vl = VALUE_LIST_INIT;
131
132         vl.values     = &value;
133         vl.values_len = 1;
134
135         if ((st->host == NULL)
136                         || (strcmp ("", st->host) == 0)
137                         || (strcmp ("localhost", st->host) == 0))
138         {
139                 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
140         }
141         else
142         {
143                 sstrncpy (vl.host, st->host, sizeof (vl.host));
144         }
145
146         sstrncpy (vl.plugin, "openldap", sizeof (vl.plugin));
147         if (st->name != NULL)
148                 sstrncpy (vl.plugin_instance, st->name,
149                                 sizeof (vl.plugin_instance));
150
151         sstrncpy (vl.type, type, sizeof (vl.type));
152         if (type_instance != NULL)
153                 sstrncpy (vl.type_instance, type_instance,
154                                 sizeof (vl.type_instance));
155
156         plugin_dispatch_values (&vl);
157 } /* }}} void ldap_submit_value */
158
159 static void ldap_submit_derive (const char *type, const char *type_instance, /* {{{ */
160                 derive_t d, ldap_t *st)
161 {
162         value_t v;
163         v.derive = d;
164         ldap_submit_value (type, type_instance, v, st);
165 } /* }}} void ldap_submit_derive */
166
167 static void ldap_submit_gauge (const char *type, const char *type_instance, /* {{{ */
168                 gauge_t g, ldap_t *st)
169 {
170         value_t v;
171         v.gauge = g;
172         ldap_submit_value (type, type_instance, v, st);
173 } /* }}} void ldap_submit_gauge */
174
175 static int ldap_read_host (user_data_t *ud) /* {{{ */
176 {
177         ldap_t *st;
178         LDAPMessage *e, *result;
179         char *dn;
180         int rc;
181         int status;
182
183         char *attrs[9] = { "monitorCounter",
184                                 "monitorOpCompleted",
185                                 "monitorOpInitiated",
186                                 "monitoredInfo",
187                                 "olmBDBEntryCache",
188                                 "olmBDBDNCache",
189                                 "olmBDBIDLCache",
190                                 "namingContexts",
191                                 NULL };
192
193         if ((ud == NULL) || (ud->data == NULL))
194         {
195                 ERROR ("openldap plugin: ldap_read_host: Invalid user data.");
196                 return (-1);
197         }
198
199         st = (ldap_t *) ud->data;
200
201         status = ldap_init_host (st);
202         if (status != 0)
203                 return (-1);
204
205         rc = ldap_search_ext_s (st->ld, "cn=Monitor", LDAP_SCOPE_SUBTREE,
206                 "(|(!(cn=* *))(cn=Database*))", attrs, 0,
207                 NULL, NULL, NULL, 0, &result);
208
209         if (rc != LDAP_SUCCESS)
210         {
211                 ERROR ("openldap plugin: Failed to execute search: %s",
212                                 ldap_err2string (rc));
213                 ldap_msgfree (result);
214                 return (-1);
215         }
216
217         for (e = ldap_first_entry (st->ld, result); e != NULL;
218                 e = ldap_next_entry (st->ld, e))
219         {
220                 if ((dn = ldap_get_dn (st->ld, e)) != NULL)
221                 {
222                         unsigned long long counter = 0;
223                         unsigned long long opc = 0;
224                         unsigned long long opi = 0;
225                         unsigned long long info = 0;
226
227                         struct berval counter_data;
228                         struct berval opc_data;
229                         struct berval opi_data;
230                         struct berval info_data;
231                         struct berval olmbdb_data;
232                         struct berval nc_data;
233
234                         struct berval **counter_list;
235                         struct berval **opc_list;
236                         struct berval **opi_list;
237                         struct berval **info_list;
238                         struct berval **olmbdb_list;
239                         struct berval **nc_list;
240
241                         if ((counter_list = ldap_get_values_len (st->ld, e,
242                                 "monitorCounter")) != NULL)
243                         {
244                                 counter_data = *counter_list[0];
245                                 counter = atoll (counter_data.bv_val);
246                         }
247
248                         if ((opc_list = ldap_get_values_len (st->ld, e,
249                                 "monitorOpCompleted")) != NULL)
250                         {
251                                 opc_data = *opc_list[0];
252                                 opc = atoll (opc_data.bv_val);
253                         }
254
255                         if ((opi_list = ldap_get_values_len (st->ld, e,
256                                 "monitorOpInitiated")) != NULL)
257                         {
258                                 opi_data = *opi_list[0];
259                                 opi = atoll (opi_data.bv_val);
260                         }
261
262                         if ((info_list = ldap_get_values_len (st->ld, e,
263                                 "monitoredInfo")) != NULL)
264                         {
265                                 info_data = *info_list[0];
266                                 info = atoll (info_data.bv_val);
267                         }
268
269                         if (strcmp (dn, "cn=Total,cn=Connections,cn=Monitor")
270                                         == 0)
271                         {
272                                 ldap_submit_derive ("total_connections", NULL,
273                                         counter, st);
274                         }
275                         else if (strcmp (dn,
276                                         "cn=Current,cn=Connections,cn=Monitor")
277                                         == 0)
278                         {
279                                 ldap_submit_gauge ("current_connections", NULL,
280                                         counter, st);
281                         }
282                         else if (strcmp (dn,
283                                         "cn=Operations,cn=Monitor") == 0)
284                         {
285                                 ldap_submit_derive ("operations",
286                                         "completed", opc, st);
287                                 ldap_submit_derive ("operations",
288                                         "initiated", opi, st);
289                         }
290                         else if (strcmp (dn,
291                                         "cn=Bind,cn=Operations,cn=Monitor")
292                                         == 0)
293                         {
294                                 ldap_submit_derive ("operations",
295                                         "bind-completed", opc, st);
296                                 ldap_submit_derive ("operations",
297                                         "bind-initiated", opi, st);
298                         }
299                         else if (strcmp (dn,
300                                         "cn=UnBind,cn=Operations,cn=Monitor")
301                                         == 0)
302                         {
303                                 ldap_submit_derive ("operations",
304                                         "unbind-completed", opc, st);
305                                 ldap_submit_derive ("operations",
306                                         "unbind-initiated", opi, st);
307                         }
308                         else if (strcmp (dn,
309                                         "cn=Search,cn=Operations,cn=Monitor")
310                                         == 0)
311                         {
312                                 ldap_submit_derive ("operations",
313                                         "search-completed", opc, st);
314                                 ldap_submit_derive ("operations",
315                                         "search-initiated", opi, st);
316                         }
317                         else if (strcmp (dn,
318                                         "cn=Compare,cn=Operations,cn=Monitor")
319                                         == 0)
320                         {
321                                 ldap_submit_derive ("operations",
322                                         "compare-completed", opc, st);
323                                 ldap_submit_derive ("operations",
324                                         "compare-initiated", opi, st);
325                         }
326                         else if (strcmp (dn,
327                                         "cn=Modify,cn=Operations,cn=Monitor")
328                                         == 0)
329                         {
330                                 ldap_submit_derive ("operations",
331                                         "modify-completed", opc, st);
332                                 ldap_submit_derive ("operations",
333                                         "modify-initiated", opi, st);
334                         }
335                         else if (strcmp (dn,
336                                         "cn=Modrdn,cn=Operations,cn=Monitor")
337                                         == 0)
338                         {
339                                 ldap_submit_derive ("operations",
340                                         "modrdn-completed", opc, st);
341                                 ldap_submit_derive ("operations",
342                                         "modrdn-initiated", opi, st);
343                         }
344                         else if (strcmp (dn,
345                                         "cn=Add,cn=Operations,cn=Monitor")
346                                         == 0)
347                         {
348                                 ldap_submit_derive ("operations",
349                                         "add-completed", opc, st);
350                                 ldap_submit_derive ("operations",
351                                         "add-initiated", opi, st);
352                         }
353                         else if (strcmp (dn,
354                                         "cn=Delete,cn=Operations,cn=Monitor")
355                                         == 0)
356                         {
357                                 ldap_submit_derive ("operations",
358                                         "delete-completed", opc, st);
359                                 ldap_submit_derive ("operations",
360                                         "delete-initiated", opi, st);
361                         }
362                         else if (strcmp (dn,
363                                         "cn=Abandon,cn=Operations,cn=Monitor")
364                                         == 0)
365                         {
366                                 ldap_submit_derive ("operations",
367                                         "abandon-completed", opc, st);
368                                 ldap_submit_derive ("operations",
369                                         "abandon-initiated", opi, st);
370                         }
371                         else if (strcmp (dn,
372                                         "cn=Extended,cn=Operations,cn=Monitor")
373                                         == 0)
374                         {
375                                 ldap_submit_derive ("operations",
376                                         "extended-completed", opc, st);
377                                 ldap_submit_derive ("operations",
378                                         "extended-initiated", opi, st);
379                         }
380                         else if ((strncmp (dn, "cn=Database", 11) == 0)
381                                 && ((nc_list = ldap_get_values_len
382                                                 (st->ld, e, "namingContexts")) != NULL))
383                         {
384                                 nc_data = *nc_list[0];
385                                 char typeinst[DATA_MAX_NAME_LEN];
386
387                                 if ((olmbdb_list = ldap_get_values_len (st->ld, e,
388                                         "olmBDBEntryCache")) != NULL)
389                                 {
390                                         olmbdb_data = *olmbdb_list[0];
391                                         ssnprintf (typeinst, sizeof (typeinst),
392                                                 "bdbentrycache-%s", nc_data.bv_val);
393                                         ldap_submit_gauge ("cache_size", typeinst,
394                                                 atoll (olmbdb_data.bv_val), st);
395                                         ldap_value_free_len (olmbdb_list);
396                                 }
397
398                                 if ((olmbdb_list = ldap_get_values_len (st->ld, e,
399                                         "olmBDBDNCache")) != NULL)
400                                 {
401                                         olmbdb_data = *olmbdb_list[0];
402                                         ssnprintf (typeinst, sizeof (typeinst),
403                                                 "bdbdncache-%s", nc_data.bv_val);
404                                         ldap_submit_gauge ("cache_size", typeinst,
405                                                 atoll (olmbdb_data.bv_val), st);
406                                         ldap_value_free_len (olmbdb_list);
407                                 }
408
409                                 if ((olmbdb_list = ldap_get_values_len (st->ld, e,
410                                         "olmBDBIDLCache")) != NULL)
411                                 {
412                                         olmbdb_data = *olmbdb_list[0];
413                                         ssnprintf (typeinst, sizeof (typeinst),
414                                                 "bdbidlcache-%s", nc_data.bv_val);
415                                         ldap_submit_gauge ("cache_size", typeinst,
416                                                 atoll (olmbdb_data.bv_val), st);
417                                         ldap_value_free_len (olmbdb_list);
418                                 }
419
420                                 ldap_value_free_len (nc_list);
421                         }
422                         else if (strcmp (dn,
423                                         "cn=Bytes,cn=Statistics,cn=Monitor")
424                                         == 0)
425                         {
426                                 ldap_submit_derive ("derive", "statistics-bytes",
427                                         counter, st);
428                         }
429                         else if (strcmp (dn,
430                                         "cn=PDU,cn=Statistics,cn=Monitor")
431                                         == 0)
432                         {
433                                 ldap_submit_derive ("derive", "statistics-pdu",
434                                         counter, st);
435                         }
436                         else if (strcmp (dn,
437                                         "cn=Entries,cn=Statistics,cn=Monitor")
438                                         == 0)
439                         {
440                                 ldap_submit_derive ("derive", "statistics-entries",
441                                         counter, st);
442                         }
443                         else if (strcmp (dn,
444                                         "cn=Referrals,cn=Statistics,cn=Monitor")
445                                         == 0)
446                         {
447                                 ldap_submit_derive ("derive", "statistics-referrals",
448                                         counter, st);
449                         }
450                         else if (strcmp (dn,
451                                         "cn=Open,cn=Threads,cn=Monitor")
452                                         == 0)
453                         {
454                                 ldap_submit_gauge ("threads", "threads-open",
455                                         info, st);
456                         }
457                         else if (strcmp (dn,
458                                         "cn=Starting,cn=Threads,cn=Monitor")
459                                         == 0)
460                         {
461                                 ldap_submit_gauge ("threads", "threads-starting",
462                                         info, st);
463                         }
464                         else if (strcmp (dn,
465                                         "cn=Active,cn=Threads,cn=Monitor")
466                                         == 0)
467                         {
468                                 ldap_submit_gauge ("threads", "threads-active",
469                                         info, st);
470                         }
471                         else if (strcmp (dn,
472                                         "cn=Pending,cn=Threads,cn=Monitor")
473                                         == 0)
474                         {
475                                 ldap_submit_gauge ("threads", "threads-pending",
476                                         info, st);
477                         }
478                         else if (strcmp (dn,
479                                         "cn=Backload,cn=Threads,cn=Monitor")
480                                         == 0)
481                         {
482                                 ldap_submit_gauge ("threads", "threads-backload",
483                                         info, st);
484                         }
485                         else if (strcmp (dn,
486                                         "cn=Read,cn=Waiters,cn=Monitor")
487                                         == 0)
488                         {
489                                 ldap_submit_derive ("derive", "waiters-read",
490                                         counter, st);
491                         }
492                         else if (strcmp (dn,
493                                         "cn=Write,cn=Waiters,cn=Monitor")
494                                         == 0)
495                         {
496                                 ldap_submit_derive ("derive", "waiters-write",
497                                         counter, st);
498                         }
499
500                         ldap_value_free_len (counter_list);
501                         ldap_value_free_len (opc_list);
502                         ldap_value_free_len (opi_list);
503                         ldap_value_free_len (info_list);
504                 }
505
506                 ldap_memfree (dn);
507         }
508
509         ldap_msgfree (result);
510         ldap_unbind_ext_s (st->ld, NULL, NULL);
511         return (0);
512 } /* }}} int ldap_read_host */
513
514 /* Configuration handling functions {{{
515  *
516  * <Plugin ldap>
517  *   <Instance "plugin_instance1">
518  *     URL "ldap://localhost"
519  *     ...
520  *   </Instance>
521  * </Plugin>
522  */
523
524 static int ldap_config_set_string (char **ret_string, /* {{{ */
525                                     oconfig_item_t *ci)
526 {
527         char *string;
528
529         if ((ci->values_num != 1)
530             || (ci->values[0].type != OCONFIG_TYPE_STRING))
531         {
532                 WARNING ("openldap plugin: The `%s' config option "
533                          "needs exactly one string argument.", ci->key);
534                 return (-1);
535         }
536
537         string = strdup (ci->values[0].value.string);
538         if (string == NULL)
539         {
540                 ERROR ("openldap plugin: strdup failed.");
541                 return (-1);
542         }
543
544         if (*ret_string != NULL)
545                 free (*ret_string);
546         *ret_string = string;
547
548         return (0);
549 } /* }}} int ldap_config_set_string */
550
551 static int ldap_config_set_int (int *ret_int, /* {{{ */
552                                  oconfig_item_t *ci)
553 {
554         if ((ci->values_num != 1)
555             || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
556         {
557                 WARNING ("openldap plugin: The `%s' config option "
558                          "needs exactly one string argument.", ci->key);
559                 return (-1);
560         }
561
562         *ret_int = ci->values[0].value.number;
563
564         return (0);
565 } /* }}} int ldap_config_set_int */
566
567 static int ldap_config_set_bool (int *ret_boolean, /* {{{ */
568                                 oconfig_item_t *ci)
569 {
570         int status = 0;
571
572         if (ci->values_num != 1)
573                 status = -1;
574
575         if (status == 0)
576         {
577                 if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
578                         *ret_boolean = ci->values[0].value.boolean;
579                 else if (ci->values[0].type == OCONFIG_TYPE_STRING)
580                 {
581                         if (IS_TRUE (ci->values[0].value.string))
582                                 *ret_boolean = 1;
583                         else if (IS_FALSE (ci->values[0].value.string))
584                                 *ret_boolean = 0;
585                         else
586                                 status = -1;
587                 }
588                 else
589                         status = -1;
590         }
591
592         if (status != 0)
593         {
594                 WARNING ("openldap plugin: The `%s' config option "
595                         "needs exactly one boolean argument.", ci->key);
596                 return (-1);
597         }
598         return (0);
599 } /* }}} int ldap_config_set_bool */
600
601 static int ldap_config_add (oconfig_item_t *ci) /* {{{ */
602 {
603         ldap_t *st;
604         int i;
605         int status;
606
607         if ((ci->values_num != 1)
608             || (ci->values[0].type != OCONFIG_TYPE_STRING))
609         {
610                 WARNING ("openldap plugin: The `%s' config option "
611                          "needs exactly one string argument.", ci->key);
612                 return (-1);
613         }
614
615         st = (ldap_t *) malloc (sizeof (*st));
616         if (st == NULL)
617         {
618                 ERROR ("openldap plugin: malloc failed.");
619                 return (-1);
620         }
621         memset (st, 0, sizeof (*st));
622
623         status = ldap_config_set_string (&st->name, ci);
624         if (status != 0)
625         {
626                 sfree (st);
627                 return (status);
628         }
629
630         st->starttls = 0;
631         st->timeout = -1;
632         st->verifyhost = 1;
633         st->version = LDAP_VERSION3;
634
635         for (i = 0; i < ci->children_num; i++)
636         {
637                 oconfig_item_t *child = ci->children + i;
638
639                 if (strcasecmp ("CACert", child->key) == 0)
640                         status = ldap_config_set_string (&st->cacert, child);
641                 else if (strcasecmp ("StartTLS", child->key) == 0)
642                         status = ldap_config_set_bool (&st->starttls, child);
643                 else if (strcasecmp ("Timeout", child->key) == 0)
644                         status = ldap_config_set_int (&st->timeout, child);
645                 else if (strcasecmp ("URL", child->key) == 0)
646                         status = ldap_config_set_string (&st->url, child);
647                 else if (strcasecmp ("VerifyHost", child->key) == 0)
648                         status = ldap_config_set_bool (&st->verifyhost, child);
649                 else if (strcasecmp ("Version", child->key) == 0)
650                         status = ldap_config_set_int (&st->version, child);
651                 else
652                 {
653                         WARNING ("openldap plugin: Option `%s' not allowed here.",
654                                         child->key);
655                         status = -1;
656                 }
657
658                 if (status != 0)
659                         break;
660         }
661
662         /* Check if struct is complete.. */
663         if ((status == 0) && (st->url == NULL))
664         {
665                 ERROR ("openldap plugin: Instance `%s': "
666                                 "No URL has been configured.",
667                                 st->name);
668                 status = -1;
669         }
670
671         /* Check if URL is valid */
672         if ((status == 0) && (st->url != NULL))
673         {
674                 LDAPURLDesc *ludpp;
675                 int rc;
676
677                 if ((rc = ldap_url_parse (st->url, &ludpp)) != 0)
678                 {
679                         ERROR ("openldap plugin: Instance `%s': "
680                                 "Invalid URL: `%s'",
681                                 st->name, st->url);
682                         status = -1;
683                 }
684                 else
685                 {
686                         st->host = strdup (ludpp->lud_host);
687                 }
688
689                 ldap_free_urldesc (ludpp);
690         }
691
692         if (status == 0)
693         {
694                 user_data_t ud;
695                 char callback_name[3*DATA_MAX_NAME_LEN];
696
697                 memset (&ud, 0, sizeof (ud));
698                 ud.data = st;
699
700                 memset (callback_name, 0, sizeof (callback_name));
701                 ssnprintf (callback_name, sizeof (callback_name),
702                                 "openldap/%s/%s",
703                                 (st->host != NULL) ? st->host : hostname_g,
704                                 (st->name != NULL) ? st->name : "default"),
705
706                 status = plugin_register_complex_read (/* group = */ NULL,
707                                 /* name      = */ callback_name,
708                                 /* callback  = */ ldap_read_host,
709                                 /* interval  = */ NULL,
710                                 /* user_data = */ &ud);
711         }
712
713         if (status != 0)
714         {
715                 ldap_free (st);
716                 return (-1);
717         }
718
719         return (0);
720 } /* }}} int ldap_config_add */
721
722 static int ldap_config (oconfig_item_t *ci) /* {{{ */
723 {
724         int i;
725         int status = 0;
726
727         for (i = 0; i < ci->children_num; i++)
728         {
729                 oconfig_item_t *child = ci->children + i;
730
731                 if (strcasecmp ("Instance", child->key) == 0)
732                         ldap_config_add (child);
733                 else
734                         WARNING ("openldap plugin: The configuration option "
735                                         "\"%s\" is not allowed here. Did you "
736                                         "forget to add an <Instance /> block "
737                                         "around the configuration?",
738                                         child->key);
739         } /* for (ci->children) */
740
741         return (status);
742 } /* }}} int ldap_config */
743
744 /* }}} End of configuration handling functions */
745
746 static int ldap_init (void) /* {{{ */
747 {
748         /* Initialize LDAP library while still single-threaded as recommended in
749          * ldap_initialize(3) */
750         int debug_level;
751         ldap_get_option (NULL, LDAP_OPT_DEBUG_LEVEL, &debug_level);
752         return (0);
753 } /* }}} int ldap_init */
754
755 void module_register (void) /* {{{ */
756 {
757         plugin_register_complex_config ("openldap", ldap_config);
758         plugin_register_init ("openldap", ldap_init);
759 } /* }}} void module_register */