Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / servers / slapd / back-ldap / monitor.c
blob8b9abc4cddc3c8839e0fb5e838bada3915211815
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.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
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>.
18 /* ACKNOWLEDGEMENTS:
19 * This work was initially developed by the Howard Chu for inclusion
20 * in OpenLDAP Software and subsequently enhanced by Pierangelo
21 * Masarati.
24 #include "portable.h"
26 #include <stdio.h>
27 #include <ac/string.h>
28 #include <ac/unistd.h>
29 #include <ac/stdlib.h>
30 #include <ac/errno.h>
31 #include <sys/stat.h>
32 #include "lutil.h"
33 #include "back-ldap.h"
35 #include "config.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
54 static struct {
55 char *name;
56 char *oid;
57 } s_oid[] = {
58 { "olmLDAPAttributes", "olmDatabaseAttributes:2" },
59 { "olmLDAPObjectClasses", "olmDatabaseObjectClasses:2" },
61 { NULL }
64 static struct {
65 char *desc;
66 AttributeDescription **ad;
67 } s_at[] = {
68 { "( olmLDAPAttributes:1 "
69 "NAME ( 'olmDbURIList' ) "
70 "DESC 'List of URIs a proxy is serving; can be modified run-time' "
71 "SUP managedInfo )",
72 &ad_olmDbURIList },
74 { NULL }
77 static struct {
78 char *desc;
79 ObjectClass **oc;
80 } s_oc[] = {
81 /* augments an existing object, so it must be AUXILIARY
82 * FIXME: derive from some ABSTRACT "monitoredEntity"? */
83 { "( olmLDAPObjectClasses:1 "
84 "NAME ( 'olmLDAPDatabase' ) "
85 "SUP top AUXILIARY "
86 "MAY ( "
87 "olmDbURIList "
88 ") )",
89 &oc_olmLDAPDatabase },
91 { NULL }
94 static int
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 ) );
108 return 0;
111 static int
112 ldap_back_monitor_update(
113 Operation *op,
114 SlapReply *rs,
115 Entry *e,
116 void *priv )
118 ldapinfo_t *li = (ldapinfo_t *)priv;
120 Attribute *a;
122 /* update olmDbURIList */
123 a = attr_find( e->e_attrs, ad_olmDbURIList );
124 if ( a != NULL ) {
125 struct berval bv;
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 );
132 if ( li->li_uri ) {
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;
144 static int
145 ldap_back_monitor_modify(
146 Operation *op,
147 SlapReply *rs,
148 Entry *e,
149 void *priv )
151 ldapinfo_t *li = (ldapinfo_t *) priv;
153 Attribute *save_attrs = NULL;
154 Modifications *ml,
155 *ml_olmDbURIList = NULL;
156 struct berval ul = BER_BVNULL;
157 int got = 0;
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";
164 goto done;
167 if ( ml->sml_op != LDAP_MOD_REPLACE ) {
168 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
169 rs->sr_text = "modification not allowed";
170 goto done;
173 ml_olmDbURIList = ml;
174 got++;
175 continue;
179 if ( got == 0 ) {
180 return SLAP_CB_CONTINUE;
183 save_attrs = attrs_dup( e->e_attrs );
185 if ( ml_olmDbURIList != NULL ) {
186 Attribute *a = NULL;
187 LDAPURLDesc *ludlist = NULL;
188 int rc;
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";
196 goto done;
199 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
200 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
201 rs->sr_text = "multiple values provided";
202 goto done;
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";
212 goto done;
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;
219 goto done;
221 ul.bv_len = strlen( ul.bv_val );
223 a = attr_find( e->e_attrs, ad_olmDbURIList );
224 if ( a != NULL ) {
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 );
232 } else {
233 attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
237 /* apply changes */
238 if ( !BER_BVISNULL( &ul ) ) {
239 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
240 if ( li->li_uri ) {
241 ch_free( li->li_uri );
243 li->li_uri = ul.bv_val;
244 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
246 BER_BVZERO( &ul );
249 done:;
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;
262 return rs->sr_err;
265 static int
266 ldap_back_monitor_free(
267 Entry *e,
268 void **priv )
270 ldapinfo_t *li = (ldapinfo_t *)(*priv);
272 *priv = NULL;
274 if ( !slapd_shutdown && !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
275 ldap_back_monitor_info_destroy( li );
278 return SLAP_CB_CONTINUE;
281 static int
282 ldap_back_monitor_conn_create(
283 Operation *op,
284 SlapReply *rs,
285 struct berval *ndn,
286 Entry *e_parent,
287 Entry **ep )
289 monitor_entry_t *mp_parent;
290 ldap_monitor_info_t *lmi;
291 ldapinfo_t *li;
293 assert( e_parent->e_private != NULL );
295 mp_parent = e_parent->e_private;
296 lmi = (ldap_monitor_info_t *)mp_parent->mp_info;
297 li = lmi->lmi_li;
299 /* do the hard work! */
301 return 1;
305 * call from within ldap_back_initialize()
307 static int
308 ldap_back_monitor_initialize( void )
310 int i, code;
311 ConfigArgs c;
312 char *argv[ 3 ];
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++ ) {
320 return 0;
323 if ( backend_info( "monitor" ) == NULL ) {
324 return -1;
327 argv[ 0 ] = "back-ldap monitor";
328 c.argv = argv;
329 c.argc = 3;
330 c.fname = argv[0];
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 );
341 return 1;
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",
350 0, 0, 0 );
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",
359 0, 0, 0 );
363 return 0;
367 * call from within ldap_back_db_init()
370 ldap_back_monitor_db_init( BackendDB *be )
372 int rc;
374 rc = ldap_back_monitor_initialize();
375 if ( rc != LDAP_SUCCESS ) {
376 return rc;
379 #if 0 /* uncomment to turn monitoring on by default */
380 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
381 #endif
383 return 0;
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 ];
394 Entry *e = NULL;
395 monitor_callback_t *cb = NULL;
396 struct berval suffix, *filter, *base;
397 char *ptr;
398 time_t now;
399 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
400 struct berval timestamp;
401 int rc = 0;
402 BackendInfo *mi;
403 monitor_extra_t *mbe;
405 if ( !SLAP_DBMONITORING( be ) ) {
406 return 0;
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;
413 return 0;
415 mbe = mi->bi_extra;
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",
425 0, 0, 0 );
428 return 0;
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 ];
448 } else {
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, "))" );
471 ptr[ 0 ] = '\0';
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, &timestamp );
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 );
491 ptr[ 0 ] = '\0';
492 ptr++;
494 snprintf( buf, sizeof( buf ),
495 "dn: %s=%s\n"
496 "objectClass: monitorContainer\n"
497 "%s: %s\n"
498 "creatorsName: %s\n"
499 "createTimestamp: %s\n"
500 "modifiersName: %s\n"
501 "modifyTimestamp: %s\n",
502 li->li_monitor_info.lmi_rdn.bv_val,
503 ptr,
504 li->li_monitor_info.lmi_rdn.bv_val,
505 ptr,
506 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
507 timestamp.bv_val,
508 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
509 timestamp.bv_val );
510 e = str2entry( buf );
511 if ( e == NULL ) {
512 rc = -1;
513 goto cleanup;
516 ptr[ -1 ] = '=';
518 /* add labeledURI and special, modifiable URI value */
519 if ( li->li_uri != NULL ) {
520 struct berval bv;
521 LDAPURLDesc *ludlist = NULL;
522 int rc;
524 rc = ldap_url_parselist_ext( &ludlist,
525 li->li_uri, NULL,
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",
532 0, 0, 0 );
533 } else {
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,
542 &bv, NULL );
543 ch_free( bv.bv_val );
545 ludlist = next;
549 ber_str2bv( li->li_uri, 0, 0, &bv );
550 attr_merge_normalize_one( e, ad_olmDbURIList,
551 &bv, NULL );
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 );
567 cleanup:;
568 if ( rc != 0 ) {
569 if ( cb != NULL ) {
570 ch_free( cb );
571 cb = NULL;
574 if ( e != NULL ) {
575 entry_free( e );
576 e = NULL;
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;
588 if ( e != NULL ) {
589 entry_free( e );
592 return rc;
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 ) ) {
604 BackendInfo *mi;
605 monitor_extra_t *mbe;
607 /* check if monitor is configured and usable */
608 mi = backend_info( "monitor" );
609 if ( mi && mi->bi_extra ) {
610 mbe = 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 );
621 return 0;
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;
632 if ( li ) {
633 (void)ldap_back_monitor_info_destroy( li );
636 return 0;