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