1 /* $NetBSD: monitor.c,v 1.1.1.4 2014/05/28 09:58:49 tron Exp $ */ 2 3 /* monitor.c - monitor ldap backend */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2014 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 static ObjectClass *oc_olmLDAPConnection; 41 42 static ObjectClass *oc_monitorContainer; 43 static ObjectClass *oc_monitorCounterObject; 44 45 static AttributeDescription *ad_olmDbURIList; 46 static AttributeDescription *ad_olmDbOperations; 47 static AttributeDescription *ad_olmDbBoundDN; 48 static AttributeDescription *ad_olmDbConnFlags; 49 static AttributeDescription *ad_olmDbConnURI; 50 static AttributeDescription *ad_olmDbPeerAddress; 51 52 /* 53 * Stolen from back-monitor/operations.c 54 * We don't need the normalized rdn's though. 55 */ 56 struct ldap_back_monitor_ops_t { 57 struct berval rdn; 58 } ldap_back_monitor_op[] = { 59 { BER_BVC( "cn=Bind" ) }, 60 { BER_BVC( "cn=Unbind" ) }, 61 { BER_BVC( "cn=Search" ) }, 62 { BER_BVC( "cn=Compare" ) }, 63 { BER_BVC( "cn=Modify" ) }, 64 { BER_BVC( "cn=Modrdn" ) }, 65 { BER_BVC( "cn=Add" ) }, 66 { BER_BVC( "cn=Delete" ) }, 67 { BER_BVC( "cn=Abandon" ) }, 68 { BER_BVC( "cn=Extended" ) }, 69 70 { BER_BVNULL } 71 }; 72 73 /* Corresponds to connection flags in back-ldap.h */ 74 static struct { 75 unsigned flag; 76 struct berval name; 77 } s_flag[] = { 78 { LDAP_BACK_FCONN_ISBOUND, BER_BVC( "bound" ) }, 79 { LDAP_BACK_FCONN_ISANON, BER_BVC( "anonymous" ) }, 80 { LDAP_BACK_FCONN_ISPRIV, BER_BVC( "privileged" ) }, 81 { LDAP_BACK_FCONN_ISTLS, BER_BVC( "TLS" ) }, 82 { LDAP_BACK_FCONN_BINDING, BER_BVC( "binding" ) }, 83 { LDAP_BACK_FCONN_TAINTED, BER_BVC( "tainted" ) }, 84 { LDAP_BACK_FCONN_ABANDON, BER_BVC( "abandon" ) }, 85 { LDAP_BACK_FCONN_ISIDASR, BER_BVC( "idassert" ) }, 86 { LDAP_BACK_FCONN_CACHED, BER_BVC( "cached" ) }, 87 88 { 0 } 89 }; 90 91 92 /* 93 * NOTE: there's some confusion in monitor OID arc; 94 * by now, let's consider: 95 * 96 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0 97 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1 98 * LDAP database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.2 99 * 100 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0 101 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1 102 * LDAP database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.2 103 */ 104 105 static struct { 106 char *name; 107 char *oid; 108 } s_oid[] = { 109 { "olmLDAPAttributes", "olmDatabaseAttributes:2" }, 110 { "olmLDAPObjectClasses", "olmDatabaseObjectClasses:2" }, 111 112 { NULL } 113 }; 114 115 static struct { 116 char *desc; 117 AttributeDescription **ad; 118 } s_at[] = { 119 { "( olmLDAPAttributes:1 " 120 "NAME ( 'olmDbURIList' ) " 121 "DESC 'List of URIs a proxy is serving; can be modified run-time' " 122 "SUP managedInfo )", 123 &ad_olmDbURIList }, 124 { "( olmLDAPAttributes:2 " 125 "NAME ( 'olmDbOperation' ) " 126 "DESC 'monitor operations performed' " 127 "SUP monitorCounter " 128 "NO-USER-MODIFICATION " 129 "USAGE dSAOperation )", 130 &ad_olmDbOperations }, 131 { "( olmLDAPAttributes:3 " 132 "NAME ( 'olmDbBoundDN' ) " 133 "DESC 'monitor connection authorization DN' " 134 "SUP monitorConnectionAuthzDN " 135 "NO-USER-MODIFICATION " 136 "USAGE dSAOperation )", 137 &ad_olmDbBoundDN }, 138 { "( olmLDAPAttributes:4 " 139 "NAME ( 'olmDbConnFlags' ) " 140 "DESC 'monitor connection flags' " 141 "SUP monitoredInfo " 142 "NO-USER-MODIFICATION " 143 "USAGE dSAOperation )", 144 &ad_olmDbConnFlags }, 145 { "( olmLDAPAttributes:5 " 146 "NAME ( 'olmDbConnURI' ) " 147 "DESC 'monitor connection URI' " 148 "SUP monitorConnectionPeerAddress " 149 "NO-USER-MODIFICATION " 150 "USAGE dSAOperation )", 151 &ad_olmDbConnURI }, 152 { "( olmLDAPAttributes:6 " 153 "NAME ( 'olmDbConnPeerAddress' ) " 154 "DESC 'monitor connection peer address' " 155 "SUP monitorConnectionPeerAddress " 156 "NO-USER-MODIFICATION " 157 "USAGE dSAOperation )", 158 &ad_olmDbPeerAddress }, 159 160 { NULL } 161 }; 162 163 static struct { 164 char *name; 165 ObjectClass **oc; 166 } s_moc[] = { 167 { "monitorContainer", &oc_monitorContainer }, 168 { "monitorCounterObject", &oc_monitorCounterObject }, 169 170 { NULL } 171 }; 172 173 static struct { 174 char *desc; 175 ObjectClass **oc; 176 } s_oc[] = { 177 /* augments an existing object, so it must be AUXILIARY 178 * FIXME: derive from some ABSTRACT "monitoredEntity"? */ 179 { "( olmLDAPObjectClasses:1 " 180 "NAME ( 'olmLDAPDatabase' ) " 181 "SUP top AUXILIARY " 182 "MAY ( " 183 "olmDbURIList " 184 ") )", 185 &oc_olmLDAPDatabase }, 186 { "( olmLDAPObjectClasses:2 " 187 "NAME ( 'olmLDAPConnection' ) " 188 "SUP monitorConnection STRUCTURAL " 189 "MAY ( " 190 "olmDbBoundDN " 191 "$ olmDbConnFlags " 192 "$ olmDbConnURI " 193 "$ olmDbConnPeerAddress " 194 ") )", 195 &oc_olmLDAPConnection }, 196 197 { NULL } 198 }; 199 200 static int 201 ldap_back_monitor_update( 202 Operation *op, 203 SlapReply *rs, 204 Entry *e, 205 void *priv ) 206 { 207 ldapinfo_t *li = (ldapinfo_t *)priv; 208 209 Attribute *a; 210 211 /* update olmDbURIList */ 212 a = attr_find( e->e_attrs, ad_olmDbURIList ); 213 if ( a != NULL ) { 214 struct berval bv; 215 216 assert( a->a_vals != NULL ); 217 assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) ); 218 assert( BER_BVISNULL( &a->a_vals[ 1 ] ) ); 219 220 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 221 if ( li->li_uri ) { 222 ber_str2bv( li->li_uri, 0, 0, &bv ); 223 if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) { 224 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 225 } 226 } 227 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 228 } 229 230 return SLAP_CB_CONTINUE; 231 } 232 233 static int 234 ldap_back_monitor_modify( 235 Operation *op, 236 SlapReply *rs, 237 Entry *e, 238 void *priv ) 239 { 240 ldapinfo_t *li = (ldapinfo_t *) priv; 241 242 Attribute *save_attrs = NULL; 243 Modifications *ml, 244 *ml_olmDbURIList = NULL; 245 struct berval ul = BER_BVNULL; 246 int got = 0; 247 248 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { 249 if ( ml->sml_desc == ad_olmDbURIList ) { 250 if ( ml_olmDbURIList != NULL ) { 251 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 252 rs->sr_text = "conflicting modifications"; 253 goto done; 254 } 255 256 if ( ml->sml_op != LDAP_MOD_REPLACE ) { 257 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 258 rs->sr_text = "modification not allowed"; 259 goto done; 260 } 261 262 ml_olmDbURIList = ml; 263 got++; 264 continue; 265 } 266 } 267 268 if ( got == 0 ) { 269 return SLAP_CB_CONTINUE; 270 } 271 272 save_attrs = attrs_dup( e->e_attrs ); 273 274 if ( ml_olmDbURIList != NULL ) { 275 Attribute *a = NULL; 276 LDAPURLDesc *ludlist = NULL; 277 int rc; 278 279 ml = ml_olmDbURIList; 280 assert( ml->sml_nvalues != NULL ); 281 282 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { 283 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 284 rs->sr_text = "no value provided"; 285 goto done; 286 } 287 288 if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) { 289 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 290 rs->sr_text = "multiple values provided"; 291 goto done; 292 } 293 294 rc = ldap_url_parselist_ext( &ludlist, 295 ml->sml_nvalues[ 0 ].bv_val, NULL, 296 LDAP_PVT_URL_PARSE_NOEMPTY_HOST 297 | LDAP_PVT_URL_PARSE_DEF_PORT ); 298 if ( rc != LDAP_URL_SUCCESS ) { 299 rs->sr_err = LDAP_INVALID_SYNTAX; 300 rs->sr_text = "unable to parse URI list"; 301 goto done; 302 } 303 304 ul.bv_val = ldap_url_list2urls( ludlist ); 305 ldap_free_urllist( ludlist ); 306 if ( ul.bv_val == NULL ) { 307 rs->sr_err = LDAP_OTHER; 308 goto done; 309 } 310 ul.bv_len = strlen( ul.bv_val ); 311 312 a = attr_find( e->e_attrs, ad_olmDbURIList ); 313 if ( a != NULL ) { 314 if ( a->a_nvals == a->a_vals ) { 315 a->a_nvals = ch_calloc( sizeof( struct berval ), 2 ); 316 } 317 318 ber_bvreplace( &a->a_vals[ 0 ], &ul ); 319 ber_bvreplace( &a->a_nvals[ 0 ], &ul ); 320 321 } else { 322 attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL ); 323 } 324 } 325 326 /* apply changes */ 327 if ( !BER_BVISNULL( &ul ) ) { 328 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 329 if ( li->li_uri ) { 330 ch_free( li->li_uri ); 331 } 332 li->li_uri = ul.bv_val; 333 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 334 335 BER_BVZERO( &ul ); 336 } 337 338 done:; 339 if ( !BER_BVISNULL( &ul ) ) { 340 ldap_memfree( ul.bv_val ); 341 } 342 343 if ( rs->sr_err == LDAP_SUCCESS ) { 344 attrs_free( save_attrs ); 345 return SLAP_CB_CONTINUE; 346 } 347 348 attrs_free( e->e_attrs ); 349 e->e_attrs = save_attrs; 350 351 return rs->sr_err; 352 } 353 354 static int 355 ldap_back_monitor_free( 356 Entry *e, 357 void **priv ) 358 { 359 ldapinfo_t *li = (ldapinfo_t *)(*priv); 360 361 *priv = NULL; 362 363 if ( !slapd_shutdown ) { 364 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) ); 365 } 366 367 return SLAP_CB_CONTINUE; 368 } 369 370 static int 371 ldap_back_monitor_subsystem_destroy( 372 BackendDB *be, 373 monitor_subsys_t *ms) 374 { 375 free(ms->mss_dn.bv_val); 376 BER_BVZERO(&ms->mss_dn); 377 378 free(ms->mss_ndn.bv_val); 379 BER_BVZERO(&ms->mss_ndn); 380 381 return LDAP_SUCCESS; 382 } 383 384 /* 385 * Connection monitoring subsystem: 386 * Tries to mimick what the cn=connections,cn=monitor subsystem does 387 * by creating volatile entries for each connection and populating them 388 * according to the information attached to the connection. 389 * At this moment the only exposed information is the DN used to bind it. 390 * Also note that the connection IDs are not and probably never will be 391 * stable. 392 */ 393 394 struct ldap_back_monitor_conn_arg { 395 Operation *op; 396 monitor_subsys_t *ms; 397 Entry **ep; 398 }; 399 400 /* code stolen from daemon.c */ 401 static int 402 ldap_back_monitor_conn_peername( 403 LDAP *ld, 404 struct berval *bv) 405 { 406 Sockbuf *sockbuf; 407 ber_socket_t socket; 408 Sockaddr sa; 409 socklen_t salen = sizeof(sa); 410 const char *peeraddr = NULL; 411 /* we assume INET6_ADDRSTRLEN > INET_ADDRSTRLEN */ 412 char addr[INET6_ADDRSTRLEN]; 413 #ifdef LDAP_PF_LOCAL 414 char peername[MAXPATHLEN + sizeof("PATH=")]; 415 #elif defined(LDAP_PF_INET6) 416 char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")]; 417 #else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */ 418 char peername[sizeof("IP=255.255.255.255:65336")]; 419 #endif /* LDAP_PF_LOCAL */ 420 421 assert( bv != NULL ); 422 423 ldap_get_option( ld, LDAP_OPT_SOCKBUF, (void **)&sockbuf ); 424 ber_sockbuf_ctrl( sockbuf, LBER_SB_OPT_GET_FD, &socket ); 425 getpeername( socket, (struct sockaddr *)&sa, &salen ); 426 427 switch ( sa.sa_addr.sa_family ) { 428 #ifdef LDAP_PF_LOCAL 429 case AF_LOCAL: 430 sprintf( peername, "PATH=%s", sa.sa_un_addr.sun_path ); 431 break; 432 #endif /* LDAP_PF_LOCAL */ 433 434 #ifdef LDAP_PF_INET6 435 case AF_INET6: 436 if ( IN6_IS_ADDR_V4MAPPED(&sa.sa_in6_addr.sin6_addr) ) { 437 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 438 peeraddr = inet_ntop( AF_INET, 439 ((struct in_addr *)&sa.sa_in6_addr.sin6_addr.s6_addr[12]), 440 addr, sizeof(addr) ); 441 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 442 peeraddr = inet_ntoa( *((struct in_addr *) 443 &sa.sa_in6_addr.sin6_addr.s6_addr[12]) ); 444 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 445 if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN; 446 sprintf( peername, "IP=%s:%d", peeraddr, 447 (unsigned) ntohs( sa.sa_in6_addr.sin6_port ) ); 448 } else { 449 peeraddr = inet_ntop( AF_INET6, 450 &sa.sa_in6_addr.sin6_addr, 451 addr, sizeof addr ); 452 if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN; 453 sprintf( peername, "IP=[%s]:%d", peeraddr, 454 (unsigned) ntohs( sa.sa_in6_addr.sin6_port ) ); 455 } 456 break; 457 #endif /* LDAP_PF_INET6 */ 458 459 case AF_INET: { 460 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 461 peeraddr = inet_ntop( AF_INET, &sa.sa_in_addr.sin_addr, 462 addr, sizeof(addr) ); 463 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 464 peeraddr = inet_ntoa( sa.sa_in_addr.sin_addr ); 465 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 466 if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN; 467 sprintf( peername, "IP=%s:%d", peeraddr, 468 (unsigned) ntohs( sa.sa_in_addr.sin_port ) ); 469 } break; 470 471 default: 472 sprintf( peername, SLAP_STRING_UNKNOWN ); 473 } 474 475 ber_str2bv( peername, 0, 1, bv ); 476 return LDAP_SUCCESS; 477 } 478 479 static int 480 ldap_back_monitor_conn_entry( 481 ldapconn_t *lc, 482 struct ldap_back_monitor_conn_arg *arg ) 483 { 484 Entry *e; 485 monitor_entry_t *mp; 486 monitor_extra_t *mbe = arg->op->o_bd->bd_info->bi_extra; 487 char buf[SLAP_TEXT_BUFLEN]; 488 char *ptr; 489 struct berval bv; 490 int i; 491 492 bv.bv_val = buf; 493 bv.bv_len = snprintf( bv.bv_val, SLAP_TEXT_BUFLEN, 494 "cn=Connection %lu", lc->lc_connid ); 495 496 e = mbe->entry_stub( &arg->ms->mss_dn, &arg->ms->mss_ndn, &bv, 497 oc_monitorContainer, NULL, NULL ); 498 499 attr_merge_normalize_one( e, ad_olmDbBoundDN, &lc->lc_bound_ndn, NULL ); 500 501 for ( i = 0; s_flag[i].flag; i++ ) 502 { 503 if ( lc->lc_flags & s_flag[i].flag ) 504 { 505 attr_merge_normalize_one( e, ad_olmDbConnFlags, &s_flag[i].name, NULL ); 506 } 507 } 508 509 ldap_get_option( lc->lc_ld, LDAP_OPT_URI, &bv.bv_val ); 510 ptr = strchr( bv.bv_val, ' ' ); 511 bv.bv_len = ptr ? ptr - bv.bv_val : strlen(bv.bv_val); 512 attr_merge_normalize_one( e, ad_olmDbConnURI, &bv, NULL ); 513 ch_free( bv.bv_val ); 514 515 ldap_back_monitor_conn_peername( lc->lc_ld, &bv ); 516 attr_merge_normalize_one( e, ad_olmDbPeerAddress, &bv, NULL ); 517 ch_free( bv.bv_val ); 518 519 mp = mbe->entrypriv_create(); 520 e->e_private = mp; 521 mp->mp_info = arg->ms; 522 mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE; 523 524 *arg->ep = e; 525 arg->ep = &mp->mp_next; 526 527 return 0; 528 } 529 530 static int 531 ldap_back_monitor_conn_create( 532 Operation *op, 533 SlapReply *rs, 534 struct berval *ndn, 535 Entry *e_parent, 536 Entry **ep ) 537 { 538 monitor_entry_t *mp_parent; 539 monitor_subsys_t *ms; 540 ldapinfo_t *li; 541 ldapconn_t *lc; 542 543 struct ldap_back_monitor_conn_arg *arg; 544 int conn_type; 545 546 assert( e_parent->e_private != NULL ); 547 548 mp_parent = e_parent->e_private; 549 ms = (monitor_subsys_t *)mp_parent->mp_info; 550 li = (ldapinfo_t *)ms->mss_private; 551 552 arg = ch_calloc( 1, sizeof(struct ldap_back_monitor_conn_arg) ); 553 arg->op = op; 554 arg->ep = ep; 555 arg->ms = ms; 556 557 for ( conn_type = LDAP_BACK_PCONN_FIRST; 558 conn_type < LDAP_BACK_PCONN_LAST; 559 conn_type++ ) 560 { 561 LDAP_TAILQ_FOREACH( lc, 562 &li->li_conn_priv[ conn_type ].lic_priv, 563 lc_q ) 564 { 565 ldap_back_monitor_conn_entry( lc, arg ); 566 } 567 } 568 569 avl_apply( li->li_conninfo.lai_tree, (AVL_APPLY)ldap_back_monitor_conn_entry, 570 arg, -1, AVL_INORDER ); 571 572 ch_free( arg ); 573 574 return 0; 575 } 576 577 static int 578 ldap_back_monitor_conn_init( 579 BackendDB *be, 580 monitor_subsys_t *ms ) 581 { 582 ldapinfo_t *li = (ldapinfo_t *) ms->mss_private; 583 monitor_extra_t *mbe; 584 585 Entry *e; 586 int rc; 587 588 assert( be != NULL ); 589 mbe = (monitor_extra_t *) be->bd_info->bi_extra; 590 591 ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn; 592 ms->mss_rdn = li->li_monitor_info.lmi_conn_rdn; 593 ms->mss_create = ldap_back_monitor_conn_create; 594 ms->mss_destroy = ldap_back_monitor_subsystem_destroy; 595 596 e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, 597 &ms->mss_rdn, oc_monitorContainer, NULL, NULL ); 598 if ( e == NULL ) { 599 Debug( LDAP_DEBUG_ANY, 600 "ldap_back_monitor_conn_init: " 601 "unable to create entry \"%s,%s\"\n", 602 li->li_monitor_info.lmi_conn_rdn.bv_val, 603 ms->mss_ndn.bv_val, 0 ); 604 return( -1 ); 605 } 606 607 ber_dupbv( &ms->mss_dn, &e->e_name ); 608 ber_dupbv( &ms->mss_ndn, &e->e_nname ); 609 610 rc = mbe->register_entry( e, NULL, ms, MONITOR_F_VOLATILE_CH ); 611 612 /* add labeledURI and special, modifiable URI value */ 613 if ( rc == LDAP_SUCCESS && li->li_uri != NULL ) { 614 struct berval bv; 615 Attribute *a; 616 LDAPURLDesc *ludlist = NULL; 617 monitor_callback_t *cb = NULL; 618 619 a = attr_alloc( ad_olmDbURIList ); 620 621 ber_str2bv( li->li_uri, 0, 0, &bv ); 622 attr_valadd( a, &bv, NULL, 1 ); 623 attr_normalize( a->a_desc, a->a_vals, &a->a_nvals, NULL ); 624 625 rc = ldap_url_parselist_ext( &ludlist, 626 li->li_uri, NULL, 627 LDAP_PVT_URL_PARSE_NOEMPTY_HOST 628 | LDAP_PVT_URL_PARSE_DEF_PORT ); 629 if ( rc != LDAP_URL_SUCCESS ) { 630 Debug( LDAP_DEBUG_ANY, 631 "ldap_back_monitor_db_open: " 632 "unable to parse URI list (ignored)\n", 633 0, 0, 0 ); 634 } else { 635 Attribute *a2 = attr_alloc( slap_schema.si_ad_labeledURI ); 636 637 a->a_next = a2; 638 639 for ( ; ludlist != NULL; ) { 640 LDAPURLDesc *next = ludlist->lud_next; 641 642 bv.bv_val = ldap_url_desc2str( ludlist ); 643 assert( bv.bv_val != NULL ); 644 ldap_free_urldesc( ludlist ); 645 bv.bv_len = strlen( bv.bv_val ); 646 attr_valadd( a2, &bv, NULL, 1 ); 647 ch_free( bv.bv_val ); 648 649 ludlist = next; 650 } 651 652 attr_normalize( a2->a_desc, a2->a_vals, &a2->a_nvals, NULL ); 653 } 654 655 cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 656 cb->mc_update = ldap_back_monitor_update; 657 cb->mc_modify = ldap_back_monitor_modify; 658 cb->mc_free = ldap_back_monitor_free; 659 cb->mc_private = (void *)li; 660 661 rc = mbe->register_entry_attrs( &ms->mss_ndn, a, cb, NULL, -1, NULL ); 662 663 attr_free( a->a_next ); 664 attr_free( a ); 665 666 if ( rc != LDAP_SUCCESS ) 667 { 668 ch_free( cb ); 669 } 670 } 671 672 entry_free( e ); 673 674 return rc; 675 } 676 677 /* 678 * Operation monitoring subsystem: 679 * Looks a lot like the cn=operations,cn=monitor subsystem except that at this 680 * moment, only completed operations are counted. Each entry has a separate 681 * callback with all the needed information linked there in the structure 682 * below so that the callback need not locate it over and over again. 683 */ 684 685 struct ldap_back_monitor_op_counter { 686 ldap_pvt_mp_t *data; 687 ldap_pvt_thread_mutex_t *mutex; 688 }; 689 690 static void 691 ldap_back_monitor_ops_dispose( 692 void **priv) 693 { 694 struct ldap_back_monitor_op_counter *counter = *priv; 695 696 ch_free( counter ); 697 counter = NULL; 698 } 699 700 static int 701 ldap_back_monitor_ops_free( 702 Entry *e, 703 void **priv) 704 { 705 ldap_back_monitor_ops_dispose( priv ); 706 return LDAP_SUCCESS; 707 } 708 709 static int 710 ldap_back_monitor_ops_update( 711 Operation *op, 712 SlapReply *rs, 713 Entry *e, 714 void *priv ) 715 { 716 struct ldap_back_monitor_op_counter *counter = priv; 717 Attribute *a; 718 719 /*TODO 720 * what about initiated/completed? 721 */ 722 a = attr_find( e->e_attrs, ad_olmDbOperations ); 723 assert( a != NULL ); 724 725 ldap_pvt_thread_mutex_lock( counter->mutex ); 726 UI2BV( &a->a_vals[ 0 ], *counter->data ); 727 ldap_pvt_thread_mutex_unlock( counter->mutex ); 728 729 return SLAP_CB_CONTINUE; 730 } 731 732 static int 733 ldap_back_monitor_ops_init( 734 BackendDB *be, 735 monitor_subsys_t *ms ) 736 { 737 ldapinfo_t *li = (ldapinfo_t *) ms->mss_private; 738 739 monitor_extra_t *mbe; 740 Entry *e, *parent; 741 int rc; 742 slap_op_t op; 743 struct berval value = BER_BVC( "0" ); 744 745 assert( be != NULL ); 746 747 mbe = (monitor_extra_t *) be->bd_info->bi_extra; 748 749 ms->mss_dn = ms->mss_ndn = li->li_monitor_info.lmi_ndn; 750 ms->mss_rdn = li->li_monitor_info.lmi_ops_rdn; 751 ms->mss_destroy = ldap_back_monitor_subsystem_destroy; 752 753 parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, 754 &ms->mss_rdn, oc_monitorContainer, NULL, NULL ); 755 if ( parent == NULL ) { 756 Debug( LDAP_DEBUG_ANY, 757 "ldap_back_monitor_ops_init: " 758 "unable to create entry \"%s,%s\"\n", 759 li->li_monitor_info.lmi_ops_rdn.bv_val, 760 ms->mss_ndn.bv_val, 0 ); 761 return( -1 ); 762 } 763 764 ber_dupbv( &ms->mss_dn, &parent->e_name ); 765 ber_dupbv( &ms->mss_ndn, &parent->e_nname ); 766 767 rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH ); 768 if ( rc != LDAP_SUCCESS ) 769 { 770 Debug( LDAP_DEBUG_ANY, 771 "ldap_back_monitor_ops_init: " 772 "unable to register entry \"%s\" for monitoring\n", 773 parent->e_name.bv_val, 0, 0 ); 774 goto done; 775 } 776 777 for ( op = 0; op < SLAP_OP_LAST; op++ ) 778 { 779 monitor_callback_t *cb; 780 struct ldap_back_monitor_op_counter *counter; 781 782 e = mbe->entry_stub( &parent->e_name, &parent->e_nname, 783 &ldap_back_monitor_op[op].rdn, 784 oc_monitorCounterObject, NULL, NULL ); 785 if ( e == NULL ) { 786 Debug( LDAP_DEBUG_ANY, 787 "ldap_back_monitor_ops_init: " 788 "unable to create entry \"%s,%s\"\n", 789 ldap_back_monitor_op[op].rdn.bv_val, 790 parent->e_nname.bv_val, 0 ); 791 return( -1 ); 792 } 793 794 attr_merge_normalize_one( e, ad_olmDbOperations, &value, NULL ); 795 796 counter = ch_malloc( sizeof( struct ldap_back_monitor_op_counter ) ); 797 counter->data = &li->li_ops_completed[ op ]; 798 counter->mutex = &li->li_counter_mutex; 799 800 /* 801 * We cannot share a single callback between entries. 802 * 803 * monitor_cache_destroy() tries to free all callbacks and it's called 804 * before mss_destroy() so we have no chance of handling it ourselves 805 */ 806 cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 807 cb->mc_update = ldap_back_monitor_ops_update; 808 cb->mc_free = ldap_back_monitor_ops_free; 809 cb->mc_dispose = ldap_back_monitor_ops_dispose; 810 cb->mc_private = (void *)counter; 811 812 rc = mbe->register_entry( e, cb, ms, 0 ); 813 814 /* TODO: register_entry has stored a duplicate so we might actually reuse it 815 * instead of recreating it every time... */ 816 entry_free( e ); 817 818 if ( rc != LDAP_SUCCESS ) 819 { 820 Debug( LDAP_DEBUG_ANY, 821 "ldap_back_monitor_ops_init: " 822 "unable to register entry \"%s\" for monitoring\n", 823 e->e_name.bv_val, 0, 0 ); 824 ch_free( cb ); 825 break; 826 } 827 } 828 829 done: 830 entry_free( parent ); 831 832 return rc; 833 } 834 835 /* 836 * call from within ldap_back_initialize() 837 */ 838 static int 839 ldap_back_monitor_initialize( void ) 840 { 841 int i, code; 842 ConfigArgs c; 843 char *argv[ 3 ]; 844 845 static int ldap_back_monitor_initialized = 0; 846 847 /* set to 0 when successfully initialized; otherwise, remember failure */ 848 static int ldap_back_monitor_initialized_failure = 1; 849 850 /* register schema here; if compiled as dynamic object, 851 * must be loaded __after__ back_monitor.la */ 852 853 if ( ldap_back_monitor_initialized++ ) { 854 return ldap_back_monitor_initialized_failure; 855 } 856 857 if ( backend_info( "monitor" ) == NULL ) { 858 return -1; 859 } 860 861 argv[ 0 ] = "back-ldap monitor"; 862 c.argv = argv; 863 c.argc = 3; 864 c.fname = argv[0]; 865 for ( i = 0; s_oid[ i ].name; i++ ) { 866 867 argv[ 1 ] = s_oid[ i ].name; 868 argv[ 2 ] = s_oid[ i ].oid; 869 870 if ( parse_oidm( &c, 0, NULL ) != 0 ) { 871 Debug( LDAP_DEBUG_ANY, 872 "ldap_back_monitor_initialize: unable to add " 873 "objectIdentifier \"%s=%s\"\n", 874 s_oid[ i ].name, s_oid[ i ].oid, 0 ); 875 return 2; 876 } 877 } 878 879 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 880 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 ); 881 if ( code != LDAP_SUCCESS ) { 882 Debug( LDAP_DEBUG_ANY, 883 "ldap_back_monitor_initialize: register_at failed for attributeType (%s)\n", 884 s_at[ i ].desc, 0, 0 ); 885 return 3; 886 887 } else { 888 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 889 } 890 } 891 892 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) { 893 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 ); 894 if ( code != LDAP_SUCCESS ) { 895 Debug( LDAP_DEBUG_ANY, 896 "ldap_back_monitor_initialize: register_oc failed for objectClass (%s)\n", 897 s_oc[ i ].desc, 0, 0 ); 898 return 4; 899 900 } else { 901 (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE; 902 } 903 } 904 905 for ( i = 0; s_moc[ i ].name != NULL; i++ ) { 906 *s_moc[i].oc = oc_find( s_moc[ i ].name ); 907 if ( ! *s_moc[i].oc ) { 908 Debug( LDAP_DEBUG_ANY, 909 "ldap_back_monitor_initialize: failed to find objectClass (%s)\n", 910 s_moc[ i ].name, 0, 0 ); 911 return 5; 912 913 } 914 } 915 916 return ( ldap_back_monitor_initialized_failure = LDAP_SUCCESS ); 917 } 918 919 /* 920 * call from within ldap_back_db_init() 921 */ 922 int 923 ldap_back_monitor_db_init( BackendDB *be ) 924 { 925 int rc; 926 927 rc = ldap_back_monitor_initialize(); 928 if ( rc != LDAP_SUCCESS ) { 929 return rc; 930 } 931 932 #if 0 /* uncomment to turn monitoring on by default */ 933 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING; 934 #endif 935 936 return 0; 937 } 938 939 /* 940 * call from within ldap_back_db_open() 941 */ 942 int 943 ldap_back_monitor_db_open( BackendDB *be ) 944 { 945 ldapinfo_t *li = (ldapinfo_t *) be->be_private; 946 monitor_subsys_t *mss = li->li_monitor_info.lmi_mss; 947 int rc = 0; 948 BackendInfo *mi; 949 monitor_extra_t *mbe; 950 951 if ( !SLAP_DBMONITORING( be ) ) { 952 return 0; 953 } 954 955 /* check if monitor is configured and usable */ 956 mi = backend_info( "monitor" ); 957 if ( !mi || !mi->bi_extra ) { 958 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; 959 return 0; 960 } 961 mbe = mi->bi_extra; 962 963 /* don't bother if monitor is not configured */ 964 if ( !mbe->is_configured() ) { 965 static int warning = 0; 966 967 if ( warning++ == 0 ) { 968 Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: " 969 "monitoring disabled; " 970 "configure monitor database to enable\n", 971 0, 0, 0 ); 972 } 973 974 return 0; 975 } 976 977 /* caller (e.g. an overlay based on back-ldap) may want to use 978 * a different DN and RDNs... */ 979 if ( BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) { 980 rc = mbe->register_database( be, &li->li_monitor_info.lmi_ndn ); 981 if ( rc != 0 ) { 982 Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: " 983 "failed to register the databse with back-monitor\n", 984 0, 0, 0 ); 985 } 986 } 987 if ( BER_BVISNULL( &li->li_monitor_info.lmi_conn_rdn ) ) { 988 ber_str2bv( "cn=Connections", 0, 1, 989 &li->li_monitor_info.lmi_conn_rdn ); 990 } 991 if ( BER_BVISNULL( &li->li_monitor_info.lmi_ops_rdn ) ) { 992 ber_str2bv( "cn=Operations", 0, 1, 993 &li->li_monitor_info.lmi_ops_rdn ); 994 } 995 996 /* set up the subsystems used to create the operation and 997 * volatile connection entries */ 998 999 mss->mss_name = "back-ldap connections"; 1000 mss->mss_flags = MONITOR_F_VOLATILE_CH; 1001 mss->mss_open = ldap_back_monitor_conn_init; 1002 mss->mss_private = li; 1003 1004 if ( mbe->register_subsys_late( mss ) ) 1005 { 1006 Debug( LDAP_DEBUG_ANY, 1007 "ldap_back_monitor_db_open: " 1008 "failed to register connection subsystem", 0, 0, 0 ); 1009 return -1; 1010 } 1011 1012 mss++; 1013 1014 mss->mss_name = "back-ldap operations"; 1015 mss->mss_flags = MONITOR_F_PERSISTENT_CH; 1016 mss->mss_open = ldap_back_monitor_ops_init; 1017 mss->mss_private = li; 1018 1019 if ( mbe->register_subsys_late( mss ) ) 1020 { 1021 Debug( LDAP_DEBUG_ANY, 1022 "ldap_back_monitor_db_open: " 1023 "failed to register operation subsystem", 0, 0, 0 ); 1024 return -1; 1025 } 1026 1027 return rc; 1028 } 1029 1030 /* 1031 * call from within ldap_back_db_close() 1032 */ 1033 int 1034 ldap_back_monitor_db_close( BackendDB *be ) 1035 { 1036 ldapinfo_t *li = (ldapinfo_t *) be->be_private; 1037 1038 if ( li && !BER_BVISNULL( &li->li_monitor_info.lmi_ndn ) ) { 1039 BackendInfo *mi; 1040 monitor_extra_t *mbe; 1041 1042 /* check if monitor is configured and usable */ 1043 mi = backend_info( "monitor" ); 1044 if ( mi && mi->bi_extra ) { 1045 mbe = mi->bi_extra; 1046 1047 /*TODO 1048 * Unregister all entries our subsystems have created. 1049 * Will only really be necessary when 1050 * SLAPD_CONFIG_DELETE is enabled. 1051 * 1052 * Might need a way to unregister subsystems instead. 1053 */ 1054 } 1055 } 1056 1057 return 0; 1058 } 1059 1060 /* 1061 * call from within ldap_back_db_destroy() 1062 */ 1063 int 1064 ldap_back_monitor_db_destroy( BackendDB *be ) 1065 { 1066 ldapinfo_t *li = (ldapinfo_t *) be->be_private; 1067 1068 if ( li ) { 1069 memset( &li->li_monitor_info, 0, sizeof( li->li_monitor_info ) ); 1070 } 1071 1072 return 0; 1073 } 1074 1075