1 /* $NetBSD: monitor.c,v 1.1.1.1 2014/05/28 09:58:50 tron Exp $ */ 2 3 /* monitor.c - monitor mdb backend */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2014 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 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. 13 * 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>. 17 */ 18 19 #include "portable.h" 20 21 #include <stdio.h> 22 #include <ac/string.h> 23 #include <ac/unistd.h> 24 #include <ac/stdlib.h> 25 #include <ac/errno.h> 26 #include <sys/stat.h> 27 #include "lutil.h" 28 #include "back-mdb.h" 29 30 #include "../back-monitor/back-monitor.h" 31 32 #include "config.h" 33 34 static ObjectClass *oc_olmMDBDatabase; 35 36 static AttributeDescription *ad_olmDbDirectory; 37 38 #ifdef MDB_MONITOR_IDX 39 static int 40 mdb_monitor_idx_entry_add( 41 struct mdb_info *mdb, 42 Entry *e ); 43 44 static AttributeDescription *ad_olmDbNotIndexed; 45 #endif /* MDB_MONITOR_IDX */ 46 47 /* 48 * NOTE: there's some confusion in monitor OID arc; 49 * by now, let's consider: 50 * 51 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0 52 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1 53 * MDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.3 54 * 55 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0 56 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1 57 * MDB database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.3 58 */ 59 60 static struct { 61 char *name; 62 char *oid; 63 } s_oid[] = { 64 { "olmMDBAttributes", "olmDatabaseAttributes:1" }, 65 { "olmMDBObjectClasses", "olmDatabaseObjectClasses:1" }, 66 67 { NULL } 68 }; 69 70 static struct { 71 char *desc; 72 AttributeDescription **ad; 73 } s_at[] = { 74 { "( olmDatabaseAttributes:1 " 75 "NAME ( 'olmDbDirectory' ) " 76 "DESC 'Path name of the directory " 77 "where the database environment resides' " 78 "SUP monitoredInfo " 79 "NO-USER-MODIFICATION " 80 "USAGE dSAOperation )", 81 &ad_olmDbDirectory }, 82 83 #ifdef MDB_MONITOR_IDX 84 { "( olmDatabaseAttributes:2 " 85 "NAME ( 'olmDbNotIndexed' ) " 86 "DESC 'Missing indexes resulting from candidate selection' " 87 "SUP monitoredInfo " 88 "NO-USER-MODIFICATION " 89 "USAGE dSAOperation )", 90 &ad_olmDbNotIndexed }, 91 #endif /* MDB_MONITOR_IDX */ 92 93 { NULL } 94 }; 95 96 static struct { 97 char *desc; 98 ObjectClass **oc; 99 } s_oc[] = { 100 /* augments an existing object, so it must be AUXILIARY 101 * FIXME: derive from some ABSTRACT "monitoredEntity"? */ 102 { "( olmMDBObjectClasses:2 " 103 "NAME ( 'olmMDBDatabase' ) " 104 "SUP top AUXILIARY " 105 "MAY ( " 106 "olmDbDirectory " 107 #ifdef MDB_MONITOR_IDX 108 "$ olmDbNotIndexed " 109 #endif /* MDB_MONITOR_IDX */ 110 ") )", 111 &oc_olmMDBDatabase }, 112 113 { NULL } 114 }; 115 116 static int 117 mdb_monitor_update( 118 Operation *op, 119 SlapReply *rs, 120 Entry *e, 121 void *priv ) 122 { 123 struct mdb_info *mdb = (struct mdb_info *) priv; 124 125 #ifdef MDB_MONITOR_IDX 126 mdb_monitor_idx_entry_add( mdb, e ); 127 #endif /* MDB_MONITOR_IDX */ 128 129 return SLAP_CB_CONTINUE; 130 } 131 132 #if 0 /* uncomment if required */ 133 static int 134 mdb_monitor_modify( 135 Operation *op, 136 SlapReply *rs, 137 Entry *e, 138 void *priv ) 139 { 140 return SLAP_CB_CONTINUE; 141 } 142 #endif 143 144 static int 145 mdb_monitor_free( 146 Entry *e, 147 void **priv ) 148 { 149 struct berval values[ 2 ]; 150 Modification mod = { 0 }; 151 152 const char *text; 153 char textbuf[ SLAP_TEXT_BUFLEN ]; 154 155 int i, rc; 156 157 /* NOTE: if slap_shutdown != 0, priv might have already been freed */ 158 *priv = NULL; 159 160 /* Remove objectClass */ 161 mod.sm_op = LDAP_MOD_DELETE; 162 mod.sm_desc = slap_schema.si_ad_objectClass; 163 mod.sm_values = values; 164 mod.sm_numvals = 1; 165 values[ 0 ] = oc_olmMDBDatabase->soc_cname; 166 BER_BVZERO( &values[ 1 ] ); 167 168 rc = modify_delete_values( e, &mod, 1, &text, 169 textbuf, sizeof( textbuf ) ); 170 /* don't care too much about return code... */ 171 172 /* remove attrs */ 173 mod.sm_values = NULL; 174 mod.sm_numvals = 0; 175 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 176 mod.sm_desc = *s_at[ i ].ad; 177 rc = modify_delete_values( e, &mod, 1, &text, 178 textbuf, sizeof( textbuf ) ); 179 /* don't care too much about return code... */ 180 } 181 182 return SLAP_CB_CONTINUE; 183 } 184 185 /* 186 * call from within mdb_initialize() 187 */ 188 static int 189 mdb_monitor_initialize( void ) 190 { 191 int i, code; 192 ConfigArgs c; 193 char *argv[ 3 ]; 194 195 static int mdb_monitor_initialized = 0; 196 197 /* set to 0 when successfully initialized; otherwise, remember failure */ 198 static int mdb_monitor_initialized_failure = 1; 199 200 if ( mdb_monitor_initialized++ ) { 201 return mdb_monitor_initialized_failure; 202 } 203 204 if ( backend_info( "monitor" ) == NULL ) { 205 return -1; 206 } 207 208 /* register schema here */ 209 210 argv[ 0 ] = "back-mdb monitor"; 211 c.argv = argv; 212 c.argc = 3; 213 c.fname = argv[0]; 214 215 for ( i = 0; s_oid[ i ].name; i++ ) { 216 c.lineno = i; 217 argv[ 1 ] = s_oid[ i ].name; 218 argv[ 2 ] = s_oid[ i ].oid; 219 220 if ( parse_oidm( &c, 0, NULL ) != 0 ) { 221 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize) 222 ": unable to add " 223 "objectIdentifier \"%s=%s\"\n", 224 s_oid[ i ].name, s_oid[ i ].oid, 0 ); 225 return 2; 226 } 227 } 228 229 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 230 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 ); 231 if ( code != LDAP_SUCCESS ) { 232 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize) 233 ": register_at failed for attributeType (%s)\n", 234 s_at[ i ].desc, 0, 0 ); 235 return 3; 236 237 } else { 238 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 239 } 240 } 241 242 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) { 243 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 ); 244 if ( code != LDAP_SUCCESS ) { 245 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize) 246 ": register_oc failed for objectClass (%s)\n", 247 s_oc[ i ].desc, 0, 0 ); 248 return 4; 249 250 } else { 251 (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE; 252 } 253 } 254 255 return ( mdb_monitor_initialized_failure = LDAP_SUCCESS ); 256 } 257 258 /* 259 * call from within mdb_db_init() 260 */ 261 int 262 mdb_monitor_db_init( BackendDB *be ) 263 { 264 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 265 266 if ( mdb_monitor_initialize() == LDAP_SUCCESS ) { 267 /* monitoring in back-mdb is on by default */ 268 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING; 269 } 270 271 #ifdef MDB_MONITOR_IDX 272 mdb->mi_idx = NULL; 273 ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex ); 274 #endif /* MDB_MONITOR_IDX */ 275 276 return 0; 277 } 278 279 /* 280 * call from within mdb_db_open() 281 */ 282 int 283 mdb_monitor_db_open( BackendDB *be ) 284 { 285 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 286 Attribute *a, *next; 287 monitor_callback_t *cb = NULL; 288 int rc = 0; 289 BackendInfo *mi; 290 monitor_extra_t *mbe; 291 292 if ( !SLAP_DBMONITORING( be ) ) { 293 return 0; 294 } 295 296 mi = backend_info( "monitor" ); 297 if ( !mi || !mi->bi_extra ) { 298 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; 299 return 0; 300 } 301 mbe = mi->bi_extra; 302 303 /* don't bother if monitor is not configured */ 304 if ( !mbe->is_configured() ) { 305 static int warning = 0; 306 307 if ( warning++ == 0 ) { 308 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open) 309 ": monitoring disabled; " 310 "configure monitor database to enable\n", 311 0, 0, 0 ); 312 } 313 314 return 0; 315 } 316 317 /* alloc as many as required (plus 1 for objectClass) */ 318 a = attrs_alloc( 1 + 1 ); 319 if ( a == NULL ) { 320 rc = 1; 321 goto cleanup; 322 } 323 324 a->a_desc = slap_schema.si_ad_objectClass; 325 attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 ); 326 next = a->a_next; 327 328 { 329 struct berval bv, nbv; 330 ber_len_t pathlen = 0, len = 0; 331 char path[ MAXPATHLEN ] = { '\0' }; 332 char *fname = mdb->mi_dbenv_home, 333 *ptr; 334 335 len = strlen( fname ); 336 if ( fname[ 0 ] != '/' ) { 337 /* get full path name */ 338 getcwd( path, sizeof( path ) ); 339 pathlen = strlen( path ); 340 341 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) { 342 fname += 2; 343 len -= 2; 344 } 345 } 346 347 bv.bv_len = pathlen + STRLENOF( "/" ) + len; 348 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 ); 349 if ( pathlen ) { 350 ptr = lutil_strncopy( ptr, path, pathlen ); 351 ptr[ 0 ] = '/'; 352 ptr++; 353 } 354 ptr = lutil_strncopy( ptr, fname, len ); 355 if ( ptr[ -1 ] != '/' ) { 356 ptr[ 0 ] = '/'; 357 ptr++; 358 } 359 ptr[ 0 ] = '\0'; 360 361 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL ); 362 363 next->a_desc = ad_olmDbDirectory; 364 next->a_vals = ch_calloc( sizeof( struct berval ), 2 ); 365 next->a_vals[ 0 ] = bv; 366 next->a_numvals = 1; 367 368 if ( BER_BVISNULL( &nbv ) ) { 369 next->a_nvals = next->a_vals; 370 371 } else { 372 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 ); 373 next->a_nvals[ 0 ] = nbv; 374 } 375 376 next = next->a_next; 377 } 378 379 cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 380 cb->mc_update = mdb_monitor_update; 381 #if 0 /* uncomment if required */ 382 cb->mc_modify = mdb_monitor_modify; 383 #endif 384 cb->mc_free = mdb_monitor_free; 385 cb->mc_private = (void *)mdb; 386 387 /* make sure the database is registered; then add monitor attributes */ 388 rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn ); 389 if ( rc == 0 ) { 390 rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb, 391 NULL, -1, NULL ); 392 } 393 394 cleanup:; 395 if ( rc != 0 ) { 396 if ( cb != NULL ) { 397 ch_free( cb ); 398 cb = NULL; 399 } 400 401 if ( a != NULL ) { 402 attrs_free( a ); 403 a = NULL; 404 } 405 } 406 407 /* store for cleanup */ 408 mdb->mi_monitor.mdm_cb = (void *)cb; 409 410 /* we don't need to keep track of the attributes, because 411 * mdb_monitor_free() takes care of everything */ 412 if ( a != NULL ) { 413 attrs_free( a ); 414 } 415 416 return rc; 417 } 418 419 /* 420 * call from within mdb_db_close() 421 */ 422 int 423 mdb_monitor_db_close( BackendDB *be ) 424 { 425 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 426 427 if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) { 428 BackendInfo *mi = backend_info( "monitor" ); 429 monitor_extra_t *mbe; 430 431 if ( mi && &mi->bi_extra ) { 432 mbe = mi->bi_extra; 433 mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn, 434 (monitor_callback_t *)mdb->mi_monitor.mdm_cb, 435 NULL, 0, NULL ); 436 } 437 438 memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) ); 439 } 440 441 return 0; 442 } 443 444 /* 445 * call from within mdb_db_destroy() 446 */ 447 int 448 mdb_monitor_db_destroy( BackendDB *be ) 449 { 450 #ifdef MDB_MONITOR_IDX 451 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 452 453 /* TODO: free tree */ 454 ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex ); 455 avl_free( mdb->mi_idx, ch_free ); 456 #endif /* MDB_MONITOR_IDX */ 457 458 return 0; 459 } 460 461 #ifdef MDB_MONITOR_IDX 462 463 #define MDB_MONITOR_IDX_TYPES (4) 464 465 typedef struct monitor_idx_t monitor_idx_t; 466 467 struct monitor_idx_t { 468 AttributeDescription *idx_ad; 469 unsigned long idx_count[MDB_MONITOR_IDX_TYPES]; 470 }; 471 472 static int 473 mdb_monitor_bitmask2key( slap_mask_t bitmask ) 474 { 475 int key; 476 477 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U ); 478 key++ ) 479 bitmask >>= 1; 480 481 return key; 482 } 483 484 static struct berval idxbv[] = { 485 BER_BVC( "present=" ), 486 BER_BVC( "equality=" ), 487 BER_BVC( "approx=" ), 488 BER_BVC( "substr=" ), 489 BER_BVNULL 490 }; 491 492 static ber_len_t 493 mdb_monitor_idx2len( monitor_idx_t *idx ) 494 { 495 int i; 496 ber_len_t len = 0; 497 498 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) { 499 if ( idx->idx_count[ i ] != 0 ) { 500 len += idxbv[i].bv_len; 501 } 502 } 503 504 return len; 505 } 506 507 static int 508 monitor_idx_cmp( const void *p1, const void *p2 ) 509 { 510 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1; 511 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2; 512 513 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ); 514 } 515 516 static int 517 monitor_idx_dup( void *p1, void *p2 ) 518 { 519 monitor_idx_t *idx1 = (monitor_idx_t *)p1; 520 monitor_idx_t *idx2 = (monitor_idx_t *)p2; 521 522 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0; 523 } 524 525 int 526 mdb_monitor_idx_add( 527 struct mdb_info *mdb, 528 AttributeDescription *desc, 529 slap_mask_t type ) 530 { 531 monitor_idx_t idx_dummy = { 0 }, 532 *idx; 533 int rc = 0, key; 534 535 idx_dummy.idx_ad = desc; 536 key = mdb_monitor_bitmask2key( type ) - 1; 537 if ( key >= MDB_MONITOR_IDX_TYPES ) { 538 /* invalid index type */ 539 return -1; 540 } 541 542 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex ); 543 544 idx = (monitor_idx_t *)avl_find( mdb->mi_idx, 545 (caddr_t)&idx_dummy, monitor_idx_cmp ); 546 if ( idx == NULL ) { 547 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 ); 548 idx->idx_ad = desc; 549 idx->idx_count[ key ] = 1; 550 551 switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx, 552 monitor_idx_cmp, monitor_idx_dup ) ) 553 { 554 case 0: 555 break; 556 557 default: 558 ch_free( idx ); 559 rc = -1; 560 } 561 562 } else { 563 idx->idx_count[ key ]++; 564 } 565 566 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex ); 567 568 return rc; 569 } 570 571 static int 572 mdb_monitor_idx_apply( void *v_idx, void *v_valp ) 573 { 574 monitor_idx_t *idx = (monitor_idx_t *)v_idx; 575 BerVarray *valp = (BerVarray *)v_valp; 576 577 struct berval bv; 578 char *ptr; 579 char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ]; 580 ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ], 581 idx_len; 582 int i, num = 0; 583 584 idx_len = mdb_monitor_idx2len( idx ); 585 586 bv.bv_len = 0; 587 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) { 588 if ( idx->idx_count[ i ] == 0 ) { 589 continue; 590 } 591 592 count_len[ i ] = snprintf( count_buf[ i ], 593 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] ); 594 bv.bv_len += count_len[ i ]; 595 num++; 596 } 597 598 bv.bv_len += idx->idx_ad->ad_cname.bv_len 599 + num 600 + idx_len; 601 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); 602 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val ); 603 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) { 604 if ( idx->idx_count[ i ] == 0 ) { 605 continue; 606 } 607 608 ptr[ 0 ] = '#'; 609 ++ptr; 610 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val ); 611 ptr = lutil_strcopy( ptr, count_buf[ i ] ); 612 } 613 614 ber_bvarray_add( valp, &bv ); 615 616 return 0; 617 } 618 619 static int 620 mdb_monitor_idx_entry_add( 621 struct mdb_info *mdb, 622 Entry *e ) 623 { 624 BerVarray vals = NULL; 625 Attribute *a; 626 627 a = attr_find( e->e_attrs, ad_olmDbNotIndexed ); 628 629 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex ); 630 631 avl_apply( mdb->mi_idx, mdb_monitor_idx_apply, 632 &vals, -1, AVL_INORDER ); 633 634 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex ); 635 636 if ( vals != NULL ) { 637 if ( a != NULL ) { 638 assert( a->a_nvals == a->a_vals ); 639 640 ber_bvarray_free( a->a_vals ); 641 642 } else { 643 Attribute **ap; 644 645 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next ) 646 ; 647 *ap = attr_alloc( ad_olmDbNotIndexed ); 648 a = *ap; 649 } 650 a->a_vals = vals; 651 a->a_nvals = a->a_vals; 652 } 653 654 return 0; 655 } 656 657 #endif /* MDB_MONITOR_IDX */ 658