1 /* monitor.c - monitor ldap backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2006 The OpenLDAP Foundation.
6 * Portions Copyright 1999-2003 Howard Chu.
7 * Portions Copyright 2000-2003 Pierangelo Masarati.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by the Howard Chu for inclusion
20 * in OpenLDAP Software and subsequently enhanced by Pierangelo
27 #include <ac/string.h>
28 #include <ac/unistd.h>
29 #include <ac/stdlib.h>
33 #include "back-ldap.h"
35 static ObjectClass *oc_olmLDAPDatabase;
37 static AttributeDescription *ad_olmDbURIList;
40 * NOTE: there's some confusion in monitor OID arc;
41 * by now, let's consider:
43 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0
44 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1
45 * LDAP database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.2
47 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0
48 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1
49 * LDAP database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.2
56 { "olmLDAPAttributes", "olmDatabaseAttributes:2" },
57 { "olmLDAPObjectClasses", "olmDatabaseObjectClasses:2" },
64 AttributeDescription **ad;
66 { "( olmLDAPAttributes:1 "
67 "NAME ( 'olmDbURIList' ) "
68 "DESC 'List of URIs a proxy is serving; can be modified run-time' "
79 /* augments an existing object, so it must be AUXILIARY
80 * FIXME: derive from some ABSTRACT "monitoredEntity"? */
81 { "( olmLDAPObjectClasses:1 "
82 "NAME ( 'olmLDAPDatabase' ) "
87 &oc_olmLDAPDatabase },
93 ldap_back_monitor_info_destroy( ldapinfo_t * li )
95 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) )
96 ch_free( li->li_monitor_info.lmi_rdn.bv_val );
97 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_nrdn ) )
98 ch_free( li->li_monitor_info.lmi_nrdn.bv_val );
99 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) )
100 ch_free( li->li_monitor_info.lmi_filter.bv_val );
101 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_more_filter ) )
102 ch_free( li->li_monitor_info.lmi_more_filter.bv_val );
104 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) );
110 ldap_back_monitor_update(
116 ldapinfo_t *li = (ldapinfo_t *)priv;
120 /* update olmDbURIList */
121 a = attr_find( e->e_attrs, ad_olmDbURIList );
125 assert( a->a_vals != NULL );
126 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) );
127 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) );
129 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
131 ber_str2bv( li->li_uri, 0, 0, &bv );
132 if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) {
133 ber_bvreplace( &a->a_vals[ 0 ], &bv );
136 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
139 return SLAP_CB_CONTINUE;
143 ldap_back_monitor_modify(
149 ldapinfo_t *li = (ldapinfo_t *) priv;
151 Attribute *save_attrs = NULL;
153 *ml_olmDbURIList = NULL;
154 struct berval ul = BER_BVNULL;
157 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
158 if ( ml->sml_desc == ad_olmDbURIList ) {
159 if ( ml_olmDbURIList != NULL ) {
160 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
161 rs->sr_text = "conflicting modifications";
165 if ( ml->sml_op != LDAP_MOD_REPLACE ) {
166 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
167 rs->sr_text = "modification not allowed";
171 ml_olmDbURIList = ml;
178 return SLAP_CB_CONTINUE;
181 save_attrs = attrs_dup( e->e_attrs );
183 if ( ml_olmDbURIList != NULL ) {
185 LDAPURLDesc *ludlist = NULL;
188 ml = ml_olmDbURIList;
189 assert( ml->sml_nvalues != NULL );
191 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
192 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
193 rs->sr_text = "no value provided";
197 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
198 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
199 rs->sr_text = "multiple values provided";
203 rc = ldap_url_parselist_ext( &ludlist,
204 ml->sml_nvalues[ 0 ].bv_val, NULL,
205 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
206 | LDAP_PVT_URL_PARSE_DEF_PORT );
207 if ( rc != LDAP_URL_SUCCESS ) {
208 rs->sr_err = LDAP_INVALID_SYNTAX;
209 rs->sr_text = "unable to parse URI list";
213 ul.bv_val = ldap_url_list2urls( ludlist );
214 ldap_free_urllist( ludlist );
215 if ( ul.bv_val == NULL ) {
216 rs->sr_err = LDAP_OTHER;
219 ul.bv_len = strlen( ul.bv_val );
221 a = attr_find( e->e_attrs, ad_olmDbURIList );
223 if ( a->a_nvals == a->a_vals ) {
224 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
227 ber_bvreplace( &a->a_vals[ 0 ], &ul );
228 ber_bvreplace( &a->a_nvals[ 0 ], &ul );
231 attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
236 if ( !BER_BVISNULL( &ul ) ) {
237 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
239 ch_free( li->li_uri );
241 li->li_uri = ul.bv_val;
242 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
248 if ( !BER_BVISNULL( &ul ) ) {
249 ldap_memfree( ul.bv_val );
252 if ( rs->sr_err == LDAP_SUCCESS ) {
253 attrs_free( save_attrs );
254 return SLAP_CB_CONTINUE;
257 attrs_free( e->e_attrs );
258 e->e_attrs = save_attrs;
264 ldap_back_monitor_free(
268 ldapinfo_t *li = (ldapinfo_t *)priv;
270 if ( !slapd_shutdown && !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
271 ldap_back_monitor_info_destroy( li );
274 return SLAP_CB_CONTINUE;
278 ldap_back_monitor_conn_create(
285 monitor_entry_t *mp_parent;
286 ldap_monitor_info_t *lmi;
289 assert( e_parent->e_private != NULL );
291 mp_parent = e_parent->e_private;
292 lmi = (ldap_monitor_info_t *)mp_parent->mp_info;
295 /* do the hard work! */
301 * call from within ldap_back_initialize()
304 ldap_back_monitor_initialize( void )
309 static int ldap_back_monitor_initialized = 0;
311 /* register schema here; if compiled as dynamic object,
312 * must be loaded __after__ back_monitor.la */
314 if ( ldap_back_monitor_initialized++ ) {
318 if ( backend_info( "monitor" ) == NULL ) {
322 for ( i = 0; s_oid[ i ].name; i++ ) {
325 argv[ 0 ] = "back-ldap monitor";
326 argv[ 1 ] = s_oid[ i ].name;
327 argv[ 2 ] = s_oid[ i ].oid;
329 if ( parse_oidm( argv[ 0 ], i, 3, argv, 0, NULL ) != 0 ) {
330 Debug( LDAP_DEBUG_ANY,
331 "ldap_back_monitor_initialize: unable to add "
332 "objectIdentifier \"%s=%s\"\n",
333 s_oid[ i ].name, s_oid[ i ].oid, 0 );
338 for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
339 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
340 if ( code != LDAP_SUCCESS ) {
341 Debug( LDAP_DEBUG_ANY,
342 "ldap_back_monitor_initialize: register_at failed\n",
347 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
348 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
349 if ( code != LDAP_SUCCESS ) {
350 Debug( LDAP_DEBUG_ANY,
351 "ldap_back_monitor_initialize: register_oc failed\n",
360 * call from within ldap_back_db_init()
363 ldap_back_monitor_db_init( BackendDB *be )
367 rc = ldap_back_monitor_initialize();
368 if ( rc != LDAP_SUCCESS ) {
372 #if 0 /* uncomment to turn monitoring on by default */
373 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
380 * call from within ldap_back_db_open()
383 ldap_back_monitor_db_open( BackendDB *be )
385 ldapinfo_t *li = (ldapinfo_t *) be->be_private;
386 char buf[ BACKMONITOR_BUFSIZE ];
388 monitor_callback_t *cb;
389 struct berval suffix, *filter, *base;
392 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
393 struct berval timestamp;
396 monitor_extra_t *mbe;
398 if ( !SLAP_DBMONITORING( be ) ) {
402 /* check if monitor is configured and usable */
403 mi = backend_info( "monitor" );
404 if ( !mi || !mi->bi_extra ) {
405 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
410 /* don't bother if monitor is not configured */
411 if ( !mbe->is_configured() ) {
412 static int warning = 0;
414 if ( warning++ == 0 ) {
415 Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
416 "monitoring disabled; "
417 "configure monitor database to enable\n",
424 /* set up the fake subsystem that is used to create
425 * the volatile connection entries */
426 li->li_monitor_info.lmi_mss.mss_name = "back-ldap";
427 li->li_monitor_info.lmi_mss.mss_flags = MONITOR_F_VOLATILE_CH;
428 li->li_monitor_info.lmi_mss.mss_create = ldap_back_monitor_conn_create;
430 li->li_monitor_info.lmi_li = li;
431 li->li_monitor_info.lmi_scope = LDAP_SCOPE_SUBORDINATE;
432 base = &li->li_monitor_info.lmi_base;
433 BER_BVSTR( base, "cn=databases,cn=monitor" );
434 filter = &li->li_monitor_info.lmi_filter;
435 BER_BVZERO( filter );
437 suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] );
438 if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) {
439 suffix = be->be_nsuffix[ 0 ];
442 ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix );
445 filter->bv_len = STRLENOF( "(&" )
446 + li->li_monitor_info.lmi_more_filter.bv_len
447 + STRLENOF( "(monitoredInfo=" )
448 + strlen( be->bd_info->bi_type )
449 + STRLENOF( ")(!(monitorOverlay=" )
450 + strlen( be->bd_info->bi_type )
451 + STRLENOF( "))(namingContexts:distinguishedNameMatch:=" )
452 + suffix.bv_len + STRLENOF( "))" );
453 ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 );
454 ptr = lutil_strcopy( ptr, "(&" );
455 ptr = lutil_strncopy( ptr, li->li_monitor_info.lmi_more_filter.bv_val,
456 li->li_monitor_info.lmi_more_filter.bv_len );
457 ptr = lutil_strcopy( ptr, "(monitoredInfo=" );
458 ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
459 ptr = lutil_strcopy( ptr, ")(!(monitorOverlay=" );
460 ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
461 ptr = lutil_strcopy( ptr, "))(namingContexts:distinguishedNameMatch:=" );
462 ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len );
463 ptr = lutil_strcopy( ptr, "))" );
465 assert( filter->bv_len == ptr - filter->bv_val );
467 if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) {
468 ch_free( suffix.bv_val );
471 now = slap_get_time();
472 timestamp.bv_val = timebuf;
473 timestamp.bv_len = sizeof( timebuf );
474 slap_timestamp( &now, ×tamp );
476 /* caller (e.g. an overlay based on back-ldap) may want to use
477 * a different RDN... */
478 if ( BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
479 ber_str2bv( "cn=Connections", 0, 1, &li->li_monitor_info.lmi_rdn );
482 ptr = ber_bvchr( &li->li_monitor_info.lmi_rdn, '=' );
483 assert( ptr != NULL );
487 snprintf( buf, sizeof( buf ),
489 "objectClass: monitorContainer\n"
492 "createTimestamp: %s\n"
493 "modifiersName: %s\n"
494 "modifyTimestamp: %s\n",
495 li->li_monitor_info.lmi_rdn.bv_val,
497 li->li_monitor_info.lmi_rdn.bv_val,
499 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
501 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
503 e = str2entry( buf );
511 /* add labeledURI and special, modifiable URI value */
512 if ( li->li_uri != NULL ) {
514 LDAPURLDesc *ludlist = NULL;
517 rc = ldap_url_parselist_ext( &ludlist,
519 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
520 | LDAP_PVT_URL_PARSE_DEF_PORT );
521 if ( rc != LDAP_URL_SUCCESS ) {
522 Debug( LDAP_DEBUG_ANY,
523 "ldap_back_monitor_db_open: "
524 "unable to parse URI list (ignored)\n",
527 for ( ; ludlist != NULL; ) {
528 LDAPURLDesc *next = ludlist->lud_next;
530 bv.bv_val = ldap_url_desc2str( ludlist );
531 assert( bv.bv_val != NULL );
532 ldap_free_urldesc( ludlist );
533 bv.bv_len = strlen( bv.bv_val );
534 attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI,
536 ch_free( bv.bv_val );
542 ber_str2bv( li->li_uri, 0, 0, &bv );
543 attr_merge_normalize_one( e, ad_olmDbURIList,
547 ber_dupbv( &li->li_monitor_info.lmi_nrdn, &e->e_nname );
549 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
550 cb->mc_update = ldap_back_monitor_update;
551 cb->mc_modify = ldap_back_monitor_modify;
552 cb->mc_free = ldap_back_monitor_free;
553 cb->mc_private = (void *)li;
555 rc = mbe->register_entry_parent( e, cb,
556 (monitor_subsys_t *)&li->li_monitor_info,
557 MONITOR_F_VOLATILE_CH,
558 base, LDAP_SCOPE_SUBORDINATE, filter );
572 if ( !BER_BVISNULL( filter ) ) {
573 ch_free( filter->bv_val );
574 BER_BVZERO( filter );
578 /* store for cleanup */
579 li->li_monitor_info.lmi_cb = (void *)cb;
589 * call from within ldap_back_db_close()
592 ldap_back_monitor_db_close( BackendDB *be )
594 ldapinfo_t *li = (ldapinfo_t *) be->be_private;
596 if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) ) {
598 monitor_extra_t *mbe;
600 /* check if monitor is configured and usable */
601 mi = backend_info( "monitor" );
602 if ( mi && mi->bi_extra ) {
605 mbe->unregister_entry_parent(
606 &li->li_monitor_info.lmi_nrdn,
607 (monitor_callback_t *)li->li_monitor_info.lmi_cb,
608 &li->li_monitor_info.lmi_base,
609 li->li_monitor_info.lmi_scope,
610 &li->li_monitor_info.lmi_filter );
618 * call from within ldap_back_db_destroy()
621 ldap_back_monitor_db_destroy( BackendDB *be )
623 ldapinfo_t *li = (ldapinfo_t *) be->be_private;
626 (void)ldap_back_monitor_info_destroy( li );