]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/monitor.c
a204a6c25fb5223ad064d3721eabcb02fdfdf3a2
[openldap] / servers / slapd / back-ldap / monitor.c
1 /* monitor.c - monitor ldap backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2012 The OpenLDAP Foundation.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * Portions Copyright 2000-2003 Pierangelo Masarati.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by the Howard Chu for inclusion
20  * in OpenLDAP Software and subsequently enhanced by Pierangelo
21  * Masarati.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include <ac/string.h>
28 #include <ac/unistd.h>
29 #include <ac/stdlib.h>
30 #include <ac/errno.h>
31 #include <sys/stat.h>
32 #include "lutil.h"
33 #include "back-ldap.h"
34
35 #include "config.h"
36
37 static ObjectClass              *oc_olmLDAPDatabase;
38 static ObjectClass              *oc_olmLDAPConnection;
39
40 static AttributeDescription     *ad_olmDbURIList;
41 static AttributeDescription     *ad_olmDbOperations;
42 static AttributeDescription     *ad_olmDbBoundDN;
43
44 /*
45  * Stolen from back-monitor/operations.c
46  * We don't need the normalized rdn's though.
47  */
48 struct ldap_back_monitor_ops_t {
49         struct berval           rdn;
50 } ldap_back_monitor_op[] = {
51         { BER_BVC( "cn=Bind" ) },
52         { BER_BVC( "cn=Unbind" ) },
53         { BER_BVC( "cn=Search" ) },
54         { BER_BVC( "cn=Compare" ) },
55         { BER_BVC( "cn=Modify" ) },
56         { BER_BVC( "cn=Modrdn" ) },
57         { BER_BVC( "cn=Add" ) },
58         { BER_BVC( "cn=Delete" ) },
59         { BER_BVC( "cn=Abandon" ) },
60         { BER_BVC( "cn=Extended" ) },
61
62         { BER_BVNULL }
63 };
64
65
66 /*
67  * NOTE: there's some confusion in monitor OID arc;
68  * by now, let's consider:
69  * 
70  * Subsystems monitor attributes        1.3.6.1.4.1.4203.666.1.55.0
71  * Databases monitor attributes         1.3.6.1.4.1.4203.666.1.55.0.1
72  * LDAP database monitor attributes     1.3.6.1.4.1.4203.666.1.55.0.1.2
73  *
74  * Subsystems monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0
75  * Databases monitor objectclasses      1.3.6.1.4.1.4203.666.3.16.0.1
76  * LDAP database monitor objectclasses  1.3.6.1.4.1.4203.666.3.16.0.1.2
77  */
78
79 static struct {
80         char                    *name;
81         char                    *oid;
82 }               s_oid[] = {
83         { "olmLDAPAttributes",                  "olmDatabaseAttributes:2" },
84         { "olmLDAPObjectClasses",               "olmDatabaseObjectClasses:2" },
85
86         { NULL }
87 };
88
89 static struct {
90         char                    *desc;
91         AttributeDescription    **ad;
92 }               s_at[] = {
93         { "( olmLDAPAttributes:1 "
94                 "NAME ( 'olmDbURIList' ) "
95                 "DESC 'List of URIs a proxy is serving; can be modified run-time' "
96                 "SUP managedInfo )",
97                 &ad_olmDbURIList },
98         { "( olmLDAPAttributes:2 "
99                 "NAME ( 'olmDbOperation' ) "
100                 "DESC 'monitor operations performed' "
101                 "SUP monitorCounter "
102                 "NO-USER-MODIFICATION "
103                 "USAGE dSAOperation )",
104                 &ad_olmDbOperations },
105         { "( olmLDAPAttributes:3 "
106                 "NAME ( 'olmDbBoundDN' ) "
107                 "DESC 'monitor connection authorization DN' "
108                 "SUP monitorConnectionAuthzDN "
109                 "NO-USER-MODIFICATION "
110                 "USAGE dSAOperation )",
111                 &ad_olmDbBoundDN },
112
113         { NULL }
114 };
115
116 static struct {
117         char            *desc;
118         ObjectClass     **oc;
119 }               s_oc[] = {
120         /* augments an existing object, so it must be AUXILIARY
121          * FIXME: derive from some ABSTRACT "monitoredEntity"? */
122         { "( olmLDAPObjectClasses:1 "
123                 "NAME ( 'olmLDAPDatabase' ) "
124                 "SUP top AUXILIARY "
125                 "MAY ( "
126                         "olmDbURIList "
127                         ") )",
128                 &oc_olmLDAPDatabase },
129         { "( olmLDAPObjectClasses:2 "
130                 "NAME ( 'olmLDAPConnection' ) "
131                 "SUP monitorConnection STRUCTURAL "
132                 "MAY ( "
133                         "olmDbBoundDN "
134                         ") )",
135                 &oc_olmLDAPConnection },
136
137         { NULL }
138 };
139
140 static int
141 ldap_back_monitor_update(
142         Operation       *op,
143         SlapReply       *rs,
144         Entry           *e,
145         void            *priv )
146 {
147         ldapinfo_t              *li = (ldapinfo_t *)priv;
148
149         Attribute               *a;
150
151         /* update olmDbURIList */
152         a = attr_find( e->e_attrs, ad_olmDbURIList );
153         if ( a != NULL ) {
154                 struct berval   bv;
155
156                 assert( a->a_vals != NULL );
157                 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) );
158                 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) );
159
160                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
161                 if ( li->li_uri ) {
162                         ber_str2bv( li->li_uri, 0, 0, &bv );
163                         if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) {
164                                 ber_bvreplace( &a->a_vals[ 0 ], &bv );
165                         }
166                 }
167                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
168         }
169
170         return SLAP_CB_CONTINUE;
171 }
172
173 static int
174 ldap_back_monitor_modify(
175         Operation       *op,
176         SlapReply       *rs,
177         Entry           *e,
178         void            *priv )
179 {
180         ldapinfo_t              *li = (ldapinfo_t *) priv;
181         
182         Attribute               *save_attrs = NULL;
183         Modifications           *ml,
184                                 *ml_olmDbURIList = NULL;
185         struct berval           ul = BER_BVNULL;
186         int                     got = 0;
187
188         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
189                 if ( ml->sml_desc == ad_olmDbURIList ) {
190                         if ( ml_olmDbURIList != NULL ) {
191                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
192                                 rs->sr_text = "conflicting modifications";
193                                 goto done;
194                         }
195
196                         if ( ml->sml_op != LDAP_MOD_REPLACE ) {
197                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
198                                 rs->sr_text = "modification not allowed";
199                                 goto done;
200                         }
201
202                         ml_olmDbURIList = ml;
203                         got++;
204                         continue;
205                 }
206         }
207
208         if ( got == 0 ) {
209                 return SLAP_CB_CONTINUE;
210         }
211
212         save_attrs = attrs_dup( e->e_attrs );
213
214         if ( ml_olmDbURIList != NULL ) {
215                 Attribute       *a = NULL;
216                 LDAPURLDesc     *ludlist = NULL;
217                 int             rc;
218
219                 ml = ml_olmDbURIList;
220                 assert( ml->sml_nvalues != NULL );
221
222                 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
223                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
224                         rs->sr_text = "no value provided";
225                         goto done;
226                 }
227
228                 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
229                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
230                         rs->sr_text = "multiple values provided";
231                         goto done;
232                 }
233
234                 rc = ldap_url_parselist_ext( &ludlist,
235                         ml->sml_nvalues[ 0 ].bv_val, NULL,
236                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
237                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
238                 if ( rc != LDAP_URL_SUCCESS ) {
239                         rs->sr_err = LDAP_INVALID_SYNTAX;
240                         rs->sr_text = "unable to parse URI list";
241                         goto done;
242                 }
243
244                 ul.bv_val = ldap_url_list2urls( ludlist );
245                 ldap_free_urllist( ludlist );
246                 if ( ul.bv_val == NULL ) {
247                         rs->sr_err = LDAP_OTHER;
248                         goto done;
249                 }
250                 ul.bv_len = strlen( ul.bv_val );
251                 
252                 a = attr_find( e->e_attrs, ad_olmDbURIList );
253                 if ( a != NULL ) {
254                         if ( a->a_nvals == a->a_vals ) {
255                                 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
256                         }
257
258                         ber_bvreplace( &a->a_vals[ 0 ], &ul );
259                         ber_bvreplace( &a->a_nvals[ 0 ], &ul );
260
261                 } else {
262                         attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
263                 }
264         }
265
266         /* apply changes */
267         if ( !BER_BVISNULL( &ul ) ) {
268                 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
269                 if ( li->li_uri ) {
270                         ch_free( li->li_uri );
271                 }
272                 li->li_uri = ul.bv_val;
273                 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
274
275                 BER_BVZERO( &ul );
276         }
277
278 done:;
279         if ( !BER_BVISNULL( &ul ) ) {
280                 ldap_memfree( ul.bv_val );
281         }
282
283         if ( rs->sr_err == LDAP_SUCCESS ) {
284                 attrs_free( save_attrs );
285                 return SLAP_CB_CONTINUE;
286         }
287
288         attrs_free( e->e_attrs );
289         e->e_attrs = save_attrs;
290
291         return rs->sr_err;
292 }
293
294 static int
295 ldap_back_monitor_free(
296         Entry           *e,
297         void            **priv )
298 {
299         ldapinfo_t              *li = (ldapinfo_t *)(*priv);
300
301         *priv = NULL;
302
303         if ( !slapd_shutdown ) {
304                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
305         }
306
307         return SLAP_CB_CONTINUE;
308 }
309
310 static int
311 ldap_back_monitor_subsystem_destroy(
312         BackendDB               *be,
313         monitor_subsys_t        *ms)
314 {
315         free(ms->mss_dn.bv_val);
316         BER_BVZERO(&ms->mss_dn);
317
318         free(ms->mss_ndn.bv_val);
319         BER_BVZERO(&ms->mss_ndn);
320
321         return LDAP_SUCCESS;
322 }
323
324 /*
325  * Connection monitoring subsystem:
326  * Tries to mimick what the cn=connections,cn=monitor subsystem does
327  * by creating volatile entries for each connection and populating them
328  * according to the information attached to the connection.
329  * At this moment the only exposed information is the DN used to bind it.
330  * Also note that the connection IDs are not and probably never will be
331  * stable.
332  */
333
334 struct ldap_back_monitor_conn_arg {
335         monitor_subsys_t *ms;
336         Entry **ep;
337 };
338
339 static int
340 ldap_back_monitor_conn_entry(
341         ldapconn_t *lc,
342         struct ldap_back_monitor_conn_arg *arg )
343 {
344         Entry *e;
345         monitor_entry_t         *mp;
346         char buf[SLAP_TEXT_BUFLEN];
347         struct berval bv, dn, ndn;
348
349         e = entry_alloc();
350
351         bv.bv_val = buf;
352         bv.bv_len = snprintf( bv.bv_val, SLAP_TEXT_BUFLEN,
353                 "cn=Connection %lu", lc->lc_connid );
354
355         build_new_dn( &dn, &arg->ms->mss_dn, &bv, NULL );
356         build_new_dn( &ndn, &arg->ms->mss_ndn, &bv, NULL );
357
358         e->e_name = dn;
359         e->e_nname = ndn;
360
361         bv.bv_val += 3;
362         bv.bv_len -= 3;
363         attr_merge_normalize_one( e, slap_schema.si_ad_cn, &bv, NULL );
364
365         BER_BVSTR( &bv, "monitorContainer" );
366         attr_merge_normalize_one( e, slap_schema.si_ad_objectClass, &bv, NULL );
367
368         attr_merge_normalize_one( e, ad_olmDbBoundDN, &lc->lc_bound_ndn, NULL );
369
370         mp = monitor_entrypriv_create();
371         e->e_private = mp;
372         mp->mp_info = arg->ms;
373         mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE;
374
375         *arg->ep = e;
376         arg->ep = &mp->mp_next;
377
378         return 0;
379 }
380
381 static int
382 ldap_back_monitor_conn_create(
383         Operation       *op,
384         SlapReply       *rs,
385         struct berval   *ndn,
386         Entry           *e_parent,
387         Entry           **ep )
388 {
389         monitor_entry_t         *mp_parent;
390         monitor_subsys_t        *ms;
391         ldapinfo_t              *li;
392         ldapconn_t              *lc;
393
394         struct ldap_back_monitor_conn_arg *arg;
395         int conn_type;
396
397         assert( e_parent->e_private != NULL );
398
399         mp_parent = e_parent->e_private;
400         ms = (monitor_subsys_t *)mp_parent->mp_info;
401         li = (ldapinfo_t *)ms->mss_private;
402
403         arg = ch_calloc( 1, sizeof(struct ldap_back_monitor_conn_arg) );
404         arg->ep = ep;
405         arg->ms = ms;
406
407         for ( conn_type = LDAP_BACK_PCONN_FIRST;
408                 conn_type < LDAP_BACK_PCONN_LAST;
409                 conn_type++ )
410         {
411                 LDAP_TAILQ_FOREACH( lc,
412                         &li->li_conn_priv[ conn_type ].lic_priv,
413                         lc_q )
414                 {
415                         ldap_back_monitor_conn_entry( lc, arg );
416                 }
417         }
418
419         avl_apply( li->li_conninfo.lai_tree, ldap_back_monitor_conn_entry,
420                 arg, -1, AVL_INORDER );
421
422         ch_free( arg );
423
424         return 0;
425 }
426
427 static int
428 ldap_back_monitor_conn_init(
429         BackendDB               *be,
430         monitor_subsys_t        *ms )
431 {
432         ldapinfo_t      *li = (ldapinfo_t *) ms->mss_private;
433         monitor_info_t  *mi;
434         monitor_extra_t *mbe;
435
436         Entry           *e;
437         int             rc;
438
439         assert( be != NULL );
440         mi = (monitor_info_t *) be->be_private;
441         mbe = (monitor_extra_t *) be->bd_info->bi_extra;
442
443         ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn;
444         ms->mss_rdn = li->li_monitor_info.lmi_conn_rdn;
445         ms->mss_create = ldap_back_monitor_conn_create;
446         ms->mss_destroy = ldap_back_monitor_subsystem_destroy;
447
448         e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn,
449                 &ms->mss_rdn,
450                 mi->mi_oc_monitorContainer, mi, NULL, NULL );
451         if ( e == NULL ) {
452                 Debug( LDAP_DEBUG_ANY,
453                         "ldap_back_monitor_conn_init: "
454                         "unable to create entry \"%s,%s\"\n",
455                         li->li_monitor_info.lmi_conn_rdn.bv_val,
456                         ms->mss_ndn.bv_val, 0 );
457                 return( -1 );
458         }
459
460         ber_dupbv( &ms->mss_dn, &e->e_name );
461         ber_dupbv( &ms->mss_ndn, &e->e_nname );
462
463         rc = mbe->register_entry( e, NULL, ms, MONITOR_F_VOLATILE_CH );
464
465         /* add labeledURI and special, modifiable URI value */
466         if ( rc == LDAP_SUCCESS && li->li_uri != NULL ) {
467                 struct berval           bv;
468                 Attribute               *a;
469                 LDAPURLDesc             *ludlist = NULL;
470                 monitor_callback_t      *cb = NULL;
471
472                 a = attr_alloc( ad_olmDbURIList );
473
474                 ber_str2bv( li->li_uri, 0, 0, &bv );
475                 attr_valadd( a, &bv, NULL, 1 );
476                 attr_normalize( a->a_desc, a->a_vals, &a->a_nvals, NULL );
477
478                 rc = ldap_url_parselist_ext( &ludlist,
479                         li->li_uri, NULL,
480                         LDAP_PVT_URL_PARSE_NOEMPTY_HOST
481                                 | LDAP_PVT_URL_PARSE_DEF_PORT );
482                 if ( rc != LDAP_URL_SUCCESS ) {
483                         Debug( LDAP_DEBUG_ANY,
484                                 "ldap_back_monitor_db_open: "
485                                 "unable to parse URI list (ignored)\n",
486                                 0, 0, 0 );
487                 } else {
488                         Attribute *a2 = attr_alloc( slap_schema.si_ad_labeledURI );
489
490                         a->a_next = a2;
491
492                         for ( ; ludlist != NULL; ) {
493                                 LDAPURLDesc     *next = ludlist->lud_next;
494
495                                 bv.bv_val = ldap_url_desc2str( ludlist );
496                                 assert( bv.bv_val != NULL );
497                                 ldap_free_urldesc( ludlist );
498                                 bv.bv_len = strlen( bv.bv_val );
499                                 attr_valadd( a2, &bv, NULL, 1 );
500                                 ch_free( bv.bv_val );
501
502                                 ludlist = next;
503                         }
504
505                         attr_normalize( a2->a_desc, a2->a_vals, &a2->a_nvals, NULL );
506                 }
507
508                 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
509                 cb->mc_update = ldap_back_monitor_update;
510                 cb->mc_modify = ldap_back_monitor_modify;
511                 cb->mc_free = ldap_back_monitor_free;
512                 cb->mc_private = (void *)li;
513
514                 rc = mbe->register_entry_attrs( &ms->mss_ndn, a, cb, NULL, 0, NULL );
515
516                 attr_free( a->a_next );
517                 attr_free( a );
518
519                 if ( rc != LDAP_SUCCESS )
520                 {
521                         ch_free( cb );
522                 }
523         }
524
525         entry_free( e );
526
527         return rc;
528 }
529
530 /*
531  * Operation monitoring subsystem:
532  * Looks a lot like the cn=operations,cn=monitor subsystem except that at this
533  * moment, only completed operations are counted. Each entry has a separate
534  * callback with all the needed information linked there in the structure
535  * below so that the callback need not locate it over and over again.
536  */
537
538 struct ldap_back_monitor_op_counter {
539         ldap_pvt_mp_t           *data;
540         ldap_pvt_thread_mutex_t *mutex;
541 };
542
543 static void
544 ldap_back_monitor_ops_dispose(
545         void    **priv)
546 {
547         struct ldap_back_monitor_op_counter *counter = *priv;
548
549         ch_free( counter );
550         counter = NULL;
551 }
552
553 static int
554 ldap_back_monitor_ops_free(
555         Entry *e,
556         void **priv)
557 {
558         ldap_back_monitor_ops_dispose( priv );
559         return LDAP_SUCCESS;
560 }
561
562 static int
563 ldap_back_monitor_ops_update(
564         Operation       *op,
565         SlapReply       *rs,
566         Entry           *e,
567         void            *priv )
568 {
569         struct ldap_back_monitor_op_counter *counter = priv;
570         Attribute *a;
571
572         /*TODO
573          * what about initiated/completed?
574          */
575         a = attr_find( e->e_attrs, ad_olmDbOperations );
576         assert( a != NULL );
577
578         ldap_pvt_thread_mutex_lock( counter->mutex );
579         UI2BV( &a->a_vals[ 0 ], *counter->data );
580         ldap_pvt_thread_mutex_unlock( counter->mutex );
581
582         return SLAP_CB_CONTINUE;
583 }
584
585 static int
586 ldap_back_monitor_ops_init(
587         BackendDB               *be,
588         monitor_subsys_t        *ms )
589 {
590         ldapinfo_t      *li = (ldapinfo_t *) ms->mss_private;
591
592         monitor_info_t  *mi;
593         monitor_extra_t *mbe;
594         Entry           *e, *parent;
595         int             rc;
596         slap_op_t       op;
597         struct berval   value = BER_BVC( "0" );
598
599         assert( be != NULL );
600
601         mi = (monitor_info_t *) be->be_private;
602         mbe = (monitor_extra_t *) be->bd_info->bi_extra;
603
604         ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn;
605         ms->mss_rdn = li->li_monitor_info.lmi_ops_rdn;
606         ms->mss_destroy = ldap_back_monitor_subsystem_destroy;
607
608         parent = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn,
609                 &ms->mss_rdn,
610                 mi->mi_oc_monitorContainer, mi, NULL, NULL );
611         if ( parent == NULL ) {
612                 Debug( LDAP_DEBUG_ANY,
613                         "ldap_back_monitor_ops_init: "
614                         "unable to create entry \"%s,%s\"\n",
615                         li->li_monitor_info.lmi_ops_rdn.bv_val,
616                         ms->mss_ndn.bv_val, 0 );
617                 return( -1 );
618         }
619
620         ber_dupbv( &ms->mss_dn, &parent->e_name );
621         ber_dupbv( &ms->mss_ndn, &parent->e_nname );
622
623         rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH );
624         if ( rc != LDAP_SUCCESS )
625         {
626                 Debug( LDAP_DEBUG_ANY,
627                         "ldap_back_monitor_ops_init: "
628                         "unable to register entry \"%s\" for monitoring\n",
629                         parent->e_name.bv_val, 0, 0 );
630                 goto done;
631         }
632
633         for ( op = 0; op < SLAP_OP_LAST; op++ )
634         {
635                 monitor_callback_t *cb;
636                 struct ldap_back_monitor_op_counter *counter;
637
638                 e = monitor_entry_stub( &parent->e_name, &parent->e_nname,
639                         &ldap_back_monitor_op[op].rdn,
640                         mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
641                 if ( e == NULL ) {
642                         Debug( LDAP_DEBUG_ANY,
643                                 "ldap_back_monitor_ops_init: "
644                                 "unable to create entry \"%s,%s\"\n",
645                                 ldap_back_monitor_op[op].rdn.bv_val,
646                                 parent->e_nname.bv_val, 0 );
647                         return( -1 );
648                 }
649
650                 attr_merge_normalize_one( e, ad_olmDbOperations, &value, NULL );
651
652                 counter = ch_malloc( sizeof( struct ldap_back_monitor_op_counter ) );
653                 counter->data = &li->li_ops_completed[ op ];
654                 counter->mutex = &li->li_counter_mutex;
655
656                 /*
657                  * We cannot share a single callback between entries.
658                  *
659                  * monitor_cache_destroy() tries to free all callbacks and it's called
660                  * before mss_destroy() so we have no chance of handling it ourselves
661                  */
662                 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
663                 cb->mc_update = ldap_back_monitor_ops_update;
664                 cb->mc_free = ldap_back_monitor_ops_free;
665                 cb->mc_dispose = ldap_back_monitor_ops_dispose;
666                 cb->mc_private = (void *)counter;
667
668                 rc = mbe->register_entry( e, cb, ms, 0 );
669
670                 /* TODO: register_entry has stored a duplicate so we might actually reuse it
671                  * instead of recreating it every time... */
672                 entry_free( e );
673
674                 if ( rc != LDAP_SUCCESS )
675                 {
676                         Debug( LDAP_DEBUG_ANY,
677                                 "ldap_back_monitor_ops_init: "
678                                 "unable to register entry \"%s\" for monitoring\n",
679                                 e->e_name.bv_val, 0, 0 );
680                         ch_free( cb );
681                         break;
682                 }
683         }
684
685 done:
686         entry_free( parent );
687
688         return rc;
689 }
690
691 /*
692  * call from within ldap_back_initialize()
693  */
694 static int
695 ldap_back_monitor_initialize( void )
696 {
697         int             i, code;
698         ConfigArgs c;
699         char    *argv[ 3 ];
700
701         static int      ldap_back_monitor_initialized = 0;
702
703         /* set to 0 when successfully initialized; otherwise, remember failure */
704         static int      ldap_back_monitor_initialized_failure = 1;
705
706         /* register schema here; if compiled as dynamic object,
707          * must be loaded __after__ back_monitor.la */
708
709         if ( ldap_back_monitor_initialized++ ) {
710                 return ldap_back_monitor_initialized_failure;
711         }
712
713         if ( backend_info( "monitor" ) == NULL ) {
714                 return -1;
715         }
716
717         argv[ 0 ] = "back-ldap monitor";
718         c.argv = argv;
719         c.argc = 3;
720         c.fname = argv[0];
721         for ( i = 0; s_oid[ i ].name; i++ ) {
722         
723                 argv[ 1 ] = s_oid[ i ].name;
724                 argv[ 2 ] = s_oid[ i ].oid;
725
726                 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
727                         Debug( LDAP_DEBUG_ANY,
728                                 "ldap_back_monitor_initialize: unable to add "
729                                 "objectIdentifier \"%s=%s\"\n",
730                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
731                         return 2;
732                 }
733         }
734
735         for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
736                 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
737                 if ( code != LDAP_SUCCESS ) {
738                         Debug( LDAP_DEBUG_ANY,
739                                 "ldap_back_monitor_initialize: register_at failed for attributeType (%s)\n",
740                                 s_at[ i ].desc, 0, 0 );
741                         return 3;
742
743                 } else {
744                         (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
745                 }
746         }
747
748         for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
749                 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
750                 if ( code != LDAP_SUCCESS ) {
751                         Debug( LDAP_DEBUG_ANY,
752                                 "ldap_back_monitor_initialize: register_oc failed for objectClass (%s)\n",
753                                 s_oc[ i ].desc, 0, 0 );
754                         return 4;
755
756                 } else {
757                         (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
758                 }
759         }
760
761         return ( ldap_back_monitor_initialized_failure = LDAP_SUCCESS );
762 }
763
764 /*
765  * call from within ldap_back_db_init()
766  */
767 int
768 ldap_back_monitor_db_init( BackendDB *be )
769 {
770         int     rc;
771
772         rc = ldap_back_monitor_initialize();
773         if ( rc != LDAP_SUCCESS ) {
774                 return rc;
775         }
776
777 #if 0   /* uncomment to turn monitoring on by default */
778         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
779 #endif
780
781         return 0;
782 }
783
784 /*
785  * call from within ldap_back_db_open()
786  */
787 int
788 ldap_back_monitor_db_open( BackendDB *be )
789 {
790         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
791         monitor_subsys_t        *mss = li->li_monitor_info.lmi_mss;
792         int                     rc = 0;
793         BackendInfo             *mi;
794         monitor_extra_t         *mbe;
795
796         if ( !SLAP_DBMONITORING( be ) ) {
797                 return 0;
798         }
799
800         /* check if monitor is configured and usable */
801         mi = backend_info( "monitor" );
802         if ( !mi || !mi->bi_extra ) {
803                 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
804                 return 0;
805         }
806         mbe = mi->bi_extra;
807
808         /* don't bother if monitor is not configured */
809         if ( !mbe->is_configured() ) {
810                 static int warning = 0;
811
812                 if ( warning++ == 0 ) {
813                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
814                                 "monitoring disabled; "
815                                 "configure monitor database to enable\n",
816                                 0, 0, 0 );
817                 }
818
819                 return 0;
820         }
821
822         /* caller (e.g. an overlay based on back-ldap) may want to use
823          * a different DN and RDNs... */
824         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
825                 rc = mbe->register_database( be, &li->li_monitor_info.lmi_ndn );
826                 if ( rc != 0 ) {
827                         Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
828                                 "failed to register the databse with back-monitor\n",
829                                 0, 0, 0 );
830                 }
831         }
832         if ( BER_BVISNULL( &li->li_monitor_info.lmi_conn_rdn ) ) {
833                 ber_str2bv( "cn=Connections", 0, 1,
834                         &li->li_monitor_info.lmi_conn_rdn );
835         }
836         if ( BER_BVISNULL( &li->li_monitor_info.lmi_ops_rdn ) ) {
837                 ber_str2bv( "cn=Operations", 0, 1,
838                         &li->li_monitor_info.lmi_ops_rdn );
839         }
840
841         /* set up the subsystems used to create the operation and
842          * volatile connection entries */
843
844         mss->mss_name = "back-ldap connections";
845         mss->mss_flags = MONITOR_F_VOLATILE_CH;
846         mss->mss_open = ldap_back_monitor_conn_init;
847         mss->mss_private = li;
848
849         if ( mbe->register_subsys( mss ) )
850         {
851                 Debug( LDAP_DEBUG_ANY,
852                         "ldap_back_monitor_db_open: "
853                         "failed to register connection subsystem", 0, 0, 0 );
854                 return -1;
855         }
856
857         mss++;
858
859         mss->mss_name = "back-ldap operations";
860         mss->mss_flags = MONITOR_F_PERSISTENT_CH;
861         mss->mss_open = ldap_back_monitor_ops_init;
862         mss->mss_private = li;
863
864         if ( mbe->register_subsys( mss ) )
865         {
866                 Debug( LDAP_DEBUG_ANY,
867                         "ldap_back_monitor_db_open: "
868                         "failed to register operation subsystem", 0, 0, 0 );
869                 return -1;
870         }
871
872         return rc;
873 }
874
875 /*
876  * call from within ldap_back_db_close()
877  */
878 int
879 ldap_back_monitor_db_close( BackendDB *be )
880 {
881         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
882
883         if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) {
884                 BackendInfo             *mi;
885                 monitor_extra_t         *mbe;
886
887                 /* check if monitor is configured and usable */
888                 mi = backend_info( "monitor" );
889                 if ( mi && mi->bi_extra ) {
890                         mbe = mi->bi_extra;
891
892                         /*TODO
893                          * Unregister all entries our subsystems have created.
894                          * Will only really be necessary when
895                          * SLAPD_CONFIG_DELETE is enabled.
896                          *
897                          * Might need a way to unregister subsystems instead.
898                          */
899                 }
900         }
901
902         return 0;
903 }
904
905 /*
906  * call from within ldap_back_db_destroy()
907  */
908 int
909 ldap_back_monitor_db_destroy( BackendDB *be )
910 {
911         ldapinfo_t              *li = (ldapinfo_t *) be->be_private;
912
913         if ( li ) {
914                 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
915         }
916
917         return 0;
918 }
919