1 /* $NetBSD: monitor.c,v 1.1.1.3 2010/12/12 15:23:06 adam Exp $ */ 2 3 /* monitor.c - monitor ldap backend */ 4 /* OpenLDAP: pkg/ldap/servers/slapd/back-ldap/monitor.c,v 1.2.2.7 2010/04/13 20:23:29 kurt Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2010 The OpenLDAP Foundation. 8 * Portions Copyright 1999-2003 Howard Chu. 9 * Portions Copyright 2000-2003 Pierangelo Masarati. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20 /* ACKNOWLEDGEMENTS: 21 * This work was initially developed by the Howard Chu for inclusion 22 * in OpenLDAP Software and subsequently enhanced by Pierangelo 23 * Masarati. 24 */ 25 26 #include "portable.h" 27 28 #include <stdio.h> 29 #include <ac/string.h> 30 #include <ac/unistd.h> 31 #include <ac/stdlib.h> 32 #include <ac/errno.h> 33 #include <sys/stat.h> 34 #include "lutil.h" 35 #include "back-ldap.h" 36 37 #include "config.h" 38 39 static ObjectClass *oc_olmLDAPDatabase; 40 41 static AttributeDescription *ad_olmDbURIList; 42 43 /* 44 * NOTE: there's some confusion in monitor OID arc; 45 * by now, let's consider: 46 * 47 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0 48 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1 49 * LDAP database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.2 50 * 51 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0 52 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1 53 * LDAP database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.2 54 */ 55 56 static struct { 57 char *name; 58 char *oid; 59 } s_oid[] = { 60 { "olmLDAPAttributes", "olmDatabaseAttributes:2" }, 61 { "olmLDAPObjectClasses", "olmDatabaseObjectClasses:2" }, 62 63 { NULL } 64 }; 65 66 static struct { 67 char *desc; 68 AttributeDescription **ad; 69 } s_at[] = { 70 { "( olmLDAPAttributes:1 " 71 "NAME ( 'olmDbURIList' ) " 72 "DESC 'List of URIs a proxy is serving; can be modified run-time' " 73 "SUP managedInfo )", 74 &ad_olmDbURIList }, 75 76 { NULL } 77 }; 78 79 static struct { 80 char *desc; 81 ObjectClass **oc; 82 } s_oc[] = { 83 /* augments an existing object, so it must be AUXILIARY 84 * FIXME: derive from some ABSTRACT "monitoredEntity"? */ 85 { "( olmLDAPObjectClasses:1 " 86 "NAME ( 'olmLDAPDatabase' ) " 87 "SUP top AUXILIARY " 88 "MAY ( " 89 "olmDbURIList " 90 ") )", 91 &oc_olmLDAPDatabase }, 92 93 { NULL } 94 }; 95 96 static int 97 ldap_back_monitor_info_destroy( ldapinfo_t * li ) 98 { 99 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) 100 ch_free( li->li_monitor_info.lmi_rdn.bv_val ); 101 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_nrdn ) ) 102 ch_free( li->li_monitor_info.lmi_nrdn.bv_val ); 103 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) ) 104 ch_free( li->li_monitor_info.lmi_filter.bv_val ); 105 if ( !BER_BVISNULL( &li->li_monitor_info.lmi_more_filter ) ) 106 ch_free( li->li_monitor_info.lmi_more_filter.bv_val ); 107 108 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) ); 109 110 return 0; 111 } 112 113 static int 114 ldap_back_monitor_update( 115 Operation *op, 116 SlapReply *rs, 117 Entry *e, 118 void *priv ) 119 { 120 ldapinfo_t *li = (ldapinfo_t *)priv; 121 122 Attribute *a; 123 124 /* update olmDbURIList */ 125 a = attr_find( e->e_attrs, ad_olmDbURIList ); 126 if ( a != NULL ) { 127 struct berval bv; 128 129 assert( a->a_vals != NULL ); 130 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) ); 131 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) ); 132 133 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 134 if ( li->li_uri ) { 135 ber_str2bv( li->li_uri, 0, 0, &bv ); 136 if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) { 137 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 138 } 139 } 140 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 141 } 142 143 return SLAP_CB_CONTINUE; 144 } 145 146 static int 147 ldap_back_monitor_modify( 148 Operation *op, 149 SlapReply *rs, 150 Entry *e, 151 void *priv ) 152 { 153 ldapinfo_t *li = (ldapinfo_t *) priv; 154 155 Attribute *save_attrs = NULL; 156 Modifications *ml, 157 *ml_olmDbURIList = NULL; 158 struct berval ul = BER_BVNULL; 159 int got = 0; 160 161 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { 162 if ( ml->sml_desc == ad_olmDbURIList ) { 163 if ( ml_olmDbURIList != NULL ) { 164 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 165 rs->sr_text = "conflicting modifications"; 166 goto done; 167 } 168 169 if ( ml->sml_op != LDAP_MOD_REPLACE ) { 170 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 171 rs->sr_text = "modification not allowed"; 172 goto done; 173 } 174 175 ml_olmDbURIList = ml; 176 got++; 177 continue; 178 } 179 } 180 181 if ( got == 0 ) { 182 return SLAP_CB_CONTINUE; 183 } 184 185 save_attrs = attrs_dup( e->e_attrs ); 186 187 if ( ml_olmDbURIList != NULL ) { 188 Attribute *a = NULL; 189 LDAPURLDesc *ludlist = NULL; 190 int rc; 191 192 ml = ml_olmDbURIList; 193 assert( ml->sml_nvalues != NULL ); 194 195 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { 196 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 197 rs->sr_text = "no value provided"; 198 goto done; 199 } 200 201 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) { 202 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 203 rs->sr_text = "multiple values provided"; 204 goto done; 205 } 206 207 rc = ldap_url_parselist_ext( &ludlist, 208 ml->sml_nvalues[ 0 ].bv_val, NULL, 209 LDAP_PVT_URL_PARSE_NOEMPTY_HOST 210 | LDAP_PVT_URL_PARSE_DEF_PORT ); 211 if ( rc != LDAP_URL_SUCCESS ) { 212 rs->sr_err = LDAP_INVALID_SYNTAX; 213 rs->sr_text = "unable to parse URI list"; 214 goto done; 215 } 216 217 ul.bv_val = ldap_url_list2urls( ludlist ); 218 ldap_free_urllist( ludlist ); 219 if ( ul.bv_val == NULL ) { 220 rs->sr_err = LDAP_OTHER; 221 goto done; 222 } 223 ul.bv_len = strlen( ul.bv_val ); 224 225 a = attr_find( e->e_attrs, ad_olmDbURIList ); 226 if ( a != NULL ) { 227 if ( a->a_nvals == a->a_vals ) { 228 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 ); 229 } 230 231 ber_bvreplace( &a->a_vals[ 0 ], &ul ); 232 ber_bvreplace( &a->a_nvals[ 0 ], &ul ); 233 234 } else { 235 attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL ); 236 } 237 } 238 239 /* apply changes */ 240 if ( !BER_BVISNULL( &ul ) ) { 241 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 242 if ( li->li_uri ) { 243 ch_free( li->li_uri ); 244 } 245 li->li_uri = ul.bv_val; 246 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 247 248 BER_BVZERO( &ul ); 249 } 250 251 done:; 252 if ( !BER_BVISNULL( &ul ) ) { 253 ldap_memfree( ul.bv_val ); 254 } 255 256 if ( rs->sr_err == LDAP_SUCCESS ) { 257 attrs_free( save_attrs ); 258 return SLAP_CB_CONTINUE; 259 } 260 261 attrs_free( e->e_attrs ); 262 e->e_attrs = save_attrs; 263 264 return rs->sr_err; 265 } 266 267 static int 268 ldap_back_monitor_free( 269 Entry *e, 270 void **priv ) 271 { 272 ldapinfo_t *li = (ldapinfo_t *)(*priv); 273 274 *priv = NULL; 275 276 if ( !slapd_shutdown && !BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) { 277 ldap_back_monitor_info_destroy( li ); 278 } 279 280 return SLAP_CB_CONTINUE; 281 } 282 283 static int 284 ldap_back_monitor_conn_create( 285 Operation *op, 286 SlapReply *rs, 287 struct berval *ndn, 288 Entry *e_parent, 289 Entry **ep ) 290 { 291 monitor_entry_t *mp_parent; 292 ldap_monitor_info_t *lmi; 293 ldapinfo_t *li; 294 295 assert( e_parent->e_private != NULL ); 296 297 mp_parent = e_parent->e_private; 298 lmi = (ldap_monitor_info_t *)mp_parent->mp_info; 299 li = lmi->lmi_li; 300 301 /* do the hard work! */ 302 303 return 1; 304 } 305 306 /* 307 * call from within ldap_back_initialize() 308 */ 309 static int 310 ldap_back_monitor_initialize( void ) 311 { 312 int i, code; 313 ConfigArgs c; 314 char *argv[ 3 ]; 315 316 static int ldap_back_monitor_initialized = 0; 317 318 /* register schema here; if compiled as dynamic object, 319 * must be loaded __after__ back_monitor.la */ 320 321 if ( ldap_back_monitor_initialized++ ) { 322 return 0; 323 } 324 325 if ( backend_info( "monitor" ) == NULL ) { 326 return -1; 327 } 328 329 argv[ 0 ] = "back-ldap monitor"; 330 c.argv = argv; 331 c.argc = 3; 332 c.fname = argv[0]; 333 for ( i = 0; s_oid[ i ].name; i++ ) { 334 335 argv[ 1 ] = s_oid[ i ].name; 336 argv[ 2 ] = s_oid[ i ].oid; 337 338 if ( parse_oidm( &c, 0, NULL ) != 0 ) { 339 Debug( LDAP_DEBUG_ANY, 340 "ldap_back_monitor_initialize: unable to add " 341 "objectIdentifier \"%s=%s\"\n", 342 s_oid[ i ].name, s_oid[ i ].oid, 0 ); 343 return 1; 344 } 345 } 346 347 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 348 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 ); 349 if ( code != LDAP_SUCCESS ) { 350 Debug( LDAP_DEBUG_ANY, 351 "ldap_back_monitor_initialize: register_at failed\n", 352 0, 0, 0 ); 353 } 354 } 355 356 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) { 357 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 ); 358 if ( code != LDAP_SUCCESS ) { 359 Debug( LDAP_DEBUG_ANY, 360 "ldap_back_monitor_initialize: register_oc failed\n", 361 0, 0, 0 ); 362 } 363 } 364 365 return 0; 366 } 367 368 /* 369 * call from within ldap_back_db_init() 370 */ 371 int 372 ldap_back_monitor_db_init( BackendDB *be ) 373 { 374 int rc; 375 376 rc = ldap_back_monitor_initialize(); 377 if ( rc != LDAP_SUCCESS ) { 378 return rc; 379 } 380 381 #if 0 /* uncomment to turn monitoring on by default */ 382 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING; 383 #endif 384 385 return 0; 386 } 387 388 /* 389 * call from within ldap_back_db_open() 390 */ 391 int 392 ldap_back_monitor_db_open( BackendDB *be ) 393 { 394 ldapinfo_t *li = (ldapinfo_t *) be->be_private; 395 char buf[ BACKMONITOR_BUFSIZE ]; 396 Entry *e = NULL; 397 monitor_callback_t *cb = NULL; 398 struct berval suffix, *filter, *base; 399 char *ptr; 400 time_t now; 401 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 402 struct berval timestamp; 403 int rc = 0; 404 BackendInfo *mi; 405 monitor_extra_t *mbe; 406 407 if ( !SLAP_DBMONITORING( be ) ) { 408 return 0; 409 } 410 411 /* check if monitor is configured and usable */ 412 mi = backend_info( "monitor" ); 413 if ( !mi || !mi->bi_extra ) { 414 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; 415 return 0; 416 } 417 mbe = mi->bi_extra; 418 419 /* don't bother if monitor is not configured */ 420 if ( !mbe->is_configured() ) { 421 static int warning = 0; 422 423 if ( warning++ == 0 ) { 424 Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: " 425 "monitoring disabled; " 426 "configure monitor database to enable\n", 427 0, 0, 0 ); 428 } 429 430 return 0; 431 } 432 433 /* set up the fake subsystem that is used to create 434 * the volatile connection entries */ 435 li->li_monitor_info.lmi_mss.mss_name = "back-ldap"; 436 li->li_monitor_info.lmi_mss.mss_flags = MONITOR_F_VOLATILE_CH; 437 li->li_monitor_info.lmi_mss.mss_create = ldap_back_monitor_conn_create; 438 439 li->li_monitor_info.lmi_li = li; 440 li->li_monitor_info.lmi_scope = LDAP_SCOPE_SUBORDINATE; 441 base = &li->li_monitor_info.lmi_base; 442 BER_BVSTR( base, "cn=databases,cn=monitor" ); 443 filter = &li->li_monitor_info.lmi_filter; 444 BER_BVZERO( filter ); 445 446 suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] ); 447 if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) { 448 suffix = be->be_nsuffix[ 0 ]; 449 450 } else { 451 ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix ); 452 } 453 454 filter->bv_len = STRLENOF( "(&" ) 455 + li->li_monitor_info.lmi_more_filter.bv_len 456 + STRLENOF( "(monitoredInfo=" ) 457 + strlen( be->bd_info->bi_type ) 458 + STRLENOF( ")(!(monitorOverlay=" ) 459 + strlen( be->bd_info->bi_type ) 460 + STRLENOF( "))(namingContexts:distinguishedNameMatch:=" ) 461 + suffix.bv_len + STRLENOF( "))" ); 462 ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 ); 463 ptr = lutil_strcopy( ptr, "(&" ); 464 ptr = lutil_strncopy( ptr, li->li_monitor_info.lmi_more_filter.bv_val, 465 li->li_monitor_info.lmi_more_filter.bv_len ); 466 ptr = lutil_strcopy( ptr, "(monitoredInfo=" ); 467 ptr = lutil_strcopy( ptr, be->bd_info->bi_type ); 468 ptr = lutil_strcopy( ptr, ")(!(monitorOverlay=" ); 469 ptr = lutil_strcopy( ptr, be->bd_info->bi_type ); 470 ptr = lutil_strcopy( ptr, "))(namingContexts:distinguishedNameMatch:=" ); 471 ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len ); 472 ptr = lutil_strcopy( ptr, "))" ); 473 ptr[ 0 ] = '\0'; 474 assert( ptr == &filter->bv_val[ filter->bv_len ] ); 475 476 if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) { 477 ch_free( suffix.bv_val ); 478 } 479 480 now = slap_get_time(); 481 timestamp.bv_val = timebuf; 482 timestamp.bv_len = sizeof( timebuf ); 483 slap_timestamp( &now, ×tamp ); 484 485 /* caller (e.g. an overlay based on back-ldap) may want to use 486 * a different RDN... */ 487 if ( BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) { 488 ber_str2bv( "cn=Connections", 0, 1, &li->li_monitor_info.lmi_rdn ); 489 } 490 491 ptr = ber_bvchr( &li->li_monitor_info.lmi_rdn, '=' ); 492 assert( ptr != NULL ); 493 ptr[ 0 ] = '\0'; 494 ptr++; 495 496 snprintf( buf, sizeof( buf ), 497 "dn: %s=%s\n" 498 "objectClass: monitorContainer\n" 499 "%s: %s\n" 500 "creatorsName: %s\n" 501 "createTimestamp: %s\n" 502 "modifiersName: %s\n" 503 "modifyTimestamp: %s\n", 504 li->li_monitor_info.lmi_rdn.bv_val, 505 ptr, 506 li->li_monitor_info.lmi_rdn.bv_val, 507 ptr, 508 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val, 509 timestamp.bv_val, 510 BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val, 511 timestamp.bv_val ); 512 e = str2entry( buf ); 513 if ( e == NULL ) { 514 rc = -1; 515 goto cleanup; 516 } 517 518 ptr[ -1 ] = '='; 519 520 /* add labeledURI and special, modifiable URI value */ 521 if ( li->li_uri != NULL ) { 522 struct berval bv; 523 LDAPURLDesc *ludlist = NULL; 524 int rc; 525 526 rc = ldap_url_parselist_ext( &ludlist, 527 li->li_uri, NULL, 528 LDAP_PVT_URL_PARSE_NOEMPTY_HOST 529 | LDAP_PVT_URL_PARSE_DEF_PORT ); 530 if ( rc != LDAP_URL_SUCCESS ) { 531 Debug( LDAP_DEBUG_ANY, 532 "ldap_back_monitor_db_open: " 533 "unable to parse URI list (ignored)\n", 534 0, 0, 0 ); 535 } else { 536 for ( ; ludlist != NULL; ) { 537 LDAPURLDesc *next = ludlist->lud_next; 538 539 bv.bv_val = ldap_url_desc2str( ludlist ); 540 assert( bv.bv_val != NULL ); 541 ldap_free_urldesc( ludlist ); 542 bv.bv_len = strlen( bv.bv_val ); 543 attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI, 544 &bv, NULL ); 545 ch_free( bv.bv_val ); 546 547 ludlist = next; 548 } 549 } 550 551 ber_str2bv( li->li_uri, 0, 0, &bv ); 552 attr_merge_normalize_one( e, ad_olmDbURIList, 553 &bv, NULL ); 554 } 555 556 ber_dupbv( &li->li_monitor_info.lmi_nrdn, &e->e_nname ); 557 558 cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 559 cb->mc_update = ldap_back_monitor_update; 560 cb->mc_modify = ldap_back_monitor_modify; 561 cb->mc_free = ldap_back_monitor_free; 562 cb->mc_private = (void *)li; 563 564 rc = mbe->register_entry_parent( e, cb, 565 (monitor_subsys_t *)&li->li_monitor_info, 566 MONITOR_F_VOLATILE_CH, 567 base, LDAP_SCOPE_SUBORDINATE, filter ); 568 569 cleanup:; 570 if ( rc != 0 ) { 571 if ( cb != NULL ) { 572 ch_free( cb ); 573 cb = NULL; 574 } 575 576 if ( e != NULL ) { 577 entry_free( e ); 578 e = NULL; 579 } 580 581 if ( !BER_BVISNULL( filter ) ) { 582 ch_free( filter->bv_val ); 583 BER_BVZERO( filter ); 584 } 585 } 586 587 /* store for cleanup */ 588 li->li_monitor_info.lmi_cb = (void *)cb; 589 590 if ( e != NULL ) { 591 entry_free( e ); 592 } 593 594 return rc; 595 } 596 597 /* 598 * call from within ldap_back_db_close() 599 */ 600 int 601 ldap_back_monitor_db_close( BackendDB *be ) 602 { 603 ldapinfo_t *li = (ldapinfo_t *) be->be_private; 604 605 if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_filter ) ) { 606 BackendInfo *mi; 607 monitor_extra_t *mbe; 608 609 /* check if monitor is configured and usable */ 610 mi = backend_info( "monitor" ); 611 if ( mi && mi->bi_extra ) { 612 mbe = mi->bi_extra; 613 614 mbe->unregister_entry_parent( 615 &li->li_monitor_info.lmi_nrdn, 616 (monitor_callback_t *)li->li_monitor_info.lmi_cb, 617 &li->li_monitor_info.lmi_base, 618 li->li_monitor_info.lmi_scope, 619 &li->li_monitor_info.lmi_filter ); 620 } 621 } 622 623 return 0; 624 } 625 626 /* 627 * call from within ldap_back_db_destroy() 628 */ 629 int 630 ldap_back_monitor_db_destroy( BackendDB *be ) 631 { 632 ldapinfo_t *li = (ldapinfo_t *) be->be_private; 633 634 if ( li ) { 635 (void)ldap_back_monitor_info_destroy( li ); 636 } 637 638 return 0; 639 } 640 641