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