Back to index

openldap  2.4.31
init.c
Go to the documentation of this file.
00001 /* init.c - initialize monitor backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2001-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2001-2003 Pierangelo Masarati.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This work was initially developed by Pierangelo Masarati for inclusion
00019  * in OpenLDAP Software.
00020  */
00021 
00022 #include "portable.h"
00023 
00024 #include <stdio.h>
00025 #include <ac/string.h>
00026 
00027 #include <lutil.h>
00028 #include "slap.h"
00029 #include "config.h"
00030 #include "lber_pvt.h"
00031 #include "back-monitor.h"
00032 
00033 #include "config.h"
00034 
00035 #undef INTEGRATE_CORE_SCHEMA
00036 
00037 /*
00038  * used by many functions to add description to entries
00039  *
00040  * WARNING: be_monitor may change as new databases are added,
00041  * so it should not be used outside monitor_back_db_init()
00042  * until monitor_back_db_open is called.
00043  */
00044 BackendDB                   *be_monitor;
00045 
00046 static struct monitor_subsys_t     **monitor_subsys;
00047 static int                  monitor_subsys_opened;
00048 static monitor_info_t              monitor_info;
00049 static const monitor_extra_t monitor_extra = {
00050        monitor_back_is_configured,
00051        monitor_back_get_subsys,
00052        monitor_back_get_subsys_by_dn,
00053 
00054        monitor_back_register_subsys,
00055        monitor_back_register_backend,
00056        monitor_back_register_database,
00057        monitor_back_register_overlay_info,
00058        monitor_back_register_overlay,
00059        monitor_back_register_entry,
00060        monitor_back_register_entry_parent,
00061        monitor_back_register_entry_attrs,
00062        monitor_back_register_entry_callback,
00063 
00064        monitor_back_unregister_entry,
00065        monitor_back_unregister_entry_parent,
00066        monitor_back_unregister_entry_attrs,
00067        monitor_back_unregister_entry_callback
00068 };
00069        
00070 
00071 /*
00072  * subsystem data
00073  *
00074  * the known subsystems are added to the subsystems
00075  * array at backend initialization; other subsystems
00076  * may be added by calling monitor_back_register_subsys()
00077  * before the database is opened (e.g. by other backends
00078  * or by overlays or modules).
00079  */
00080 static struct monitor_subsys_t known_monitor_subsys[] = {
00081        { 
00082               SLAPD_MONITOR_BACKEND_NAME, 
00083               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00084               { BER_BVC( "This subsystem contains information about available backends." ),
00085                      BER_BVNULL },
00086               MONITOR_F_PERSISTENT_CH,
00087               monitor_subsys_backend_init,
00088               NULL,  /* destroy */
00089               NULL,   /* update */
00090               NULL,   /* create */
00091               NULL   /* modify */
00092               }, { 
00093               SLAPD_MONITOR_CONN_NAME,
00094               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00095               { BER_BVC( "This subsystem contains information about connections." ),
00096                      BER_BVNULL },
00097               MONITOR_F_VOLATILE_CH,
00098               monitor_subsys_conn_init,
00099               NULL,  /* destroy */
00100               NULL,   /* update */
00101               NULL,   /* create */
00102               NULL   /* modify */
00103               }, { 
00104               SLAPD_MONITOR_DATABASE_NAME,       
00105               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00106               { BER_BVC( "This subsystem contains information about configured databases." ),
00107                      BER_BVNULL },
00108               MONITOR_F_PERSISTENT_CH,
00109               monitor_subsys_database_init,
00110               NULL,  /* destroy */
00111               NULL,   /* update */
00112               NULL,   /* create */
00113               NULL   /* modify */
00114               }, { 
00115               SLAPD_MONITOR_LISTENER_NAME,       
00116               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00117               { BER_BVC( "This subsystem contains information about active listeners." ),
00118                      BER_BVNULL },
00119               MONITOR_F_PERSISTENT_CH,
00120               monitor_subsys_listener_init,
00121               NULL,  /* destroy */
00122               NULL,  /* update */
00123               NULL,  /* create */
00124               NULL   /* modify */
00125               }, { 
00126               SLAPD_MONITOR_LOG_NAME,
00127               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00128               { BER_BVC( "This subsystem contains information about logging." ),
00129                      BER_BVC( "Set the attribute \"managedInfo\" to the desired log levels." ),
00130                      BER_BVNULL },
00131               MONITOR_F_NONE,
00132               monitor_subsys_log_init,
00133               NULL,  /* destroy */
00134               NULL,  /* update */
00135               NULL,   /* create */
00136               NULL,  /* modify */
00137               }, { 
00138               SLAPD_MONITOR_OPS_NAME,
00139               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00140               { BER_BVC( "This subsystem contains information about performed operations." ),
00141                      BER_BVNULL },
00142               MONITOR_F_PERSISTENT_CH,
00143               monitor_subsys_ops_init,
00144               NULL,  /* destroy */
00145               NULL,  /* update */
00146               NULL,   /* create */
00147               NULL,  /* modify */
00148               }, { 
00149               SLAPD_MONITOR_OVERLAY_NAME,
00150               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00151               { BER_BVC( "This subsystem contains information about available overlays." ),
00152                      BER_BVNULL },
00153               MONITOR_F_PERSISTENT_CH,
00154               monitor_subsys_overlay_init,
00155               NULL,  /* destroy */
00156               NULL,  /* update */
00157               NULL,   /* create */
00158               NULL,  /* modify */
00159        }, { 
00160               SLAPD_MONITOR_SASL_NAME,    
00161               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00162               { BER_BVC( "This subsystem contains information about SASL." ),
00163                      BER_BVNULL },
00164               MONITOR_F_NONE,
00165               NULL,   /* init */
00166               NULL,  /* destroy */
00167               NULL,   /* update */
00168               NULL,   /* create */
00169               NULL   /* modify */
00170               }, { 
00171               SLAPD_MONITOR_SENT_NAME,
00172               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00173               { BER_BVC( "This subsystem contains statistics." ),
00174                      BER_BVNULL },
00175               MONITOR_F_PERSISTENT_CH,
00176               monitor_subsys_sent_init,
00177               NULL,  /* destroy */
00178               NULL,   /* update */
00179               NULL,   /* create */
00180               NULL,  /* modify */
00181               }, { 
00182               SLAPD_MONITOR_THREAD_NAME,  
00183               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00184               { BER_BVC( "This subsystem contains information about threads." ),
00185                      BER_BVNULL },
00186               MONITOR_F_PERSISTENT_CH,
00187               monitor_subsys_thread_init,
00188               NULL,  /* destroy */
00189               NULL,   /* update */
00190               NULL,   /* create */
00191               NULL   /* modify */
00192               }, { 
00193               SLAPD_MONITOR_TIME_NAME,
00194               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00195               { BER_BVC( "This subsystem contains information about time." ),
00196                      BER_BVNULL },
00197               MONITOR_F_PERSISTENT_CH,
00198               monitor_subsys_time_init,
00199               NULL,  /* destroy */
00200               NULL,   /* update */
00201               NULL,   /* create */
00202               NULL,  /* modify */
00203               }, { 
00204               SLAPD_MONITOR_TLS_NAME,
00205               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00206               { BER_BVC( "This subsystem contains information about TLS." ),
00207                      BER_BVNULL },
00208               MONITOR_F_NONE,
00209               NULL,   /* init */
00210               NULL,  /* destroy */
00211               NULL,   /* update */
00212               NULL,   /* create */
00213               NULL   /* modify */
00214               }, { 
00215               SLAPD_MONITOR_RWW_NAME,
00216               BER_BVNULL, BER_BVNULL, BER_BVNULL,
00217               { BER_BVC( "This subsystem contains information about read/write waiters." ),
00218                      BER_BVNULL },
00219               MONITOR_F_PERSISTENT_CH,
00220               monitor_subsys_rww_init,
00221               NULL,  /* destroy */
00222               NULL,   /* update */
00223               NULL,  /* create */
00224               NULL   /* modify */
00225               }, { NULL }
00226 };
00227 
00228 int
00229 monitor_subsys_is_opened( void )
00230 {
00231        return monitor_subsys_opened;
00232 }
00233 
00234 int
00235 monitor_back_register_subsys(
00236        monitor_subsys_t     *ms )
00237 {
00238        int    i = 0;
00239 
00240        if ( monitor_subsys ) {
00241               for ( ; monitor_subsys[ i ] != NULL; i++ )
00242                      /* just count'em */ ;
00243        }
00244 
00245        monitor_subsys = ch_realloc( monitor_subsys,
00246                      ( 2 + i ) * sizeof( monitor_subsys_t * ) );
00247 
00248        if ( monitor_subsys == NULL ) {
00249               return -1;
00250        }
00251 
00252        monitor_subsys[ i ] = ms;
00253        monitor_subsys[ i + 1 ] = NULL;
00254 
00255        /* if a subsystem is registered __AFTER__ subsystem 
00256         * initialization (depending on the sequence the databases
00257         * are listed in slapd.conf), init it */
00258        if ( monitor_subsys_is_opened() ) {
00259 
00260               /* FIXME: this should only be possible
00261                * if be_monitor is already initialized */
00262               assert( be_monitor != NULL );
00263 
00264               if ( ms->mss_open && ( *ms->mss_open )( be_monitor, ms ) ) {
00265                      return -1;
00266               }
00267 
00268               ms->mss_flags |= MONITOR_F_OPENED;
00269        }
00270 
00271        return 0;
00272 }
00273 
00274 enum {
00275        LIMBO_ENTRY,
00276        LIMBO_ENTRY_PARENT,
00277        LIMBO_ATTRS,
00278        LIMBO_CB,
00279        LIMBO_BACKEND,
00280        LIMBO_DATABASE,
00281        LIMBO_OVERLAY_INFO,
00282        LIMBO_OVERLAY,
00283 
00284        LIMBO_LAST
00285 };
00286 
00287 typedef struct entry_limbo_t {
00288        int                  el_type;
00289        BackendInfo          *el_bi;
00290        BackendDB            *el_be;
00291        slap_overinst        *el_on;
00292        Entry                *el_e;
00293        Attribute            *el_a;
00294        struct berval        *el_ndn;
00295        struct berval        el_nbase;
00296        int                  el_scope;
00297        struct berval        el_filter;
00298        monitor_callback_t   *el_cb;
00299        monitor_subsys_t     *el_mss;
00300        unsigned long        el_flags;
00301        struct entry_limbo_t *el_next;
00302 } entry_limbo_t;
00303 
00304 int
00305 monitor_back_is_configured( void )
00306 {
00307        return be_monitor != NULL;
00308 }
00309 
00310 int
00311 monitor_back_register_backend(
00312        BackendInfo          *bi )
00313 {
00314        return -1;
00315 }
00316 
00317 int
00318 monitor_back_register_overlay_info(
00319        slap_overinst        *on )
00320 {
00321        return -1;
00322 }
00323 
00324 int
00325 monitor_back_register_backend_limbo(
00326        BackendInfo          *bi )
00327 {
00328        return -1;
00329 }
00330 
00331 int
00332 monitor_back_register_database_limbo(
00333        BackendDB            *be,
00334        struct berval        *ndn_out )
00335 {
00336        entry_limbo_t **elpp, el = { 0 };
00337        monitor_info_t       *mi;
00338 
00339        if ( be_monitor == NULL ) {
00340               Debug( LDAP_DEBUG_ANY,
00341                      "monitor_back_register_database_limbo: "
00342                      "monitor database not configured.\n",
00343                      0, 0, 0 );
00344               return -1;
00345        }
00346 
00347        mi = ( monitor_info_t * )be_monitor->be_private;
00348 
00349 
00350        el.el_type = LIMBO_DATABASE;
00351 
00352        el.el_be = be->bd_self;
00353        el.el_ndn = ndn_out;
00354        
00355        for ( elpp = &mi->mi_entry_limbo;
00356                      *elpp;
00357                      elpp = &(*elpp)->el_next )
00358               /* go to last */;
00359 
00360        *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
00361 
00362        el.el_next = NULL;
00363        **elpp = el;
00364 
00365        return 0;
00366 }
00367 
00368 int
00369 monitor_back_register_overlay_info_limbo(
00370        slap_overinst        *on )
00371 {
00372        return -1;
00373 }
00374 
00375 int
00376 monitor_back_register_overlay_limbo(
00377        BackendDB            *be,
00378        struct slap_overinst *on,
00379        struct berval        *ndn_out )
00380 {
00381        entry_limbo_t **elpp, el = { 0 };
00382        monitor_info_t       *mi;
00383 
00384        if ( be_monitor == NULL ) {
00385               Debug( LDAP_DEBUG_ANY,
00386                      "monitor_back_register_overlay_limbo: "
00387                      "monitor database not configured.\n",
00388                      0, 0, 0 );
00389               return -1;
00390        }
00391 
00392        mi = ( monitor_info_t * )be_monitor->be_private;
00393 
00394 
00395        el.el_type = LIMBO_OVERLAY;
00396 
00397        el.el_be = be->bd_self;
00398        el.el_on = on;
00399        el.el_ndn = ndn_out;
00400        
00401        for ( elpp = &mi->mi_entry_limbo;
00402                      *elpp;
00403                      elpp = &(*elpp)->el_next )
00404               /* go to last */;
00405 
00406        *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
00407 
00408        el.el_next = NULL;
00409        **elpp = el;
00410 
00411        return 0;
00412 }
00413 
00414 int
00415 monitor_back_register_entry(
00416        Entry                *e,
00417        monitor_callback_t   *cb,
00418        monitor_subsys_t     *mss,
00419        unsigned long        flags )
00420 {
00421        monitor_info_t       *mi;
00422 
00423        if ( be_monitor == NULL ) {
00424               Debug( LDAP_DEBUG_ANY,
00425                      "monitor_back_register_entry(\"%s\"): "
00426                      "monitor database not configured.\n",
00427                      e->e_name.bv_val, 0, 0 );
00428               return -1;
00429        }
00430 
00431        mi = ( monitor_info_t * )be_monitor->be_private;
00432 
00433        assert( mi != NULL );
00434        assert( e != NULL );
00435        assert( e->e_private == NULL );
00436        
00437        if ( monitor_subsys_is_opened() ) {
00438               Entry         *e_parent = NULL,
00439                             *e_new = NULL,
00440                             **ep = NULL;
00441               struct berval pdn = BER_BVNULL;
00442               monitor_entry_t *mp = NULL,
00443                             *mp_parent = NULL;
00444               int           rc = 0;
00445 
00446               if ( monitor_cache_get( mi, &e->e_nname, &e_parent ) == 0 ) {
00447                      /* entry exists */
00448                      Debug( LDAP_DEBUG_ANY,
00449                             "monitor_back_register_entry(\"%s\"): "
00450                             "entry exists\n",
00451                             e->e_name.bv_val, 0, 0 );
00452                      monitor_cache_release( mi, e_parent );
00453                      return -1;
00454               }
00455 
00456               dnParent( &e->e_nname, &pdn );
00457               if ( monitor_cache_get( mi, &pdn, &e_parent ) != 0 ) {
00458                      /* parent does not exist */
00459                      Debug( LDAP_DEBUG_ANY,
00460                             "monitor_back_register_entry(\"%s\"): "
00461                             "parent \"%s\" not found\n",
00462                             e->e_name.bv_val, pdn.bv_val, 0 );
00463                      return -1;
00464               }
00465 
00466               assert( e_parent->e_private != NULL );
00467               mp_parent = ( monitor_entry_t * )e_parent->e_private;
00468 
00469               if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
00470                      /* entry is volatile; cannot append children */
00471                      Debug( LDAP_DEBUG_ANY,
00472                             "monitor_back_register_entry(\"%s\"): "
00473                             "parent \"%s\" is volatile\n",
00474                             e->e_name.bv_val, e_parent->e_name.bv_val, 0 );
00475                      rc = -1;
00476                      goto done;
00477               }
00478 
00479               mp = monitor_entrypriv_create();
00480               if ( mp == NULL ) {
00481                      Debug( LDAP_DEBUG_ANY,
00482                             "monitor_back_register_entry(\"%s\"): "
00483                             "monitor_entrypriv_create() failed\n",
00484                             e->e_name.bv_val, 0, 0 );
00485                      rc = -1;
00486                      goto done;
00487               }
00488 
00489               e_new = entry_dup( e );
00490               if ( e_new == NULL ) {
00491                      Debug( LDAP_DEBUG_ANY,
00492                             "monitor_back_register_entry(\"%s\"): "
00493                             "entry_dup() failed\n",
00494                             e->e_name.bv_val, 0, 0 );
00495                      rc = -1;
00496                      goto done;
00497               }
00498               
00499               e_new->e_private = ( void * )mp;
00500               if ( mss != NULL ) {
00501                      mp->mp_info = mss;
00502                      mp->mp_flags = flags;
00503 
00504               } else {
00505                      mp->mp_info = mp_parent->mp_info;
00506                      mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
00507               }
00508               mp->mp_cb = cb;
00509 
00510               ep = &mp_parent->mp_children;
00511               for ( ; *ep; ) {
00512                      mp_parent = ( monitor_entry_t * )(*ep)->e_private;
00513                      ep = &mp_parent->mp_next;
00514               }
00515               *ep = e_new;
00516 
00517               if ( monitor_cache_add( mi, e_new ) ) {
00518                      Debug( LDAP_DEBUG_ANY,
00519                             "monitor_back_register_entry(\"%s\"): "
00520                             "unable to add entry\n",
00521                             e->e_name.bv_val, 0, 0 );
00522                      rc = -1;
00523                      goto done;
00524               }
00525 
00526 done:;
00527               if ( rc ) {
00528                      if ( mp ) {
00529                             ch_free( mp );
00530                      }
00531                      if ( e_new ) {
00532                             e_new->e_private = NULL;
00533                             entry_free( e_new );
00534                      }
00535               }
00536 
00537               if ( e_parent ) {
00538                      monitor_cache_release( mi, e_parent );
00539               }
00540 
00541        } else {
00542               entry_limbo_t **elpp, el = { 0 };
00543 
00544               el.el_type = LIMBO_ENTRY;
00545 
00546               el.el_e = entry_dup( e );
00547               if ( el.el_e == NULL ) {
00548                      Debug( LDAP_DEBUG_ANY,
00549                             "monitor_back_register_entry(\"%s\"): "
00550                             "entry_dup() failed\n",
00551                             e->e_name.bv_val, 0, 0 );
00552                      return -1;
00553               }
00554               
00555               el.el_cb = cb;
00556               el.el_mss = mss;
00557               el.el_flags = flags;
00558 
00559               for ( elpp = &mi->mi_entry_limbo;
00560                             *elpp;
00561                             elpp = &(*elpp)->el_next )
00562                      /* go to last */;
00563 
00564               *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
00565               if ( *elpp == NULL ) {
00566                      el.el_e->e_private = NULL;
00567                      entry_free( el.el_e );
00568                      return -1;
00569               }
00570 
00571               el.el_next = NULL;
00572               **elpp = el;
00573        }
00574 
00575        return 0;
00576 }
00577 
00578 int
00579 monitor_back_register_entry_parent(
00580        Entry                *e,
00581        monitor_callback_t   *cb,
00582        monitor_subsys_t     *mss,
00583        unsigned long        flags,
00584        struct berval        *nbase,
00585        int                  scope,
00586        struct berval        *filter )
00587 {
00588        monitor_info_t       *mi;
00589        struct berval ndn = BER_BVNULL;
00590 
00591        if ( be_monitor == NULL ) {
00592               Debug( LDAP_DEBUG_ANY,
00593                      "monitor_back_register_entry_parent(base=\"%s\" scope=%s filter=\"%s\"): "
00594                      "monitor database not configured.\n",
00595                      BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
00596                      ldap_pvt_scope2str( scope ),
00597                      BER_BVISNULL( filter ) ? "" : filter->bv_val );
00598               return -1;
00599        }
00600 
00601        mi = ( monitor_info_t * )be_monitor->be_private;
00602 
00603        assert( mi != NULL );
00604        assert( e != NULL );
00605        assert( e->e_private == NULL );
00606 
00607        if ( BER_BVISNULL( filter ) ) {
00608               /* need a filter */
00609               Debug( LDAP_DEBUG_ANY,
00610                      "monitor_back_register_entry_parent(\"\"): "
00611                      "need a valid filter\n",
00612                      0, 0, 0 );
00613               return -1;
00614        }
00615 
00616        if ( monitor_subsys_is_opened() ) {
00617               Entry         *e_parent = NULL,
00618                             *e_new = NULL,
00619                             **ep = NULL;
00620               struct berval e_name = BER_BVNULL,
00621                             e_nname = BER_BVNULL;
00622               monitor_entry_t *mp = NULL,
00623                             *mp_parent = NULL;
00624               int           rc = 0;
00625 
00626               if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
00627                      /* entry does not exist */
00628                      Debug( LDAP_DEBUG_ANY,
00629                             "monitor_back_register_entry_parent(\"\"): "
00630                             "base=\"%s\" scope=%s filter=\"%s\": "
00631                             "unable to find entry\n",
00632                             nbase->bv_val ? nbase->bv_val : "\"\"",
00633                             ldap_pvt_scope2str( scope ),
00634                             filter->bv_val );
00635                      return -1;
00636               }
00637 
00638               if ( monitor_cache_get( mi, &ndn, &e_parent ) != 0 ) {
00639                      /* entry does not exist */
00640                      Debug( LDAP_DEBUG_ANY,
00641                             "monitor_back_register_entry_parent(\"%s\"): "
00642                             "parent entry does not exist\n",
00643                             ndn.bv_val, 0, 0 );
00644                      rc = -1;
00645                      goto done;
00646               }
00647 
00648               assert( e_parent->e_private != NULL );
00649               mp_parent = ( monitor_entry_t * )e_parent->e_private;
00650 
00651               if ( mp_parent->mp_flags & MONITOR_F_VOLATILE ) {
00652                      /* entry is volatile; cannot append callback */
00653                      Debug( LDAP_DEBUG_ANY,
00654                             "monitor_back_register_entry_parent(\"%s\"): "
00655                             "entry is volatile\n",
00656                             e_parent->e_name.bv_val, 0, 0 );
00657                      rc = -1;
00658                      goto done;
00659               }
00660 
00661               build_new_dn( &e_name, &e_parent->e_name, &e->e_name, NULL );
00662               build_new_dn( &e_nname, &e_parent->e_nname, &e->e_nname, NULL );
00663 
00664               if ( monitor_cache_get( mi, &e_nname, &e_new ) == 0 ) {
00665                      /* entry already exists */
00666                      Debug( LDAP_DEBUG_ANY,
00667                             "monitor_back_register_entry_parent(\"%s\"): "
00668                             "entry already exists\n",
00669                             e_name.bv_val, 0, 0 );
00670                      monitor_cache_release( mi, e_new );
00671                      e_new = NULL;
00672                      rc = -1;
00673                      goto done;
00674               }
00675 
00676               mp = monitor_entrypriv_create();
00677               if ( mp == NULL ) {
00678                      Debug( LDAP_DEBUG_ANY,
00679                             "monitor_back_register_entry_parent(\"%s\"): "
00680                             "monitor_entrypriv_create() failed\n",
00681                             e->e_name.bv_val, 0, 0 );
00682                      rc = -1;
00683                      goto done;
00684               }
00685 
00686               e_new = entry_dup( e );
00687               if ( e_new == NULL ) {
00688                      Debug( LDAP_DEBUG_ANY,
00689                             "monitor_back_register_entry(\"%s\"): "
00690                             "entry_dup() failed\n",
00691                             e->e_name.bv_val, 0, 0 );
00692                      rc = -1;
00693                      goto done;
00694               }
00695               ch_free( e_new->e_name.bv_val );
00696               ch_free( e_new->e_nname.bv_val );
00697               e_new->e_name = e_name;
00698               e_new->e_nname = e_nname;
00699               
00700               e_new->e_private = ( void * )mp;
00701               if ( mss != NULL ) {
00702                      mp->mp_info = mss;
00703                      mp->mp_flags = flags;
00704 
00705               } else {
00706                      mp->mp_info = mp_parent->mp_info;
00707                      mp->mp_flags = mp_parent->mp_flags | MONITOR_F_SUB;
00708               }
00709               mp->mp_cb = cb;
00710 
00711               ep = &mp_parent->mp_children;
00712               for ( ; *ep; ) {
00713                      mp_parent = ( monitor_entry_t * )(*ep)->e_private;
00714                      ep = &mp_parent->mp_next;
00715               }
00716               *ep = e_new;
00717 
00718               if ( monitor_cache_add( mi, e_new ) ) {
00719                      Debug( LDAP_DEBUG_ANY,
00720                             "monitor_back_register_entry(\"%s\"): "
00721                             "unable to add entry\n",
00722                             e->e_name.bv_val, 0, 0 );
00723                      rc = -1;
00724                      goto done;
00725               }
00726 
00727 done:;
00728               if ( !BER_BVISNULL( &ndn ) ) {
00729                      ch_free( ndn.bv_val );
00730               }
00731 
00732               if ( rc ) {
00733                      if ( mp ) {
00734                             ch_free( mp );
00735                      }
00736                      if ( e_new ) {
00737                             e_new->e_private = NULL;
00738                             entry_free( e_new );
00739                      }
00740               }
00741 
00742               if ( e_parent ) {
00743                      monitor_cache_release( mi, e_parent );
00744               }
00745 
00746        } else {
00747               entry_limbo_t **elpp = NULL, el = { 0 };
00748 
00749               el.el_type = LIMBO_ENTRY_PARENT;
00750 
00751               el.el_e = entry_dup( e );
00752               if ( el.el_e == NULL ) {
00753                      Debug( LDAP_DEBUG_ANY,
00754                             "monitor_back_register_entry(\"%s\"): "
00755                             "entry_dup() failed\n",
00756                             e->e_name.bv_val, 0, 0 );
00757                      goto done_limbo;
00758               }
00759               
00760               if ( !BER_BVISNULL( nbase ) ) {
00761                      ber_dupbv( &el.el_nbase, nbase );
00762               }
00763 
00764               el.el_scope = scope;
00765               if ( !BER_BVISNULL( filter ) ) {
00766                      ber_dupbv( &el.el_filter, filter  );
00767               }
00768 
00769               el.el_cb = cb;
00770               el.el_mss = mss;
00771               el.el_flags = flags;
00772 
00773               for ( elpp = &mi->mi_entry_limbo;
00774                             *elpp;
00775                             elpp = &(*elpp)->el_next )
00776                      /* go to last */;
00777 
00778               *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
00779               if ( *elpp == NULL ) {
00780                      goto done_limbo;
00781               }
00782 
00783 done_limbo:;
00784               if ( *elpp != NULL ) {
00785                      el.el_next = NULL;
00786                      **elpp = el;
00787 
00788               } else {
00789                      if ( !BER_BVISNULL( &el.el_filter ) ) {
00790                             ch_free( el.el_filter.bv_val );
00791                      }
00792                      if ( !BER_BVISNULL( &el.el_nbase ) ) {
00793                             ch_free( el.el_nbase.bv_val );
00794                      }
00795                      entry_free( el.el_e );
00796                      return -1;
00797               }
00798        }
00799 
00800        return 0;
00801 }
00802 
00803 static int
00804 monitor_search2ndn_cb( Operation *op, SlapReply *rs )
00805 {
00806        if ( rs->sr_type == REP_SEARCH ) {
00807               struct berval *ndn = op->o_callback->sc_private;
00808 
00809               if ( !BER_BVISNULL( ndn ) ) {
00810                      rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
00811                      ch_free( ndn->bv_val );
00812                      BER_BVZERO( ndn );
00813                      return rs->sr_err;
00814               }
00815               
00816               ber_dupbv( ndn, &rs->sr_entry->e_nname );
00817        }
00818 
00819        return 0;
00820 }
00821 
00822 int
00823 monitor_search2ndn(
00824        struct berval *nbase,
00825        int           scope,
00826        struct berval *filter,
00827        struct berval *ndn )
00828 {
00829        Connection    conn = { 0 };
00830        OperationBuffer      opbuf;
00831        Operation     *op;
00832        void   *thrctx;
00833        SlapReply     rs = { REP_RESULT };
00834        slap_callback cb = { NULL, monitor_search2ndn_cb, NULL, NULL };
00835        int           rc;
00836 
00837        BER_BVZERO( ndn );
00838 
00839        if ( be_monitor == NULL ) {
00840               return -1;
00841        }
00842 
00843        thrctx = ldap_pvt_thread_pool_context();
00844        connection_fake_init2( &conn, &opbuf, thrctx, 0 );
00845        op = &opbuf.ob_op;
00846 
00847        op->o_tag = LDAP_REQ_SEARCH;
00848 
00849        /* use global malloc for now */
00850        if ( op->o_tmpmemctx ) {
00851               op->o_tmpmemctx = NULL;
00852        }
00853        op->o_tmpmfuncs = &ch_mfuncs;
00854 
00855        op->o_bd = be_monitor;
00856        if ( nbase == NULL || BER_BVISNULL( nbase ) ) {
00857               ber_dupbv_x( &op->o_req_dn, &op->o_bd->be_suffix[ 0 ],
00858                             op->o_tmpmemctx );
00859               ber_dupbv_x( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ],
00860                             op->o_tmpmemctx );
00861 
00862        } else {
00863               if ( dnPrettyNormal( NULL, nbase, &op->o_req_dn, &op->o_req_ndn,
00864                                    op->o_tmpmemctx ) ) {
00865                      return -1;
00866               }
00867        }
00868 
00869        op->o_callback = &cb;
00870        cb.sc_private = (void *)ndn;
00871 
00872        op->ors_scope = scope;
00873        op->ors_filter = str2filter_x( op, filter->bv_val );
00874        if ( op->ors_filter == NULL ) {
00875               rc = LDAP_OTHER;
00876               goto cleanup;
00877        }
00878        ber_dupbv_x( &op->ors_filterstr, filter, op->o_tmpmemctx );
00879        op->ors_attrs = slap_anlist_no_attrs;
00880        op->ors_attrsonly = 0;
00881        op->ors_tlimit = SLAP_NO_LIMIT;
00882        op->ors_slimit = 1;
00883        op->ors_limit = NULL;
00884        op->ors_deref = LDAP_DEREF_NEVER;
00885 
00886        op->o_nocaching = 1;
00887        op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
00888 
00889        op->o_dn = be_monitor->be_rootdn;
00890        op->o_ndn = be_monitor->be_rootndn;
00891 
00892        rc = op->o_bd->be_search( op, &rs );
00893 
00894 cleanup:;
00895        if ( op->ors_filter != NULL ) {
00896               filter_free_x( op, op->ors_filter, 1 );
00897        }
00898        if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
00899               op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
00900        }
00901        if ( !BER_BVISNULL( &op->o_req_dn ) ) {
00902               op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
00903        }
00904        if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
00905               op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
00906        }
00907 
00908        if ( rc != 0 ) {
00909               return rc;
00910        }
00911 
00912        switch ( rs.sr_err ) {
00913        case LDAP_SUCCESS:
00914               if ( BER_BVISNULL( ndn ) ) {
00915                      rc = -1;
00916               }
00917               break;
00918                      
00919        case LDAP_SIZELIMIT_EXCEEDED:
00920        default:
00921               if ( !BER_BVISNULL( ndn ) ) {
00922                      ber_memfree( ndn->bv_val );
00923                      BER_BVZERO( ndn );
00924               }
00925               rc = -1;
00926               break;
00927        }
00928 
00929        return rc;
00930 }
00931 
00932 int
00933 monitor_back_register_entry_attrs(
00934        struct berval        *ndn_in,
00935        Attribute            *a,
00936        monitor_callback_t   *cb,
00937        struct berval        *nbase,
00938        int                  scope,
00939        struct berval        *filter )
00940 {
00941        monitor_info_t       *mi;
00942        struct berval ndn = BER_BVNULL;
00943        char          *fname = ( a == NULL ? "callback" : "attrs" );
00944 
00945        if ( be_monitor == NULL ) {
00946               char          buf[ SLAP_TEXT_BUFLEN ];
00947 
00948               snprintf( buf, sizeof( buf ),
00949                      "monitor_back_register_entry_%s(base=\"%s\" scope=%s filter=\"%s\"): "
00950                      "monitor database not configured.\n",
00951                      fname,
00952                      BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
00953                      ldap_pvt_scope2str( scope ),
00954                      BER_BVISNULL( filter ) ? "" : filter->bv_val );
00955               Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
00956 
00957               return -1;
00958        }
00959 
00960        mi = ( monitor_info_t * )be_monitor->be_private;
00961 
00962        assert( mi != NULL );
00963 
00964        if ( ndn_in != NULL ) {
00965               ndn = *ndn_in;
00966        }
00967 
00968        if ( a == NULL && cb == NULL ) {
00969               /* nothing to do */
00970               return -1;
00971        }
00972 
00973        if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
00974                      && BER_BVISNULL( filter ) )
00975        {
00976               /* need a filter */
00977               Debug( LDAP_DEBUG_ANY,
00978                      "monitor_back_register_entry_%s(\"\"): "
00979                      "need a valid filter\n",
00980                      fname, 0, 0 );
00981               return -1;
00982        }
00983 
00984        if ( monitor_subsys_is_opened() ) {
00985               Entry                *e = NULL;
00986               Attribute            **atp = NULL;
00987               monitor_entry_t      *mp = NULL;
00988               monitor_callback_t   **mcp = NULL;
00989               int                  rc = 0;
00990               int                  freeit = 0;
00991 
00992               if ( BER_BVISNULL( &ndn ) ) {
00993                      if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
00994                             char          buf[ SLAP_TEXT_BUFLEN ];
00995 
00996                             snprintf( buf, sizeof( buf ),
00997                                    "monitor_back_register_entry_%s(\"\"): "
00998                                    "base=\"%s\" scope=%s filter=\"%s\": "
00999                                    "unable to find entry\n",
01000                                    fname,
01001                                    nbase->bv_val ? nbase->bv_val : "\"\"",
01002                                    ldap_pvt_scope2str( scope ),
01003                                    filter->bv_val );
01004 
01005                             /* entry does not exist */
01006                             Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
01007                             return -1;
01008                      }
01009 
01010                      freeit = 1;
01011               }
01012 
01013               if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
01014                      /* entry does not exist */
01015                      Debug( LDAP_DEBUG_ANY,
01016                             "monitor_back_register_entry_%s(\"%s\"): "
01017                             "entry does not exist\n",
01018                             fname, ndn.bv_val, 0 );
01019                      rc = -1;
01020                      goto done;
01021               }
01022 
01023               assert( e->e_private != NULL );
01024               mp = ( monitor_entry_t * )e->e_private;
01025 
01026               if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
01027                      /* entry is volatile; cannot append callback */
01028                      Debug( LDAP_DEBUG_ANY,
01029                             "monitor_back_register_entry_%s(\"%s\"): "
01030                             "entry is volatile\n",
01031                             fname, e->e_name.bv_val, 0 );
01032                      rc = -1;
01033                      goto done;
01034               }
01035 
01036               if ( a ) {
01037                      for ( atp = &e->e_attrs; *atp; atp = &(*atp)->a_next )
01038                             /* just get to last */ ;
01039 
01040                      for ( ; a != NULL; a = a->a_next ) {
01041                             assert( a->a_desc != NULL );
01042                             assert( a->a_vals != NULL );
01043 
01044                             if ( attr_find( e->e_attrs, a->a_desc ) ) {
01045                                    attr_merge( e, a->a_desc, a->a_vals,
01046                                           a->a_nvals == a->a_vals ? NULL : a->a_nvals );
01047 
01048                             } else {
01049                                    *atp = attr_dup( a );
01050                                    if ( *atp == NULL ) {
01051                                           Debug( LDAP_DEBUG_ANY,
01052                                                  "monitor_back_register_entry_%s(\"%s\"): "
01053                                                  "attr_dup() failed\n",
01054                                                  fname, e->e_name.bv_val, 0 );
01055                                           rc = -1;
01056                                           goto done;
01057                                    }
01058                                    atp = &(*atp)->a_next;
01059                             }
01060                      }
01061               }
01062 
01063               if ( cb ) {
01064                      for ( mcp = &mp->mp_cb; *mcp; mcp = &(*mcp)->mc_next )
01065                             /* go to tail */ ;
01066               
01067                      /* NOTE: we do not clear cb->mc_next, so this function
01068                       * can be used to append a list of callbacks */
01069                      (*mcp) = cb;
01070               }
01071 
01072 done:;
01073               if ( rc ) {
01074                      if ( atp && *atp ) {
01075                             attrs_free( *atp );
01076                             *atp = NULL;
01077                      }
01078               }
01079 
01080               if ( freeit ) {
01081                      ber_memfree( ndn.bv_val );
01082               }
01083 
01084               if ( e ) {
01085                      monitor_cache_release( mi, e );
01086               }
01087 
01088        } else {
01089               entry_limbo_t **elpp, el = { 0 };
01090 
01091               el.el_type = LIMBO_ATTRS;
01092               el.el_ndn = ndn_in;
01093               if ( !BER_BVISNULL( nbase ) ) {
01094                      ber_dupbv( &el.el_nbase, nbase);
01095               }
01096               el.el_scope = scope;
01097               if ( !BER_BVISNULL( filter ) ) {
01098                      ber_dupbv( &el.el_filter, filter  );
01099               }
01100 
01101               el.el_a = attrs_dup( a );
01102               el.el_cb = cb;
01103 
01104               for ( elpp = &mi->mi_entry_limbo;
01105                             *elpp;
01106                             elpp = &(*elpp)->el_next )
01107                      /* go to last */;
01108 
01109               *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
01110               if ( *elpp == NULL ) {
01111                      if ( !BER_BVISNULL( &el.el_filter ) ) {
01112                             ch_free( el.el_filter.bv_val );
01113                      }
01114                      if ( el.el_a != NULL ) {
01115                             attrs_free( el.el_a );
01116                      }
01117                      if ( !BER_BVISNULL( &el.el_nbase ) ) {
01118                             ch_free( &el.el_nbase.bv_val );
01119                      }
01120                      return -1;
01121               }
01122 
01123               el.el_next = NULL;
01124               **elpp = el;
01125        }
01126 
01127        return 0;
01128 }
01129 
01130 int
01131 monitor_back_register_entry_callback(
01132        struct berval        *ndn,
01133        monitor_callback_t   *cb,
01134        struct berval        *nbase,
01135        int                  scope,
01136        struct berval        *filter )
01137 {
01138        return monitor_back_register_entry_attrs( ndn, NULL, cb,
01139                      nbase, scope, filter );
01140 }
01141 
01142 /*
01143  * TODO: add corresponding calls to remove installed callbacks, entries
01144  * and so, in case the entity that installed them is removed (e.g. a 
01145  * database, via back-config)
01146  */
01147 int
01148 monitor_back_unregister_entry(
01149        struct berval *ndn )
01150 {
01151        monitor_info_t       *mi;
01152 
01153        if ( be_monitor == NULL ) {
01154               Debug( LDAP_DEBUG_ANY,
01155                      "monitor_back_unregister_entry(\"%s\"): "
01156                      "monitor database not configured.\n",
01157                      ndn->bv_val, 0, 0 );
01158 
01159               return -1;
01160        }
01161 
01162        /* entry will be regularly freed, and resources released
01163         * according to callbacks */
01164        if ( slapd_shutdown ) {
01165               return 0;
01166        }
01167 
01168        mi = ( monitor_info_t * )be_monitor->be_private;
01169 
01170        assert( mi != NULL );
01171 
01172        if ( monitor_subsys_is_opened() ) {
01173               Entry                *e = NULL;
01174               monitor_entry_t      *mp = NULL;
01175               monitor_callback_t   *cb = NULL;
01176 
01177               if ( monitor_cache_remove( mi, ndn, &e ) != 0 ) {
01178                      /* entry does not exist */
01179                      Debug( LDAP_DEBUG_ANY,
01180                             "monitor_back_unregister_entry(\"%s\"): "
01181                             "entry removal failed.\n",
01182                             ndn->bv_val, 0, 0 );
01183                      return -1;
01184               }
01185 
01186               mp = (monitor_entry_t *)e->e_private;
01187               assert( mp != NULL );
01188 
01189               for ( cb = mp->mp_cb; cb != NULL; ) {
01190                      monitor_callback_t   *next = cb->mc_next;
01191 
01192                      if ( cb->mc_free ) {
01193                             (void)cb->mc_free( e, &cb->mc_private );
01194                      }
01195                      ch_free( cb );
01196 
01197                      cb = next;
01198               }
01199 
01200               ch_free( mp );
01201               e->e_private = NULL;
01202               entry_free( e );
01203 
01204        } else {
01205               entry_limbo_t **elpp;
01206 
01207               for ( elpp = &mi->mi_entry_limbo;
01208                      *elpp;
01209                      elpp = &(*elpp)->el_next )
01210               {
01211                      entry_limbo_t *elp = *elpp;
01212 
01213                      if ( elp->el_type == LIMBO_ENTRY
01214                             && dn_match( ndn, &elp->el_e->e_nname ) )
01215                      {
01216                             monitor_callback_t   *cb, *next;
01217 
01218                             for ( cb = elp->el_cb; cb; cb = next ) {
01219                                    /* FIXME: call callbacks? */
01220                                    next = cb->mc_next;
01221                                    if ( cb->mc_dispose ) {
01222                                           cb->mc_dispose( &cb->mc_private );
01223                                    }
01224                                    ch_free( cb );
01225                             }
01226                             assert( elp->el_e != NULL );
01227                             elp->el_e->e_private = NULL;
01228                             entry_free( elp->el_e );
01229                             *elpp = elp->el_next;
01230                             ch_free( elp );
01231                             elpp = NULL;
01232                             break;
01233                      }
01234               }
01235 
01236               if ( elpp != NULL ) {
01237                      /* not found!  where did it go? */
01238                      return 1;
01239               }
01240        }
01241 
01242        return 0;
01243 }
01244 
01245 int
01246 monitor_back_unregister_entry_parent(
01247        struct berval        *nrdn,
01248        monitor_callback_t   *target_cb,
01249        struct berval        *nbase,
01250        int                  scope,
01251        struct berval        *filter )
01252 {
01253        monitor_info_t       *mi;
01254        struct berval ndn = BER_BVNULL;
01255 
01256        if ( be_monitor == NULL ) {
01257               Debug( LDAP_DEBUG_ANY,
01258                      "monitor_back_unregister_entry_parent(base=\"%s\" scope=%s filter=\"%s\"): "
01259                      "monitor database not configured.\n",
01260                      BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
01261                      ldap_pvt_scope2str( scope ),
01262                      BER_BVISNULL( filter ) ? "" : filter->bv_val );
01263 
01264               return -1;
01265        }
01266 
01267        /* entry will be regularly freed, and resources released
01268         * according to callbacks */
01269        if ( slapd_shutdown ) {
01270               return 0;
01271        }
01272 
01273        mi = ( monitor_info_t * )be_monitor->be_private;
01274 
01275        assert( mi != NULL );
01276 
01277        if ( ( nrdn == NULL || BER_BVISNULL( nrdn ) )
01278                      && BER_BVISNULL( filter ) )
01279        {
01280               /* need a filter */
01281               Debug( LDAP_DEBUG_ANY,
01282                      "monitor_back_unregister_entry_parent(\"\"): "
01283                      "need a valid filter\n",
01284                      0, 0, 0 );
01285               return -1;
01286        }
01287 
01288        if ( monitor_subsys_is_opened() ) {
01289               Entry                *e = NULL;
01290               monitor_entry_t      *mp = NULL;
01291 
01292               if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
01293                      /* entry does not exist */
01294                      Debug( LDAP_DEBUG_ANY,
01295                             "monitor_back_unregister_entry_parent(\"\"): "
01296                             "base=\"%s\" scope=%s filter=\"%s\": "
01297                             "unable to find entry\n",
01298                             nbase->bv_val ? nbase->bv_val : "\"\"",
01299                             ldap_pvt_scope2str( scope ),
01300                             filter->bv_val );
01301                      return -1;
01302               }
01303 
01304               if ( monitor_cache_remove( mi, &ndn, &e ) != 0 ) {
01305                      /* entry does not exist */
01306                      Debug( LDAP_DEBUG_ANY,
01307                             "monitor_back_unregister_entry(\"%s\"): "
01308                             "entry removal failed.\n",
01309                             ndn.bv_val, 0, 0 );
01310                      ber_memfree( ndn.bv_val );
01311                      return -1;
01312               }
01313               ber_memfree( ndn.bv_val );
01314 
01315               mp = (monitor_entry_t *)e->e_private;
01316               assert( mp != NULL );
01317 
01318               if ( target_cb != NULL ) {
01319                      monitor_callback_t   **cbp;
01320 
01321                      for ( cbp = &mp->mp_cb; *cbp != NULL; cbp = &(*cbp)->mc_next ) {
01322                             if ( *cbp == target_cb ) {
01323                                    if ( (*cbp)->mc_free ) {
01324                                           (void)(*cbp)->mc_free( e, &(*cbp)->mc_private );
01325                                    }
01326                                    *cbp = (*cbp)->mc_next;
01327                                    ch_free( target_cb );
01328                                    break;
01329                             }
01330                      }
01331               }
01332 
01333 
01334               ch_free( mp );
01335               e->e_private = NULL;
01336               entry_free( e );
01337 
01338        } else {
01339               entry_limbo_t **elpp;
01340 
01341               for ( elpp = &mi->mi_entry_limbo;
01342                      *elpp;
01343                      elpp = &(*elpp)->el_next )
01344               {
01345                      entry_limbo_t *elp = *elpp;
01346 
01347                      if ( elp->el_type == LIMBO_ENTRY_PARENT
01348                             && dn_match( nrdn, &elp->el_e->e_nname )
01349                             && dn_match( nbase, &elp->el_nbase )
01350                             && scope == elp->el_scope
01351                             && bvmatch( filter, &elp->el_filter ) )
01352                      {
01353                             monitor_callback_t   *cb, *next;
01354 
01355                             for ( cb = elp->el_cb; cb; cb = next ) {
01356                                    /* FIXME: call callbacks? */
01357                                    next = cb->mc_next;
01358                                    if ( cb->mc_dispose ) {
01359                                           cb->mc_dispose( &cb->mc_private );
01360                                    }
01361                                    ch_free( cb );
01362                             }
01363                             assert( elp->el_e != NULL );
01364                             elp->el_e->e_private = NULL;
01365                             entry_free( elp->el_e );
01366                             if ( !BER_BVISNULL( &elp->el_nbase ) ) {
01367                                    ch_free( elp->el_nbase.bv_val );
01368                             }
01369                             if ( !BER_BVISNULL( &elp->el_filter ) ) {
01370                                    ch_free( elp->el_filter.bv_val );
01371                             }
01372                             *elpp = elp->el_next;
01373                             ch_free( elp );
01374                             elpp = NULL;
01375                             break;
01376                      }
01377               }
01378 
01379               if ( elpp != NULL ) {
01380                      /* not found!  where did it go? */
01381                      return 1;
01382               }
01383        }
01384 
01385        return 0;
01386 }
01387 
01388 int
01389 monitor_back_unregister_entry_attrs(
01390        struct berval        *ndn_in,
01391        Attribute            *target_a,
01392        monitor_callback_t   *target_cb,
01393        struct berval        *nbase,
01394        int                  scope,
01395        struct berval        *filter )
01396 {
01397        monitor_info_t       *mi;
01398        struct berval ndn = BER_BVNULL;
01399        char          *fname = ( target_a == NULL ? "callback" : "attrs" );
01400 
01401        if ( be_monitor == NULL ) {
01402               char          buf[ SLAP_TEXT_BUFLEN ];
01403 
01404               snprintf( buf, sizeof( buf ),
01405                      "monitor_back_unregister_entry_%s(base=\"%s\" scope=%s filter=\"%s\"): "
01406                      "monitor database not configured.\n",
01407                      fname,
01408                      BER_BVISNULL( nbase ) ? "" : nbase->bv_val,
01409                      ldap_pvt_scope2str( scope ),
01410                      BER_BVISNULL( filter ) ? "" : filter->bv_val );
01411               Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
01412 
01413               return -1;
01414        }
01415 
01416        /* entry will be regularly freed, and resources released
01417         * according to callbacks */
01418        if ( slapd_shutdown ) {
01419               return 0;
01420        }
01421 
01422        mi = ( monitor_info_t * )be_monitor->be_private;
01423 
01424        assert( mi != NULL );
01425 
01426        if ( ndn_in != NULL ) {
01427               ndn = *ndn_in;
01428        }
01429 
01430        if ( target_a == NULL && target_cb == NULL ) {
01431               /* nothing to do */
01432               return -1;
01433        }
01434 
01435        if ( ( ndn_in == NULL || BER_BVISNULL( &ndn ) )
01436                      && BER_BVISNULL( filter ) )
01437        {
01438               /* need a filter */
01439               Debug( LDAP_DEBUG_ANY,
01440                      "monitor_back_unregister_entry_%s(\"\"): "
01441                      "need a valid filter\n",
01442                      fname, 0, 0 );
01443               return -1;
01444        }
01445 
01446        if ( monitor_subsys_is_opened() ) {
01447               Entry                *e = NULL;
01448               monitor_entry_t      *mp = NULL;
01449               int                  freeit = 0;
01450 
01451               if ( BER_BVISNULL( &ndn ) ) {
01452                      if ( monitor_search2ndn( nbase, scope, filter, &ndn ) ) {
01453                             char          buf[ SLAP_TEXT_BUFLEN ];
01454 
01455                             snprintf( buf, sizeof( buf ),
01456                                    "monitor_back_unregister_entry_%s(\"\"): "
01457                                    "base=\"%s\" scope=%d filter=\"%s\": "
01458                                    "unable to find entry\n",
01459                                    fname,
01460                                    nbase->bv_val ? nbase->bv_val : "\"\"",
01461                                    scope, filter->bv_val );
01462 
01463                             /* entry does not exist */
01464                             Debug( LDAP_DEBUG_ANY, "%s\n", buf, 0, 0 );
01465                             return -1;
01466                      }
01467 
01468                      freeit = 1;
01469               }
01470 
01471               if ( monitor_cache_get( mi, &ndn, &e ) != 0 ) {
01472                      /* entry does not exist */
01473                      Debug( LDAP_DEBUG_ANY,
01474                             "monitor_back_unregister_entry(\"%s\"): "
01475                             "entry removal failed.\n",
01476                             ndn.bv_val, 0, 0 );
01477                      return -1;
01478               }
01479 
01480               mp = (monitor_entry_t *)e->e_private;
01481               assert( mp != NULL );
01482 
01483               if ( target_cb != NULL ) {
01484                      monitor_callback_t   **cbp;
01485 
01486                      for ( cbp = &mp->mp_cb; *cbp != NULL; cbp = &(*cbp)->mc_next ) {
01487                             if ( *cbp == target_cb ) {
01488                                    if ( (*cbp)->mc_free ) {
01489                                           (void)(*cbp)->mc_free( e, &(*cbp)->mc_private );
01490                                    }
01491                                    *cbp = (*cbp)->mc_next;
01492                                    ch_free( target_cb );
01493                                    break;
01494                             }
01495                      }
01496               }
01497 
01498               if ( target_a != NULL ) {
01499                      Attribute     *a;
01500 
01501                      for ( a = target_a; a != NULL; a = a->a_next ) {
01502                             Modification  mod = { 0 };
01503                             const char    *text;
01504                             char          textbuf[ SLAP_TEXT_BUFLEN ];
01505 
01506                             mod.sm_op = LDAP_MOD_DELETE;
01507                             mod.sm_desc = a->a_desc;
01508                             mod.sm_values = a->a_vals;
01509                             mod.sm_nvalues = a->a_nvals;
01510 
01511                             (void)modify_delete_values( e, &mod, 1,
01512                                    &text, textbuf, sizeof( textbuf ) );
01513                      }
01514               }
01515 
01516               if ( freeit ) {
01517                      ber_memfree( ndn.bv_val );
01518               }
01519 
01520               monitor_cache_release( mi, e );
01521 
01522        } else {
01523               entry_limbo_t **elpp;
01524 
01525               for ( elpp = &mi->mi_entry_limbo;
01526                      *elpp;
01527                      elpp = &(*elpp)->el_next )
01528               {
01529                      entry_limbo_t *elp = *elpp;
01530 
01531                      if ( elp->el_type == LIMBO_ATTRS
01532                             && dn_match( nbase, &elp->el_nbase )
01533                             && scope == elp->el_scope
01534                             && bvmatch( filter, &elp->el_filter ) )
01535                      {
01536                             monitor_callback_t   *cb, *next;
01537 
01538                             for ( cb = elp->el_cb; cb; cb = next ) {
01539                                    /* FIXME: call callbacks? */
01540                                    next = cb->mc_next;
01541                                    if ( cb->mc_dispose ) {
01542                                           cb->mc_dispose( &cb->mc_private );
01543                                    }
01544                                    ch_free( cb );
01545                             }
01546                             assert( elp->el_e == NULL );
01547                             if ( elp->el_a != NULL ) {
01548                                    attrs_free( elp->el_a );
01549                             }
01550                             if ( !BER_BVISNULL( &elp->el_nbase ) ) {
01551                                    ch_free( elp->el_nbase.bv_val );
01552                             }
01553                             if ( !BER_BVISNULL( &elp->el_filter ) ) {
01554                                    ch_free( elp->el_filter.bv_val );
01555                             }
01556                             *elpp = elp->el_next;
01557                             ch_free( elp );
01558                             elpp = NULL;
01559                             break;
01560                      }
01561               }
01562 
01563               if ( elpp != NULL ) {
01564                      /* not found!  where did it go? */
01565                      return 1;
01566               }
01567        }
01568 
01569        return 0;
01570 }
01571 
01572 int
01573 monitor_back_unregister_entry_callback(
01574        struct berval        *ndn,
01575        monitor_callback_t   *cb,
01576        struct berval        *nbase,
01577        int                  scope,
01578        struct berval        *filter )
01579 {
01580        /* TODO: lookup entry (by ndn, if not NULL, and/or by callback);
01581         * unregister the callback; if a is not null, unregister the
01582         * given attrs.  In any case, call cb->cb_free */
01583        return monitor_back_unregister_entry_attrs( ndn,
01584               NULL, cb, nbase, scope, filter );
01585 }
01586 
01587 monitor_subsys_t *
01588 monitor_back_get_subsys( const char *name )
01589 {
01590        if ( monitor_subsys != NULL ) {
01591               int    i;
01592               
01593               for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
01594                      if ( strcasecmp( monitor_subsys[ i ]->mss_name, name ) == 0 ) {
01595                             return monitor_subsys[ i ];
01596                      }
01597               }
01598        }
01599 
01600        return NULL;
01601 }
01602 
01603 monitor_subsys_t *
01604 monitor_back_get_subsys_by_dn(
01605        struct berval *ndn,
01606        int           sub )
01607 {
01608        if ( monitor_subsys != NULL ) {
01609               int    i;
01610 
01611               if ( sub ) {
01612                      for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
01613                             if ( dnIsSuffix( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
01614                                    return monitor_subsys[ i ];
01615                             }
01616                      }
01617 
01618               } else {
01619                      for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
01620                             if ( dn_match( ndn, &monitor_subsys[ i ]->mss_ndn ) ) {
01621                                    return monitor_subsys[ i ];
01622                             }
01623                      }
01624               }
01625        }
01626 
01627        return NULL;
01628 }
01629 
01630 int
01631 monitor_back_initialize(
01632        BackendInfo   *bi )
01633 {
01634        static char          *controls[] = {
01635               LDAP_CONTROL_MANAGEDSAIT,
01636               NULL
01637        };
01638 
01639        static ConfigTable monitorcfg[] = {
01640               { NULL, NULL, 0, 0, 0, ARG_IGNORED,
01641                      NULL, NULL, NULL, NULL }
01642        };
01643 
01644        static ConfigOCs monitorocs[] = {
01645               { "( OLcfgDbOc:4.1 "
01646                      "NAME 'olcMonitorConfig' "
01647                      "DESC 'Monitor backend configuration' "
01648                      "SUP olcDatabaseConfig "
01649                      ")",
01650                             Cft_Database, monitorcfg },
01651               { NULL, 0, NULL }
01652        };
01653 
01654        struct m_s {
01655               char   *schema;
01656               slap_mask_t flags;
01657               int    offset;
01658        } moc[] = {
01659               { "( 1.3.6.1.4.1.4203.666.3.16.1 "
01660                      "NAME 'monitor' "
01661                      "DESC 'OpenLDAP system monitoring' "
01662                      "SUP top STRUCTURAL "
01663                      "MUST cn "
01664                      "MAY ( "
01665                             "description "
01666                             "$ seeAlso "
01667                             "$ labeledURI "
01668                             "$ monitoredInfo "
01669                             "$ managedInfo "
01670                             "$ monitorOverlay "
01671                      ") )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01672                      offsetof(monitor_info_t, mi_oc_monitor) },
01673               { "( 1.3.6.1.4.1.4203.666.3.16.2 "
01674                      "NAME 'monitorServer' "
01675                      "DESC 'Server monitoring root entry' "
01676                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01677                      offsetof(monitor_info_t, mi_oc_monitorServer) },
01678               { "( 1.3.6.1.4.1.4203.666.3.16.3 "
01679                      "NAME 'monitorContainer' "
01680                      "DESC 'monitor container class' "
01681                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01682                      offsetof(monitor_info_t, mi_oc_monitorContainer) },
01683               { "( 1.3.6.1.4.1.4203.666.3.16.4 "
01684                      "NAME 'monitorCounterObject' "
01685                      "DESC 'monitor counter class' "
01686                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01687                      offsetof(monitor_info_t, mi_oc_monitorCounterObject) },
01688               { "( 1.3.6.1.4.1.4203.666.3.16.5 "
01689                      "NAME 'monitorOperation' "
01690                      "DESC 'monitor operation class' "
01691                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01692                      offsetof(monitor_info_t, mi_oc_monitorOperation) },
01693               { "( 1.3.6.1.4.1.4203.666.3.16.6 "
01694                      "NAME 'monitorConnection' "
01695                      "DESC 'monitor connection class' "
01696                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01697                      offsetof(monitor_info_t, mi_oc_monitorConnection) },
01698               { "( 1.3.6.1.4.1.4203.666.3.16.7 "
01699                      "NAME 'managedObject' "
01700                      "DESC 'monitor managed entity class' "
01701                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01702                      offsetof(monitor_info_t, mi_oc_managedObject) },
01703               { "( 1.3.6.1.4.1.4203.666.3.16.8 "
01704                      "NAME 'monitoredObject' "
01705                      "DESC 'monitor monitored entity class' "
01706                      "SUP monitor STRUCTURAL )", SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
01707                      offsetof(monitor_info_t, mi_oc_monitoredObject) },
01708               { NULL, 0, -1 }
01709        }, mat[] = {
01710               { "( 1.3.6.1.4.1.4203.666.1.55.1 "
01711                      "NAME 'monitoredInfo' "
01712                      "DESC 'monitored info' "
01713                      /* "SUP name " */
01714                      "EQUALITY caseIgnoreMatch "
01715                      "SUBSTR caseIgnoreSubstringsMatch "
01716                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} "
01717                      "NO-USER-MODIFICATION "
01718                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01719                      offsetof(monitor_info_t, mi_ad_monitoredInfo) },
01720               { "( 1.3.6.1.4.1.4203.666.1.55.2 "
01721                      "NAME 'managedInfo' "
01722                      "DESC 'monitor managed info' "
01723                      "SUP name )", SLAP_AT_HIDE,
01724                      offsetof(monitor_info_t, mi_ad_managedInfo) },
01725               { "( 1.3.6.1.4.1.4203.666.1.55.3 "
01726                      "NAME 'monitorCounter' "
01727                      "DESC 'monitor counter' "
01728                      "EQUALITY integerMatch "
01729                      "ORDERING integerOrderingMatch "
01730                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
01731                      "NO-USER-MODIFICATION "
01732                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01733                      offsetof(monitor_info_t, mi_ad_monitorCounter) },
01734               { "( 1.3.6.1.4.1.4203.666.1.55.4 "
01735                      "NAME 'monitorOpCompleted' "
01736                      "DESC 'monitor completed operations' "
01737                      "SUP monitorCounter "
01738                      "NO-USER-MODIFICATION "
01739                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01740                      offsetof(monitor_info_t, mi_ad_monitorOpCompleted) },
01741               { "( 1.3.6.1.4.1.4203.666.1.55.5 "
01742                      "NAME 'monitorOpInitiated' "
01743                      "DESC 'monitor initiated operations' "
01744                      "SUP monitorCounter "
01745                      "NO-USER-MODIFICATION "
01746                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01747                      offsetof(monitor_info_t, mi_ad_monitorOpInitiated) },
01748               { "( 1.3.6.1.4.1.4203.666.1.55.6 "
01749                      "NAME 'monitorConnectionNumber' "
01750                      "DESC 'monitor connection number' "
01751                      "SUP monitorCounter "
01752                      "NO-USER-MODIFICATION "
01753                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01754                      offsetof(monitor_info_t, mi_ad_monitorConnectionNumber) },
01755               { "( 1.3.6.1.4.1.4203.666.1.55.7 "
01756                      "NAME 'monitorConnectionAuthzDN' "
01757                      "DESC 'monitor connection authorization DN' "
01758                      /* "SUP distinguishedName " */
01759                      "EQUALITY distinguishedNameMatch "
01760                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
01761                      "NO-USER-MODIFICATION "
01762                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01763                      offsetof(monitor_info_t, mi_ad_monitorConnectionAuthzDN) },
01764               { "( 1.3.6.1.4.1.4203.666.1.55.8 "
01765                      "NAME 'monitorConnectionLocalAddress' "
01766                      "DESC 'monitor connection local address' "
01767                      "SUP monitoredInfo "
01768                      "NO-USER-MODIFICATION "
01769                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01770                      offsetof(monitor_info_t, mi_ad_monitorConnectionLocalAddress) },
01771               { "( 1.3.6.1.4.1.4203.666.1.55.9 "
01772                      "NAME 'monitorConnectionPeerAddress' "
01773                      "DESC 'monitor connection peer address' "
01774                      "SUP monitoredInfo "
01775                      "NO-USER-MODIFICATION "
01776                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01777                      offsetof(monitor_info_t, mi_ad_monitorConnectionPeerAddress) },
01778               { "( 1.3.6.1.4.1.4203.666.1.55.10 "
01779                      "NAME 'monitorTimestamp' "
01780                      "DESC 'monitor timestamp' "
01781                      "EQUALITY generalizedTimeMatch "
01782                      "ORDERING generalizedTimeOrderingMatch "
01783                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
01784                      "SINGLE-VALUE "
01785                      "NO-USER-MODIFICATION "
01786                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01787                      offsetof(monitor_info_t, mi_ad_monitorTimestamp) },
01788               { "( 1.3.6.1.4.1.4203.666.1.55.11 "
01789                      "NAME 'monitorOverlay' "
01790                      "DESC 'name of overlays defined for a given database' "
01791                      "SUP monitoredInfo "
01792                      "NO-USER-MODIFICATION "
01793                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01794                      offsetof(monitor_info_t, mi_ad_monitorOverlay) },
01795               { "( 1.3.6.1.4.1.4203.666.1.55.12 "
01796                      "NAME 'readOnly' "
01797                      "DESC 'read/write status of a given database' "
01798                      "EQUALITY booleanMatch "
01799                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
01800                      "SINGLE-VALUE "
01801                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01802                      offsetof(monitor_info_t, mi_ad_readOnly) },
01803               { "( 1.3.6.1.4.1.4203.666.1.55.13 "
01804                      "NAME 'restrictedOperation' "
01805                      "DESC 'name of restricted operation for a given database' "
01806                      "SUP managedInfo )", SLAP_AT_HIDE,
01807                      offsetof(monitor_info_t, mi_ad_restrictedOperation ) },
01808               { "( 1.3.6.1.4.1.4203.666.1.55.14 "
01809                      "NAME 'monitorConnectionProtocol' "
01810                      "DESC 'monitor connection protocol' "
01811                      "SUP monitoredInfo "
01812                      "NO-USER-MODIFICATION "
01813                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01814                      offsetof(monitor_info_t, mi_ad_monitorConnectionProtocol) },
01815               { "( 1.3.6.1.4.1.4203.666.1.55.15 "
01816                      "NAME 'monitorConnectionOpsReceived' "
01817                      "DESC 'monitor number of operations received by the connection' "
01818                      "SUP monitorCounter "
01819                      "NO-USER-MODIFICATION "
01820                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01821                      offsetof(monitor_info_t, mi_ad_monitorConnectionOpsReceived) },
01822               { "( 1.3.6.1.4.1.4203.666.1.55.16 "
01823                      "NAME 'monitorConnectionOpsExecuting' "
01824                      "DESC 'monitor number of operations in execution within the connection' "
01825                      "SUP monitorCounter "
01826                      "NO-USER-MODIFICATION "
01827                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01828                      offsetof(monitor_info_t, mi_ad_monitorConnectionOpsExecuting) },
01829               { "( 1.3.6.1.4.1.4203.666.1.55.17 "
01830                      "NAME 'monitorConnectionOpsPending' "
01831                      "DESC 'monitor number of pending operations within the connection' "
01832                      "SUP monitorCounter "
01833                      "NO-USER-MODIFICATION "
01834                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01835                      offsetof(monitor_info_t, mi_ad_monitorConnectionOpsPending) },
01836               { "( 1.3.6.1.4.1.4203.666.1.55.18 "
01837                      "NAME 'monitorConnectionOpsCompleted' "
01838                      "DESC 'monitor number of operations completed within the connection' "
01839                      "SUP monitorCounter "
01840                      "NO-USER-MODIFICATION "
01841                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01842                      offsetof(monitor_info_t, mi_ad_monitorConnectionOpsCompleted) },
01843               { "( 1.3.6.1.4.1.4203.666.1.55.19 "
01844                      "NAME 'monitorConnectionGet' "
01845                      "DESC 'number of times connection_get() was called so far' "
01846                      "SUP monitorCounter "
01847                      "NO-USER-MODIFICATION "
01848                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01849                      offsetof(monitor_info_t, mi_ad_monitorConnectionGet) },
01850               { "( 1.3.6.1.4.1.4203.666.1.55.20 "
01851                      "NAME 'monitorConnectionRead' "
01852                      "DESC 'number of times connection_read() was called so far' "
01853                      "SUP monitorCounter "
01854                      "NO-USER-MODIFICATION "
01855                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01856                      offsetof(monitor_info_t, mi_ad_monitorConnectionRead) },
01857               { "( 1.3.6.1.4.1.4203.666.1.55.21 "
01858                      "NAME 'monitorConnectionWrite' "
01859                      "DESC 'number of times connection_write() was called so far' "
01860                      "SUP monitorCounter "
01861                      "NO-USER-MODIFICATION "
01862                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01863                      offsetof(monitor_info_t, mi_ad_monitorConnectionWrite) },
01864               { "( 1.3.6.1.4.1.4203.666.1.55.22 "
01865                      "NAME 'monitorConnectionMask' "
01866                      "DESC 'monitor connection mask' "
01867                      "SUP monitoredInfo "
01868                      "NO-USER-MODIFICATION "
01869                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01870                      offsetof(monitor_info_t, mi_ad_monitorConnectionMask) },
01871               { "( 1.3.6.1.4.1.4203.666.1.55.23 "
01872                      "NAME 'monitorConnectionListener' "
01873                      "DESC 'monitor connection listener' "
01874                      "SUP monitoredInfo "
01875                      "NO-USER-MODIFICATION "
01876                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01877                      offsetof(monitor_info_t, mi_ad_monitorConnectionListener) },
01878               { "( 1.3.6.1.4.1.4203.666.1.55.24 "
01879                      "NAME 'monitorConnectionPeerDomain' "
01880                      "DESC 'monitor connection peer domain' "
01881                      "SUP monitoredInfo "
01882                      "NO-USER-MODIFICATION "
01883                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01884                      offsetof(monitor_info_t, mi_ad_monitorConnectionPeerDomain) },
01885               { "( 1.3.6.1.4.1.4203.666.1.55.25 "
01886                      "NAME 'monitorConnectionStartTime' "
01887                      "DESC 'monitor connection start time' "
01888                      "SUP monitorTimestamp "
01889                      "SINGLE-VALUE "
01890                      "NO-USER-MODIFICATION "
01891                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01892                      offsetof(monitor_info_t, mi_ad_monitorConnectionStartTime) },
01893               { "( 1.3.6.1.4.1.4203.666.1.55.26 "
01894                      "NAME 'monitorConnectionActivityTime' "
01895                      "DESC 'monitor connection activity time' "
01896                      "SUP monitorTimestamp "
01897                      "SINGLE-VALUE "
01898                      "NO-USER-MODIFICATION "
01899                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01900                      offsetof(monitor_info_t, mi_ad_monitorConnectionActivityTime) },
01901               { "( 1.3.6.1.4.1.4203.666.1.55.27 "
01902                      "NAME 'monitorIsShadow' "
01903                      "DESC 'TRUE if the database is shadow' "
01904                      "EQUALITY booleanMatch "
01905                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
01906                      "SINGLE-VALUE "
01907                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01908                      offsetof(monitor_info_t, mi_ad_monitorIsShadow) },
01909               { "( 1.3.6.1.4.1.4203.666.1.55.28 "
01910                      "NAME 'monitorUpdateRef' "
01911                      "DESC 'update referral for shadow databases' "
01912                      "SUP monitoredInfo "
01913                      "SINGLE-VALUE "
01914                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01915                      offsetof(monitor_info_t, mi_ad_monitorUpdateRef) },
01916               { "( 1.3.6.1.4.1.4203.666.1.55.29 "
01917                      "NAME 'monitorRuntimeConfig' "
01918                      "DESC 'TRUE if component allows runtime configuration' "
01919                      "EQUALITY booleanMatch "
01920                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
01921                      "SINGLE-VALUE "
01922                      "USAGE dSAOperation )", SLAP_AT_HIDE,
01923                      offsetof(monitor_info_t, mi_ad_monitorRuntimeConfig) },
01924               { "( 1.3.6.1.4.1.4203.666.1.55.30 "
01925                      "NAME 'monitorSuperiorDN' "
01926                      "DESC 'monitor superior DN' "
01927                      /* "SUP distinguishedName " */
01928                      "EQUALITY distinguishedNameMatch "
01929                      "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
01930                      "NO-USER-MODIFICATION "
01931                      "USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
01932                      offsetof(monitor_info_t, mi_ad_monitorSuperiorDN) },
01933               { NULL, 0, -1 }
01934        };
01935 
01936        static struct {
01937               char                 *name;
01938               char                 *oid;
01939        }             s_oid[] = {
01940               { "olmAttributes",                 "1.3.6.1.4.1.4203.666.1.55" },
01941               { "olmSubSystemAttributes",        "olmAttributes:0" },
01942               { "olmGenericAttributes",          "olmSubSystemAttributes:0" },
01943               { "olmDatabaseAttributes",         "olmSubSystemAttributes:1" },
01944 
01945               /* for example, back-bdb specific attrs
01946                * are in "olmDatabaseAttributes:1"
01947                *
01948                * NOTE: developers, please record here OID assignments
01949                * for other modules */
01950 
01951               { "olmObjectClasses",                     "1.3.6.1.4.1.4203.666.3.16" },
01952               { "olmSubSystemObjectClasses",            "olmObjectClasses:0" },
01953               { "olmGenericObjectClasses",              "olmSubSystemObjectClasses:0" },
01954               { "olmDatabaseObjectClasses",             "olmSubSystemObjectClasses:1" },
01955 
01956               /* for example, back-bdb specific objectClasses
01957                * are in "olmDatabaseObjectClasses:1"
01958                *
01959                * NOTE: developers, please record here OID assignments
01960                * for other modules */
01961 
01962               { NULL }
01963        };
01964 
01965        int                  i, rc;
01966        monitor_info_t              *mi = &monitor_info;
01967        ConfigArgs c;
01968        char   *argv[ 3 ];
01969 
01970        argv[ 0 ] = "monitor";
01971        c.argv = argv;
01972        c.argc = 3;
01973        c.fname = argv[0];
01974 
01975        for ( i = 0; s_oid[ i ].name; i++ ) {
01976               argv[ 1 ] = s_oid[ i ].name;
01977               argv[ 2 ] = s_oid[ i ].oid;
01978 
01979               if ( parse_oidm( &c, 0, NULL ) != 0 ) {
01980                      Debug( LDAP_DEBUG_ANY,
01981                             "monitor_back_initialize: unable to add "
01982                             "objectIdentifier \"%s=%s\"\n",
01983                             s_oid[ i ].name, s_oid[ i ].oid, 0 );
01984                      return 1;
01985               }
01986        }
01987 
01988        /* schema integration */
01989        for ( i = 0; mat[ i ].schema; i++ ) {
01990               int                  code;
01991               AttributeDescription **ad =
01992                      ((AttributeDescription **)&(((char *)mi)[ mat[ i ].offset ]));
01993 
01994               *ad = NULL;
01995               code = register_at( mat[ i ].schema, ad, 0 );
01996 
01997               if ( code ) {
01998                      Debug( LDAP_DEBUG_ANY,
01999                             "monitor_back_db_init: register_at failed\n", 0, 0, 0 );
02000                      return -1;
02001               }
02002               (*ad)->ad_type->sat_flags |= mat[ i ].flags;
02003        }
02004 
02005        for ( i = 0; moc[ i ].schema; i++ ) {
02006               int                  code;
02007               ObjectClass          **Oc =
02008                      ((ObjectClass **)&(((char *)mi)[ moc[ i ].offset ]));
02009 
02010               code = register_oc( moc[ i ].schema, Oc, 0 );
02011               if ( code ) {
02012                      Debug( LDAP_DEBUG_ANY,
02013                             "monitor_back_db_init: register_oc failed\n", 0, 0, 0 );
02014                      return -1;
02015               }
02016               (*Oc)->soc_flags |= moc[ i ].flags;
02017        }
02018 
02019        bi->bi_controls = controls;
02020 
02021        bi->bi_init = 0;
02022        bi->bi_open = 0;
02023        bi->bi_config = monitor_back_config;
02024        bi->bi_close = 0;
02025        bi->bi_destroy = 0;
02026 
02027        bi->bi_db_init = monitor_back_db_init;
02028 #if 0
02029        bi->bi_db_config = monitor_back_db_config;
02030 #endif
02031        bi->bi_db_open = monitor_back_db_open;
02032        bi->bi_db_close = 0;
02033        bi->bi_db_destroy = monitor_back_db_destroy;
02034 
02035        bi->bi_op_bind = monitor_back_bind;
02036        bi->bi_op_unbind = 0;
02037        bi->bi_op_search = monitor_back_search;
02038        bi->bi_op_compare = monitor_back_compare;
02039        bi->bi_op_modify = monitor_back_modify;
02040        bi->bi_op_modrdn = 0;
02041        bi->bi_op_add = 0;
02042        bi->bi_op_delete = 0;
02043        bi->bi_op_abandon = 0;
02044 
02045        bi->bi_extended = 0;
02046 
02047        bi->bi_entry_release_rw = monitor_back_release;
02048        bi->bi_chk_referrals = 0;
02049        bi->bi_operational = monitor_back_operational;
02050 
02051        /*
02052         * hooks for slap tools
02053         */
02054        bi->bi_tool_entry_open = 0;
02055        bi->bi_tool_entry_close = 0;
02056        bi->bi_tool_entry_first = 0;
02057        bi->bi_tool_entry_first_x = 0;
02058        bi->bi_tool_entry_next = 0;
02059        bi->bi_tool_entry_get = 0;
02060        bi->bi_tool_entry_put = 0;
02061        bi->bi_tool_entry_reindex = 0;
02062        bi->bi_tool_sync = 0;
02063        bi->bi_tool_dn2id_get = 0;
02064        bi->bi_tool_entry_modify = 0;
02065 
02066        bi->bi_connection_init = 0;
02067        bi->bi_connection_destroy = 0;
02068 
02069        bi->bi_extra = (void *)&monitor_extra;
02070 
02071        /*
02072         * configuration objectClasses (fake)
02073         */
02074        bi->bi_cf_ocs = monitorocs;
02075 
02076        rc = config_register_schema( monitorcfg, monitorocs );
02077        if ( rc ) {
02078               return rc;
02079        }
02080 
02081        return 0;
02082 }
02083 
02084 int
02085 monitor_back_db_init(
02086        BackendDB     *be,
02087        ConfigReply   *c)
02088 {
02089        int                  rc;
02090        struct berval        dn = BER_BVC( SLAPD_MONITOR_DN ),
02091                             pdn,
02092                             ndn;
02093        BackendDB            *be2;
02094 
02095        monitor_subsys_t     *ms;
02096 
02097        /*
02098         * database monitor can be defined once only
02099         */
02100        if ( be_monitor != NULL ) {
02101               if (c) {
02102                      snprintf(c->msg, sizeof(c->msg),"only one monitor database allowed");
02103               }
02104               return( -1 );
02105        }
02106        be_monitor = be;
02107 
02108        /*
02109         * register subsys
02110         */
02111        for ( ms = known_monitor_subsys; ms->mss_name != NULL; ms++ ) {
02112               if ( monitor_back_register_subsys( ms ) ) {
02113                      return -1;
02114               }
02115        }
02116 
02117        /* indicate system schema supported */
02118        SLAP_BFLAGS(be) |= SLAP_BFLAG_MONITOR;
02119 
02120        rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL );
02121        if( rc != LDAP_SUCCESS ) {
02122               Debug( LDAP_DEBUG_ANY,
02123                      "unable to normalize/pretty monitor DN \"%s\" (%d)\n",
02124                      dn.bv_val, rc, 0 );
02125               return -1;
02126        }
02127 
02128        ber_bvarray_add( &be->be_suffix, &pdn );
02129        ber_bvarray_add( &be->be_nsuffix, &ndn );
02130 
02131        /* NOTE: only one monitor database is allowed,
02132         * so we use static storage */
02133        ldap_pvt_thread_mutex_init( &monitor_info.mi_cache_mutex );
02134 
02135        be->be_private = &monitor_info;
02136 
02137        be2 = select_backend( &ndn, 0 );
02138        if ( be2 != be ) {
02139               char   *type = be2->bd_info->bi_type;
02140 
02141               if ( overlay_is_over( be2 ) ) {
02142                      slap_overinfo *oi = (slap_overinfo *)be2->bd_info->bi_private;
02143                      type = oi->oi_orig->bi_type;
02144               }
02145 
02146               if (c) {
02147                      snprintf(c->msg, sizeof(c->msg),
02148                                    "\"monitor\" database serving namingContext \"%s\" "
02149                                    "is hidden by \"%s\" database serving namingContext \"%s\".\n",
02150                                    pdn.bv_val, type, be2->be_nsuffix[ 0 ].bv_val );
02151               }
02152               return -1;
02153        }
02154 
02155        return 0;
02156 }
02157 
02158 static void
02159 monitor_back_destroy_limbo_entry(
02160        entry_limbo_t *el,
02161        int           dispose )
02162 {
02163        if ( el->el_e ) {
02164               entry_free( el->el_e );
02165        }
02166        if ( el->el_a ) {
02167               attrs_free( el->el_a );
02168        }
02169        if ( !BER_BVISNULL( &el->el_nbase ) ) {
02170               ber_memfree( el->el_nbase.bv_val );
02171        }
02172        if ( !BER_BVISNULL( &el->el_filter ) ) {
02173               ber_memfree( el->el_filter.bv_val );
02174        }
02175 
02176        /* NOTE: callbacks are not copied; so only free them
02177         * if disposing of */
02178        if ( el->el_cb && dispose != 0 ) {
02179               monitor_callback_t *next;
02180 
02181               for ( ; el->el_cb; el->el_cb = next ) {
02182                      next = el->el_cb->mc_next;
02183                      if ( el->el_cb->mc_dispose ) {
02184                             el->el_cb->mc_dispose( &el->el_cb->mc_private );
02185                      }
02186                      ch_free( el->el_cb );
02187               }
02188        }
02189 
02190        ch_free( el );
02191 }
02192 
02193 int
02194 monitor_back_db_open(
02195        BackendDB     *be,
02196        ConfigReply   *cr)
02197 {
02198        monitor_info_t              *mi = (monitor_info_t *)be->be_private;
02199        struct monitor_subsys_t     **ms;
02200        Entry                *e, **ep, *root;
02201        monitor_entry_t             *mp;
02202        int                  i;
02203        struct berval        bv, rdn = BER_BVC(SLAPD_MONITOR_DN);
02204        struct tm            tms;
02205        static char          tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
02206        struct berval desc[] = {
02207               BER_BVC("This subtree contains monitoring/managing objects."),
02208               BER_BVC("This object contains information about this server."),
02209               BER_BVC("Most of the information is held in operational"
02210               " attributes, which must be explicitly requested."),
02211               BER_BVNULL };
02212 
02213        int                  retcode = 0;
02214 
02215        assert( be_monitor != NULL );
02216        if ( be != be_monitor ) {
02217               be_monitor = be;
02218        }
02219 
02220        /*
02221         * Start
02222         */
02223        ldap_pvt_gmtime( &starttime, &tms );
02224        lutil_gentime( tmbuf, sizeof(tmbuf), &tms );
02225 
02226        mi->mi_startTime.bv_val = tmbuf;
02227        mi->mi_startTime.bv_len = strlen( tmbuf );
02228 
02229        if ( BER_BVISEMPTY( &be->be_rootdn ) ) {
02230               BER_BVSTR( &mi->mi_creatorsName, SLAPD_ANONYMOUS );
02231               BER_BVSTR( &mi->mi_ncreatorsName, SLAPD_ANONYMOUS );
02232        } else {
02233               mi->mi_creatorsName = be->be_rootdn;
02234               mi->mi_ncreatorsName = be->be_rootndn;
02235        }
02236 
02237        /*
02238         * creates the "cn=Monitor" entry 
02239         */
02240        e = monitor_entry_stub( NULL, NULL, &rdn, mi->mi_oc_monitorServer, mi,
02241               NULL, NULL );
02242 
02243        if ( e == NULL) {
02244               Debug( LDAP_DEBUG_ANY,
02245                      "unable to create \"%s\" entry\n",
02246                      SLAPD_MONITOR_DN, 0, 0 );
02247               return( -1 );
02248        }
02249 
02250        attr_merge_normalize( e, slap_schema.si_ad_description, desc, NULL );
02251 
02252        bv.bv_val = strchr( (char *) Versionstr, '$' );
02253        if ( bv.bv_val != NULL ) {
02254               char   *end;
02255 
02256               bv.bv_val++;
02257               for ( ; bv.bv_val[ 0 ] == ' '; bv.bv_val++ )
02258                      ;
02259 
02260               end = strchr( bv.bv_val, '$' );
02261               if ( end != NULL ) {
02262                      end--;
02263 
02264                      for ( ; end > bv.bv_val && end[ 0 ] == ' '; end-- )
02265                             ;
02266 
02267                      end++;
02268 
02269                      bv.bv_len = end - bv.bv_val;
02270 
02271               } else {
02272                      bv.bv_len = strlen( bv.bv_val );
02273               }
02274 
02275               if ( attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo,
02276                                    &bv, NULL ) ) {
02277                      Debug( LDAP_DEBUG_ANY,
02278                             "unable to add monitoredInfo to \"%s\" entry\n",
02279                             SLAPD_MONITOR_DN, 0, 0 );
02280                      return( -1 );
02281               }
02282        }
02283 
02284        mp = monitor_entrypriv_create();
02285        if ( mp == NULL ) {
02286               return -1;
02287        }
02288        e->e_private = ( void * )mp;
02289        ep = &mp->mp_children;
02290 
02291        if ( monitor_cache_add( mi, e ) ) {
02292               Debug( LDAP_DEBUG_ANY,
02293                      "unable to add entry \"%s\" to cache\n",
02294                      SLAPD_MONITOR_DN, 0, 0 );
02295               return -1;
02296        }
02297        root = e;
02298 
02299        /*     
02300         * Create all the subsystem specific entries
02301         */
02302        for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
02303               int           len = strlen( monitor_subsys[ i ]->mss_name );
02304               struct berval dn;
02305               int           rc;
02306 
02307               dn.bv_len = len + sizeof( "cn=" ) - 1;
02308               dn.bv_val = ch_calloc( sizeof( char ), dn.bv_len + 1 );
02309               strcpy( dn.bv_val, "cn=" );
02310               strcat( dn.bv_val, monitor_subsys[ i ]->mss_name );
02311               rc = dnPretty( NULL, &dn, &monitor_subsys[ i ]->mss_rdn, NULL );
02312               free( dn.bv_val );
02313               if ( rc != LDAP_SUCCESS ) {
02314                      Debug( LDAP_DEBUG_ANY,
02315                             "monitor RDN \"%s\" is invalid\n", 
02316                             dn.bv_val, 0, 0 );
02317                      return( -1 );
02318               }
02319 
02320               e = monitor_entry_stub( &root->e_name, &root->e_nname,
02321                      &monitor_subsys[ i ]->mss_rdn, mi->mi_oc_monitorContainer, mi,
02322                      NULL, NULL );
02323 
02324               if ( e == NULL) {
02325                      Debug( LDAP_DEBUG_ANY,
02326                             "unable to create \"%s\" entry\n", 
02327                             monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
02328                      return( -1 );
02329               }
02330               monitor_subsys[i]->mss_dn = e->e_name;
02331               monitor_subsys[i]->mss_ndn = e->e_nname;
02332 
02333               if ( !BER_BVISNULL( &monitor_subsys[ i ]->mss_desc[ 0 ] ) ) {
02334                      attr_merge_normalize( e, slap_schema.si_ad_description,
02335                                    monitor_subsys[ i ]->mss_desc, NULL );
02336               }
02337 
02338               mp = monitor_entrypriv_create();
02339               if ( mp == NULL ) {
02340                      return -1;
02341               }
02342               e->e_private = ( void * )mp;
02343               mp->mp_info = monitor_subsys[ i ];
02344               mp->mp_flags = monitor_subsys[ i ]->mss_flags;
02345 
02346               if ( monitor_cache_add( mi, e ) ) {
02347                      Debug( LDAP_DEBUG_ANY,
02348                             "unable to add entry \"%s\" to cache\n",
02349                             monitor_subsys[ i ]->mss_dn.bv_val, 0, 0 );
02350                      return -1;
02351               }
02352 
02353               *ep = e;
02354               ep = &mp->mp_next;
02355        }
02356 
02357        assert( be != NULL );
02358 
02359        be->be_private = mi;
02360        
02361        /*
02362         * opens the monitor backend subsystems
02363         */
02364        for ( ms = monitor_subsys; ms[ 0 ] != NULL; ms++ ) {
02365               if ( ms[ 0 ]->mss_open && ms[ 0 ]->mss_open( be, ms[ 0 ] ) ) {
02366                      return( -1 );
02367               }
02368               ms[ 0 ]->mss_flags |= MONITOR_F_OPENED;
02369        }
02370 
02371        monitor_subsys_opened = 1;
02372 
02373        if ( mi->mi_entry_limbo ) {
02374               entry_limbo_t *el = mi->mi_entry_limbo;
02375 
02376               for ( ; el; ) {
02377                      entry_limbo_t *tmp;
02378                      int           rc;
02379 
02380                      switch ( el->el_type ) {
02381                      case LIMBO_ENTRY:
02382                             rc = monitor_back_register_entry(
02383                                           el->el_e,
02384                                           el->el_cb,
02385                                           el->el_mss,
02386                                           el->el_flags );
02387                             break;
02388 
02389                      case LIMBO_ENTRY_PARENT:
02390                             rc = monitor_back_register_entry_parent(
02391                                           el->el_e,
02392                                           el->el_cb,
02393                                           el->el_mss,
02394                                           el->el_flags,
02395                                           &el->el_nbase,
02396                                           el->el_scope,
02397                                           &el->el_filter );
02398                             break;
02399                             
02400 
02401                      case LIMBO_ATTRS:
02402                             rc = monitor_back_register_entry_attrs(
02403                                           el->el_ndn,
02404                                           el->el_a,
02405                                           el->el_cb,
02406                                           &el->el_nbase,
02407                                           el->el_scope,
02408                                           &el->el_filter );
02409                             break;
02410 
02411                      case LIMBO_CB:
02412                             rc = monitor_back_register_entry_callback(
02413                                           el->el_ndn,
02414                                           el->el_cb,
02415                                           &el->el_nbase,
02416                                           el->el_scope,
02417                                           &el->el_filter );
02418                             break;
02419 
02420                      case LIMBO_BACKEND:
02421                             rc = monitor_back_register_backend( el->el_bi );
02422                             break;
02423 
02424                      case LIMBO_DATABASE:
02425                             rc = monitor_back_register_database( el->el_be, el->el_ndn );
02426                             break;
02427 
02428                      case LIMBO_OVERLAY_INFO:
02429                             rc = monitor_back_register_overlay_info( el->el_on );
02430                             break;
02431 
02432                      case LIMBO_OVERLAY:
02433                             rc = monitor_back_register_overlay( el->el_be, el->el_on, el->el_ndn );
02434                             break;
02435 
02436                      default:
02437                             assert( 0 );
02438                      }
02439 
02440                      tmp = el;
02441                      el = el->el_next;
02442                      monitor_back_destroy_limbo_entry( tmp, rc );
02443 
02444                      if ( rc != 0 ) {
02445                             /* try all, but report error at end */
02446                             retcode = 1;
02447                      }
02448               }
02449 
02450               mi->mi_entry_limbo = NULL;
02451        }
02452 
02453        return retcode;
02454 }
02455 
02456 int
02457 monitor_back_config(
02458        BackendInfo   *bi,
02459        const char    *fname,
02460        int           lineno,
02461        int           argc,
02462        char          **argv )
02463 {
02464        /*
02465         * eventually, will hold backend specific configuration parameters
02466         */
02467        return SLAP_CONF_UNKNOWN;
02468 }
02469 
02470 #if 0
02471 int
02472 monitor_back_db_config(
02473        Backend     *be,
02474        const char  *fname,
02475        int         lineno,
02476        int         argc,
02477        char        **argv )
02478 {
02479        monitor_info_t       *mi = ( monitor_info_t * )be->be_private;
02480 
02481        /*
02482         * eventually, will hold database specific configuration parameters
02483         */
02484        return SLAP_CONF_UNKNOWN;
02485 }
02486 #endif
02487 
02488 int
02489 monitor_back_db_destroy(
02490        BackendDB     *be,
02491        ConfigReply   *cr)
02492 {
02493        monitor_info_t       *mi = ( monitor_info_t * )be->be_private;
02494 
02495        if ( mi == NULL ) {
02496               return -1;
02497        }
02498 
02499        /*
02500         * FIXME: destroys all the data
02501         */
02502        /* NOTE: mi points to static storage; don't free it */
02503        
02504        (void)monitor_cache_destroy( mi );
02505 
02506        if ( monitor_subsys ) {
02507               int    i;
02508 
02509               for ( i = 0; monitor_subsys[ i ] != NULL; i++ ) {
02510                      if ( monitor_subsys[ i ]->mss_destroy ) {
02511                             monitor_subsys[ i ]->mss_destroy( be, monitor_subsys[ i ] );
02512                      }
02513 
02514                      if ( !BER_BVISNULL( &monitor_subsys[ i ]->mss_rdn ) ) {
02515                             ch_free( monitor_subsys[ i ]->mss_rdn.bv_val );
02516                      }
02517               }
02518 
02519               ch_free( monitor_subsys );
02520        }
02521 
02522        if ( mi->mi_entry_limbo ) {
02523               entry_limbo_t *el = mi->mi_entry_limbo;
02524 
02525               for ( ; el; ) {
02526                      entry_limbo_t *tmp = el;
02527                      el = el->el_next;
02528                      monitor_back_destroy_limbo_entry( tmp, 1 );
02529               }
02530        }
02531        
02532        ldap_pvt_thread_mutex_destroy( &monitor_info.mi_cache_mutex );
02533 
02534        be->be_private = NULL;
02535 
02536        return 0;
02537 }
02538 
02539 #if SLAPD_MONITOR == SLAPD_MOD_DYNAMIC
02540 
02541 /* conditionally define the init_module() function */
02542 SLAP_BACKEND_INIT_MODULE( monitor )
02543 
02544 #endif /* SLAPD_MONITOR == SLAPD_MOD_DYNAMIC */
02545