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