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