xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-monitor/init.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: init.c,v 1.1.1.3 2010/12/12 15:23:15 adam Exp $	*/
2 
3 /* init.c - initialize monitor backend */
4 /* OpenLDAP: pkg/ldap/servers/slapd/back-monitor/init.c,v 1.125.2.14 2010/04/19 16:53:03 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2001-2010 The OpenLDAP Foundation.
8  * Portions Copyright 2001-2003 Pierangelo Masarati.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by Pierangelo Masarati for inclusion
21  * in OpenLDAP Software.
22  */
23 
24 #include "portable.h"
25 
26 #include <stdio.h>
27 #include <ac/string.h>
28 
29 #include <lutil.h>
30 #include "slap.h"
31 #include "config.h"
32 #include "lber_pvt.h"
33 #include "back-monitor.h"
34 
35 #include "config.h"
36 
37 #undef INTEGRATE_CORE_SCHEMA
38 
39 /*
40  * used by many functions to add description to entries
41  *
42  * WARNING: be_monitor may change as new databases are added,
43  * so it should not be used outside monitor_back_db_init()
44  * until monitor_back_db_open is called.
45  */
46 BackendDB			*be_monitor;
47 
48 static struct monitor_subsys_t	**monitor_subsys;
49 static int			monitor_subsys_opened;
50 static monitor_info_t		monitor_info;
51 static const monitor_extra_t monitor_extra = {
52 	monitor_back_is_configured,
53 	monitor_back_get_subsys,
54 	monitor_back_get_subsys_by_dn,
55 
56 	monitor_back_register_subsys,
57 	monitor_back_register_backend,
58 	monitor_back_register_database,
59 	monitor_back_register_overlay_info,
60 	monitor_back_register_overlay,
61 	monitor_back_register_entry,
62 	monitor_back_register_entry_parent,
63 	monitor_back_register_entry_attrs,
64 	monitor_back_register_entry_callback,
65 
66 	monitor_back_unregister_entry,
67 	monitor_back_unregister_entry_parent,
68 	monitor_back_unregister_entry_attrs,
69 	monitor_back_unregister_entry_callback
70 };
71 
72 
73 /*
74  * subsystem data
75  *
76  * the known subsystems are added to the subsystems
77  * array at backend initialization; other subsystems
78  * may be added by calling monitor_back_register_subsys()
79  * before the database is opened (e.g. by other backends
80  * or by overlays or modules).
81  */
82 static struct monitor_subsys_t known_monitor_subsys[] = {
83 	{
84 		SLAPD_MONITOR_BACKEND_NAME,
85 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
86 		{ BER_BVC( "This subsystem contains information about available backends." ),
87 			BER_BVNULL },
88 		MONITOR_F_PERSISTENT_CH,
89 		monitor_subsys_backend_init,
90 		NULL,	/* destroy */
91 		NULL,   /* update */
92 		NULL,   /* create */
93 		NULL	/* modify */
94        	}, {
95 		SLAPD_MONITOR_CONN_NAME,
96 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
97 		{ BER_BVC( "This subsystem contains information about connections." ),
98 			BER_BVNULL },
99 		MONITOR_F_VOLATILE_CH,
100 		monitor_subsys_conn_init,
101 		NULL,	/* destroy */
102 		NULL,   /* update */
103 		NULL,   /* create */
104 		NULL	/* modify */
105        	}, {
106 		SLAPD_MONITOR_DATABASE_NAME,
107 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
108 		{ BER_BVC( "This subsystem contains information about configured databases." ),
109 			BER_BVNULL },
110 		MONITOR_F_PERSISTENT_CH,
111 		monitor_subsys_database_init,
112 		NULL,	/* destroy */
113 		NULL,   /* update */
114 		NULL,   /* create */
115 		NULL	/* modify */
116        	}, {
117 		SLAPD_MONITOR_LISTENER_NAME,
118 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
119 		{ BER_BVC( "This subsystem contains information about active listeners." ),
120 			BER_BVNULL },
121 		MONITOR_F_PERSISTENT_CH,
122 		monitor_subsys_listener_init,
123 		NULL,	/* destroy */
124 		NULL,	/* update */
125 		NULL,	/* create */
126 		NULL	/* modify */
127        	}, {
128 		SLAPD_MONITOR_LOG_NAME,
129 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
130 		{ BER_BVC( "This subsystem contains information about logging." ),
131 		  	BER_BVC( "Set the attribute \"managedInfo\" to the desired log levels." ),
132 			BER_BVNULL },
133 		MONITOR_F_NONE,
134 		monitor_subsys_log_init,
135 		NULL,	/* destroy */
136 		NULL,	/* update */
137 		NULL,   /* create */
138 		NULL,	/* modify */
139        	}, {
140 		SLAPD_MONITOR_OPS_NAME,
141 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
142 		{ BER_BVC( "This subsystem contains information about performed operations." ),
143 			BER_BVNULL },
144 		MONITOR_F_PERSISTENT_CH,
145 		monitor_subsys_ops_init,
146 		NULL,	/* destroy */
147 		NULL,	/* update */
148 		NULL,   /* create */
149 		NULL,	/* modify */
150        	}, {
151 		SLAPD_MONITOR_OVERLAY_NAME,
152 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
153 		{ BER_BVC( "This subsystem contains information about available overlays." ),
154 			BER_BVNULL },
155 		MONITOR_F_PERSISTENT_CH,
156 		monitor_subsys_overlay_init,
157 		NULL,	/* destroy */
158 		NULL,	/* update */
159 		NULL,   /* create */
160 		NULL,	/* modify */
161 	}, {
162 		SLAPD_MONITOR_SASL_NAME,
163 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
164 		{ BER_BVC( "This subsystem contains information about SASL." ),
165 			BER_BVNULL },
166 		MONITOR_F_NONE,
167 		NULL,   /* init */
168 		NULL,	/* destroy */
169 		NULL,   /* update */
170 		NULL,   /* create */
171 		NULL	/* modify */
172        	}, {
173 		SLAPD_MONITOR_SENT_NAME,
174 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
175 		{ BER_BVC( "This subsystem contains statistics." ),
176 			BER_BVNULL },
177 		MONITOR_F_PERSISTENT_CH,
178 		monitor_subsys_sent_init,
179 		NULL,	/* destroy */
180 		NULL,   /* update */
181 		NULL,   /* create */
182 		NULL,	/* modify */
183        	}, {
184 		SLAPD_MONITOR_THREAD_NAME,
185 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
186 		{ BER_BVC( "This subsystem contains information about threads." ),
187 			BER_BVNULL },
188 		MONITOR_F_PERSISTENT_CH,
189 		monitor_subsys_thread_init,
190 		NULL,	/* destroy */
191 		NULL,   /* update */
192 		NULL,   /* create */
193 		NULL	/* modify */
194        	}, {
195 		SLAPD_MONITOR_TIME_NAME,
196 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
197 		{ BER_BVC( "This subsystem contains information about time." ),
198 			BER_BVNULL },
199 		MONITOR_F_PERSISTENT_CH,
200 		monitor_subsys_time_init,
201 		NULL,	/* destroy */
202 		NULL,   /* update */
203 		NULL,   /* create */
204 		NULL,	/* modify */
205        	}, {
206 		SLAPD_MONITOR_TLS_NAME,
207 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
208 		{ BER_BVC( "This subsystem contains information about TLS." ),
209 			BER_BVNULL },
210 		MONITOR_F_NONE,
211 		NULL,   /* init */
212 		NULL,	/* destroy */
213 		NULL,   /* update */
214 		NULL,   /* create */
215 		NULL	/* modify */
216        	}, {
217 		SLAPD_MONITOR_RWW_NAME,
218 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
219 		{ BER_BVC( "This subsystem contains information about read/write waiters." ),
220 			BER_BVNULL },
221 		MONITOR_F_PERSISTENT_CH,
222 		monitor_subsys_rww_init,
223 		NULL,	/* destroy */
224 		NULL,   /* update */
225 		NULL, 	/* create */
226 		NULL	/* modify */
227        	}, { NULL }
228 };
229 
230 int
231 monitor_subsys_is_opened( void )
232 {
233 	return monitor_subsys_opened;
234 }
235 
236 int
237 monitor_back_register_subsys(
238 	monitor_subsys_t	*ms )
239 {
240 	int	i = 0;
241 
242 	if ( monitor_subsys ) {
243 		for ( ; monitor_subsys[ i ] != NULL; i++ )
244 			/* just count'em */ ;
245 	}
246 
247 	monitor_subsys = ch_realloc( monitor_subsys,
248 			( 2 + i ) * sizeof( monitor_subsys_t * ) );
249 
250 	if ( monitor_subsys == NULL ) {
251 		return -1;
252 	}
253 
254 	monitor_subsys[ i ] = ms;
255 	monitor_subsys[ i + 1 ] = NULL;
256 
257 	/* if a subsystem is registered __AFTER__ subsystem
258 	 * initialization (depending on the sequence the databases
259 	 * are listed in slapd.conf), init it */
260 	if ( monitor_subsys_is_opened() ) {
261 
262 		/* FIXME: this should only be possible
263 		 * if be_monitor is already initialized */
264 		assert( be_monitor != NULL );
265 
266 		if ( ms->mss_open && ( *ms->mss_open )( be_monitor, ms ) ) {
267 			return -1;
268 		}
269 
270 		ms->mss_flags |= MONITOR_F_OPENED;
271 	}
272 
273 	return 0;
274 }
275 
276 enum {
277 	LIMBO_ENTRY,
278 	LIMBO_ENTRY_PARENT,
279 	LIMBO_ATTRS,
280 	LIMBO_CB,
281 	LIMBO_BACKEND,
282 	LIMBO_DATABASE,
283 	LIMBO_OVERLAY_INFO,
284 	LIMBO_OVERLAY,
285 
286 	LIMBO_LAST
287 };
288 
289 typedef struct entry_limbo_t {
290 	int			el_type;
291 	BackendInfo		*el_bi;
292 	BackendDB		*el_be;
293 	slap_overinst		*el_on;
294 	Entry			*el_e;
295 	Attribute		*el_a;
296 	struct berval		*el_ndn;
297 	struct berval		el_nbase;
298 	int			el_scope;
299 	struct berval		el_filter;
300 	monitor_callback_t	*el_cb;
301 	monitor_subsys_t	*el_mss;
302 	unsigned long		el_flags;
303 	struct entry_limbo_t	*el_next;
304 } entry_limbo_t;
305 
306 int
307 monitor_back_is_configured( void )
308 {
309 	return be_monitor != NULL;
310 }
311 
312 int
313 monitor_back_register_backend(
314 	BackendInfo		*bi )
315 {
316 	return -1;
317 }
318 
319 int
320 monitor_back_register_overlay_info(
321 	slap_overinst		*on )
322 {
323 	return -1;
324 }
325 
326 int
327 monitor_back_register_backend_limbo(
328 	BackendInfo		*bi )
329 {
330 	return -1;
331 }
332 
333 int
334 monitor_back_register_database_limbo(
335 	BackendDB		*be,
336 	struct berval		*ndn_out )
337 {
338 	entry_limbo_t	**elpp, el = { 0 };
339 	monitor_info_t 	*mi;
340 
341 	if ( be_monitor == NULL ) {
342 		Debug( LDAP_DEBUG_ANY,
343 			"monitor_back_register_database_limbo: "
344 			"monitor database not configured.\n",
345 			0, 0, 0 );
346 		return -1;
347 	}
348 
349 	mi = ( monitor_info_t * )be_monitor->be_private;
350 
351 
352 	el.el_type = LIMBO_DATABASE;
353 
354 	el.el_be = be->bd_self;
355 	el.el_ndn = ndn_out;
356 
357 	for ( elpp = &mi->mi_entry_limbo;
358 			*elpp;
359 			elpp = &(*elpp)->el_next )
360 		/* go to last */;
361 
362 	*elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
363 
364 	el.el_next = NULL;
365 	**elpp = el;
366 
367 	return 0;
368 }
369 
370 int
371 monitor_back_register_overlay_info_limbo(
372 	slap_overinst		*on )
373 {
374 	return -1;
375 }
376 
377 int
378 monitor_back_register_overlay_limbo(
379 	BackendDB		*be,
380 	struct slap_overinst	*on,
381 	struct berval		*ndn_out )
382 {
383 	entry_limbo_t	**elpp, el = { 0 };
384 	monitor_info_t 	*mi;
385 
386 	if ( be_monitor == NULL ) {
387 		Debug( LDAP_DEBUG_ANY,
388 			"monitor_back_register_overlay_limbo: "
389 			"monitor database not configured.\n",
390 			0, 0, 0 );
391 		return -1;
392 	}
393 
394 	mi = ( monitor_info_t * )be_monitor->be_private;
395 
396 
397 	el.el_type = LIMBO_OVERLAY;
398 
399 	el.el_be = be->bd_self;
400 	el.el_on = on;
401 	el.el_ndn = ndn_out;
402 
403 	for ( elpp = &mi->mi_entry_limbo;
404 			*elpp;
405 			elpp = &(*elpp)->el_next )
406 		/* go to last */;
407 
408 	*elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
409 
410 	el.el_next = NULL;
411 	**elpp = el;
412 
413 	return 0;
414 }
415 
416 int
417 monitor_back_register_entry(
418 	Entry			*e,
419 	monitor_callback_t	*cb,
420 	monitor_subsys_t	*mss,
421 	unsigned long		flags )
422 {
423 	monitor_info_t 	*mi;
424 
425 	if ( be_monitor == NULL ) {
426 		Debug( LDAP_DEBUG_ANY,
427 			"monitor_back_register_entry(\"%s\"): "
428 			"monitor database not configured.\n",
429 			e->e_name.bv_val, 0, 0 );
430 		return -1;
431 	}
432 
433 	mi = ( monitor_info_t * )be_monitor->be_private;
434 
435 	assert( mi != NULL );
436 	assert( e != NULL );
437 	assert( e->e_private == NULL );
438 
439 	if ( monitor_subsys_is_opened() ) {
440 		Entry		*e_parent = NULL,
441 				*e_new = NULL,
442 				**ep = NULL;
443 		struct berval	pdn = BER_BVNULL;
444 		monitor_entry_t *mp = NULL,
445 				*mp_parent = NULL;
446 		int		rc = 0;
447 
448 		if ( monitor_cache_get( mi, &e->e_nname, &e_parent ) == 0 ) {
449 			/* entry exists */
450 			Debug( LDAP_DEBUG_ANY,
451 				"monitor_back_register_entry(\"%s\"): "
452 				"entry exists\n",
453 				e->e_name.bv_val, 0, 0 );
454 			monitor_cache_release( mi, e_parent );
455 			return -1;
456 		}
457 
458 		dnParent( &e->e_nname, &pdn );
459 		if ( monitor_cache_get( mi, &pdn, &e_parent ) != 0 ) {
460 			/* parent does not exist */
461 			Debug( LDAP_DEBUG_ANY,
462 				"monitor_back_register_entry(\"%s\"): "
463 				"parent \"%s\" not found\n",
464 				e->e_name.bv_val, pdn.bv_val, 0 );
465 			return -1;
466 		}
467 
468 		assert( e_parent->e_private != NULL );
469 		mp_parent = ( monitor_entry_t * )e_parent->e_private;
470 
471 		if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
472 			/* entry is volatile; cannot append children */
473 			Debug( LDAP_DEBUG_ANY,
474 				"monitor_back_register_entry(\"%s\"): "
475 				"parent \"%s\" is volatile\n",
476 				e->e_name.bv_val, e_parent->e_name.bv_val, 0 );
477 			rc = -1;
478 			goto done;
479 		}
480 
481 		mp = monitor_entrypriv_create();
482 		if ( mp == NULL ) {
483 			Debug( LDAP_DEBUG_ANY,
484 				"monitor_back_register_entry(\"%s\"): "
485 				"monitor_entrypriv_create() failed\n",
486 				e->e_name.bv_val, 0, 0 );
487 			rc = -1;
488 			goto done;
489 		}
490 
491 		e_new = entry_dup( e );
492 		if ( e_new == NULL ) {
493 			Debug( LDAP_DEBUG_ANY,
494 				"monitor_back_register_entry(\"%s\"): "
495 				"entry_dup() failed\n",
496 				e->e_name.bv_val, 0, 0 );
497 			rc = -1;
498 			goto done;
499 		}
500 
501 		e_new->e_private = ( void * )mp;
502 		if ( mss != NULL ) {
503 			mp->mp_info = mss;
504 			mp->mp_flags = flags;
505 
506 		} else {
507 			mp->mp_info = mp_parent->mp_info;
508 			mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
509 		}
510 		mp->mp_cb = cb;
511 
512 		ep = &mp_parent->mp_children;
513 		for ( ; *ep; ) {
514 			mp_parent = ( monitor_entry_t * )(*ep)->e_private;
515 			ep = &mp_parent->mp_next;
516 		}
517 		*ep = e_new;
518 
519 		if ( monitor_cache_add( mi, e_new ) ) {
520 			Debug( LDAP_DEBUG_ANY,
521 				"monitor_back_register_entry(\"%s\"): "
522 				"unable to add entry\n",
523 				e->e_name.bv_val, 0, 0 );
524 			rc = -1;
525 			goto done;
526 		}
527 
528 done:;
529 		if ( rc ) {
530 			if ( mp ) {
531 				ch_free( mp );
532 			}
533 			if ( e_new ) {
534 				e_new->e_private = NULL;
535 				entry_free( e_new );
536 			}
537 		}
538 
539 		if ( e_parent ) {
540 			monitor_cache_release( mi, e_parent );
541 		}
542 
543 	} else {
544 		entry_limbo_t	**elpp, el = { 0 };
545 
546 		el.el_type = LIMBO_ENTRY;
547 
548 		el.el_e = entry_dup( e );
549 		if ( el.el_e == NULL ) {
550 			Debug( LDAP_DEBUG_ANY,
551 				"monitor_back_register_entry(\"%s\"): "
552 				"entry_dup() failed\n",
553 				e->e_name.bv_val, 0, 0 );
554 			return -1;
555 		}
556 
557 		el.el_cb = cb;
558 		el.el_mss = mss;
559 		el.el_flags = flags;
560 
561 		for ( elpp = &mi->mi_entry_limbo;
562 				*elpp;
563 				elpp = &(*elpp)->el_next )
564 			/* go to last */;
565 
566 		*elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
567 		if ( *elpp == NULL ) {
568 			el.el_e->e_private = NULL;
569 			entry_free( el.el_e );
570 			return -1;
571 		}
572 
573 		el.el_next = NULL;
574 		**elpp = el;
575 	}
576 
577 	return 0;
578 }
579 
580 int
581 monitor_back_register_entry_parent(
582 	Entry			*e,
583 	monitor_callback_t	*cb,
584 	monitor_subsys_t	*mss,
585 	unsigned long		flags,
586 	struct berval		*nbase,
587 	int			scope,
588 	struct berval		*filter )
589 {
590 	monitor_info_t 	*mi;
591 	struct berval	ndn = BER_BVNULL;
592 
593 	if ( be_monitor == NULL ) {
594 		Debug( LDAP_DEBUG_ANY,
595 			"monitor_back_register_entry_parent(base=\"%s\" scope=%s filter=\"%s\"): "
596 			"monitor database not configured.\n",
597 			BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
598 			ldap_pvt_scope2str( scope ),
599 			BER_BVISNULL( filter ) ? "" : filter->bv_val );
600 		return -1;
601 	}
602 
603 	mi = ( monitor_info_t * )be_monitor->be_private;
604 
605 	assert( mi != NULL );
606 	assert( e != NULL );
607 	assert( e->e_private == NULL );
608 
609 	if ( BER_BVISNULL( filter ) ) {
610 		/* need a filter */
611 		Debug( LDAP_DEBUG_ANY,
612 			"monitor_back_register_entry_parent(\"\"): "
613 			"need a valid filter\n",
614 			0, 0, 0 );
615 		return -1;
616 	}
617 
618 	if ( monitor_subsys_is_opened() ) {
619 		Entry		*e_parent = NULL,
620 				*e_new = NULL,
621 				**ep = NULL;
622 		struct berval	e_name = BER_BVNULL,
623 				e_nname = BER_BVNULL;
624 		monitor_entry_t *mp = NULL,
625 				*mp_parent = NULL;
626 		int		rc = 0;
627 
628 		if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
629 			/* entry does not exist */
630 			Debug( LDAP_DEBUG_ANY,
631 				"monitor_back_register_entry_parent(\"\"): "
632 				"base=\"%s\" scope=%s filter=\"%s\": "
633 				"unable to find entry\n",
634 				nbase->bv_val ? nbase->bv_val : "\"\"",
635 				ldap_pvt_scope2str( scope ),
636 				filter->bv_val );
637 			return -1;
638 		}
639 
640 		if ( monitor_cache_get( mi, &ndn, &e_parent ) != 0 ) {
641 			/* entry does not exist */
642 			Debug( LDAP_DEBUG_ANY,
643 				"monitor_back_register_entry_parent(\"%s\"): "
644 				"parent entry does not exist\n",
645 				ndn.bv_val, 0, 0 );
646 			rc = -1;
647 			goto done;
648 		}
649 
650 		assert( e_parent->e_private != NULL );
651 		mp_parent = ( monitor_entry_t * )e_parent->e_private;
652 
653 		if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
654 			/* entry is volatile; cannot append callback */
655 			Debug( LDAP_DEBUG_ANY,
656 				"monitor_back_register_entry_parent(\"%s\"): "
657 				"entry is volatile\n",
658 				e_parent->e_name.bv_val, 0, 0 );
659 			rc = -1;
660 			goto done;
661 		}
662 
663 		build_new_dn( &e_name, &e_parent->e_name, &e->e_name, NULL );
664 		build_new_dn( &e_nname, &e_parent->e_nname, &e->e_nname, NULL );
665 
666 		if ( monitor_cache_get( mi, &e_nname, &e_new ) == 0 ) {
667 			/* entry already exists */
668 			Debug( LDAP_DEBUG_ANY,
669 				"monitor_back_register_entry_parent(\"%s\"): "
670 				"entry already exists\n",
671 				e_name.bv_val, 0, 0 );
672 			monitor_cache_release( mi, e_new );
673 			e_new = NULL;
674 			rc = -1;
675 			goto done;
676 		}
677 
678 		mp = monitor_entrypriv_create();
679 		if ( mp == NULL ) {
680 			Debug( LDAP_DEBUG_ANY,
681 				"monitor_back_register_entry_parent(\"%s\"): "
682 				"monitor_entrypriv_create() failed\n",
683 				e->e_name.bv_val, 0, 0 );
684 			rc = -1;
685 			goto done;
686 		}
687 
688 		e_new = entry_dup( e );
689 		if ( e_new == NULL ) {
690 			Debug( LDAP_DEBUG_ANY,
691 				"monitor_back_register_entry(\"%s\"): "
692 				"entry_dup() failed\n",
693 				e->e_name.bv_val, 0, 0 );
694 			rc = -1;
695 			goto done;
696 		}
697 		ch_free( e_new->e_name.bv_val );
698 		ch_free( e_new->e_nname.bv_val );
699 		e_new->e_name = e_name;
700 		e_new->e_nname = e_nname;
701 
702 		e_new->e_private = ( void * )mp;
703 		if ( mss != NULL ) {
704 			mp->mp_info = mss;
705 			mp->mp_flags = flags;
706 
707 		} else {
708 			mp->mp_info = mp_parent->mp_info;
709 			mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
710 		}
711 		mp->mp_cb = cb;
712 
713 		ep = &mp_parent->mp_children;
714 		for ( ; *ep; ) {
715 			mp_parent = ( monitor_entry_t * )(*ep)->e_private;
716 			ep = &mp_parent->mp_next;
717 		}
718 		*ep = e_new;
719 
720 		if ( monitor_cache_add( mi, e_new ) ) {
721 			Debug( LDAP_DEBUG_ANY,
722 				"monitor_back_register_entry(\"%s\"): "
723 				"unable to add entry\n",
724 				e->e_name.bv_val, 0, 0 );
725 			rc = -1;
726 			goto done;
727 		}
728 
729 done:;
730 		if ( !BER_BVISNULL( &ndn ) ) {
731 			ch_free( ndn.bv_val );
732 		}
733 
734 		if ( rc ) {
735 			if ( mp ) {
736 				ch_free( mp );
737 			}
738 			if ( e_new ) {
739 				e_new->e_private = NULL;
740 				entry_free( e_new );
741 			}
742 		}
743 
744 		if ( e_parent ) {
745 			monitor_cache_release( mi, e_parent );
746 		}
747 
748 	} else {
749 		entry_limbo_t	**elpp = NULL, el = { 0 };
750 
751 		el.el_type = LIMBO_ENTRY_PARENT;
752 
753 		el.el_e = entry_dup( e );
754 		if ( el.el_e == NULL ) {
755 			Debug( LDAP_DEBUG_ANY,
756 				"monitor_back_register_entry(\"%s\"): "
757 				"entry_dup() failed\n",
758 				e->e_name.bv_val, 0, 0 );
759 			goto done_limbo;
760 		}
761 
762 		if ( !BER_BVISNULL( nbase ) ) {
763 			ber_dupbv( &el.el_nbase, nbase );
764 		}
765 
766 		el.el_scope = scope;
767 		if ( !BER_BVISNULL( filter ) ) {
768 			ber_dupbv( &el.el_filter, filter  );
769 		}
770 
771 		el.el_cb = cb;
772 		el.el_mss = mss;
773 		el.el_flags = flags;
774 
775 		for ( elpp = &mi->mi_entry_limbo;
776 				*elpp;
777 				elpp = &(*elpp)->el_next )
778 			/* go to last */;
779 
780 		*elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
781 		if ( *elpp == NULL ) {
782 			goto done_limbo;
783 		}
784 
785 done_limbo:;
786 		if ( *elpp != NULL ) {
787 			el.el_next = NULL;
788 			**elpp = el;
789 
790 		} else {
791 			if ( !BER_BVISNULL( &el.el_filter ) ) {
792 				ch_free( el.el_filter.bv_val );
793 			}
794 			if ( !BER_BVISNULL( &el.el_nbase ) ) {
795 				ch_free( el.el_nbase.bv_val );
796 			}
797 			entry_free( el.el_e );
798 			return -1;
799 		}
800 	}
801 
802 	return 0;
803 }
804 
805 static int
806 monitor_search2ndn_cb( Operation *op, SlapReply *rs )
807 {
808 	if ( rs->sr_type == REP_SEARCH ) {
809 		struct berval	*ndn = op->o_callback->sc_private;
810 
811 		if ( !BER_BVISNULL( ndn ) ) {
812 			rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
813 			ch_free( ndn->bv_val );
814 			BER_BVZERO( ndn );
815 			return rs->sr_err;
816 		}
817 
818 		ber_dupbv( ndn, &rs->sr_entry->e_nname );
819 	}
820 
821 	return 0;
822 }
823 
824 int
825 monitor_search2ndn(
826 	struct berval	*nbase,
827 	int		scope,
828 	struct berval	*filter,
829 	struct berval	*ndn )
830 {
831 	Connection	conn = { 0 };
832 	OperationBuffer	opbuf;
833 	Operation	*op;
834 	void	*thrctx;
835 	SlapReply	rs = { 0 };
836 	slap_callback	cb = { NULL, monitor_search2ndn_cb, NULL, NULL };
837 	int		rc;
838 
839 	BER_BVZERO( ndn );
840 
841 	if ( be_monitor == NULL ) {
842 		return -1;
843 	}
844 
845 	thrctx = ldap_pvt_thread_pool_context();
846 	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
847 	op = &opbuf.ob_op;
848 
849 	op->o_tag = LDAP_REQ_SEARCH;
850 
851 	/* use global malloc for now */
852 	if ( op->o_tmpmemctx ) {
853 		op->o_tmpmemctx = NULL;
854 	}
855 	op->o_tmpmfuncs = &ch_mfuncs;
856 
857 	op->o_bd = be_monitor;
858 	if ( nbase == NULL || BER_BVISNULL( nbase ) ) {
859 		ber_dupbv_x( &op->o_req_dn, &op->o_bd->be_suffix[ 0 ],
860 				op->o_tmpmemctx );
861 		ber_dupbv_x( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ],
862 				op->o_tmpmemctx );
863 
864 	} else {
865 		if ( dnPrettyNormal( NULL, nbase, &op->o_req_dn, &op->o_req_ndn,
866 					op->o_tmpmemctx ) ) {
867 			return -1;
868 		}
869 	}
870 
871 	op->o_callback = &cb;
872 	cb.sc_private = (void *)ndn;
873 
874 	op->ors_scope = scope;
875 	op->ors_filter = str2filter_x( op, filter->bv_val );
876 	if ( op->ors_filter == NULL ) {
877 		rc = LDAP_OTHER;
878 		goto cleanup;
879 	}
880 	ber_dupbv_x( &op->ors_filterstr, filter, op->o_tmpmemctx );
881 	op->ors_attrs = slap_anlist_no_attrs;
882 	op->ors_attrsonly = 0;
883 	op->ors_tlimit = SLAP_NO_LIMIT;
884 	op->ors_slimit = 1;
885 	op->ors_limit = NULL;
886 	op->ors_deref = LDAP_DEREF_NEVER;
887 
888 	op->o_nocaching = 1;
889 	op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
890 
891 	op->o_dn = be_monitor->be_rootdn;
892 	op->o_ndn = be_monitor->be_rootndn;
893 
894 	rc = op->o_bd->be_search( op, &rs );
895 
896 cleanup:;
897 	if ( op->ors_filter != NULL ) {
898 		filter_free_x( op, op->ors_filter, 1 );
899 	}
900 	if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
901 		op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
902 	}
903 	if ( !BER_BVISNULL( &op->o_req_dn ) ) {
904 		op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
905 	}
906 	if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
907 		op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
908 	}
909 
910 	if ( rc != 0 ) {
911 		return rc;
912 	}
913 
914 	switch ( rs.sr_err ) {
915 	case LDAP_SUCCESS:
916 		if ( BER_BVISNULL( ndn ) ) {
917 			rc = -1;
918 		}
919 		break;
920 
921 	case LDAP_SIZELIMIT_EXCEEDED:
922 	default:
923 		if ( !BER_BVISNULL( ndn ) ) {
924 			ber_memfree( ndn->bv_val );
925 			BER_BVZERO( ndn );
926 		}
927 		rc = -1;
928 		break;
929 	}
930 
931 	return rc;
932 }
933 
934 int
935 monitor_back_register_entry_attrs(
936 	struct berval		*ndn_in,
937 	Attribute		*a,
938 	monitor_callback_t	*cb,
939 	struct berval		*nbase,
940 	int			scope,
941 	struct berval		*filter )
942 {
943 	monitor_info_t 	*mi;
944 	struct berval	ndn = BER_BVNULL;
945 	char		*fname = ( a == NULL ? "callback" : "attrs" );
946 
947 	if ( be_monitor == NULL ) {
948 		char		buf[ SLAP_TEXT_BUFLEN ];
949 
950 		snprintf( buf, sizeof( buf ),
951 			"monitor_back_register_entry_%s(base=\"%s\" scope=%s filter=\"%s\"): "
952 			"monitor database not configured.\n",
953 			fname,
954 			BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
955 			ldap_pvt_scope2str( scope ),
956 			BER_BVISNULL( filter ) ? "" : filter->bv_val );
957 		Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
958 
959 		return -1;
960 	}
961 
962 	mi = ( monitor_info_t * )be_monitor->be_private;
963 
964 	assert( mi != NULL );
965 
966 	if ( ndn_in != NULL ) {
967 		ndn = *ndn_in;
968 	}
969 
970 	if ( a == NULL && cb == NULL ) {
971 		/* nothing to do */
972 		return -1;
973 	}
974 
975 	if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
976 			&& BER_BVISNULL( filter ) )
977 	{
978 		/* need a filter */
979 		Debug( LDAP_DEBUG_ANY,
980 			"monitor_back_register_entry_%s(\"\"): "
981 			"need a valid filter\n",
982 			fname, 0, 0 );
983 		return -1;
984 	}
985 
986 	if ( monitor_subsys_is_opened() ) {
987 		Entry			*e = NULL;
988 		Attribute		**atp = NULL;
989 		monitor_entry_t 	*mp = NULL;
990 		monitor_callback_t	**mcp = NULL;
991 		int			rc = 0;
992 		int			freeit = 0;
993 
994 		if ( BER_BVISNULL( &ndn ) ) {
995 			if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
996 				char		buf[ SLAP_TEXT_BUFLEN ];
997 
998 				snprintf( buf, sizeof( buf ),
999 					"monitor_back_register_entry_%s(\"\"): "
1000 					"base=\"%s\" scope=%s filter=\"%s\": "
1001 					"unable to find entry\n",
1002 					fname,
1003 					nbase->bv_val ? nbase->bv_val : "\"\"",
1004 					ldap_pvt_scope2str( scope ),
1005 					filter->bv_val );
1006 
1007 				/* entry does not exist */
1008 				Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
1009 				return -1;
1010 			}
1011 
1012 			freeit = 1;
1013 		}
1014 
1015 		if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
1016 			/* entry does not exist */
1017 			Debug( LDAP_DEBUG_ANY,
1018 				"monitor_back_register_entry_%s(\"%s\"): "
1019 				"entry does not exist\n",
1020 				fname, ndn.bv_val, 0 );
1021 			rc = -1;
1022 			goto done;
1023 		}
1024 
1025 		assert( e->e_private != NULL );
1026 		mp = ( monitor_entry_t * )e->e_private;
1027 
1028 		if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
1029 			/* entry is volatile; cannot append callback */
1030 			Debug( LDAP_DEBUG_ANY,
1031 				"monitor_back_register_entry_%s(\"%s\"): "
1032 				"entry is volatile\n",
1033 				fname, e->e_name.bv_val, 0 );
1034 			rc = -1;
1035 			goto done;
1036 		}
1037 
1038 		if ( a ) {
1039 			for ( atp = &e->e_attrs; *atp; atp = &(*atp)->a_next )
1040 				/* just get to last */ ;
1041 
1042 			for ( ; a != NULL; a = a->a_next ) {
1043 				assert( a->a_desc != NULL );
1044 				assert( a->a_vals != NULL );
1045 
1046 				if ( attr_find( e->e_attrs, a->a_desc ) ) {
1047 					attr_merge( e, a->a_desc, a->a_vals,
1048 						a->a_nvals == a->a_vals ? NULL : a->a_nvals );
1049 
1050 				} else {
1051 					*atp = attr_dup( a );
1052 					if ( *atp == NULL ) {
1053 						Debug( LDAP_DEBUG_ANY,
1054 							"monitor_back_register_entry_%s(\"%s\"): "
1055 							"attr_dup() failed\n",
1056 							fname, e->e_name.bv_val, 0 );
1057 						rc = -1;
1058 						goto done;
1059 					}
1060 					atp = &(*atp)->a_next;
1061 				}
1062 			}
1063 		}
1064 
1065 		if ( cb ) {
1066 			for ( mcp = &mp->mp_cb; *mcp; mcp = &(*mcp)->mc_next )
1067 				/* go to tail */ ;
1068 
1069 			/* NOTE: we do not clear cb->mc_next, so this function
1070 			 * can be used to append a list of callbacks */
1071 			(*mcp) = cb;
1072 		}
1073 
1074 done:;
1075 		if ( rc ) {
1076 			if ( atp && *atp ) {
1077 				attrs_free( *atp );
1078 				*atp = NULL;
1079 			}
1080 		}
1081 
1082 		if ( freeit ) {
1083 			ber_memfree( ndn.bv_val );
1084 		}
1085 
1086 		if ( e ) {
1087 			monitor_cache_release( mi, e );
1088 		}
1089 
1090 	} else {
1091 		entry_limbo_t	**elpp, el = { 0 };
1092 
1093 		el.el_type = LIMBO_ATTRS;
1094 		el.el_ndn = ndn_in;
1095 		if ( !BER_BVISNULL( nbase ) ) {
1096 			ber_dupbv( &el.el_nbase, nbase);
1097 		}
1098 		el.el_scope = scope;
1099 		if ( !BER_BVISNULL( filter ) ) {
1100 			ber_dupbv( &el.el_filter, filter  );
1101 		}
1102 
1103 		el.el_a = attrs_dup( a );
1104 		el.el_cb = cb;
1105 
1106 		for ( elpp = &mi->mi_entry_limbo;
1107 				*elpp;
1108 				elpp = &(*elpp)->el_next )
1109 			/* go to last */;
1110 
1111 		*elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
1112 		if ( *elpp == NULL ) {
1113 			el.el_e->e_private = NULL;
1114 			entry_free( el.el_e );
1115 			return -1;
1116 		}
1117 
1118 		if ( *elpp != NULL ) {
1119 			el.el_next = NULL;
1120 			**elpp = el;
1121 
1122 		} else {
1123 			if ( !BER_BVISNULL( &el.el_filter ) ) {
1124 				ch_free( el.el_filter.bv_val );
1125 			}
1126 			if ( el.el_a != NULL ) {
1127 				attrs_free( el.el_a );
1128 			}
1129 			if ( !BER_BVISNULL( &el.el_nbase ) ) {
1130 				ch_free( &el.el_nbase.bv_val );
1131 			}
1132 			return -1;
1133 		}
1134 	}
1135 
1136 	return 0;
1137 }
1138 
1139 int
1140 monitor_back_register_entry_callback(
1141 	struct berval		*ndn,
1142 	monitor_callback_t	*cb,
1143 	struct berval		*nbase,
1144 	int			scope,
1145 	struct berval		*filter )
1146 {
1147 	return monitor_back_register_entry_attrs( ndn, NULL, cb,
1148 			nbase, scope, filter );
1149 }
1150 
1151 /*
1152  * TODO: add corresponding calls to remove installed callbacks, entries
1153  * and so, in case the entity that installed them is removed (e.g. a
1154  * database, via back-config)
1155  */
1156 int
1157 monitor_back_unregister_entry(
1158 	struct berval	*ndn )
1159 {
1160 	monitor_info_t 	*mi;
1161 
1162 	if ( be_monitor == NULL ) {
1163 		Debug( LDAP_DEBUG_ANY,
1164 			"monitor_back_unregister_entry(\"%s\"): "
1165 			"monitor database not configured.\n",
1166 			ndn->bv_val, 0, 0 );
1167 
1168 		return -1;
1169 	}
1170 
1171 	/* entry will be regularly freed, and resources released
1172 	 * according to callbacks */
1173 	if ( slapd_shutdown ) {
1174 		return 0;
1175 	}
1176 
1177 	mi = ( monitor_info_t * )be_monitor->be_private;
1178 
1179 	assert( mi != NULL );
1180 
1181 	if ( monitor_subsys_is_opened() ) {
1182 		Entry			*e = NULL;
1183 		monitor_entry_t 	*mp = NULL;
1184 		monitor_callback_t	*cb = NULL;
1185 
1186 		if ( monitor_cache_remove( mi, ndn, &e ) != 0 ) {
1187 			/* entry does not exist */
1188 			Debug( LDAP_DEBUG_ANY,
1189 				"monitor_back_unregister_entry(\"%s\"): "
1190 				"entry removal failed.\n",
1191 				ndn->bv_val, 0, 0 );
1192 			return -1;
1193 		}
1194 
1195 		mp = (monitor_entry_t *)e->e_private;
1196 		assert( mp != NULL );
1197 
1198 		for ( cb = mp->mp_cb; cb != NULL; ) {
1199 			monitor_callback_t	*next = cb->mc_next;
1200 
1201 			if ( cb->mc_free ) {
1202 				(void)cb->mc_free( e, &cb->mc_private );
1203 			}
1204 			ch_free( cb );
1205 
1206 			cb = next;
1207 		}
1208 
1209 		ch_free( mp );
1210 		e->e_private = NULL;
1211 		entry_free( e );
1212 
1213 	} else {
1214 		entry_limbo_t	**elpp;
1215 
1216 		for ( elpp = &mi->mi_entry_limbo;
1217 			*elpp;
1218 			elpp = &(*elpp)->el_next )
1219 		{
1220 			entry_limbo_t	*elp = *elpp;
1221 
1222 			if ( elp->el_type == LIMBO_ENTRY
1223 				&& dn_match( ndn, &elp->el_e->e_nname ) )
1224 			{
1225 				monitor_callback_t	*cb, *next;
1226 
1227 				for ( cb = elp->el_cb; cb; cb = next ) {
1228 					/* FIXME: call callbacks? */
1229 					next = cb->mc_next;
1230 					if ( cb->mc_dispose ) {
1231 						cb->mc_dispose( &cb->mc_private );
1232 					}
1233 					ch_free( cb );
1234 				}
1235 				assert( elp->el_e != NULL );
1236 				elp->el_e->e_private = NULL;
1237 				entry_free( elp->el_e );
1238 				*elpp = elp->el_next;
1239 				ch_free( elp );
1240 				elpp = NULL;
1241 				break;
1242 			}
1243 		}
1244 
1245 		if ( elpp != NULL ) {
1246 			/* not found!  where did it go? */
1247 			return 1;
1248 		}
1249 	}
1250 
1251 	return 0;
1252 }
1253 
1254 int
1255 monitor_back_unregister_entry_parent(
1256 	struct berval		*nrdn,
1257 	monitor_callback_t	*target_cb,
1258 	struct berval		*nbase,
1259 	int			scope,
1260 	struct berval		*filter )
1261 {
1262 	monitor_info_t 	*mi;
1263 	struct berval	ndn = BER_BVNULL;
1264 
1265 	if ( be_monitor == NULL ) {
1266 		Debug( LDAP_DEBUG_ANY,
1267 			"monitor_back_unregister_entry_parent(base=\"%s\" scope=%s filter=\"%s\"): "
1268 			"monitor database not configured.\n",
1269 			BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
1270 			ldap_pvt_scope2str( scope ),
1271 			BER_BVISNULL( filter ) ? "" : filter->bv_val );
1272 
1273 		return -1;
1274 	}
1275 
1276 	/* entry will be regularly freed, and resources released
1277 	 * according to callbacks */
1278 	if ( slapd_shutdown ) {
1279 		return 0;
1280 	}
1281 
1282 	mi = ( monitor_info_t * )be_monitor->be_private;
1283 
1284 	assert( mi != NULL );
1285 
1286 	if ( ( nrdn == NULL || BER_BVISNULL( nrdn ) )
1287 			&& BER_BVISNULL( filter ) )
1288 	{
1289 		/* need a filter */
1290 		Debug( LDAP_DEBUG_ANY,
1291 			"monitor_back_unregister_entry_parent(\"\"): "
1292 			"need a valid filter\n",
1293 			0, 0, 0 );
1294 		return -1;
1295 	}
1296 
1297 	if ( monitor_subsys_is_opened() ) {
1298 		Entry			*e = NULL;
1299 		monitor_entry_t 	*mp = NULL;
1300 
1301 		if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
1302 			/* entry does not exist */
1303 			Debug( LDAP_DEBUG_ANY,
1304 				"monitor_back_unregister_entry_parent(\"\"): "
1305 				"base=\"%s\" scope=%s filter=\"%s\": "
1306 				"unable to find entry\n",
1307 				nbase->bv_val ? nbase->bv_val : "\"\"",
1308 				ldap_pvt_scope2str( scope ),
1309 				filter->bv_val );
1310 			return -1;
1311 		}
1312 
1313 		if ( monitor_cache_remove( mi, &ndn, &e ) != 0 ) {
1314 			/* entry does not exist */
1315 			Debug( LDAP_DEBUG_ANY,
1316 				"monitor_back_unregister_entry(\"%s\"): "
1317 				"entry removal failed.\n",
1318 				ndn.bv_val, 0, 0 );
1319 			ber_memfree( ndn.bv_val );
1320 			return -1;
1321 		}
1322 		ber_memfree( ndn.bv_val );
1323 
1324 		mp = (monitor_entry_t *)e->e_private;
1325 		assert( mp != NULL );
1326 
1327 		if ( target_cb != NULL ) {
1328 			monitor_callback_t	**cbp;
1329 
1330 			for ( cbp = &mp->mp_cb; *cbp != NULL; cbp = &(*cbp)->mc_next ) {
1331 				if ( *cbp == target_cb ) {
1332 					if ( (*cbp)->mc_free ) {
1333 						(void)(*cbp)->mc_free( e, &(*cbp)->mc_private );
1334 					}
1335 					*cbp = (*cbp)->mc_next;
1336 					ch_free( target_cb );
1337 					break;
1338 				}
1339 			}
1340 		}
1341 
1342 
1343 		ch_free( mp );
1344 		e->e_private = NULL;
1345 		entry_free( e );
1346 
1347 	} else {
1348 		entry_limbo_t	**elpp;
1349 
1350 		for ( elpp = &mi->mi_entry_limbo;
1351 			*elpp;
1352 			elpp = &(*elpp)->el_next )
1353 		{
1354 			entry_limbo_t	*elp = *elpp;
1355 
1356 			if ( elp->el_type == LIMBO_ENTRY_PARENT
1357 				&& dn_match( nrdn, &elp->el_e->e_nname )
1358 				&& dn_match( nbase, &elp->el_nbase )
1359 				&& scope == elp->el_scope
1360 				&& bvmatch( filter, &elp->el_filter ) )
1361 			{
1362 				monitor_callback_t	*cb, *next;
1363 
1364 				for ( cb = elp->el_cb; cb; cb = next ) {
1365 					/* FIXME: call callbacks? */
1366 					next = cb->mc_next;
1367 					if ( cb->mc_dispose ) {
1368 						cb->mc_dispose( &cb->mc_private );
1369 					}
1370 					ch_free( cb );
1371 				}
1372 				assert( elp->el_e != NULL );
1373 				elp->el_e->e_private = NULL;
1374 				entry_free( elp->el_e );
1375 				if ( !BER_BVISNULL( &elp->el_nbase ) ) {
1376 					ch_free( elp->el_nbase.bv_val );
1377 				}
1378 				if ( !BER_BVISNULL( &elp->el_filter ) ) {
1379 					ch_free( elp->el_filter.bv_val );
1380 				}
1381 				*elpp = elp->el_next;
1382 				ch_free( elp );
1383 				elpp = NULL;
1384 				break;
1385 			}
1386 		}
1387 
1388 		if ( elpp != NULL ) {
1389 			/* not found!  where did it go? */
1390 			return 1;
1391 		}
1392 	}
1393 
1394 	return 0;
1395 }
1396 
1397 int
1398 monitor_back_unregister_entry_attrs(
1399 	struct berval		*ndn_in,
1400 	Attribute		*target_a,
1401 	monitor_callback_t	*target_cb,
1402 	struct berval		*nbase,
1403 	int			scope,
1404 	struct berval		*filter )
1405 {
1406 	monitor_info_t 	*mi;
1407 	struct berval	ndn = BER_BVNULL;
1408 	char		*fname = ( target_a == NULL ? "callback" : "attrs" );
1409 
1410 	if ( be_monitor == NULL ) {
1411 		char		buf[ SLAP_TEXT_BUFLEN ];
1412 
1413 		snprintf( buf, sizeof( buf ),
1414 			"monitor_back_unregister_entry_%s(base=\"%s\" scope=%s filter=\"%s\"): "
1415 			"monitor database not configured.\n",
1416 			fname,
1417 			BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
1418 			ldap_pvt_scope2str( scope ),
1419 			BER_BVISNULL( filter ) ? "" : filter->bv_val );
1420 		Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
1421 
1422 		return -1;
1423 	}
1424 
1425 	/* entry will be regularly freed, and resources released
1426 	 * according to callbacks */
1427 	if ( slapd_shutdown ) {
1428 		return 0;
1429 	}
1430 
1431 	mi = ( monitor_info_t * )be_monitor->be_private;
1432 
1433 	assert( mi != NULL );
1434 
1435 	if ( ndn_in != NULL ) {
1436 		ndn = *ndn_in;
1437 	}
1438 
1439 	if ( target_a == NULL && target_cb == NULL ) {
1440 		/* nothing to do */
1441 		return -1;
1442 	}
1443 
1444 	if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
1445 			&& BER_BVISNULL( filter ) )
1446 	{
1447 		/* need a filter */
1448 		Debug( LDAP_DEBUG_ANY,
1449 			"monitor_back_unregister_entry_%s(\"\"): "
1450 			"need a valid filter\n",
1451 			fname, 0, 0 );
1452 		return -1;
1453 	}
1454 
1455 	if ( monitor_subsys_is_opened() ) {
1456 		Entry			*e = NULL;
1457 		monitor_entry_t 	*mp = NULL;
1458 		int			freeit = 0;
1459 
1460 		if ( BER_BVISNULL( &ndn ) ) {
1461 			if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
1462 				char		buf[ SLAP_TEXT_BUFLEN ];
1463 
1464 				snprintf( buf, sizeof( buf ),
1465 					"monitor_back_unregister_entry_%s(\"\"): "
1466 					"base=\"%s\" scope=%d filter=\"%s\": "
1467 					"unable to find entry\n",
1468 					fname,
1469 					nbase->bv_val ? nbase->bv_val : "\"\"",
1470 					scope, filter->bv_val );
1471 
1472 				/* entry does not exist */
1473 				Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
1474 				return -1;
1475 			}
1476 
1477 			freeit = 1;
1478 		}
1479 
1480 		if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
1481 			/* entry does not exist */
1482 			Debug( LDAP_DEBUG_ANY,
1483 				"monitor_back_unregister_entry(\"%s\"): "
1484 				"entry removal failed.\n",
1485 				ndn.bv_val, 0, 0 );
1486 			return -1;
1487 		}
1488 
1489 		mp = (monitor_entry_t *)e->e_private;
1490 		assert( mp != NULL );
1491 
1492 		if ( target_cb != NULL ) {
1493 			monitor_callback_t	**cbp;
1494 
1495 			for ( cbp = &mp->mp_cb; *cbp != NULL; cbp = &(*cbp)->mc_next ) {
1496 				if ( *cbp == target_cb ) {
1497 					if ( (*cbp)->mc_free ) {
1498 						(void)(*cbp)->mc_free( e, &(*cbp)->mc_private );
1499 					}
1500 					*cbp = (*cbp)->mc_next;
1501 					ch_free( target_cb );
1502 					break;
1503 				}
1504 			}
1505 		}
1506 
1507 		if ( target_a != NULL ) {
1508 			Attribute	*a;
1509 
1510 			for ( a = target_a; a != NULL; a = a->a_next ) {
1511 				Modification	mod = { 0 };
1512 				const char	*text;
1513 				char		textbuf[ SLAP_TEXT_BUFLEN ];
1514 
1515 				mod.sm_op = LDAP_MOD_DELETE;
1516 				mod.sm_desc = a->a_desc;
1517 				mod.sm_values = a->a_vals;
1518 				mod.sm_nvalues = a->a_nvals;
1519 
1520 				(void)modify_delete_values( e, &mod, 1,
1521 					&text, textbuf, sizeof( textbuf ) );
1522 			}
1523 		}
1524 
1525 		if ( freeit ) {
1526 			ber_memfree( ndn.bv_val );
1527 		}
1528 
1529 		monitor_cache_release( mi, e );
1530 
1531 	} else {
1532 		entry_limbo_t	**elpp;
1533 
1534 		for ( elpp = &mi->mi_entry_limbo;
1535 			*elpp;
1536 			elpp = &(*elpp)->el_next )
1537 		{
1538 			entry_limbo_t	*elp = *elpp;
1539 
1540 			if ( elp->el_type == LIMBO_ATTRS
1541 				&& dn_match( nbase, &elp->el_nbase )
1542 				&& scope == elp->el_scope
1543 				&& bvmatch( filter, &elp->el_filter ) )
1544 			{
1545 				monitor_callback_t	*cb, *next;
1546 
1547 				for ( cb = elp->el_cb; cb; cb = next ) {
1548 					/* FIXME: call callbacks? */
1549 					next = cb->mc_next;
1550 					if ( cb->mc_dispose ) {
1551 						cb->mc_dispose( &cb->mc_private );
1552 					}
1553 					ch_free( cb );
1554 				}
1555 				assert( elp->el_e == NULL );
1556 				if ( elp->el_a != NULL ) {
1557 					attrs_free( elp->el_a );
1558 				}
1559 				if ( !BER_BVISNULL( &elp->el_nbase ) ) {
1560 					ch_free( elp->el_nbase.bv_val );
1561 				}
1562 				if ( !BER_BVISNULL( &elp->el_filter ) ) {
1563 					ch_free( elp->el_filter.bv_val );
1564 				}
1565 				*elpp = elp->el_next;
1566 				ch_free( elp );
1567 				elpp = NULL;
1568 				break;
1569 			}
1570 		}
1571 
1572 		if ( elpp != NULL ) {
1573 			/* not found!  where did it go? */
1574 			return 1;
1575 		}
1576 	}
1577 
1578 	return 0;
1579 }
1580 
1581 int
1582 monitor_back_unregister_entry_callback(
1583 	struct berval		*ndn,
1584 	monitor_callback_t	*cb,
1585 	struct berval		*nbase,
1586 	int			scope,
1587 	struct berval		*filter )
1588 {
1589 	/* TODO: lookup entry (by ndn, if not NULL, and/or by callback);
1590 	 * unregister the callback; if a is not null, unregister the
1591 	 * given attrs.  In any case, call cb->cb_free */
1592 	return monitor_back_unregister_entry_attrs( ndn,
1593 		NULL, cb, nbase, scope, filter );
1594 }
1595 
1596 monitor_subsys_t *
1597 monitor_back_get_subsys( const char *name )
1598 {
1599 	if ( monitor_subsys != NULL ) {
1600 		int	i;
1601 
1602 		for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
1603 			if ( strcasecmp( monitor_subsys[ i ]->mss_name, name ) == 0 ) {
1604 				return monitor_subsys[ i ];
1605 			}
1606 		}
1607 	}
1608 
1609 	return NULL;
1610 }
1611 
1612 monitor_subsys_t *
1613 monitor_back_get_subsys_by_dn(
1614 	struct berval	*ndn,
1615 	int		sub )
1616 {
1617 	if ( monitor_subsys != NULL ) {
1618 		int	i;
1619 
1620 		if ( sub ) {
1621 			for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
1622 				if ( dnIsSuffix( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
1623 					return monitor_subsys[ i ];
1624 				}
1625 			}
1626 
1627 		} else {
1628 			for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
1629 				if ( dn_match( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
1630 					return monitor_subsys[ i ];
1631 				}
1632 			}
1633 		}
1634 	}
1635 
1636 	return NULL;
1637 }
1638 
1639 int
1640 monitor_back_initialize(
1641 	BackendInfo	*bi )
1642 {
1643 	static char		*controls[] = {
1644 		LDAP_CONTROL_MANAGEDSAIT,
1645 		NULL
1646 	};
1647 
1648 	static ConfigTable monitorcfg[] = {
1649 		{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
1650 			NULL, NULL, NULL, NULL }
1651 	};
1652 
1653 	static ConfigOCs monitorocs[] = {
1654 		{ "( OLcfgDbOc:4.1 "
1655 			"NAME 'olcMonitorConfig' "
1656 			"DESC 'Monitor backend configuration' "
1657 			"SUP olcDatabaseConfig "
1658 			")",
1659 			 	Cft_Database, monitorcfg },
1660 		{ NULL, 0, NULL }
1661 	};
1662 
1663 	struct m_s {
1664 		char	*schema;
1665 		slap_mask_t flags;
1666 		int	offset;
1667 	} moc[] = {
1668 		{ "( 1.3.6.1.4.1.4203.666.3.16.1 "
1669 			"NAME 'monitor' "
1670 			"DESC 'OpenLDAP system monitoring' "
1671 			"SUP top STRUCTURAL "
1672 			"MUST cn "
1673 			"MAY ( "
1674 				"description "
1675 				"$ seeAlso "
1676 				"$ labeledURI "
1677 				"$ monitoredInfo "
1678 				"$ managedInfo "
1679 				"$ monitorOverlay "
1680 			") )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1681 			offsetof(monitor_info_t, mi_oc_monitor) },
1682 		{ "( 1.3.6.1.4.1.4203.666.3.16.2 "
1683 			"NAME 'monitorServer' "
1684 			"DESC 'Server monitoring root entry' "
1685 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1686 			offsetof(monitor_info_t, mi_oc_monitorServer) },
1687 		{ "( 1.3.6.1.4.1.4203.666.3.16.3 "
1688 			"NAME 'monitorContainer' "
1689 			"DESC 'monitor container class' "
1690 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1691 			offsetof(monitor_info_t, mi_oc_monitorContainer) },
1692 		{ "( 1.3.6.1.4.1.4203.666.3.16.4 "
1693 			"NAME 'monitorCounterObject' "
1694 			"DESC 'monitor counter class' "
1695 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1696 			offsetof(monitor_info_t, mi_oc_monitorCounterObject) },
1697 		{ "( 1.3.6.1.4.1.4203.666.3.16.5 "
1698 			"NAME 'monitorOperation' "
1699 			"DESC 'monitor operation class' "
1700 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1701 			offsetof(monitor_info_t, mi_oc_monitorOperation) },
1702 		{ "( 1.3.6.1.4.1.4203.666.3.16.6 "
1703 			"NAME 'monitorConnection' "
1704 			"DESC 'monitor connection class' "
1705 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1706 			offsetof(monitor_info_t, mi_oc_monitorConnection) },
1707 		{ "( 1.3.6.1.4.1.4203.666.3.16.7 "
1708 			"NAME 'managedObject' "
1709 			"DESC 'monitor managed entity class' "
1710 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1711 			offsetof(monitor_info_t, mi_oc_managedObject) },
1712 		{ "( 1.3.6.1.4.1.4203.666.3.16.8 "
1713 			"NAME 'monitoredObject' "
1714 			"DESC 'monitor monitored entity class' "
1715 			"SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
1716 			offsetof(monitor_info_t, mi_oc_monitoredObject) },
1717 		{ NULL, 0, -1 }
1718 	}, mat[] = {
1719 		{ "( 1.3.6.1.4.1.4203.666.1.55.1 "
1720 			"NAME 'monitoredInfo' "
1721 			"DESC 'monitored info' "
1722 			/* "SUP name " */
1723 			"EQUALITY caseIgnoreMatch "
1724 			"SUBSTR caseIgnoreSubstringsMatch "
1725 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} "
1726 			"NO-USER-MODIFICATION "
1727 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1728 			offsetof(monitor_info_t, mi_ad_monitoredInfo) },
1729 		{ "( 1.3.6.1.4.1.4203.666.1.55.2 "
1730 			"NAME 'managedInfo' "
1731 			"DESC 'monitor managed info' "
1732 			"SUP name )", SLAP_AT_HIDE,
1733 			offsetof(monitor_info_t, mi_ad_managedInfo) },
1734 		{ "( 1.3.6.1.4.1.4203.666.1.55.3 "
1735 			"NAME 'monitorCounter' "
1736 			"DESC 'monitor counter' "
1737 			"EQUALITY integerMatch "
1738 			"ORDERING integerOrderingMatch "
1739 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
1740 			"NO-USER-MODIFICATION "
1741 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1742 			offsetof(monitor_info_t, mi_ad_monitorCounter) },
1743 		{ "( 1.3.6.1.4.1.4203.666.1.55.4 "
1744 			"NAME 'monitorOpCompleted' "
1745 			"DESC 'monitor completed operations' "
1746 			"SUP monitorCounter "
1747 			"NO-USER-MODIFICATION "
1748 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1749 			offsetof(monitor_info_t, mi_ad_monitorOpCompleted) },
1750 		{ "( 1.3.6.1.4.1.4203.666.1.55.5 "
1751 			"NAME 'monitorOpInitiated' "
1752 			"DESC 'monitor initiated operations' "
1753 			"SUP monitorCounter "
1754 			"NO-USER-MODIFICATION "
1755 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1756 			offsetof(monitor_info_t, mi_ad_monitorOpInitiated) },
1757 		{ "( 1.3.6.1.4.1.4203.666.1.55.6 "
1758 			"NAME 'monitorConnectionNumber' "
1759 			"DESC 'monitor connection number' "
1760 			"SUP monitorCounter "
1761 			"NO-USER-MODIFICATION "
1762 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1763 			offsetof(monitor_info_t, mi_ad_monitorConnectionNumber) },
1764 		{ "( 1.3.6.1.4.1.4203.666.1.55.7 "
1765 			"NAME 'monitorConnectionAuthzDN' "
1766 			"DESC 'monitor connection authorization DN' "
1767 			/* "SUP distinguishedName " */
1768 			"EQUALITY distinguishedNameMatch "
1769 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
1770 			"NO-USER-MODIFICATION "
1771 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1772 			offsetof(monitor_info_t, mi_ad_monitorConnectionAuthzDN) },
1773 		{ "( 1.3.6.1.4.1.4203.666.1.55.8 "
1774 			"NAME 'monitorConnectionLocalAddress' "
1775 			"DESC 'monitor connection local address' "
1776 			"SUP monitoredInfo "
1777 			"NO-USER-MODIFICATION "
1778 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1779 			offsetof(monitor_info_t, mi_ad_monitorConnectionLocalAddress) },
1780 		{ "( 1.3.6.1.4.1.4203.666.1.55.9 "
1781 			"NAME 'monitorConnectionPeerAddress' "
1782 			"DESC 'monitor connection peer address' "
1783 			"SUP monitoredInfo "
1784 			"NO-USER-MODIFICATION "
1785 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1786 			offsetof(monitor_info_t, mi_ad_monitorConnectionPeerAddress) },
1787 		{ "( 1.3.6.1.4.1.4203.666.1.55.10 "
1788 			"NAME 'monitorTimestamp' "
1789 			"DESC 'monitor timestamp' "
1790 			"EQUALITY generalizedTimeMatch "
1791 			"ORDERING generalizedTimeOrderingMatch "
1792 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
1793 			"SINGLE-VALUE "
1794 			"NO-USER-MODIFICATION "
1795 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1796 			offsetof(monitor_info_t, mi_ad_monitorTimestamp) },
1797 		{ "( 1.3.6.1.4.1.4203.666.1.55.11 "
1798 			"NAME 'monitorOverlay' "
1799 			"DESC 'name of overlays defined for a given database' "
1800 			"SUP monitoredInfo "
1801 			"NO-USER-MODIFICATION "
1802 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1803 			offsetof(monitor_info_t, mi_ad_monitorOverlay) },
1804 		{ "( 1.3.6.1.4.1.4203.666.1.55.12 "
1805 			"NAME 'readOnly' "
1806 			"DESC 'read/write status of a given database' "
1807 			"EQUALITY booleanMatch "
1808 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
1809 			"SINGLE-VALUE "
1810 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1811 			offsetof(monitor_info_t, mi_ad_readOnly) },
1812 		{ "( 1.3.6.1.4.1.4203.666.1.55.13 "
1813 			"NAME 'restrictedOperation' "
1814 			"DESC 'name of restricted operation for a given database' "
1815 			"SUP managedInfo )", SLAP_AT_HIDE,
1816 			offsetof(monitor_info_t, mi_ad_restrictedOperation ) },
1817 		{ "( 1.3.6.1.4.1.4203.666.1.55.14 "
1818 			"NAME 'monitorConnectionProtocol' "
1819 			"DESC 'monitor connection protocol' "
1820 			"SUP monitoredInfo "
1821 			"NO-USER-MODIFICATION "
1822 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1823 			offsetof(monitor_info_t, mi_ad_monitorConnectionProtocol) },
1824 		{ "( 1.3.6.1.4.1.4203.666.1.55.15 "
1825 			"NAME 'monitorConnectionOpsReceived' "
1826 			"DESC 'monitor number of operations received by the connection' "
1827 			"SUP monitorCounter "
1828 			"NO-USER-MODIFICATION "
1829 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1830 			offsetof(monitor_info_t, mi_ad_monitorConnectionOpsReceived) },
1831 		{ "( 1.3.6.1.4.1.4203.666.1.55.16 "
1832 			"NAME 'monitorConnectionOpsExecuting' "
1833 			"DESC 'monitor number of operations in execution within the connection' "
1834 			"SUP monitorCounter "
1835 			"NO-USER-MODIFICATION "
1836 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1837 			offsetof(monitor_info_t, mi_ad_monitorConnectionOpsExecuting) },
1838 		{ "( 1.3.6.1.4.1.4203.666.1.55.17 "
1839 			"NAME 'monitorConnectionOpsPending' "
1840 			"DESC 'monitor number of pending operations within the connection' "
1841 			"SUP monitorCounter "
1842 			"NO-USER-MODIFICATION "
1843 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1844 			offsetof(monitor_info_t, mi_ad_monitorConnectionOpsPending) },
1845 		{ "( 1.3.6.1.4.1.4203.666.1.55.18 "
1846 			"NAME 'monitorConnectionOpsCompleted' "
1847 			"DESC 'monitor number of operations completed within the connection' "
1848 			"SUP monitorCounter "
1849 			"NO-USER-MODIFICATION "
1850 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1851 			offsetof(monitor_info_t, mi_ad_monitorConnectionOpsCompleted) },
1852 		{ "( 1.3.6.1.4.1.4203.666.1.55.19 "
1853 			"NAME 'monitorConnectionGet' "
1854 			"DESC 'number of times connection_get() was called so far' "
1855 			"SUP monitorCounter "
1856 			"NO-USER-MODIFICATION "
1857 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1858 			offsetof(monitor_info_t, mi_ad_monitorConnectionGet) },
1859 		{ "( 1.3.6.1.4.1.4203.666.1.55.20 "
1860 			"NAME 'monitorConnectionRead' "
1861 			"DESC 'number of times connection_read() was called so far' "
1862 			"SUP monitorCounter "
1863 			"NO-USER-MODIFICATION "
1864 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1865 			offsetof(monitor_info_t, mi_ad_monitorConnectionRead) },
1866 		{ "( 1.3.6.1.4.1.4203.666.1.55.21 "
1867 			"NAME 'monitorConnectionWrite' "
1868 			"DESC 'number of times connection_write() was called so far' "
1869 			"SUP monitorCounter "
1870 			"NO-USER-MODIFICATION "
1871 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1872 			offsetof(monitor_info_t, mi_ad_monitorConnectionWrite) },
1873 		{ "( 1.3.6.1.4.1.4203.666.1.55.22 "
1874 			"NAME 'monitorConnectionMask' "
1875 			"DESC 'monitor connection mask' "
1876 			"SUP monitoredInfo "
1877 			"NO-USER-MODIFICATION "
1878 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1879 			offsetof(monitor_info_t, mi_ad_monitorConnectionMask) },
1880 		{ "( 1.3.6.1.4.1.4203.666.1.55.23 "
1881 			"NAME 'monitorConnectionListener' "
1882 			"DESC 'monitor connection listener' "
1883 			"SUP monitoredInfo "
1884 			"NO-USER-MODIFICATION "
1885 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1886 			offsetof(monitor_info_t, mi_ad_monitorConnectionListener) },
1887 		{ "( 1.3.6.1.4.1.4203.666.1.55.24 "
1888 			"NAME 'monitorConnectionPeerDomain' "
1889 			"DESC 'monitor connection peer domain' "
1890 			"SUP monitoredInfo "
1891 			"NO-USER-MODIFICATION "
1892 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1893 			offsetof(monitor_info_t, mi_ad_monitorConnectionPeerDomain) },
1894 		{ "( 1.3.6.1.4.1.4203.666.1.55.25 "
1895 			"NAME 'monitorConnectionStartTime' "
1896 			"DESC 'monitor connection start time' "
1897 			"SUP monitorTimestamp "
1898 			"SINGLE-VALUE "
1899 			"NO-USER-MODIFICATION "
1900 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1901 			offsetof(monitor_info_t, mi_ad_monitorConnectionStartTime) },
1902 		{ "( 1.3.6.1.4.1.4203.666.1.55.26 "
1903 			"NAME 'monitorConnectionActivityTime' "
1904 			"DESC 'monitor connection activity time' "
1905 			"SUP monitorTimestamp "
1906 			"SINGLE-VALUE "
1907 			"NO-USER-MODIFICATION "
1908 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1909 			offsetof(monitor_info_t, mi_ad_monitorConnectionActivityTime) },
1910 		{ "( 1.3.6.1.4.1.4203.666.1.55.27 "
1911 			"NAME 'monitorIsShadow' "
1912 			"DESC 'TRUE if the database is shadow' "
1913 			"EQUALITY booleanMatch "
1914 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
1915 			"SINGLE-VALUE "
1916 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1917 			offsetof(monitor_info_t, mi_ad_monitorIsShadow) },
1918 		{ "( 1.3.6.1.4.1.4203.666.1.55.28 "
1919 			"NAME 'monitorUpdateRef' "
1920 			"DESC 'update referral for shadow databases' "
1921 			"SUP monitoredInfo "
1922 			"SINGLE-VALUE "
1923 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1924 			offsetof(monitor_info_t, mi_ad_monitorUpdateRef) },
1925 		{ "( 1.3.6.1.4.1.4203.666.1.55.29 "
1926 			"NAME 'monitorRuntimeConfig' "
1927 			"DESC 'TRUE if component allows runtime configuration' "
1928 			"EQUALITY booleanMatch "
1929 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
1930 			"SINGLE-VALUE "
1931 			"USAGE dSAOperation )", SLAP_AT_HIDE,
1932 			offsetof(monitor_info_t, mi_ad_monitorRuntimeConfig) },
1933 		{ "( 1.3.6.1.4.1.4203.666.1.55.30 "
1934 			"NAME 'monitorSuperiorDN' "
1935 			"DESC 'monitor superior DN' "
1936 			/* "SUP distinguishedName " */
1937 			"EQUALITY distinguishedNameMatch "
1938 			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
1939 			"NO-USER-MODIFICATION "
1940 			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
1941 			offsetof(monitor_info_t, mi_ad_monitorSuperiorDN) },
1942 		{ NULL, 0, -1 }
1943 	};
1944 
1945 	static struct {
1946 		char			*name;
1947 		char			*oid;
1948 	}		s_oid[] = {
1949 		{ "olmAttributes",			"1.3.6.1.4.1.4203.666.1.55" },
1950 		{ "olmSubSystemAttributes",		"olmAttributes:0" },
1951 		{ "olmGenericAttributes",		"olmSubSystemAttributes:0" },
1952 		{ "olmDatabaseAttributes",		"olmSubSystemAttributes:1" },
1953 
1954 		/* for example, back-bdb specific attrs
1955 		 * are in "olmDatabaseAttributes:1"
1956 		 *
1957 		 * NOTE: developers, please record here OID assignments
1958 		 * for other modules */
1959 
1960 		{ "olmObjectClasses",			"1.3.6.1.4.1.4203.666.3.16" },
1961 		{ "olmSubSystemObjectClasses",		"olmObjectClasses:0" },
1962 		{ "olmGenericObjectClasses",		"olmSubSystemObjectClasses:0" },
1963 		{ "olmDatabaseObjectClasses",		"olmSubSystemObjectClasses:1" },
1964 
1965 		/* for example, back-bdb specific objectClasses
1966 		 * are in "olmDatabaseObjectClasses:1"
1967 		 *
1968 		 * NOTE: developers, please record here OID assignments
1969 		 * for other modules */
1970 
1971 		{ NULL }
1972 	};
1973 
1974 	int			i, rc;
1975 	monitor_info_t		*mi = &monitor_info;
1976 	ConfigArgs c;
1977 	char	*argv[ 3 ];
1978 
1979 	argv[ 0 ] = "monitor";
1980 	c.argv = argv;
1981 	c.argc = 3;
1982 	c.fname = argv[0];
1983 
1984 	for ( i = 0; s_oid[ i ].name; i++ ) {
1985 		argv[ 1 ] = s_oid[ i ].name;
1986 		argv[ 2 ] = s_oid[ i ].oid;
1987 
1988 		if ( parse_oidm( &c, 0, NULL ) != 0 ) {
1989 			Debug( LDAP_DEBUG_ANY,
1990 				"monitor_back_initialize: unable to add "
1991 				"objectIdentifier \"%s=%s\"\n",
1992 				s_oid[ i ].name, s_oid[ i ].oid, 0 );
1993 			return 1;
1994 		}
1995 	}
1996 
1997 	/* schema integration */
1998 	for ( i = 0; mat[ i ].schema; i++ ) {
1999 		int			code;
2000 		AttributeDescription **ad =
2001 			((AttributeDescription **)&(((char *)mi)[ mat[ i ].offset ]));
2002 
2003 		*ad = NULL;
2004 		code = register_at( mat[ i ].schema, ad, 0 );
2005 
2006 		if ( code ) {
2007 			Debug( LDAP_DEBUG_ANY,
2008 				"monitor_back_db_init: register_at failed\n", 0, 0, 0 );
2009 			return -1;
2010 		}
2011 		(*ad)->ad_type->sat_flags |= mat[ i ].flags;
2012 	}
2013 
2014 	for ( i = 0; moc[ i ].schema; i++ ) {
2015 		int			code;
2016 		ObjectClass		**Oc =
2017 			((ObjectClass **)&(((char *)mi)[ moc[ i ].offset ]));
2018 
2019 		code = register_oc( moc[ i ].schema, Oc, 0 );
2020 		if ( code ) {
2021 			Debug( LDAP_DEBUG_ANY,
2022 				"monitor_back_db_init: register_oc failed\n", 0, 0, 0 );
2023 			return -1;
2024 		}
2025 		(*Oc)->soc_flags |= moc[ i ].flags;
2026 	}
2027 
2028 	bi->bi_controls = controls;
2029 
2030 	bi->bi_init = 0;
2031 	bi->bi_open = 0;
2032 	bi->bi_config = monitor_back_config;
2033 	bi->bi_close = 0;
2034 	bi->bi_destroy = 0;
2035 
2036 	bi->bi_db_init = monitor_back_db_init;
2037 #if 0
2038 	bi->bi_db_config = monitor_back_db_config;
2039 #endif
2040 	bi->bi_db_open = monitor_back_db_open;
2041 	bi->bi_db_close = 0;
2042 	bi->bi_db_destroy = monitor_back_db_destroy;
2043 
2044 	bi->bi_op_bind = monitor_back_bind;
2045 	bi->bi_op_unbind = 0;
2046 	bi->bi_op_search = monitor_back_search;
2047 	bi->bi_op_compare = monitor_back_compare;
2048 	bi->bi_op_modify = monitor_back_modify;
2049 	bi->bi_op_modrdn = 0;
2050 	bi->bi_op_add = 0;
2051 	bi->bi_op_delete = 0;
2052 	bi->bi_op_abandon = 0;
2053 
2054 	bi->bi_extended = 0;
2055 
2056 	bi->bi_entry_release_rw = 0;
2057 	bi->bi_chk_referrals = 0;
2058 	bi->bi_operational = monitor_back_operational;
2059 
2060 	/*
2061 	 * hooks for slap tools
2062 	 */
2063 	bi->bi_tool_entry_open = 0;
2064 	bi->bi_tool_entry_close = 0;
2065 	bi->bi_tool_entry_first = 0;
2066 	bi->bi_tool_entry_first_x = 0;
2067 	bi->bi_tool_entry_next = 0;
2068 	bi->bi_tool_entry_get = 0;
2069 	bi->bi_tool_entry_put = 0;
2070 	bi->bi_tool_entry_reindex = 0;
2071 	bi->bi_tool_sync = 0;
2072 	bi->bi_tool_dn2id_get = 0;
2073 	bi->bi_tool_entry_modify = 0;
2074 
2075 	bi->bi_connection_init = 0;
2076 	bi->bi_connection_destroy = 0;
2077 
2078 	bi->bi_extra = (void *)&monitor_extra;
2079 
2080 	/*
2081 	 * configuration objectClasses (fake)
2082 	 */
2083 	bi->bi_cf_ocs = monitorocs;
2084 
2085 	rc = config_register_schema( monitorcfg, monitorocs );
2086 	if ( rc ) {
2087 		return rc;
2088 	}
2089 
2090 	return 0;
2091 }
2092 
2093 int
2094 monitor_back_db_init(
2095 	BackendDB	*be,
2096 	ConfigReply	*c)
2097 {
2098 	int			rc;
2099 	struct berval		dn = BER_BVC( SLAPD_MONITOR_DN ),
2100 				pdn,
2101 				ndn;
2102 	BackendDB		*be2;
2103 
2104 	monitor_subsys_t	*ms;
2105 
2106 	/*
2107 	 * database monitor can be defined once only
2108 	 */
2109 	if ( be_monitor != NULL ) {
2110 		if (c) {
2111 			snprintf(c->msg, sizeof(c->msg),"only one monitor database allowed");
2112 		}
2113 		return( -1 );
2114 	}
2115 	be_monitor = be;
2116 
2117 	/*
2118 	 * register subsys
2119 	 */
2120 	for ( ms = known_monitor_subsys; ms->mss_name != NULL; ms++ ) {
2121 		if ( monitor_back_register_subsys( ms ) ) {
2122 			return -1;
2123 		}
2124 	}
2125 
2126 	/* indicate system schema supported */
2127 	SLAP_BFLAGS(be) |= SLAP_BFLAG_MONITOR;
2128 
2129 	rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL );
2130 	if( rc != LDAP_SUCCESS ) {
2131 		Debug( LDAP_DEBUG_ANY,
2132 			"unable to normalize/pretty monitor DN \"%s\" (%d)\n",
2133 			dn.bv_val, rc, 0 );
2134 		return -1;
2135 	}
2136 
2137 	ber_bvarray_add( &be->be_suffix, &pdn );
2138 	ber_bvarray_add( &be->be_nsuffix, &ndn );
2139 
2140 	/* NOTE: only one monitor database is allowed,
2141 	 * so we use static storage */
2142 	ldap_pvt_thread_mutex_init( &monitor_info.mi_cache_mutex );
2143 
2144 	be->be_private = &monitor_info;
2145 
2146 	be2 = select_backend( &ndn, 0 );
2147 	if ( be2 != be ) {
2148 		char	*type = be2->bd_info->bi_type;
2149 
2150 		if ( overlay_is_over( be2 ) ) {
2151 			slap_overinfo	*oi = (slap_overinfo *)be2->bd_info->bi_private;
2152 			type = oi->oi_orig->bi_type;
2153 		}
2154 
2155 		if (c) {
2156 			snprintf(c->msg, sizeof(c->msg),
2157 					"\"monitor\" database serving namingContext \"%s\" "
2158 					"is hidden by \"%s\" database serving namingContext \"%s\".\n",
2159 					pdn.bv_val, type, be2->be_nsuffix[ 0 ].bv_val );
2160 		}
2161 		return -1;
2162 	}
2163 
2164 	return 0;
2165 }
2166 
2167 static void
2168 monitor_back_destroy_limbo_entry(
2169 	entry_limbo_t	*el,
2170 	int		dispose )
2171 {
2172 	if ( el->el_e ) {
2173 		entry_free( el->el_e );
2174 	}
2175 	if ( el->el_a ) {
2176 		attrs_free( el->el_a );
2177 	}
2178 	if ( !BER_BVISNULL( &el->el_nbase ) ) {
2179 		ber_memfree( el->el_nbase.bv_val );
2180 	}
2181 	if ( !BER_BVISNULL( &el->el_filter ) ) {
2182 		ber_memfree( el->el_filter.bv_val );
2183 	}
2184 
2185 	/* NOTE: callbacks are not copied; so only free them
2186 	 * if disposing of */
2187 	if ( el->el_cb && dispose != 0 ) {
2188 		monitor_callback_t *next;
2189 
2190 		for ( ; el->el_cb; el->el_cb = next ) {
2191 			next = el->el_cb->mc_next;
2192 			if ( el->el_cb->mc_dispose ) {
2193 				el->el_cb->mc_dispose( &el->el_cb->mc_private );
2194 			}
2195 			ch_free( el->el_cb );
2196 		}
2197 	}
2198 
2199 	ch_free( el );
2200 }
2201 
2202 int
2203 monitor_back_db_open(
2204 	BackendDB	*be,
2205 	ConfigReply	*cr)
2206 {
2207 	monitor_info_t 		*mi = (monitor_info_t *)be->be_private;
2208 	struct monitor_subsys_t	**ms;
2209 	Entry 			*e, **ep, *root;
2210 	monitor_entry_t		*mp;
2211 	int			i;
2212 	struct berval		bv, rdn = BER_BVC(SLAPD_MONITOR_DN);
2213 	struct tm		tms;
2214 	static char		tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
2215 	struct berval	desc[] = {
2216 		BER_BVC("This subtree contains monitoring/managing objects."),
2217 		BER_BVC("This object contains information about this server."),
2218 		BER_BVC("Most of the information is held in operational"
2219 		" attributes, which must be explicitly requested."),
2220 		BER_BVNULL };
2221 
2222 	int			retcode = 0;
2223 
2224 	assert( be_monitor != NULL );
2225 	if ( be != be_monitor ) {
2226 		be_monitor = be;
2227 	}
2228 
2229 	/*
2230 	 * Start
2231 	 */
2232 	ldap_pvt_gmtime( &starttime, &tms );
2233 	lutil_gentime( tmbuf, sizeof(tmbuf), &tms );
2234 
2235 	mi->mi_startTime.bv_val = tmbuf;
2236 	mi->mi_startTime.bv_len = strlen( tmbuf );
2237 
2238 	if ( BER_BVISEMPTY( &be->be_rootdn ) ) {
2239 		BER_BVSTR( &mi->mi_creatorsName, SLAPD_ANONYMOUS );
2240 		BER_BVSTR( &mi->mi_ncreatorsName, SLAPD_ANONYMOUS );
2241 	} else {
2242 		mi->mi_creatorsName = be->be_rootdn;
2243 		mi->mi_ncreatorsName = be->be_rootndn;
2244 	}
2245 
2246 	/*
2247 	 * creates the "cn=Monitor" entry
2248 	 */
2249 	e = monitor_entry_stub( NULL, NULL, &rdn, mi->mi_oc_monitorServer, mi,
2250 		NULL, NULL );
2251 
2252 	if ( e == NULL) {
2253 		Debug( LDAP_DEBUG_ANY,
2254 			"unable to create \"%s\" entry\n",
2255 			SLAPD_MONITOR_DN, 0, 0 );
2256 		return( -1 );
2257 	}
2258 
2259 	attr_merge_normalize( e, slap_schema.si_ad_description, desc, NULL );
2260 
2261 	bv.bv_val = strchr( (char *) Versionstr, '$' );
2262 	if ( bv.bv_val != NULL ) {
2263 		char	*end;
2264 
2265 		bv.bv_val++;
2266 		for ( ; bv.bv_val[ 0 ] == ' '; bv.bv_val++ )
2267 			;
2268 
2269 		end = strchr( bv.bv_val, '$' );
2270 		if ( end != NULL ) {
2271 			end--;
2272 
2273 			for ( ; end > bv.bv_val && end[ 0 ] == ' '; end-- )
2274 				;
2275 
2276 			end++;
2277 
2278 			bv.bv_len = end - bv.bv_val;
2279 
2280 		} else {
2281 			bv.bv_len = strlen( bv.bv_val );
2282 		}
2283 
2284 		if ( attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
2285 					&bv, NULL ) ) {
2286 			Debug( LDAP_DEBUG_ANY,
2287 				"unable to add monitoredInfo to \"%s\" entry\n",
2288 				SLAPD_MONITOR_DN, 0, 0 );
2289 			return( -1 );
2290 		}
2291 	}
2292 
2293 	mp = monitor_entrypriv_create();
2294 	if ( mp == NULL ) {
2295 		return -1;
2296 	}
2297 	e->e_private = ( void * )mp;
2298 	ep = &mp->mp_children;
2299 
2300 	if ( monitor_cache_add( mi, e ) ) {
2301 		Debug( LDAP_DEBUG_ANY,
2302 			"unable to add entry \"%s\" to cache\n",
2303 			SLAPD_MONITOR_DN, 0, 0 );
2304 		return -1;
2305 	}
2306 	root = e;
2307 
2308 	/*
2309 	 * Create all the subsystem specific entries
2310 	 */
2311 	for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
2312 		int 		len = strlen( monitor_subsys[ i ]->mss_name );
2313 		struct berval	dn;
2314 		int		rc;
2315 
2316 		dn.bv_len = len + sizeof( "cn=" ) - 1;
2317 		dn.bv_val = ch_calloc( sizeof( char ), dn.bv_len + 1 );
2318 		strcpy( dn.bv_val, "cn=" );
2319 		strcat( dn.bv_val, monitor_subsys[ i ]->mss_name );
2320 		rc = dnPretty( NULL, &dn, &monitor_subsys[ i ]->mss_rdn, NULL );
2321 		free( dn.bv_val );
2322 		if ( rc != LDAP_SUCCESS ) {
2323 			Debug( LDAP_DEBUG_ANY,
2324 				"monitor RDN \"%s\" is invalid\n",
2325 				dn.bv_val, 0, 0 );
2326 			return( -1 );
2327 		}
2328 
2329 		e = monitor_entry_stub( &root->e_name, &root->e_nname,
2330 			&monitor_subsys[ i ]->mss_rdn, mi->mi_oc_monitorContainer, mi,
2331 			NULL, NULL );
2332 
2333 		if ( e == NULL) {
2334 			Debug( LDAP_DEBUG_ANY,
2335 				"unable to create \"%s\" entry\n",
2336 				monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
2337 			return( -1 );
2338 		}
2339 		monitor_subsys[i]->mss_dn = e->e_name;
2340 		monitor_subsys[i]->mss_ndn = e->e_nname;
2341 
2342 		if ( !BER_BVISNULL( &monitor_subsys[ i ]->mss_desc[ 0 ] ) ) {
2343 			attr_merge_normalize( e, slap_schema.si_ad_description,
2344 					monitor_subsys[ i ]->mss_desc, NULL );
2345 		}
2346 
2347 		mp = monitor_entrypriv_create();
2348 		if ( mp == NULL ) {
2349 			return -1;
2350 		}
2351 		e->e_private = ( void * )mp;
2352 		mp->mp_info = monitor_subsys[ i ];
2353 		mp->mp_flags = monitor_subsys[ i ]->mss_flags;
2354 
2355 		if ( monitor_cache_add( mi, e ) ) {
2356 			Debug( LDAP_DEBUG_ANY,
2357 				"unable to add entry \"%s\" to cache\n",
2358 				monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
2359 			return -1;
2360 		}
2361 
2362 		*ep = e;
2363 		ep = &mp->mp_next;
2364 	}
2365 
2366 	assert( be != NULL );
2367 
2368 	be->be_private = mi;
2369 
2370 	/*
2371 	 * opens the monitor backend subsystems
2372 	 */
2373 	for ( ms = monitor_subsys; ms[ 0 ] != NULL; ms++ ) {
2374 		if ( ms[ 0 ]->mss_open && ms[ 0 ]->mss_open( be, ms[ 0 ] ) ) {
2375 			return( -1 );
2376 		}
2377 		ms[ 0 ]->mss_flags |= MONITOR_F_OPENED;
2378 	}
2379 
2380 	monitor_subsys_opened = 1;
2381 
2382 	if ( mi->mi_entry_limbo ) {
2383 		entry_limbo_t	*el = mi->mi_entry_limbo;
2384 
2385 		for ( ; el; ) {
2386 			entry_limbo_t	*tmp;
2387 			int		rc;
2388 
2389 			switch ( el->el_type ) {
2390 			case LIMBO_ENTRY:
2391 				rc = monitor_back_register_entry(
2392 						el->el_e,
2393 						el->el_cb,
2394 						el->el_mss,
2395 						el->el_flags );
2396 				break;
2397 
2398 			case LIMBO_ENTRY_PARENT:
2399 				rc = monitor_back_register_entry_parent(
2400 						el->el_e,
2401 						el->el_cb,
2402 						el->el_mss,
2403 						el->el_flags,
2404 						&el->el_nbase,
2405 						el->el_scope,
2406 						&el->el_filter );
2407 				break;
2408 
2409 
2410 			case LIMBO_ATTRS:
2411 				rc = monitor_back_register_entry_attrs(
2412 						el->el_ndn,
2413 						el->el_a,
2414 						el->el_cb,
2415 						&el->el_nbase,
2416 						el->el_scope,
2417 						&el->el_filter );
2418 				break;
2419 
2420 			case LIMBO_CB:
2421 				rc = monitor_back_register_entry_callback(
2422 						el->el_ndn,
2423 						el->el_cb,
2424 						&el->el_nbase,
2425 						el->el_scope,
2426 						&el->el_filter );
2427 				break;
2428 
2429 			case LIMBO_BACKEND:
2430 				rc = monitor_back_register_backend( el->el_bi );
2431 				break;
2432 
2433 			case LIMBO_DATABASE:
2434 				rc = monitor_back_register_database( el->el_be, el->el_ndn );
2435 				break;
2436 
2437 			case LIMBO_OVERLAY_INFO:
2438 				rc = monitor_back_register_overlay_info( el->el_on );
2439 				break;
2440 
2441 			case LIMBO_OVERLAY:
2442 				rc = monitor_back_register_overlay( el->el_be, el->el_on, el->el_ndn );
2443 				break;
2444 
2445 			default:
2446 				assert( 0 );
2447 			}
2448 
2449 			tmp = el;
2450 			el = el->el_next;
2451 			monitor_back_destroy_limbo_entry( tmp, rc );
2452 
2453 			if ( rc != 0 ) {
2454 				/* try all, but report error at end */
2455 				retcode = 1;
2456 			}
2457 		}
2458 
2459 		mi->mi_entry_limbo = NULL;
2460 	}
2461 
2462 	return retcode;
2463 }
2464 
2465 int
2466 monitor_back_config(
2467 	BackendInfo	*bi,
2468 	const char	*fname,
2469 	int		lineno,
2470 	int		argc,
2471 	char		**argv )
2472 {
2473 	/*
2474 	 * eventually, will hold backend specific configuration parameters
2475 	 */
2476 	return SLAP_CONF_UNKNOWN;
2477 }
2478 
2479 #if 0
2480 int
2481 monitor_back_db_config(
2482 	Backend     *be,
2483 	const char  *fname,
2484 	int         lineno,
2485 	int         argc,
2486 	char        **argv )
2487 {
2488 	monitor_info_t	*mi = ( monitor_info_t * )be->be_private;
2489 
2490 	/*
2491 	 * eventually, will hold database specific configuration parameters
2492 	 */
2493 	return SLAP_CONF_UNKNOWN;
2494 }
2495 #endif
2496 
2497 int
2498 monitor_back_db_destroy(
2499 	BackendDB	*be,
2500 	ConfigReply	*cr)
2501 {
2502 	monitor_info_t	*mi = ( monitor_info_t * )be->be_private;
2503 
2504 	if ( mi == NULL ) {
2505 		return -1;
2506 	}
2507 
2508 	/*
2509 	 * FIXME: destroys all the data
2510 	 */
2511 	/* NOTE: mi points to static storage; don't free it */
2512 
2513 	(void)monitor_cache_destroy( mi );
2514 
2515 	if ( monitor_subsys ) {
2516 		int	i;
2517 
2518 		for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
2519 			if ( monitor_subsys[ i ]->mss_destroy ) {
2520 				monitor_subsys[ i ]->mss_destroy( be, monitor_subsys[ i ] );
2521 			}
2522 
2523 			if ( !BER_BVISNULL( &monitor_subsys[ i ]->mss_rdn ) ) {
2524 				ch_free( monitor_subsys[ i ]->mss_rdn.bv_val );
2525 			}
2526 		}
2527 
2528 		ch_free( monitor_subsys );
2529 	}
2530 
2531 	if ( mi->mi_entry_limbo ) {
2532 		entry_limbo_t	*el = mi->mi_entry_limbo;
2533 
2534 		for ( ; el; ) {
2535 			entry_limbo_t *tmp = el;
2536 			el = el->el_next;
2537 			monitor_back_destroy_limbo_entry( tmp, 1 );
2538 		}
2539 	}
2540 
2541 	ldap_pvt_thread_mutex_destroy( &monitor_info.mi_cache_mutex );
2542 
2543 	be->be_private = NULL;
2544 
2545 	return 0;
2546 }
2547 
2548 #if SLAPD_MONITOR == SLAPD_MOD_DYNAMIC
2549 
2550 /* conditionally define the init_module() function */
2551 SLAP_BACKEND_INIT_MODULE( monitor )
2552 
2553 #endif /* SLAPD_MONITOR == SLAPD_MOD_DYNAMIC */
2554 
2555