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