1 /* monitor.c - monitor ldap backend */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/monitor.c,v 1.2.2.4 2008/02/11 23:26:46 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2008 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"
37 static ObjectClass
*oc_olmLDAPDatabase
;
39 static AttributeDescription
*ad_olmDbURIList
;
42 * NOTE: there's some confusion in monitor OID arc;
43 * by now, let's consider:
45 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0
46 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1
47 * LDAP database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.2
49 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0
50 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1
51 * LDAP database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.2
58 { "olmLDAPAttributes", "olmDatabaseAttributes:2" },
59 { "olmLDAPObjectClasses", "olmDatabaseObjectClasses:2" },
66 AttributeDescription
**ad
;
68 { "( olmLDAPAttributes:1 "
69 "NAME ( 'olmDbURIList' ) "
70 "DESC 'List of URIs a proxy is serving; can be modified run-time' "
81 /* augments an existing object, so it must be AUXILIARY
82 * FIXME: derive from some ABSTRACT "monitoredEntity"? */
83 { "( olmLDAPObjectClasses:1 "
84 "NAME ( 'olmLDAPDatabase' ) "
89 &oc_olmLDAPDatabase
},
95 ldap_back_monitor_info_destroy( ldapinfo_t
* li
)
97 if ( !BER_BVISNULL( &li
->li_monitor_info
.lmi_rdn
) )
98 ch_free( li
->li_monitor_info
.lmi_rdn
.bv_val
);
99 if ( !BER_BVISNULL( &li
->li_monitor_info
.lmi_nrdn
) )
100 ch_free( li
->li_monitor_info
.lmi_nrdn
.bv_val
);
101 if ( !BER_BVISNULL( &li
->li_monitor_info
.lmi_filter
) )
102 ch_free( li
->li_monitor_info
.lmi_filter
.bv_val
);
103 if ( !BER_BVISNULL( &li
->li_monitor_info
.lmi_more_filter
) )
104 ch_free( li
->li_monitor_info
.lmi_more_filter
.bv_val
);
106 memset( &li
->li_monitor_info
, 0, sizeof( li
->li_monitor_info
) );
112 ldap_back_monitor_update(
118 ldapinfo_t
*li
= (ldapinfo_t
*)priv
;
122 /* update olmDbURIList */
123 a
= attr_find( e
->e_attrs
, ad_olmDbURIList
);
127 assert( a
->a_vals
!= NULL
);
128 assert( !BER_BVISNULL( &a
->a_vals
[ 0 ] ) );
129 assert( BER_BVISNULL( &a
->a_vals
[ 1 ] ) );
131 ldap_pvt_thread_mutex_lock( &li
->li_uri_mutex
);
133 ber_str2bv( li
->li_uri
, 0, 0, &bv
);
134 if ( !bvmatch( &a
->a_vals
[ 0 ], &bv
) ) {
135 ber_bvreplace( &a
->a_vals
[ 0 ], &bv
);
138 ldap_pvt_thread_mutex_unlock( &li
->li_uri_mutex
);
141 return SLAP_CB_CONTINUE
;
145 ldap_back_monitor_modify(
151 ldapinfo_t
*li
= (ldapinfo_t
*) priv
;
153 Attribute
*save_attrs
= NULL
;
155 *ml_olmDbURIList
= NULL
;
156 struct berval ul
= BER_BVNULL
;
159 for ( ml
= op
->orm_modlist
; ml
; ml
= ml
->sml_next
) {
160 if ( ml
->sml_desc
== ad_olmDbURIList
) {
161 if ( ml_olmDbURIList
!= NULL
) {
162 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
163 rs
->sr_text
= "conflicting modifications";
167 if ( ml
->sml_op
!= LDAP_MOD_REPLACE
) {
168 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
169 rs
->sr_text
= "modification not allowed";
173 ml_olmDbURIList
= ml
;
180 return SLAP_CB_CONTINUE
;
183 save_attrs
= attrs_dup( e
->e_attrs
);
185 if ( ml_olmDbURIList
!= NULL
) {
187 LDAPURLDesc
*ludlist
= NULL
;
190 ml
= ml_olmDbURIList
;
191 assert( ml
->sml_nvalues
!= NULL
);
193 if ( BER_BVISNULL( &ml
->sml_nvalues
[ 0 ] ) ) {
194 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
195 rs
->sr_text
= "no value provided";
199 if ( !BER_BVISNULL( &ml
->sml_nvalues
[ 1 ] ) ) {
200 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
201 rs
->sr_text
= "multiple values provided";
205 rc
= ldap_url_parselist_ext( &ludlist
,
206 ml
->sml_nvalues
[ 0 ].bv_val
, NULL
,
207 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
208 | LDAP_PVT_URL_PARSE_DEF_PORT
);
209 if ( rc
!= LDAP_URL_SUCCESS
) {
210 rs
->sr_err
= LDAP_INVALID_SYNTAX
;
211 rs
->sr_text
= "unable to parse URI list";
215 ul
.bv_val
= ldap_url_list2urls( ludlist
);
216 ldap_free_urllist( ludlist
);
217 if ( ul
.bv_val
== NULL
) {
218 rs
->sr_err
= LDAP_OTHER
;
221 ul
.bv_len
= strlen( ul
.bv_val
);
223 a
= attr_find( e
->e_attrs
, ad_olmDbURIList
);
225 if ( a
->a_nvals
== a
->a_vals
) {
226 a
->a_nvals
= ch_calloc( sizeof( struct berval
), 2 );
229 ber_bvreplace( &a
->a_vals
[ 0 ], &ul
);
230 ber_bvreplace( &a
->a_nvals
[ 0 ], &ul
);
233 attr_merge_normalize_one( e
, ad_olmDbURIList
, &ul
, NULL
);
238 if ( !BER_BVISNULL( &ul
) ) {
239 ldap_pvt_thread_mutex_lock( &li
->li_uri_mutex
);
241 ch_free( li
->li_uri
);
243 li
->li_uri
= ul
.bv_val
;
244 ldap_pvt_thread_mutex_unlock( &li
->li_uri_mutex
);
250 if ( !BER_BVISNULL( &ul
) ) {
251 ldap_memfree( ul
.bv_val
);
254 if ( rs
->sr_err
== LDAP_SUCCESS
) {
255 attrs_free( save_attrs
);
256 return SLAP_CB_CONTINUE
;
259 attrs_free( e
->e_attrs
);
260 e
->e_attrs
= save_attrs
;
266 ldap_back_monitor_free(
270 ldapinfo_t
*li
= (ldapinfo_t
*)(*priv
);
274 if ( !slapd_shutdown
&& !BER_BVISNULL( &li
->li_monitor_info
.lmi_rdn
) ) {
275 ldap_back_monitor_info_destroy( li
);
278 return SLAP_CB_CONTINUE
;
282 ldap_back_monitor_conn_create(
289 monitor_entry_t
*mp_parent
;
290 ldap_monitor_info_t
*lmi
;
293 assert( e_parent
->e_private
!= NULL
);
295 mp_parent
= e_parent
->e_private
;
296 lmi
= (ldap_monitor_info_t
*)mp_parent
->mp_info
;
299 /* do the hard work! */
305 * call from within ldap_back_initialize()
308 ldap_back_monitor_initialize( void )
314 static int ldap_back_monitor_initialized
= 0;
316 /* register schema here; if compiled as dynamic object,
317 * must be loaded __after__ back_monitor.la */
319 if ( ldap_back_monitor_initialized
++ ) {
323 if ( backend_info( "monitor" ) == NULL
) {
327 argv
[ 0 ] = "back-ldap monitor";
331 for ( i
= 0; s_oid
[ i
].name
; i
++ ) {
333 argv
[ 1 ] = s_oid
[ i
].name
;
334 argv
[ 2 ] = s_oid
[ i
].oid
;
336 if ( parse_oidm( &c
, 0, NULL
) != 0 ) {
337 Debug( LDAP_DEBUG_ANY
,
338 "ldap_back_monitor_initialize: unable to add "
339 "objectIdentifier \"%s=%s\"\n",
340 s_oid
[ i
].name
, s_oid
[ i
].oid
, 0 );
345 for ( i
= 0; s_at
[ i
].desc
!= NULL
; i
++ ) {
346 code
= register_at( s_at
[ i
].desc
, s_at
[ i
].ad
, 1 );
347 if ( code
!= LDAP_SUCCESS
) {
348 Debug( LDAP_DEBUG_ANY
,
349 "ldap_back_monitor_initialize: register_at failed\n",
354 for ( i
= 0; s_oc
[ i
].desc
!= NULL
; i
++ ) {
355 code
= register_oc( s_oc
[ i
].desc
, s_oc
[ i
].oc
, 1 );
356 if ( code
!= LDAP_SUCCESS
) {
357 Debug( LDAP_DEBUG_ANY
,
358 "ldap_back_monitor_initialize: register_oc failed\n",
367 * call from within ldap_back_db_init()
370 ldap_back_monitor_db_init( BackendDB
*be
)
374 rc
= ldap_back_monitor_initialize();
375 if ( rc
!= LDAP_SUCCESS
) {
379 #if 0 /* uncomment to turn monitoring on by default */
380 SLAP_DBFLAGS( be
) |= SLAP_DBFLAG_MONITORING
;
387 * call from within ldap_back_db_open()
390 ldap_back_monitor_db_open( BackendDB
*be
)
392 ldapinfo_t
*li
= (ldapinfo_t
*) be
->be_private
;
393 char buf
[ BACKMONITOR_BUFSIZE
];
395 monitor_callback_t
*cb
= NULL
;
396 struct berval suffix
, *filter
, *base
;
399 char timebuf
[ LDAP_LUTIL_GENTIME_BUFSIZE
];
400 struct berval timestamp
;
403 monitor_extra_t
*mbe
;
405 if ( !SLAP_DBMONITORING( be
) ) {
409 /* check if monitor is configured and usable */
410 mi
= backend_info( "monitor" );
411 if ( !mi
|| !mi
->bi_extra
) {
412 SLAP_DBFLAGS( be
) ^= SLAP_DBFLAG_MONITORING
;
417 /* don't bother if monitor is not configured */
418 if ( !mbe
->is_configured() ) {
419 static int warning
= 0;
421 if ( warning
++ == 0 ) {
422 Debug( LDAP_DEBUG_ANY
, "ldap_back_monitor_db_open: "
423 "monitoring disabled; "
424 "configure monitor database to enable\n",
431 /* set up the fake subsystem that is used to create
432 * the volatile connection entries */
433 li
->li_monitor_info
.lmi_mss
.mss_name
= "back-ldap";
434 li
->li_monitor_info
.lmi_mss
.mss_flags
= MONITOR_F_VOLATILE_CH
;
435 li
->li_monitor_info
.lmi_mss
.mss_create
= ldap_back_monitor_conn_create
;
437 li
->li_monitor_info
.lmi_li
= li
;
438 li
->li_monitor_info
.lmi_scope
= LDAP_SCOPE_SUBORDINATE
;
439 base
= &li
->li_monitor_info
.lmi_base
;
440 BER_BVSTR( base
, "cn=databases,cn=monitor" );
441 filter
= &li
->li_monitor_info
.lmi_filter
;
442 BER_BVZERO( filter
);
444 suffix
.bv_len
= ldap_bv2escaped_filter_value_len( &be
->be_nsuffix
[ 0 ] );
445 if ( suffix
.bv_len
== be
->be_nsuffix
[ 0 ].bv_len
) {
446 suffix
= be
->be_nsuffix
[ 0 ];
449 ldap_bv2escaped_filter_value( &be
->be_nsuffix
[ 0 ], &suffix
);
452 filter
->bv_len
= STRLENOF( "(&" )
453 + li
->li_monitor_info
.lmi_more_filter
.bv_len
454 + STRLENOF( "(monitoredInfo=" )
455 + strlen( be
->bd_info
->bi_type
)
456 + STRLENOF( ")(!(monitorOverlay=" )
457 + strlen( be
->bd_info
->bi_type
)
458 + STRLENOF( "))(namingContexts:distinguishedNameMatch:=" )
459 + suffix
.bv_len
+ STRLENOF( "))" );
460 ptr
= filter
->bv_val
= ch_malloc( filter
->bv_len
+ 1 );
461 ptr
= lutil_strcopy( ptr
, "(&" );
462 ptr
= lutil_strncopy( ptr
, li
->li_monitor_info
.lmi_more_filter
.bv_val
,
463 li
->li_monitor_info
.lmi_more_filter
.bv_len
);
464 ptr
= lutil_strcopy( ptr
, "(monitoredInfo=" );
465 ptr
= lutil_strcopy( ptr
, be
->bd_info
->bi_type
);
466 ptr
= lutil_strcopy( ptr
, ")(!(monitorOverlay=" );
467 ptr
= lutil_strcopy( ptr
, be
->bd_info
->bi_type
);
468 ptr
= lutil_strcopy( ptr
, "))(namingContexts:distinguishedNameMatch:=" );
469 ptr
= lutil_strncopy( ptr
, suffix
.bv_val
, suffix
.bv_len
);
470 ptr
= lutil_strcopy( ptr
, "))" );
472 assert( filter
->bv_len
== ptr
- filter
->bv_val
);
474 if ( suffix
.bv_val
!= be
->be_nsuffix
[ 0 ].bv_val
) {
475 ch_free( suffix
.bv_val
);
478 now
= slap_get_time();
479 timestamp
.bv_val
= timebuf
;
480 timestamp
.bv_len
= sizeof( timebuf
);
481 slap_timestamp( &now
, ×tamp
);
483 /* caller (e.g. an overlay based on back-ldap) may want to use
484 * a different RDN... */
485 if ( BER_BVISNULL( &li
->li_monitor_info
.lmi_rdn
) ) {
486 ber_str2bv( "cn=Connections", 0, 1, &li
->li_monitor_info
.lmi_rdn
);
489 ptr
= ber_bvchr( &li
->li_monitor_info
.lmi_rdn
, '=' );
490 assert( ptr
!= NULL
);
494 snprintf( buf
, sizeof( buf
),
496 "objectClass: monitorContainer\n"
499 "createTimestamp: %s\n"
500 "modifiersName: %s\n"
501 "modifyTimestamp: %s\n",
502 li
->li_monitor_info
.lmi_rdn
.bv_val
,
504 li
->li_monitor_info
.lmi_rdn
.bv_val
,
506 BER_BVISNULL( &be
->be_rootdn
) ? SLAPD_ANONYMOUS
: be
->be_rootdn
.bv_val
,
508 BER_BVISNULL( &be
->be_rootdn
) ? SLAPD_ANONYMOUS
: be
->be_rootdn
.bv_val
,
510 e
= str2entry( buf
);
518 /* add labeledURI and special, modifiable URI value */
519 if ( li
->li_uri
!= NULL
) {
521 LDAPURLDesc
*ludlist
= NULL
;
524 rc
= ldap_url_parselist_ext( &ludlist
,
526 LDAP_PVT_URL_PARSE_NOEMPTY_HOST
527 | LDAP_PVT_URL_PARSE_DEF_PORT
);
528 if ( rc
!= LDAP_URL_SUCCESS
) {
529 Debug( LDAP_DEBUG_ANY
,
530 "ldap_back_monitor_db_open: "
531 "unable to parse URI list (ignored)\n",
534 for ( ; ludlist
!= NULL
; ) {
535 LDAPURLDesc
*next
= ludlist
->lud_next
;
537 bv
.bv_val
= ldap_url_desc2str( ludlist
);
538 assert( bv
.bv_val
!= NULL
);
539 ldap_free_urldesc( ludlist
);
540 bv
.bv_len
= strlen( bv
.bv_val
);
541 attr_merge_normalize_one( e
, slap_schema
.si_ad_labeledURI
,
543 ch_free( bv
.bv_val
);
549 ber_str2bv( li
->li_uri
, 0, 0, &bv
);
550 attr_merge_normalize_one( e
, ad_olmDbURIList
,
554 ber_dupbv( &li
->li_monitor_info
.lmi_nrdn
, &e
->e_nname
);
556 cb
= ch_calloc( sizeof( monitor_callback_t
), 1 );
557 cb
->mc_update
= ldap_back_monitor_update
;
558 cb
->mc_modify
= ldap_back_monitor_modify
;
559 cb
->mc_free
= ldap_back_monitor_free
;
560 cb
->mc_private
= (void *)li
;
562 rc
= mbe
->register_entry_parent( e
, cb
,
563 (monitor_subsys_t
*)&li
->li_monitor_info
,
564 MONITOR_F_VOLATILE_CH
,
565 base
, LDAP_SCOPE_SUBORDINATE
, filter
);
579 if ( !BER_BVISNULL( filter
) ) {
580 ch_free( filter
->bv_val
);
581 BER_BVZERO( filter
);
585 /* store for cleanup */
586 li
->li_monitor_info
.lmi_cb
= (void *)cb
;
596 * call from within ldap_back_db_close()
599 ldap_back_monitor_db_close( BackendDB
*be
)
601 ldapinfo_t
*li
= (ldapinfo_t
*) be
->be_private
;
603 if ( li
&& !BER_BVISNULL( &li
->li_monitor_info
.lmi_filter
) ) {
605 monitor_extra_t
*mbe
;
607 /* check if monitor is configured and usable */
608 mi
= backend_info( "monitor" );
609 if ( mi
&& mi
->bi_extra
) {
612 mbe
->unregister_entry_parent(
613 &li
->li_monitor_info
.lmi_nrdn
,
614 (monitor_callback_t
*)li
->li_monitor_info
.lmi_cb
,
615 &li
->li_monitor_info
.lmi_base
,
616 li
->li_monitor_info
.lmi_scope
,
617 &li
->li_monitor_info
.lmi_filter
);
625 * call from within ldap_back_db_destroy()
628 ldap_back_monitor_db_destroy( BackendDB
*be
)
630 ldapinfo_t
*li
= (ldapinfo_t
*) be
->be_private
;
633 (void)ldap_back_monitor_info_destroy( li
);