]> git.sur5r.net Git - openldap/blob - servers/slapd/back-monitor/init.c
cleanup entity registration
[openldap] / servers / slapd / back-monitor / init.c
1 /* init.c - initialize monitor backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2001-2005 The OpenLDAP Foundation.
6  * Portions Copyright 2001-2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/string.h>
26
27 #include <lutil.h>
28 #include "slap.h"
29 #include "lber_pvt.h"
30 #include "back-monitor.h"
31
32 #undef INTEGRATE_CORE_SCHEMA
33
34 /*
35  * used by many functions to add description to entries
36  *
37  * WARNING: be_monitor may change as new databases are added,
38  * so it should not be used outside monitor_back_db_init()
39  * until monitor_back_db_open is called.
40  */
41 BackendDB *be_monitor = NULL;
42
43 static struct monitor_subsys_t  **monitor_subsys = NULL;
44 static int                      monitor_subsys_opened = 0;
45
46 /*
47  * subsystem data
48  *
49  * the known subsystems are added to the subsystems
50  * array at backend initialization; other subsystems
51  * may be added by calling monitor_back_register_subsys()
52  * before the database is opened (e.g. by other backends
53  * or by overlays or modules).
54  */
55 static struct monitor_subsys_t known_monitor_subsys[] = {
56         { 
57                 SLAPD_MONITOR_BACKEND_NAME, 
58                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
59                 MONITOR_F_PERSISTENT_CH,
60                 monitor_subsys_backend_init,
61                 NULL,   /* update */
62                 NULL,   /* create */
63                 NULL    /* modify */
64         }, { 
65                 SLAPD_MONITOR_CONN_NAME,
66                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
67                 MONITOR_F_VOLATILE_CH,
68                 monitor_subsys_conn_init,
69                 monitor_subsys_conn_update,
70                 monitor_subsys_conn_create,
71                 NULL    /* modify */
72         }, { 
73                 SLAPD_MONITOR_DATABASE_NAME,    
74                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
75                 MONITOR_F_PERSISTENT_CH,
76                 monitor_subsys_database_init,
77                 NULL,   /* update */
78                 NULL,   /* create */
79                 monitor_subsys_database_modify
80         }, { 
81                 SLAPD_MONITOR_LISTENER_NAME,    
82                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
83                 MONITOR_F_PERSISTENT_CH,
84                 monitor_subsys_listener_init,
85                 NULL,   /* update */
86                 NULL,   /* create */
87                 NULL    /* modify */
88         }, { 
89                 SLAPD_MONITOR_LOG_NAME,
90                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
91                 MONITOR_F_NONE,
92                 monitor_subsys_log_init,
93                 NULL,   /* update */
94                 NULL,   /* create */
95                 monitor_subsys_log_modify
96         }, { 
97                 SLAPD_MONITOR_OPS_NAME,
98                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
99                 MONITOR_F_PERSISTENT_CH,
100                 monitor_subsys_ops_init,
101                 monitor_subsys_ops_update,
102                 NULL,   /* create */
103                 NULL,   /* modify */
104         }, { 
105                 SLAPD_MONITOR_OVERLAY_NAME,
106                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
107                 MONITOR_F_PERSISTENT_CH,
108                 monitor_subsys_overlay_init,
109                 NULL,   /* update */
110                 NULL,   /* create */
111                 NULL,   /* modify */
112         }, { 
113                 SLAPD_MONITOR_SASL_NAME,        
114                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
115                 MONITOR_F_NONE,
116                 NULL,   /* init */
117                 NULL,   /* update */
118                 NULL,   /* create */
119                 NULL    /* modify */
120         }, { 
121                 SLAPD_MONITOR_SENT_NAME,
122                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
123                 MONITOR_F_PERSISTENT_CH,
124                 monitor_subsys_sent_init,
125                 monitor_subsys_sent_update,
126                 NULL,   /* create */
127                 NULL,   /* modify */
128         }, { 
129                 SLAPD_MONITOR_THREAD_NAME,      
130                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
131                 MONITOR_F_PERSISTENT_CH,
132                 monitor_subsys_thread_init,
133                 monitor_subsys_thread_update,
134                 NULL,   /* create */
135                 NULL    /* modify */
136         }, { 
137                 SLAPD_MONITOR_TIME_NAME,
138                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
139                 MONITOR_F_PERSISTENT_CH,
140                 monitor_subsys_time_init,
141                 monitor_subsys_time_update,
142                 NULL,   /* create */
143                 NULL,   /* modify */
144         }, { 
145                 SLAPD_MONITOR_TLS_NAME,
146                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
147                 MONITOR_F_NONE,
148                 NULL,   /* init */
149                 NULL,   /* update */
150                 NULL,   /* create */
151                 NULL    /* modify */
152         }, { 
153                 SLAPD_MONITOR_RWW_NAME,
154                 BER_BVNULL, BER_BVNULL, BER_BVNULL,
155                 MONITOR_F_PERSISTENT_CH,
156                 monitor_subsys_rww_init,
157                 monitor_subsys_rww_update,
158                 NULL,   /* create */
159                 NULL    /* modify */
160         }, { NULL }
161 };
162
163 int
164 monitor_back_register_subsys( monitor_subsys_t *ms )
165 {
166         int     i = 0;
167
168         if ( monitor_subsys ) {
169                 for ( ; monitor_subsys[ i ] != NULL; i++ )
170                         /* just count'em */ ;
171         }
172
173         monitor_subsys = ch_realloc( monitor_subsys,
174                         ( 2 + i ) * sizeof( monitor_subsys_t * ) );
175
176         if ( monitor_subsys == NULL ) {
177                 return -1;
178         }
179
180         monitor_subsys[ i ] = ms;
181         monitor_subsys[ i + 1 ] = NULL;
182
183         /* if a subsystem is registered __AFTER__ subsystem 
184          * initialization (depending on the sequence the databases
185          * are listed in slapd.conf), init it */
186         if ( monitor_subsys_opened ) {
187
188                 /* FIXME: this should only be possible
189                  * if be_monitor is already initialized */
190                 assert( be_monitor );
191
192                 if ( ms->mss_open && ( *ms->mss_open )( be_monitor, ms ) ) {
193                         return -1;
194                 }
195
196                 ms->mss_flags |= MONITOR_F_OPENED;
197         }
198
199         return 0;
200 }
201
202 enum {
203         LIMBO_ENTRY,
204         LIMBO_ENTRY_PARENT,
205         LIMBO_ATTRS,
206         LIMBO_CB
207 };
208
209 typedef struct entry_limbo_t {
210         int                     el_type;
211         Entry                   *el_e;
212         Attribute               *el_a;
213         struct berval           el_ndn;
214         struct berval           el_base;
215         int                     el_scope;
216         struct berval           el_filter;
217         monitor_callback_t      *el_cb;
218         struct entry_limbo_t    *el_next;
219 } entry_limbo_t;
220
221 int
222 monitor_back_register_entry(
223                 Entry                   *e,
224                 monitor_callback_t      *cb )
225 {
226         monitor_info_t  *mi = ( monitor_info_t * )be_monitor->be_private;
227
228         assert( mi != NULL );
229         assert( e != NULL );
230         assert( e->e_private == NULL );
231         
232         if ( monitor_subsys_opened ) {
233                 Entry           *e_parent = NULL,
234                                 *e_new = NULL,
235                                 **ep = NULL;
236                 struct berval   pdn = BER_BVNULL;
237                 monitor_entry_t *mp = NULL,
238                                 *mp_parent = NULL;
239                 int             rc = 0;
240
241                 if ( monitor_cache_get( mi, &e->e_nname, &e_parent ) == 0 ) {
242                         /* entry exists */
243                         Debug( LDAP_DEBUG_ANY,
244                                 "monitor_back_register_entry(\"%s\"): "
245                                 "entry exists\n",
246                                 e->e_name.bv_val, 0, 0 );
247                         monitor_cache_release( mi, e_parent );
248                         return -1;
249                 }
250
251                 dnParent( &e->e_nname, &pdn );
252                 if ( monitor_cache_get( mi, &pdn, &e_parent ) != 0 ) {
253                         /* parent does not exist */
254                         Debug( LDAP_DEBUG_ANY,
255                                 "monitor_back_register_entry(\"%s\"): "
256                                 "parent \"%s\" not found\n",
257                                 e->e_name.bv_val, pdn.bv_val, 0 );
258                         return -1;
259                 }
260
261                 assert( e_parent->e_private != NULL );
262                 mp_parent = ( monitor_entry_t * )e_parent->e_private;
263
264                 if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
265                         /* entry is volatile; cannot append children */
266                         Debug( LDAP_DEBUG_ANY,
267                                 "monitor_back_register_entry(\"%s\"): "
268                                 "parent \"%s\" is volatile\n",
269                                 e->e_name.bv_val, e_parent->e_name.bv_val, 0 );
270                         rc = -1;
271                         goto done;
272                 }
273
274                 mp = monitor_entrypriv_create();
275                 if ( mp == NULL ) {
276                         Debug( LDAP_DEBUG_ANY,
277                                 "monitor_back_register_entry(\"%s\"): "
278                                 "monitor_entrypriv_create() failed\n",
279                                 e->e_name.bv_val, 0, 0 );
280                         rc = -1;
281                         goto done;
282                 }
283
284                 e_new = entry_dup( e );
285                 if ( e_new == NULL ) {
286                         Debug( LDAP_DEBUG_ANY,
287                                 "monitor_back_register_entry(\"%s\"): "
288                                 "entry_dup() failed\n",
289                                 e->e_name.bv_val, 0, 0 );
290                         rc = -1;
291                         goto done;
292                 }
293                 
294                 e_new->e_private = ( void * )mp;
295                 mp->mp_info = mp_parent->mp_info;
296                 mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
297                 mp->mp_cb = cb;
298
299                 ep = &mp_parent->mp_children;
300                 for ( ; *ep; ) {
301                         mp_parent = ( monitor_entry_t * )(*ep)->e_private;
302                         ep = &mp_parent->mp_next;
303                 }
304                 *ep = e_new;
305
306                 if ( monitor_cache_add( mi, e_new ) ) {
307                         Debug( LDAP_DEBUG_ANY,
308                                 "monitor_back_register_entry(\"%s\"): "
309                                 "unable to add entry\n",
310                                 e->e_name.bv_val, 0, 0 );
311                         rc = -1;
312                         goto done;
313                 }
314
315 done:;
316                 if ( rc ) {
317                         if ( mp ) {
318                                 ch_free( mp );
319                         }
320                         if ( e_new ) {
321                                 e_new->e_private = NULL;
322                                 entry_free( e_new );
323                         }
324                 }
325
326                 if ( e_parent ) {
327                         monitor_cache_release( mi, e_parent );
328                 }
329
330         } else {
331                 entry_limbo_t   **elpp, el = { 0 };
332
333                 el.el_type = LIMBO_ENTRY;
334
335                 el.el_e = entry_dup( e );
336                 if ( el.el_e == NULL ) {
337                         Debug( LDAP_DEBUG_ANY,
338                                 "monitor_back_register_entry(\"%s\"): "
339                                 "entry_dup() failed\n",
340                                 e->e_name.bv_val, 0, 0 );
341                         return -1;
342                 }
343                 
344                 el.el_cb = cb;
345
346                 for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo;
347                                 *elpp;
348                                 elpp = &(*elpp)->el_next )
349                         /* go to last */;
350
351                 *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
352                 if ( *elpp == NULL ) {
353                         el.el_e->e_private = NULL;
354                         entry_free( el.el_e );
355                         return -1;
356                 }
357
358                 el.el_next = NULL;
359                 **elpp = el;
360         }
361
362         return 0;
363 }
364
365 int
366 monitor_back_register_entry_parent(
367                 Entry                   *e,
368                 monitor_callback_t      *cb,
369                 struct berval           *base,
370                 int                     scope,
371                 struct berval           *filter )
372 {
373         monitor_info_t  *mi = ( monitor_info_t * )be_monitor->be_private;
374         struct berval   ndn = BER_BVNULL;
375
376         assert( mi != NULL );
377         assert( e != NULL );
378         assert( e->e_private == NULL );
379
380         if ( BER_BVISNULL( filter ) ) {
381                 /* need a filter */
382                 Debug( LDAP_DEBUG_ANY,
383                         "monitor_back_register_entry_parent(\"\"): "
384                         "need a valid filter\n",
385                         0, 0, 0 );
386                 return -1;
387         }
388
389         if ( monitor_subsys_opened ) {
390                 Entry           *e_parent = NULL,
391                                 *e_new = NULL,
392                                 **ep = NULL;
393                 struct berval   e_name = BER_BVNULL,
394                                 e_nname = BER_BVNULL;
395                 monitor_entry_t *mp = NULL,
396                                 *mp_parent = NULL;
397                 int             rc = 0;
398
399                 if ( monitor_filter2ndn( base, scope, filter, &ndn ) ) {
400                         /* entry does not exist */
401                         Debug( LDAP_DEBUG_ANY,
402                                 "monitor_back_register_entry_*(\"\"): "
403                                 "base=%s scope=%d filter=%s : "
404                                 "unable to find entry\n",
405                                 base->bv_val ? base->bv_val : "\"\"",
406                                 scope, filter->bv_val );
407                         return -1;
408                 }
409
410                 if ( monitor_cache_get( mi, &ndn, &e_parent ) != 0 ) {
411                         /* entry does not exist */
412                         Debug( LDAP_DEBUG_ANY,
413                                 "monitor_back_register_entry_parent(\"%s\"): "
414                                 "parent entry does not exist\n",
415                                 ndn.bv_val, 0, 0 );
416                         rc = -1;
417                         goto done;
418                 }
419
420                 assert( e_parent->e_private != NULL );
421                 mp_parent = ( monitor_entry_t * )e_parent->e_private;
422
423                 if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
424                         /* entry is volatile; cannot append callback */
425                         Debug( LDAP_DEBUG_ANY,
426                                 "monitor_back_register_entry_*(\"%s\"): "
427                                 "entry is volatile\n",
428                                 e_parent->e_name.bv_val, 0, 0 );
429                         rc = -1;
430                         goto done;
431                 }
432
433                 build_new_dn( &e_name, &e_parent->e_name, &e->e_name, NULL );
434                 build_new_dn( &e_nname, &e_parent->e_nname, &e->e_nname, NULL );
435
436                 if ( monitor_cache_get( mi, &e_nname, &e_new ) == 0 ) {
437                         /* entry already exists */
438                         Debug( LDAP_DEBUG_ANY,
439                                 "monitor_back_register_entry_parent(\"%s\"): "
440                                 "entry already exists\n",
441                                 e_name.bv_val, 0, 0 );
442                         monitor_cache_release( mi, e_new );
443                         rc = -1;
444                         goto done;
445                 }
446
447                 mp = monitor_entrypriv_create();
448                 if ( mp == NULL ) {
449                         Debug( LDAP_DEBUG_ANY,
450                                 "monitor_back_register_entry_parent(\"%s\"): "
451                                 "monitor_entrypriv_create() failed\n",
452                                 e->e_name.bv_val, 0, 0 );
453                         rc = -1;
454                         goto done;
455                 }
456
457                 e_new = entry_dup( e );
458                 if ( e_new == NULL ) {
459                         Debug( LDAP_DEBUG_ANY,
460                                 "monitor_back_register_entry(\"%s\"): "
461                                 "entry_dup() failed\n",
462                                 e->e_name.bv_val, 0, 0 );
463                         rc = -1;
464                         goto done;
465                 }
466                 ch_free( e_new->e_name.bv_val );
467                 ch_free( e_new->e_nname.bv_val );
468                 e_new->e_name = e_name;
469                 e_new->e_nname = e_nname;
470                 
471                 e_new->e_private = ( void * )mp;
472                 mp->mp_info = mp_parent->mp_info;
473                 mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
474                 mp->mp_cb = cb;
475
476                 ep = &mp_parent->mp_children;
477                 for ( ; *ep; ) {
478                         mp_parent = ( monitor_entry_t * )(*ep)->e_private;
479                         ep = &mp_parent->mp_next;
480                 }
481                 *ep = e_new;
482
483                 if ( monitor_cache_add( mi, e_new ) ) {
484                         Debug( LDAP_DEBUG_ANY,
485                                 "monitor_back_register_entry(\"%s\"): "
486                                 "unable to add entry\n",
487                                 e->e_name.bv_val, 0, 0 );
488                         rc = -1;
489                         goto done;
490                 }
491
492 done:;
493                 if ( !BER_BVISNULL( &ndn ) ) {
494                         ch_free( ndn.bv_val );
495                 }
496
497                 if ( rc ) {
498                         if ( mp ) {
499                                 ch_free( mp );
500                         }
501                         if ( e_new ) {
502                                 e_new->e_private = NULL;
503                                 entry_free( e_new );
504                         }
505                 }
506
507                 if ( e_parent ) {
508                         monitor_cache_release( mi, e_parent );
509                 }
510
511         } else {
512                 entry_limbo_t   **elpp, el = { 0 };
513
514                 el.el_type = LIMBO_ENTRY_PARENT;
515
516                 el.el_e = entry_dup( e );
517                 if ( el.el_e == NULL ) {
518                         Debug( LDAP_DEBUG_ANY,
519                                 "monitor_back_register_entry(\"%s\"): "
520                                 "entry_dup() failed\n",
521                                 e->e_name.bv_val, 0, 0 );
522                         return -1;
523                 }
524                 
525                 if ( !BER_BVISNULL( base ) ) {
526                         ber_dupbv( &el.el_base, base );
527                 }
528                 el.el_scope = scope;
529                 if ( !BER_BVISNULL( filter ) ) {
530                         ber_dupbv( &el.el_filter, filter );
531                 }
532
533                 el.el_cb = cb;
534
535                 for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo;
536                                 *elpp;
537                                 elpp = &(*elpp)->el_next )
538                         /* go to last */;
539
540                 *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
541                 if ( *elpp == NULL ) {
542                         el.el_e->e_private = NULL;
543                         entry_free( el.el_e );
544                         return -1;
545                 }
546
547                 el.el_next = NULL;
548                 **elpp = el;
549         }
550
551         return 0;
552 }
553
554 static int
555 monitor_filter2ndn_cb( Operation *op, SlapReply *rs )
556 {
557         if ( rs->sr_type == REP_SEARCH ) {
558                 struct berval   *ndn = op->o_callback->sc_private;
559                 
560                 ber_dupbv( ndn, &rs->sr_entry->e_nname );
561         }
562
563         return 0;
564 }
565
566 int
567 monitor_filter2ndn( struct berval *base, int scope, struct berval *filter,
568                 struct berval *ndn )
569 {
570         Connection      conn = { 0 };
571         char            opbuf[OPERATION_BUFFER_SIZE];
572         Operation       *op;
573         SlapReply       rs = { 0 };
574         slap_callback   cb = { NULL, monitor_filter2ndn_cb, NULL, NULL };
575         int             rc;
576
577         BER_BVZERO( ndn );
578
579         if ( be_monitor == NULL ) {
580                 return -1;
581         }
582
583         op = (Operation *)opbuf;
584         connection_fake_init( &conn, op, &conn );
585
586         op->o_tag = LDAP_REQ_SEARCH;
587
588         /* use global malloc for now */
589         op->o_tmpmemctx = NULL;
590         op->o_tmpmfuncs = &ch_mfuncs;
591
592         op->o_bd = be_monitor;
593         if ( base == NULL || BER_BVISNULL( base ) ) {
594                 ber_dupbv_x( &op->o_req_dn, &op->o_bd->be_suffix[ 0 ],
595                                 op->o_tmpmemctx );
596                 ber_dupbv_x( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ],
597                                 op->o_tmpmemctx );
598
599         } else {
600                 if ( dnPrettyNormal( NULL, base, &op->o_req_dn, &op->o_req_ndn,
601                                         op->o_tmpmemctx ) ) {
602                         /* error */
603                 }
604         }
605
606         op->o_callback = &cb;
607         cb.sc_private = (void *)ndn;
608
609         op->ors_scope = scope;
610         ber_dupbv_x( &op->ors_filterstr, filter, op->o_tmpmemctx );
611         op->ors_filter = str2filter_x( op, filter->bv_val );
612         op->ors_attrs = slap_anlist_no_attrs;
613         op->ors_attrsonly = 0;
614         op->ors_tlimit = SLAP_NO_LIMIT;
615         op->ors_slimit = 1;
616         op->ors_limit = NULL;
617         op->ors_deref = LDAP_DEREF_NEVER;
618
619         op->o_nocaching = 1;
620         op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
621
622         rc = op->o_bd->be_search( op, &rs );
623
624         filter_free_x( op, op->ors_filter );
625         op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
626         op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
627         op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
628
629         if ( rc != 0 ) {
630                 return rc;
631         }
632
633         switch ( rs.sr_err ) {
634         case LDAP_SUCCESS:
635                 if ( BER_BVISNULL( ndn ) ) {
636                         rc = -1;
637                 }
638                 break;
639                         
640         case LDAP_SIZELIMIT_EXCEEDED:
641         default:
642                 if ( !BER_BVISNULL( ndn ) ) {
643                         ber_memfree( ndn->bv_val );
644                         BER_BVZERO( ndn );
645                 }
646                 rc = -1;
647                 break;
648         }
649
650         return rc;
651 }
652
653 int
654 monitor_back_register_entry_attrs(
655                 struct berval           *ndn_in,
656                 Attribute               *a,
657                 monitor_callback_t      *cb,
658                 struct berval           *base,
659                 int                     scope,
660                 struct berval           *filter )
661 {
662         monitor_info_t  *mi = ( monitor_info_t * )be_monitor->be_private;
663         struct berval   ndn = BER_BVNULL;
664
665         assert( mi != NULL );
666
667         if ( ndn_in != NULL ) {
668                 ndn = *ndn_in;
669         }
670
671         if ( a == NULL && cb == NULL ) {
672                 /* nothing to do */
673                 return -1;
674         }
675
676         if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
677                         && BER_BVISNULL( filter ) )
678         {
679                 /* need a filter */
680                 Debug( LDAP_DEBUG_ANY,
681                         "monitor_back_register_entry_*(\"\"): "
682                         "need a valid filter\n",
683                         0, 0, 0 );
684                 return -1;
685         }
686
687         if ( monitor_subsys_opened ) {
688                 Entry                   *e = NULL;
689                 Attribute               **atp = NULL;
690                 monitor_entry_t         *mp = NULL;
691                 monitor_callback_t      **mcp = NULL;
692                 int                     rc = 0;
693                 int                     freeit = 0;
694
695                 if ( BER_BVISNULL( &ndn ) ) {
696                         if ( monitor_filter2ndn( base, scope, filter, &ndn ) ) {
697                                 /* entry does not exist */
698                                 Debug( LDAP_DEBUG_ANY,
699                                         "monitor_back_register_entry_*(\"\"): "
700                                         "base=%s scope=%d filter=%s : "
701                                         "unable to find entry\n",
702                                         base->bv_val ? base->bv_val : "\"\"",
703                                         scope, filter->bv_val );
704                                 return -1;
705                         }
706
707                         freeit = 1;
708                 }
709
710                 if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
711                         /* entry does not exist */
712                         Debug( LDAP_DEBUG_ANY,
713                                 "monitor_back_register_entry_*(\"%s\"): "
714                                 "entry does not exist\n",
715                                 ndn.bv_val, 0, 0 );
716                         rc = -1;
717                         goto done;
718                 }
719
720                 assert( e->e_private != NULL );
721                 mp = ( monitor_entry_t * )e->e_private;
722
723                 if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
724                         /* entry is volatile; cannot append callback */
725                         Debug( LDAP_DEBUG_ANY,
726                                 "monitor_back_register_entry_*(\"%s\"): "
727                                 "entry is volatile\n",
728                                 e->e_name.bv_val, 0, 0 );
729                         rc = -1;
730                         goto done;
731                 }
732
733                 if ( a ) {
734                         for ( atp = &e->e_attrs; *atp; atp = &(*atp)->a_next )
735                                 /* just get to last */ ;
736
737                         *atp = attrs_dup( a );
738                         if ( *atp == NULL ) {
739                                 Debug( LDAP_DEBUG_ANY,
740                                         "monitor_back_register_entry_*(\"%s\"): "
741                                         "attrs_dup() failed\n",
742                                         e->e_name.bv_val, 0, 0 );
743                                 rc = -1;
744                                 goto done;
745                         }
746                 }
747
748                 if ( cb ) {
749                         for ( mcp = &mp->mp_cb; *mcp; mcp = &(*mcp)->mc_next )
750                                 /* go to tail */ ;
751                 
752                         /* NOTE: we do not clear cb->mc_next, so this function
753                          * can be used to append a list of callbacks */
754                         (*mcp) = cb;
755                 }
756
757 done:;
758                 if ( rc ) {
759                         if ( *atp ) {
760                                 attrs_free( *atp );
761                                 *atp = NULL;
762                         }
763                 }
764
765                 if ( freeit ) {
766                         ber_memfree( ndn.bv_val );
767                 }
768
769                 if ( e ) {
770                         monitor_cache_release( mi, e );
771                 }
772
773         } else {
774                 entry_limbo_t   **elpp, el = { 0 };
775
776                 el.el_type = LIMBO_ATTRS;
777                 if ( !BER_BVISNULL( &ndn ) ) {
778                         ber_dupbv( &el.el_ndn, &ndn );
779                 }
780                 if ( !BER_BVISNULL( base ) ) {
781                         ber_dupbv( &el.el_base, base);
782                 }
783                 el.el_scope = scope;
784                 if ( !BER_BVISNULL( filter ) ) {
785                         ber_dupbv( &el.el_filter, filter );
786                 }
787
788                 el.el_a = attrs_dup( a );
789                 el.el_cb = cb;
790
791                 for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo;
792                                 *elpp;
793                                 elpp = &(*elpp)->el_next )
794                         /* go to last */;
795
796                 *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
797                 if ( *elpp == NULL ) {
798                         el.el_e->e_private = NULL;
799                         entry_free( el.el_e );
800                         return -1;
801                 }
802
803                 el.el_next = NULL;
804                 **elpp = el;
805         }
806
807         return 0;
808 }
809
810 int
811 monitor_back_register_entry_callback(
812                 struct berval           *ndn,
813                 monitor_callback_t      *cb,
814                 struct berval           *base,
815                 int                     scope,
816                 struct berval           *filter )
817 {
818         return monitor_back_register_entry_attrs( ndn, NULL, cb,
819                         base, scope, filter );
820 }
821
822 monitor_subsys_t *
823 monitor_back_get_subsys( const char *name )
824 {
825         if ( monitor_subsys != NULL ) {
826                 int     i;
827                 
828                 for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
829                         if ( strcasecmp( monitor_subsys[ i ]->mss_name, name ) == 0 ) {
830                                 return monitor_subsys[ i ];
831                         }
832                 }
833         }
834
835         return NULL;
836 }
837
838 monitor_subsys_t *
839 monitor_back_get_subsys_by_dn( struct berval *ndn, int sub )
840 {
841         if ( monitor_subsys != NULL ) {
842                 int     i;
843
844                 if ( sub ) {
845                         for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
846                                 if ( dnIsSuffix( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
847                                         return monitor_subsys[ i ];
848                                 }
849                         }
850
851                 } else {
852                         for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
853                                 if ( dn_match( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
854                                         return monitor_subsys[ i ];
855                                 }
856                         }
857                 }
858         }
859
860         return NULL;
861 }
862
863 int
864 monitor_back_initialize(
865         BackendInfo     *bi
866 )
867 {
868         monitor_subsys_t        *ms;
869         static char             *controls[] = {
870                 LDAP_CONTROL_MANAGEDSAIT,
871                 NULL
872         };
873
874         bi->bi_controls = controls;
875
876         bi->bi_init = 0;
877         bi->bi_open = 0;
878         bi->bi_config = monitor_back_config;
879         bi->bi_close = 0;
880         bi->bi_destroy = 0;
881
882         bi->bi_db_init = monitor_back_db_init;
883         bi->bi_db_config = monitor_back_db_config;
884         bi->bi_db_open = monitor_back_db_open;
885         bi->bi_db_close = 0;
886         bi->bi_db_destroy = monitor_back_db_destroy;
887
888         bi->bi_op_bind = monitor_back_bind;
889         bi->bi_op_unbind = 0;
890         bi->bi_op_search = monitor_back_search;
891         bi->bi_op_compare = monitor_back_compare;
892         bi->bi_op_modify = monitor_back_modify;
893         bi->bi_op_modrdn = 0;
894         bi->bi_op_add = 0;
895         bi->bi_op_delete = 0;
896         bi->bi_op_abandon = 0;
897
898         bi->bi_extended = 0;
899
900         bi->bi_entry_release_rw = 0;
901         bi->bi_chk_referrals = 0;
902         bi->bi_operational = monitor_back_operational;
903
904         /*
905          * hooks for slap tools
906          */
907         bi->bi_tool_entry_open = 0;
908         bi->bi_tool_entry_close = 0;
909         bi->bi_tool_entry_first = 0;
910         bi->bi_tool_entry_next = 0;
911         bi->bi_tool_entry_get = 0;
912         bi->bi_tool_entry_put = 0;
913         bi->bi_tool_entry_reindex = 0;
914         bi->bi_tool_sync = 0;
915         bi->bi_tool_dn2id_get = 0;
916         bi->bi_tool_id2entry_get = 0;
917         bi->bi_tool_entry_modify = 0;
918
919         bi->bi_connection_init = 0;
920         bi->bi_connection_destroy = 0;
921
922         for ( ms = known_monitor_subsys; ms->mss_name != NULL; ms++ ) {
923                 if ( monitor_back_register_subsys( ms ) ) {
924                         return -1;
925                 }
926         }
927
928         return 0;
929 }
930
931 int
932 monitor_back_db_init(
933         BackendDB       *be
934 )
935 {
936         monitor_info_t  *mi;
937         int             i, rc;
938         struct berval   dn, ndn;
939         struct berval   bv;
940         const char      *text;
941
942         struct m_s {
943                 char    *name;
944                 char    *schema;
945                 slap_mask_t flags;
946                 int     offset;
947         } moc[] = {
948                 { "monitor", "( 1.3.6.1.4.1.4203.666.3.2 "
949                         "NAME 'monitor' "
950                         "DESC 'OpenLDAP system monitoring' "
951                         "SUP top STRUCTURAL "
952                         "MUST cn "
953                         "MAY ( "
954                                 "description "
955                                 "$ l "
956 #if 0   /* temporarily disabled */
957                                 "$ st "
958                                 "$ street "
959                                 "$ postalAddress "
960                                 "$ postalCode "
961 #endif
962                                 "$ seeAlso "
963                                 "$ labeledURI "
964                                 "$ monitoredInfo "
965                                 "$ managedInfo "
966                                 "$ monitorOverlay "
967                         ") )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
968                         offsetof(monitor_info_t, mi_oc_monitor) },
969                 { "monitorServer", "( 1.3.6.1.4.1.4203.666.3.7 "
970                         "NAME 'monitorServer' "
971                         "DESC 'Server monitoring root entry' "
972                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
973                         offsetof(monitor_info_t, mi_oc_monitorServer) },
974                 { "monitorContainer", "( 1.3.6.1.4.1.4203.666.3.8 "
975                         "NAME 'monitorContainer' "
976                         "DESC 'monitor container class' "
977                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
978                         offsetof(monitor_info_t, mi_oc_monitorContainer) },
979                 { "monitorCounterObject", "( 1.3.6.1.4.1.4203.666.3.9 "
980                         "NAME 'monitorCounterObject' "
981                         "DESC 'monitor counter class' "
982                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
983                         offsetof(monitor_info_t, mi_oc_monitorCounterObject) },
984                 { "monitorOperation", "( 1.3.6.1.4.1.4203.666.3.10 "
985                         "NAME 'monitorOperation' "
986                         "DESC 'monitor operation class' "
987                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
988                         offsetof(monitor_info_t, mi_oc_monitorOperation) },
989                 { "monitorConnection", "( 1.3.6.1.4.1.4203.666.3.11 "
990                         "NAME 'monitorConnection' "
991                         "DESC 'monitor connection class' "
992                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
993                         offsetof(monitor_info_t, mi_oc_monitorConnection) },
994                 { "managedObject", "( 1.3.6.1.4.1.4203.666.3.12 "
995                         "NAME 'managedObject' "
996                         "DESC 'monitor managed entity class' "
997                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
998                         offsetof(monitor_info_t, mi_oc_managedObject) },
999                 { "monitoredObject", "( 1.3.6.1.4.1.4203.666.3.14 "
1000                         "NAME 'monitoredObject' "
1001                         "DESC 'monitor monitored entity class' "
1002                         "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1003                         offsetof(monitor_info_t, mi_oc_monitoredObject) },
1004                 { NULL, NULL, 0, -1 }
1005         }, mat[] = {
1006                 { "monitoredInfo", "( 1.3.6.1.4.1.4203.666.1.14 "
1007                         "NAME 'monitoredInfo' "
1008                         "DESC 'monitored info' "
1009                         /* "SUP name " */
1010                         "EQUALITY caseIgnoreMatch "
1011                         "SUBSTR caseIgnoreSubstringsMatch "
1012                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} "
1013                         "NO-USER-MODIFICATION "
1014                         "USAGE directoryOperation )", SLAP_AT_HIDE,
1015                         offsetof(monitor_info_t, mi_ad_monitoredInfo) },
1016                 { "managedInfo", "( 1.3.6.1.4.1.4203.666.1.15 "
1017                         "NAME 'managedInfo' "
1018                         "DESC 'monitor managed info' "
1019                         "SUP name )", SLAP_AT_HIDE,
1020                         offsetof(monitor_info_t, mi_ad_managedInfo) },
1021                 { "monitorCounter", "( 1.3.6.1.4.1.4203.666.1.16 "
1022                         "NAME 'monitorCounter' "
1023                         "DESC 'monitor counter' "
1024                         "EQUALITY integerMatch "
1025                         "ORDERING integerOrderingMatch "
1026                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
1027                         "NO-USER-MODIFICATION "
1028                         "USAGE directoryOperation )", SLAP_AT_HIDE,
1029                         offsetof(monitor_info_t, mi_ad_monitorCounter) },
1030                 { "monitorOpCompleted", "( 1.3.6.1.4.1.4203.666.1.17 "
1031                         "NAME 'monitorOpCompleted' "
1032                         "DESC 'monitor completed operations' "
1033                         "SUP monitorCounter "
1034                         "NO-USER-MODIFICATION "
1035                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1036                         offsetof(monitor_info_t, mi_ad_monitorOpCompleted) },
1037                 { "monitorOpInitiated", "( 1.3.6.1.4.1.4203.666.1.18 "
1038                         "NAME 'monitorOpInitiated' "
1039                         "DESC 'monitor initiated operations' "
1040                         "SUP monitorCounter "
1041                         "NO-USER-MODIFICATION "
1042                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1043                         offsetof(monitor_info_t, mi_ad_monitorOpInitiated) },
1044                 { "monitorConnectionNumber", "( 1.3.6.1.4.1.4203.666.1.19 "
1045                         "NAME 'monitorConnectionNumber' "
1046                         "DESC 'monitor connection number' "
1047                         "SUP monitorCounter "
1048                         "NO-USER-MODIFICATION "
1049                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1050                         offsetof(monitor_info_t, mi_ad_monitorConnectionNumber) },
1051                 { "monitorConnectionAuthzDN", "( 1.3.6.1.4.1.4203.666.1.20 "
1052                         "NAME 'monitorConnectionAuthzDN' "
1053                         "DESC 'monitor connection authorization DN' "
1054                         /* "SUP distinguishedName " */
1055                         "EQUALITY distinguishedNameMatch "
1056                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
1057                         "NO-USER-MODIFICATION "
1058                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1059                         offsetof(monitor_info_t, mi_ad_monitorConnectionAuthzDN) },
1060                 { "monitorConnectionLocalAddress", "( 1.3.6.1.4.1.4203.666.1.21 "
1061                         "NAME 'monitorConnectionLocalAddress' "
1062                         "DESC 'monitor connection local address' "
1063                         "SUP monitoredInfo "
1064                         "NO-USER-MODIFICATION "
1065                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1066                         offsetof(monitor_info_t, mi_ad_monitorConnectionLocalAddress) },
1067                 { "monitorConnectionPeerAddress", "( 1.3.6.1.4.1.4203.666.1.22 "
1068                         "NAME 'monitorConnectionPeerAddress' "
1069                         "DESC 'monitor connection peer address' "
1070                         "SUP monitoredInfo "
1071                         "NO-USER-MODIFICATION "
1072                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1073                         offsetof(monitor_info_t, mi_ad_monitorConnectionPeerAddress) },
1074                 { "monitorTimestamp", "( 1.3.6.1.4.1.4203.666.1.24 "
1075                         "NAME 'monitorTimestamp' "
1076                         "DESC 'monitor timestamp' "
1077                         "EQUALITY generalizedTimeMatch "
1078                         "ORDERING generalizedTimeOrderingMatch "
1079                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
1080                         "SINGLE-VALUE "
1081                         "NO-USER-MODIFICATION "
1082                         "USAGE directoryOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1083                         offsetof(monitor_info_t, mi_ad_monitorTimestamp) },
1084                 { "monitorOverlay", "( 1.3.6.1.4.1.4203.666.1.27 "
1085                         "NAME 'monitorOverlay' "
1086                         "DESC 'name of overlays defined for a given database' "
1087                         "SUP monitoredInfo "
1088                         "NO-USER-MODIFICATION "
1089                         "USAGE directoryOperation )", SLAP_AT_HIDE,
1090                         offsetof(monitor_info_t, mi_ad_monitorOverlay) },
1091                 { "readOnly", "( 1.3.6.1.4.1.4203.666.1.31 "
1092                         "NAME 'readOnly' "
1093                         "DESC 'read/write status of a given database' "
1094                         "EQUALITY booleanMatch "
1095                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
1096                         "SINGLE-VALUE "
1097                         "USAGE directoryOperation )", SLAP_AT_HIDE,
1098                         offsetof(monitor_info_t, mi_ad_readOnly) },
1099                 { "restrictedOperation", "( 1.3.6.1.4.1.4203.666.1.32 "
1100                         "NAME 'restrictedOperation' "
1101                         "DESC 'name of restricted operation for a given database' "
1102                         "SUP managedInfo )", SLAP_AT_HIDE,
1103                         offsetof(monitor_info_t, mi_ad_restrictedOperation ) },
1104 #ifdef INTEGRATE_CORE_SCHEMA
1105                 { NULL, NULL, 0, -1 },  /* description */
1106                 { NULL, NULL, 0, -1 },  /* seeAlso */
1107                 { NULL, NULL, 0, -1 },  /* l */
1108                 { NULL, NULL, 0, -1 },  /* labeledURI */
1109 #endif /* INTEGRATE_CORE_SCHEMA */
1110                 { NULL, NULL, 0, -1 }
1111         }, mat_core[] = {
1112                 { "description", "( 2.5.4.13 "
1113                         "NAME 'description' "
1114                         "DESC 'RFC2256: descriptive information' "
1115                         "EQUALITY caseIgnoreMatch "
1116                         "SUBSTR caseIgnoreSubstringsMatch "
1117                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )", 0,
1118                         offsetof(monitor_info_t, mi_ad_description) },
1119                 { "seeAlso", "( 2.5.4.34 "
1120                         "NAME 'seeAlso' "
1121                         "DESC 'RFC2256: DN of related object' "
1122                         "SUP distinguishedName )", 0,
1123                         offsetof(monitor_info_t, mi_ad_seeAlso) },
1124                 { "l", "( 2.5.4.7 "
1125                         "NAME ( 'l' 'localityName' ) "
1126                         "DESC 'RFC2256: locality which this object resides in' "
1127                         "SUP name )", 0,
1128                         offsetof(monitor_info_t, mi_ad_l) },
1129 #ifdef MONITOR_DEFINE_LABELEDURI
1130                 { "labeledURI", "( 1.3.6.1.4.1.250.1.57 "
1131                         "NAME 'labeledURI' "
1132                         "DESC 'RFC2079: Uniform Resource Identifier with optional label' "
1133                         "EQUALITY caseExactMatch "
1134                         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", 0,
1135                         offsetof(monitor_info_t, mi_ad_labeledURI) },
1136 #endif /* MONITOR_DEFINE_LABELEDURI */
1137                 { NULL, NULL, 0, -1 }
1138         };
1139         
1140         /*
1141          * database monitor can be defined once only
1142          */
1143         if ( be_monitor ) {
1144                 Debug( LDAP_DEBUG_ANY,
1145                         "only one monitor backend is allowed\n", 0, 0, 0 );
1146                 return( -1 );
1147         }
1148         be_monitor = be;
1149
1150         /* indicate system schema supported */
1151         SLAP_BFLAGS(be) |= SLAP_BFLAG_MONITOR;
1152
1153         dn.bv_val = SLAPD_MONITOR_DN;
1154         dn.bv_len = sizeof( SLAPD_MONITOR_DN ) - 1;
1155
1156         rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
1157         if( rc != LDAP_SUCCESS ) {
1158                 Debug( LDAP_DEBUG_ANY,
1159                         "unable to normalize monitor DN \"%s\"\n",
1160                         SLAPD_MONITOR_DN, 0, 0 );
1161                 return -1;
1162         }
1163
1164         ber_dupbv( &bv, &dn );
1165         ber_bvarray_add( &be->be_suffix, &bv );
1166         ber_bvarray_add( &be->be_nsuffix, &ndn );
1167
1168         mi = ( monitor_info_t * )ch_calloc( sizeof( monitor_info_t ), 1 );
1169         if ( mi == NULL ) {
1170                 Debug( LDAP_DEBUG_ANY,
1171                         "unable to initialize monitor backend\n", 0, 0, 0 );
1172                 return -1;
1173         }
1174
1175         memset( mi, 0, sizeof( monitor_info_t ) );
1176
1177         ldap_pvt_thread_mutex_init( &mi->mi_cache_mutex );
1178
1179         be->be_private = mi;
1180         
1181 #ifdef INTEGRATE_CORE_SCHEMA
1182         /* prepare for schema integration */
1183         for ( k = 0; mat[ k ].name != NULL; k++ );
1184 #endif /* INTEGRATE_CORE_SCHEMA */
1185
1186         for ( i = 0; mat_core[ i ].name != NULL; i++ ) {
1187                 AttributeDescription    **ad;
1188                 const char              *text;
1189
1190                 ad = ((AttributeDescription **)&(((char *)mi)[ mat_core[ i ].offset ]));
1191                 ad[ 0 ] = NULL;
1192
1193                 switch (slap_str2ad( mat_core[ i ].name, ad, &text ) ) {
1194                 case LDAP_SUCCESS:
1195                         break;
1196
1197 #ifdef INTEGRATE_CORE_SCHEMA
1198                 case LDAP_UNDEFINED_TYPE:
1199                         mat[ k ] = mat_core[ i ];
1200                         k++;
1201                         break;
1202 #endif /* INTEGRATE_CORE_SCHEMA */
1203
1204                 default:
1205                         Debug( LDAP_DEBUG_ANY,
1206                                 "monitor_back_db_init: %s: %s\n",
1207                                 mat_core[ i ].name, text, 0 );
1208                         return( -1 );
1209                 }
1210         }
1211
1212         /* schema integration */
1213         for ( i = 0; mat[ i ].name; i++ ) {
1214                 LDAPAttributeType       *at;
1215                 int                     code;
1216                 const char              *err;
1217                 AttributeDescription    **ad;
1218
1219                 at = ldap_str2attributetype( mat[ i ].schema, &code,
1220                         &err, LDAP_SCHEMA_ALLOW_ALL );
1221                 if ( !at ) {
1222                         Debug( LDAP_DEBUG_ANY, "monitor_back_db_init: "
1223                                 "in AttributeType \"%s\" %s before %s\n",
1224                                 mat[ i ].name, ldap_scherr2str(code), err );
1225                         return -1;
1226                 }
1227
1228                 if ( at->at_oid == NULL ) {
1229                         Debug( LDAP_DEBUG_ANY, "monitor_back_db_init: "
1230                                 "null OID for attributeType \"%s\"\n",
1231                                 mat[ i ].name, 0, 0 );
1232                         return -1;
1233                 }
1234
1235                 code = at_add(at, 0, NULL, &err);
1236                 if ( code ) {
1237                         Debug( LDAP_DEBUG_ANY, "monitor_back_db_init: "
1238                                 "%s in attributeType \"%s\"\n",
1239                                 scherr2str(code), mat[ i ].name, 0 );
1240                         return -1;
1241                 }
1242                 ldap_memfree(at);
1243
1244                 ad = ((AttributeDescription **)&(((char *)mi)[ mat[ i ].offset ]));
1245                 ad[ 0 ] = NULL;
1246                 if ( slap_str2ad( mat[ i ].name, ad, &text ) ) {
1247                         Debug( LDAP_DEBUG_ANY,
1248                                 "monitor_back_db_init: %s\n", text, 0, 0 );
1249                         return -1;
1250                 }
1251
1252                 (*ad)->ad_type->sat_flags |= mat[ i ].flags;
1253         }
1254
1255         for ( i = 0; moc[ i ].name; i++ ) {
1256                 LDAPObjectClass         *oc;
1257                 int                     code;
1258                 const char              *err;
1259                 ObjectClass             *Oc;
1260
1261                 oc = ldap_str2objectclass(moc[ i ].schema, &code, &err,
1262                                 LDAP_SCHEMA_ALLOW_ALL );
1263                 if ( !oc ) {
1264                         Debug( LDAP_DEBUG_ANY,
1265                                 "unable to parse monitor objectclass \"%s\": "
1266                                 "%s before %s\n" , moc[ i ].name,
1267                                 ldap_scherr2str(code), err );
1268                         return -1;
1269                 }
1270
1271                 if ( oc->oc_oid == NULL ) {
1272                         Debug( LDAP_DEBUG_ANY,
1273                                 "objectclass \"%s\" has no OID\n" ,
1274                                 moc[ i ].name, 0, 0 );
1275                         return -1;
1276                 }
1277
1278                 code = oc_add(oc, 0, NULL, &err);
1279                 if ( code ) {
1280                         Debug( LDAP_DEBUG_ANY,
1281                                 "objectclass \"%s\": %s \"%s\"\n" ,
1282                                 moc[ i ].name, scherr2str(code), err );
1283                         return -1;
1284                 }
1285
1286                 ldap_memfree(oc);
1287
1288                 Oc = oc_find( moc[ i ].name );
1289                 if ( Oc == NULL ) {
1290                         Debug( LDAP_DEBUG_ANY, "monitor_back_db_init: "
1291                                         "unable to find objectClass %s "
1292                                         "(just added)\n", moc[ i ].name, 0, 0 );
1293                         return -1;
1294                 }
1295
1296                 Oc->soc_flags |= moc[ i ].flags;
1297
1298                 ((ObjectClass **)&(((char *)mi)[ moc[ i ].offset ]))[ 0 ] = Oc;
1299         }
1300
1301         return 0;
1302 }
1303
1304 int
1305 monitor_back_db_open(
1306         BackendDB       *be
1307 )
1308 {
1309         monitor_info_t          *mi = (monitor_info_t *)be->be_private;
1310         struct monitor_subsys_t **ms;
1311         Entry                   *e, **ep;
1312         monitor_entry_t         *mp;
1313         int                     i;
1314         char                    buf[ BACKMONITOR_BUFSIZE ],
1315                                 *end_of_line;
1316         struct berval           bv;
1317         struct tm               *tms;
1318 #ifdef HAVE_GMTIME_R
1319         struct tm               tm_buf;
1320 #endif
1321         static char             tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1322
1323         assert( be_monitor );
1324         if ( be != be_monitor ) {
1325                 be_monitor = be;
1326         }
1327
1328         /*
1329          * Start
1330          */
1331 #ifndef HAVE_GMTIME_R
1332         ldap_pvt_thread_mutex_lock( &gmtime_mutex );
1333 #endif
1334 #ifdef HACK_LOCAL_TIME
1335 # ifdef HAVE_LOCALTIME_R
1336         tms = localtime_r( &starttime, &tm_buf );
1337 # else
1338         tms = localtime( &starttime );
1339 # endif /* HAVE_LOCALTIME_R */
1340         lutil_localtime( tmbuf, sizeof(tmbuf), tms, -timezone );
1341 #else /* !HACK_LOCAL_TIME */
1342 # ifdef HAVE_GMTIME_R
1343         tms = gmtime_r( &starttime, &tm_buf );
1344 # else
1345         tms = gmtime( &starttime );
1346 # endif /* HAVE_GMTIME_R */
1347         lutil_gentime( tmbuf, sizeof(tmbuf), tms );
1348 #endif /* !HACK_LOCAL_TIME */
1349 #ifndef HAVE_GMTIME_R
1350         ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
1351 #endif
1352
1353         mi->mi_startTime.bv_val = tmbuf;
1354         mi->mi_startTime.bv_len = strlen( tmbuf );
1355
1356         if ( BER_BVISEMPTY( &be->be_rootdn ) ) {
1357                 BER_BVSTR( &mi->mi_creatorsName, SLAPD_ANONYMOUS );
1358         } else {
1359                 mi->mi_creatorsName = be->be_rootdn;
1360         }
1361
1362         /*
1363          * creates the "cn=Monitor" entry 
1364          */
1365         snprintf( buf, sizeof( buf ), 
1366                 "dn: %s\n"
1367                 "objectClass: %s\n"
1368                 "structuralObjectClass: %s\n"
1369                 "cn: Monitor\n"
1370                 "%s: This subtree contains monitoring/managing objects.\n"
1371                 "%s: This object contains information about this server.\n"
1372 #if 0
1373                 "%s: createTimestamp reflects the time this server instance was created.\n"
1374                 "%s: modifyTimestamp reflects the time this server instance was last accessed.\n"
1375 #endif
1376                 "creatorsName: %s\n"
1377                 "modifiersName: %s\n"
1378                 "createTimestamp: %s\n"
1379                 "modifyTimestamp: %s\n",
1380                 SLAPD_MONITOR_DN,
1381                 mi->mi_oc_monitorServer->soc_cname.bv_val,
1382                 mi->mi_oc_monitorServer->soc_cname.bv_val,
1383                 mi->mi_ad_description->ad_cname.bv_val,
1384                 mi->mi_ad_description->ad_cname.bv_val,
1385 #if 0
1386                 mi->mi_ad_description->ad_cname.bv_val,
1387                 mi->mi_ad_description->ad_cname.bv_val,
1388 #endif
1389                 mi->mi_creatorsName.bv_val,
1390                 mi->mi_creatorsName.bv_val,
1391                 mi->mi_startTime.bv_val,
1392                 mi->mi_startTime.bv_val );
1393
1394         e = str2entry( buf );
1395         if ( e == NULL) {
1396                 Debug( LDAP_DEBUG_ANY,
1397                         "unable to create \"%s\" entry\n",
1398                         SLAPD_MONITOR_DN, 0, 0 );
1399                 return( -1 );
1400         }
1401
1402         bv.bv_val = (char *) Versionstr;
1403         end_of_line = strchr( Versionstr, '\n' );
1404         if ( end_of_line ) {
1405                 bv.bv_len = end_of_line - Versionstr;
1406         } else {
1407                 bv.bv_len = strlen( Versionstr );
1408         }
1409
1410         if ( attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
1411                                 &bv, NULL ) ) {
1412                 Debug( LDAP_DEBUG_ANY,
1413                         "unable to add monitoredInfo to \"%s\" entry\n",
1414                         SLAPD_MONITOR_DN, 0, 0 );
1415                 return( -1 );
1416         }
1417
1418         if ( mi->mi_l.bv_len ) {
1419                 if ( attr_merge_normalize_one( e, mi->mi_ad_l, &mi->mi_l, NULL ) ) {
1420                         Debug( LDAP_DEBUG_ANY,
1421                                 "unable to add locality to \"%s\" entry\n",
1422                                 SLAPD_MONITOR_DN, 0, 0 );
1423                         return( -1 );
1424                 }
1425         }
1426
1427         mp = monitor_entrypriv_create();
1428         if ( mp == NULL ) {
1429                 return -1;
1430         }
1431         e->e_private = ( void * )mp;
1432         ep = &mp->mp_children;
1433
1434         if ( monitor_cache_add( mi, e ) ) {
1435                 Debug( LDAP_DEBUG_ANY,
1436                         "unable to add entry \"%s\" to cache\n",
1437                         SLAPD_MONITOR_DN, 0, 0 );
1438                 return -1;
1439         }
1440
1441         /*      
1442          * Create all the subsystem specific entries
1443          */
1444         for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
1445                 int             len = strlen( monitor_subsys[ i ]->mss_name );
1446                 struct berval   dn;
1447                 int             rc;
1448
1449                 dn.bv_len = len + sizeof( "cn=" ) - 1;
1450                 dn.bv_val = ch_calloc( sizeof( char ), dn.bv_len + 1 );
1451                 strcpy( dn.bv_val, "cn=" );
1452                 strcat( dn.bv_val, monitor_subsys[ i ]->mss_name );
1453                 rc = dnPretty( NULL, &dn, &monitor_subsys[ i ]->mss_rdn, NULL );
1454                 free( dn.bv_val );
1455                 if ( rc != LDAP_SUCCESS ) {
1456                         Debug( LDAP_DEBUG_ANY,
1457                                 "monitor RDN \"%s\" is invalid\n", 
1458                                 dn.bv_val, 0, 0 );
1459                         return( -1 );
1460                 }
1461
1462                 dn.bv_len += sizeof( SLAPD_MONITOR_DN ); /* 1 for the , */
1463                 dn.bv_val = ch_malloc( dn.bv_len + 1 );
1464                 strcpy( dn.bv_val , monitor_subsys[ i ]->mss_rdn.bv_val );
1465                 strcat( dn.bv_val, "," SLAPD_MONITOR_DN );
1466                 rc = dnPrettyNormal( NULL, &dn, &monitor_subsys[ i ]->mss_dn,
1467                         &monitor_subsys[ i ]->mss_ndn, NULL );
1468                 free( dn.bv_val );
1469                 if ( rc != LDAP_SUCCESS ) {
1470                         Debug( LDAP_DEBUG_ANY,
1471                                 "monitor DN \"%s\" is invalid\n", 
1472                                 dn.bv_val, 0, 0 );
1473                         return( -1 );
1474                 }
1475
1476                 snprintf( buf, sizeof( buf ),
1477                                 "dn: %s\n"
1478                                 "objectClass: %s\n"
1479                                 "structuralObjectClass: %s\n"
1480                                 "cn: %s\n"
1481                                 "creatorsName: %s\n"
1482                                 "modifiersName: %s\n"
1483                                 "createTimestamp: %s\n"
1484                                 "modifyTimestamp: %s\n",
1485                                 monitor_subsys[ i ]->mss_dn.bv_val,
1486                                 mi->mi_oc_monitorContainer->soc_cname.bv_val,
1487                                 mi->mi_oc_monitorContainer->soc_cname.bv_val,
1488                                 monitor_subsys[ i ]->mss_name,
1489                                 mi->mi_creatorsName.bv_val,
1490                                 mi->mi_creatorsName.bv_val,
1491                                 mi->mi_startTime.bv_val,
1492                                 mi->mi_startTime.bv_val );
1493                 
1494                 e = str2entry( buf );
1495                 
1496                 if ( e == NULL) {
1497                         Debug( LDAP_DEBUG_ANY,
1498                                 "unable to create \"%s\" entry\n", 
1499                                 monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
1500                         return( -1 );
1501                 }
1502
1503                 mp = monitor_entrypriv_create();
1504                 if ( mp == NULL ) {
1505                         return -1;
1506                 }
1507                 e->e_private = ( void * )mp;
1508                 mp->mp_info = monitor_subsys[ i ];
1509                 mp->mp_flags = monitor_subsys[ i ]->mss_flags;
1510
1511                 if ( monitor_cache_add( mi, e ) ) {
1512                         Debug( LDAP_DEBUG_ANY,
1513                                 "unable to add entry \"%s\" to cache\n",
1514                                 monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
1515                         return -1;
1516                 }
1517
1518                 *ep = e;
1519                 ep = &mp->mp_next;
1520         }
1521
1522         assert( be );
1523
1524         be->be_private = mi;
1525         
1526         /*
1527          * opens the monitor backend subsystems
1528          */
1529         for ( ms = monitor_subsys; ms[ 0 ] != NULL; ms++ ) {
1530                 if ( ms[ 0 ]->mss_open && ( *ms[ 0 ]->mss_open )( be, ms[ 0 ] ) )
1531                 {
1532                         return( -1 );
1533                 }
1534                 ms[ 0 ]->mss_flags |= MONITOR_F_OPENED;
1535         }
1536
1537         monitor_subsys_opened = 1;
1538
1539         if ( mi->mi_entry_limbo ) {
1540                 entry_limbo_t   *el = (entry_limbo_t *)mi->mi_entry_limbo;
1541
1542                 for ( ; el; ) {
1543                         entry_limbo_t   *tmp;
1544
1545                         switch ( el->el_type ) {
1546                         case LIMBO_ENTRY:
1547                                 monitor_back_register_entry(
1548                                                 el->el_e,
1549                                                 el->el_cb );
1550                                 break;
1551
1552                         case LIMBO_ENTRY_PARENT:
1553                                 monitor_back_register_entry_parent(
1554                                                 el->el_e,
1555                                                 el->el_cb,
1556                                                 &el->el_base,
1557                                                 el->el_scope,
1558                                                 &el->el_filter );
1559                                 break;
1560                                 
1561
1562                         case LIMBO_ATTRS:
1563                                 monitor_back_register_entry_attrs(
1564                                                 &el->el_ndn,
1565                                                 el->el_a,
1566                                                 el->el_cb,
1567                                                 &el->el_base,
1568                                                 el->el_scope,
1569                                                 &el->el_filter );
1570                                 break;
1571
1572                         case LIMBO_CB:
1573                                 monitor_back_register_entry_callback(
1574                                                 &el->el_ndn,
1575                                                 el->el_cb,
1576                                                 &el->el_base,
1577                                                 el->el_scope,
1578                                                 &el->el_filter );
1579                                 break;
1580
1581                         default:
1582                                 assert( 0 );
1583                         }
1584
1585                         if ( el->el_e ) {
1586                                 entry_free( el->el_e );
1587                         }
1588                         if ( el->el_a ) {
1589                                 attrs_free( el->el_a );
1590                         }
1591                         if ( !BER_BVISNULL( &el->el_ndn ) ) {
1592                                 ber_memfree( el->el_ndn.bv_val );
1593                         }
1594                         if ( !BER_BVISNULL( &el->el_base ) ) {
1595                                 ber_memfree( el->el_base.bv_val );
1596                         }
1597                         if ( !BER_BVISNULL( &el->el_filter ) ) {
1598                                 ber_memfree( el->el_filter.bv_val );
1599                         }
1600
1601                         tmp = el;
1602                         el = el->el_next;
1603                         ch_free( tmp );
1604                 }
1605
1606                 mi->mi_entry_limbo = NULL;
1607         }
1608
1609         return( 0 );
1610 }
1611
1612 int
1613 monitor_back_config(
1614         BackendInfo     *bi,
1615         const char      *fname,
1616         int             lineno,
1617         int             argc,
1618         char            **argv
1619 )
1620 {
1621         /*
1622          * eventually, will hold backend specific configuration parameters
1623          */
1624         return SLAP_CONF_UNKNOWN;
1625 }
1626
1627 int
1628 monitor_back_db_config(
1629         Backend     *be,
1630         const char  *fname,
1631         int         lineno,
1632         int         argc,
1633         char        **argv
1634 )
1635 {
1636         monitor_info_t  *mi = ( monitor_info_t * )be->be_private;
1637
1638         /*
1639          * eventually, will hold database specific configuration parameters
1640          */
1641         if ( strcasecmp( argv[ 0 ], "l" ) == 0 ) {
1642                 if ( argc != 2 ) {
1643                         return 1;
1644                 }
1645                 
1646                 ber_str2bv( argv[ 1 ], 0, 1, &mi->mi_l );
1647
1648         } else {
1649                 return SLAP_CONF_UNKNOWN;
1650         }
1651
1652         return( 0 );
1653 }
1654
1655 int
1656 monitor_back_db_destroy(
1657         BackendDB       *be
1658 )
1659 {
1660         /*
1661          * FIXME: destroys all the data
1662          */
1663         return 0;
1664 }
1665
1666 #if SLAPD_MONITOR == SLAPD_MOD_DYNAMIC
1667
1668 /* conditionally define the init_module() function */
1669 SLAP_BACKEND_INIT_MODULE( monitor )
1670
1671 #endif /* SLAPD_MONITOR == SLAPD_MOD_DYNAMIC */
1672