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