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