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