Back to index

openldap  2.4.31
dds.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2005-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 2005-2006 SysNet s.n.c.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Pierangelo Masarati for inclusion
00018  * in OpenLDAP Software, sponsored by SysNet s.n.c.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #ifdef SLAPD_OVER_DDS
00024 
00025 #include <stdio.h>
00026 
00027 #include <ac/string.h>
00028 #include <ac/time.h>
00029 
00030 #include "slap.h"
00031 #include "lutil.h"
00032 #include "ldap_rq.h"
00033 
00034 #include "config.h"
00035 
00036 #define       DDS_RF2589_MAX_TTL          (31557600)    /* 1 year + 6 hours */
00037 #define       DDS_RF2589_DEFAULT_TTL             (86400)              /* 1 day */
00038 #define       DDS_DEFAULT_INTERVAL        (3600)        /* 1 hour */
00039 
00040 typedef struct dds_info_t {
00041        unsigned             di_flags;
00042 #define       DDS_FOFF             (0x1U)        /* is this really needed? */
00043 #define       DDS_SET(di, f)              ( (di)->di_flags & (f) )
00044 
00045 #define DDS_OFF(di)         DDS_SET( (di), DDS_FOFF )
00046 
00047        time_t               di_max_ttl;
00048        time_t               di_min_ttl;
00049        time_t               di_default_ttl;
00050 #define       DDS_DEFAULT_TTL(di)  \
00051        ( (di)->di_default_ttl ? (di)->di_default_ttl : (di)->di_max_ttl )
00052 
00053        time_t               di_tolerance;
00054 
00055        /* expire check interval and task */
00056        time_t               di_interval;
00057 #define       DDS_INTERVAL(di)     \
00058        ( (di)->di_interval ? (di)->di_interval : DDS_DEFAULT_INTERVAL )
00059        struct re_s          *di_expire_task;
00060 
00061        /* allows to limit the maximum number of dynamic objects */
00062        ldap_pvt_thread_mutex_t     di_mutex;
00063        int                  di_num_dynamicObjects;
00064        int                  di_max_dynamicObjects;
00065 
00066        /* used to advertize the dynamicSubtrees in the root DSE,
00067         * and to select the database in the expiration task */
00068        BerVarray            di_suffix;
00069        BerVarray            di_nsuffix;
00070 } dds_info_t;
00071 
00072 static struct berval slap_EXOP_REFRESH = BER_BVC( LDAP_EXOP_REFRESH );
00073 static AttributeDescription *ad_entryExpireTimestamp;
00074 
00075 /* list of expired DNs */
00076 typedef struct dds_expire_t {
00077        struct berval        de_ndn;
00078        struct dds_expire_t  *de_next;
00079 } dds_expire_t;
00080 
00081 typedef struct dds_cb_t {
00082        dds_expire_t  *dc_ndnlist;
00083 } dds_cb_t;
00084 
00085 static int
00086 dds_expire_cb( Operation *op, SlapReply *rs )
00087 {
00088        dds_cb_t      *dc = (dds_cb_t *)op->o_callback->sc_private;
00089        dds_expire_t  *de;
00090        int           rc;
00091 
00092        switch ( rs->sr_type ) {
00093        case REP_SEARCH:
00094               /* alloc list and buffer for berval all in one */
00095               de = op->o_tmpalloc( sizeof( dds_expire_t ) + rs->sr_entry->e_nname.bv_len + 1,
00096                      op->o_tmpmemctx );
00097 
00098               de->de_next = dc->dc_ndnlist;
00099               dc->dc_ndnlist = de;
00100 
00101               de->de_ndn.bv_len = rs->sr_entry->e_nname.bv_len;
00102               de->de_ndn.bv_val = (char *)&de[ 1 ];
00103               AC_MEMCPY( de->de_ndn.bv_val, rs->sr_entry->e_nname.bv_val,
00104                      rs->sr_entry->e_nname.bv_len + 1 );
00105               rc = 0;
00106               break;
00107 
00108        case REP_SEARCHREF:
00109        case REP_RESULT:
00110               rc = rs->sr_err;
00111               break;
00112 
00113        default:
00114               assert( 0 );
00115        }
00116 
00117        return rc;
00118 }
00119 
00120 static int
00121 dds_expire( void *ctx, dds_info_t *di )
00122 {
00123        Connection    conn = { 0 };
00124        OperationBuffer opbuf;
00125        Operation     *op;
00126        slap_callback sc = { 0 };
00127        dds_cb_t      dc = { 0 };
00128        dds_expire_t  *de = NULL, **dep;
00129        SlapReply     rs = { REP_RESULT };
00130 
00131        time_t        expire;
00132        char          tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
00133        struct berval ts;
00134 
00135        int           ndeletes, ntotdeletes;
00136 
00137        int           rc;
00138        char          *extra = "";
00139 
00140        connection_fake_init2( &conn, &opbuf, ctx, 0 );
00141        op = &opbuf.ob_op;
00142 
00143        op->o_tag = LDAP_REQ_SEARCH;
00144        memset( &op->oq_search, 0, sizeof( op->oq_search ) );
00145 
00146        op->o_bd = select_backend( &di->di_nsuffix[ 0 ], 0 );
00147 
00148        op->o_req_dn = op->o_bd->be_suffix[ 0 ];
00149        op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ];
00150 
00151        op->o_dn = op->o_bd->be_rootdn;
00152        op->o_ndn = op->o_bd->be_rootndn;
00153 
00154        op->ors_scope = LDAP_SCOPE_SUBTREE;
00155        op->ors_tlimit = DDS_INTERVAL( di )/2 + 1;
00156        op->ors_slimit = SLAP_NO_LIMIT;
00157        op->ors_attrs = slap_anlist_no_attrs;
00158 
00159        expire = slap_get_time() - di->di_tolerance;
00160        ts.bv_val = tsbuf;
00161        ts.bv_len = sizeof( tsbuf );
00162        slap_timestamp( &expire, &ts );
00163 
00164        op->ors_filterstr.bv_len = STRLENOF( "(&(objectClass=" ")(" "<=" "))" )
00165               + slap_schema.si_oc_dynamicObject->soc_cname.bv_len
00166               + ad_entryExpireTimestamp->ad_cname.bv_len
00167               + ts.bv_len;
00168        op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
00169        snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1,
00170               "(&(objectClass=%s)(%s<=%s))",
00171               slap_schema.si_oc_dynamicObject->soc_cname.bv_val,
00172               ad_entryExpireTimestamp->ad_cname.bv_val, ts.bv_val );
00173 
00174        op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
00175        if ( op->ors_filter == NULL ) {
00176               rs.sr_err = LDAP_OTHER;
00177               goto done_search;
00178        }
00179        
00180        op->o_callback = &sc;
00181        sc.sc_response = dds_expire_cb;
00182        sc.sc_private = &dc;
00183 
00184        (void)op->o_bd->bd_info->bi_op_search( op, &rs );
00185 
00186 done_search:;
00187        op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
00188        filter_free_x( op, op->ors_filter, 1 );
00189 
00190        rc = rs.sr_err;
00191        switch ( rs.sr_err ) {
00192        case LDAP_SUCCESS:
00193               break;
00194 
00195        case LDAP_NO_SUCH_OBJECT:
00196               /* (ITS#5267) database not created yet? */
00197               rs.sr_err = LDAP_SUCCESS;
00198               extra = " (ignored)";
00199               /* fallthru */
00200 
00201        default:
00202               Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
00203                      "DDS expired objects lookup failed err=%d%s\n",
00204                      rc, extra );
00205               goto done;
00206        }
00207 
00208        op->o_tag = LDAP_REQ_DELETE;
00209        op->o_callback = &sc;
00210        sc.sc_response = slap_null_cb;
00211        sc.sc_private = NULL;
00212 
00213        for ( ntotdeletes = 0, ndeletes = 1; dc.dc_ndnlist != NULL  && ndeletes > 0; ) {
00214               ndeletes = 0;
00215 
00216               for ( dep = &dc.dc_ndnlist; *dep != NULL; ) {
00217                      de = *dep;
00218 
00219                      op->o_req_dn = de->de_ndn;
00220                      op->o_req_ndn = de->de_ndn;
00221                      (void)op->o_bd->bd_info->bi_op_delete( op, &rs );
00222                      switch ( rs.sr_err ) {
00223                      case LDAP_SUCCESS:
00224                             Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
00225                                    "DDS dn=\"%s\" expired.\n",
00226                                    de->de_ndn.bv_val );
00227                             ndeletes++;
00228                             break;
00229 
00230                      case LDAP_NOT_ALLOWED_ON_NONLEAF:
00231                             Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
00232                                    "DDS dn=\"%s\" is non-leaf; "
00233                                    "deferring.\n",
00234                                    de->de_ndn.bv_val );
00235                             dep = &de->de_next;
00236                             de = NULL;
00237                             break;
00238        
00239                      default:
00240                             Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
00241                                    "DDS dn=\"%s\" err=%d; "
00242                                    "deferring.\n",
00243                                    de->de_ndn.bv_val, rs.sr_err );
00244                             break;
00245                      }
00246 
00247                      if ( de != NULL ) {
00248                             *dep = de->de_next;
00249                             op->o_tmpfree( de, op->o_tmpmemctx );
00250                      }
00251               }
00252 
00253               ntotdeletes += ndeletes;
00254        }
00255 
00256        rs.sr_err = LDAP_SUCCESS;
00257 
00258        Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
00259               "DDS expired=%d\n", ntotdeletes );
00260 
00261 done:;
00262        return rs.sr_err;
00263 }
00264 
00265 static void *
00266 dds_expire_fn( void *ctx, void *arg )
00267 {
00268        struct re_s     *rtask = arg;
00269        dds_info_t    *di = rtask->arg;
00270 
00271        assert( di->di_expire_task == rtask );
00272 
00273        (void)dds_expire( ctx, di );
00274        
00275        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00276        if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
00277               ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
00278        }
00279        ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
00280        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00281 
00282        return NULL;
00283 }
00284 
00285 /* frees the callback */
00286 static int
00287 dds_freeit_cb( Operation *op, SlapReply *rs )
00288 {
00289        op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
00290        op->o_callback = NULL;
00291 
00292        return SLAP_CB_CONTINUE;
00293 }
00294 
00295 /* updates counter - installed on add/delete only if required */
00296 static int
00297 dds_counter_cb( Operation *op, SlapReply *rs )
00298 {
00299        assert( rs->sr_type == REP_RESULT );
00300 
00301        if ( rs->sr_err == LDAP_SUCCESS ) {
00302               dds_info_t    *di = op->o_callback->sc_private;
00303 
00304               ldap_pvt_thread_mutex_lock( &di->di_mutex );
00305               switch ( op->o_tag ) {
00306               case LDAP_REQ_DELETE:
00307                      assert( di->di_num_dynamicObjects > 0 );
00308                      di->di_num_dynamicObjects--;
00309                      break;
00310 
00311               case LDAP_REQ_ADD:
00312                      assert( di->di_num_dynamicObjects < di->di_max_dynamicObjects );
00313                      di->di_num_dynamicObjects++;
00314                      break;
00315 
00316               default:
00317                      assert( 0 );
00318               }
00319               ldap_pvt_thread_mutex_unlock( &di->di_mutex );
00320        }
00321 
00322        return dds_freeit_cb( op, rs );
00323 }
00324 
00325 static int
00326 dds_op_add( Operation *op, SlapReply *rs )
00327 {
00328        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00329        dds_info_t    *di = on->on_bi.bi_private;
00330        int           is_dynamicObject;
00331 
00332        if ( DDS_OFF( di ) ) {
00333               return SLAP_CB_CONTINUE;
00334        }
00335 
00336        is_dynamicObject = is_entry_dynamicObject( op->ora_e );
00337 
00338        /* FIXME: do not allow this right now, pending clarification */
00339        if ( is_dynamicObject ) {
00340               rs->sr_err = LDAP_SUCCESS;
00341 
00342               if ( is_entry_referral( op->ora_e ) ) {
00343                      rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
00344                      rs->sr_text = "a referral cannot be a dynamicObject";
00345 
00346               } else if ( is_entry_alias( op->ora_e ) ) {
00347                      rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
00348                      rs->sr_text = "an alias cannot be a dynamicObject";
00349               }
00350 
00351               if ( rs->sr_err != LDAP_SUCCESS ) {
00352                      op->o_bd->bd_info = (BackendInfo *)on->on_info;
00353                      send_ldap_result( op, rs );
00354                      return rs->sr_err;
00355               }
00356        }
00357 
00358        /* we don't allow dynamicObjects to have static subordinates */
00359        if ( !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) {
00360               struct berval p_ndn;
00361               Entry         *e = NULL;
00362               int           rc;
00363               BackendInfo   *bi = op->o_bd->bd_info;
00364 
00365               dnParent( &op->o_req_ndn, &p_ndn );
00366               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00367               rc = be_entry_get_rw( op, &p_ndn,
00368                      slap_schema.si_oc_dynamicObject, NULL, 0, &e );
00369               if ( rc == LDAP_SUCCESS && e != NULL ) {
00370                      if ( !is_dynamicObject ) {
00371                             /* return referral only if "disclose"
00372                              * is granted on the object */
00373                             if ( ! access_allowed( op, e,
00374                                           slap_schema.si_ad_entry,
00375                                           NULL, ACL_DISCLOSE, NULL ) )
00376                             {
00377                                    rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
00378                                    send_ldap_result( op, rs );
00379 
00380                             } else {
00381                                    rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
00382                                    send_ldap_error( op, rs, rc, "no static subordinate entries allowed for dynamicObject" );
00383                             }
00384                      }
00385 
00386                      be_entry_release_r( op, e );
00387                      if ( rc != LDAP_SUCCESS ) {
00388                             return rc;
00389                      }
00390               }
00391               op->o_bd->bd_info = bi;
00392        }
00393 
00394        /* handle dynamic object operational attr(s) */
00395        if ( is_dynamicObject ) {
00396               time_t        ttl, expire;
00397               char          ttlbuf[STRLENOF("31557600") + 1];
00398               char          tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
00399               struct berval bv;
00400 
00401               if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
00402                      ldap_pvt_thread_mutex_lock( &di->di_mutex );
00403                      rs->sr_err = ( di->di_max_dynamicObjects && 
00404                             di->di_num_dynamicObjects >= di->di_max_dynamicObjects );
00405                      ldap_pvt_thread_mutex_unlock( &di->di_mutex );
00406                      if ( rs->sr_err ) {
00407                             op->o_bd->bd_info = (BackendInfo *)on->on_info;
00408                             send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00409                                    "too many dynamicObjects in context" );
00410                             return rs->sr_err;
00411                      }
00412               }
00413 
00414               ttl = DDS_DEFAULT_TTL( di );
00415 
00416               /* assert because should be checked at configure */
00417               assert( ttl <= DDS_RF2589_MAX_TTL );
00418 
00419               bv.bv_val = ttlbuf;
00420               bv.bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl );
00421               assert( bv.bv_len < sizeof( ttlbuf ) );
00422 
00423               /* FIXME: apparently, values in op->ora_e are malloc'ed
00424                * on the thread's slab; works fine by chance,
00425                * only because the attribute doesn't exist yet. */
00426               assert( attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryTtl ) == NULL );
00427               attr_merge_one( op->ora_e, slap_schema.si_ad_entryTtl, &bv, &bv );
00428 
00429               expire = slap_get_time() + ttl;
00430               bv.bv_val = tsbuf;
00431               bv.bv_len = sizeof( tsbuf );
00432               slap_timestamp( &expire, &bv );
00433               assert( attr_find( op->ora_e->e_attrs, ad_entryExpireTimestamp ) == NULL );
00434               attr_merge_one( op->ora_e, ad_entryExpireTimestamp, &bv, &bv );
00435 
00436               /* if required, install counter callback */
00437               if ( di->di_max_dynamicObjects > 0) {
00438                      slap_callback *sc;
00439 
00440                      sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
00441                      sc->sc_cleanup = dds_freeit_cb;
00442                      sc->sc_response = dds_counter_cb;
00443                      sc->sc_private = di;
00444                      sc->sc_next = op->o_callback;
00445 
00446                      op->o_callback = sc;
00447               }
00448        }
00449 
00450        return SLAP_CB_CONTINUE;
00451 }
00452 
00453 static int
00454 dds_op_delete( Operation *op, SlapReply *rs )
00455 {
00456        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00457        dds_info_t    *di = on->on_bi.bi_private;
00458 
00459        /* if required, install counter callback */
00460        if ( !DDS_OFF( di ) && di->di_max_dynamicObjects > 0 ) {
00461               Entry         *e = NULL;
00462               BackendInfo   *bi = op->o_bd->bd_info;
00463 
00464               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00465               rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
00466                      slap_schema.si_oc_dynamicObject, NULL, 0, &e );
00467 
00468               /* FIXME: couldn't the entry be added before deletion? */
00469               if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
00470                      slap_callback *sc;
00471        
00472                      be_entry_release_r( op, e );
00473                      e = NULL;
00474        
00475                      sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
00476                      sc->sc_cleanup = dds_freeit_cb;
00477                      sc->sc_response = dds_counter_cb;
00478                      sc->sc_private = di;
00479                      sc->sc_next = op->o_callback;
00480        
00481                      op->o_callback = sc;
00482               }
00483               op->o_bd->bd_info = bi;
00484        }
00485 
00486        return SLAP_CB_CONTINUE;
00487 }
00488 
00489 static int
00490 dds_op_modify( Operation *op, SlapReply *rs )
00491 {
00492        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00493        dds_info_t    *di = (dds_info_t *)on->on_bi.bi_private;
00494        Modifications *mod;
00495        Entry         *e = NULL;
00496        BackendInfo   *bi = op->o_bd->bd_info;
00497        int           was_dynamicObject = 0,
00498                      is_dynamicObject = 0;
00499        struct berval bv_entryTtl = BER_BVNULL;
00500        time_t        entryTtl = 0;
00501        char          textbuf[ SLAP_TEXT_BUFLEN ];
00502 
00503        if ( DDS_OFF( di ) ) {
00504               return SLAP_CB_CONTINUE;
00505        }
00506 
00507        /* bv_entryTtl stores the string representation of the entryTtl
00508         * across modifies for consistency checks of the final value;
00509         * the bv_val points to a static buffer; the bv_len is zero when
00510         * the attribute is deleted.
00511         * entryTtl stores the integer representation of the entryTtl;
00512         * its value is -1 when the attribute is deleted; it is 0 only
00513         * if no modifications of the entryTtl occurred, as an entryTtl
00514         * of 0 is invalid. */
00515        bv_entryTtl.bv_val = textbuf;
00516 
00517        op->o_bd->bd_info = (BackendInfo *)on->on_info;
00518        rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
00519               slap_schema.si_oc_dynamicObject, slap_schema.si_ad_entryTtl, 0, &e );
00520        if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
00521               Attribute     *a = attr_find( e->e_attrs, slap_schema.si_ad_entryTtl );
00522 
00523               /* the value of the entryTtl is saved for later checks */
00524               if ( a != NULL ) {
00525                      unsigned long ttl;
00526                      int           rc;
00527 
00528                      bv_entryTtl.bv_len = a->a_nvals[ 0 ].bv_len;
00529                      AC_MEMCPY( bv_entryTtl.bv_val, a->a_nvals[ 0 ].bv_val, bv_entryTtl.bv_len );
00530                      bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
00531                      rc = lutil_atoul( &ttl, bv_entryTtl.bv_val );
00532                      assert( rc == 0 );
00533                      entryTtl = (time_t)ttl;
00534               }
00535 
00536               be_entry_release_r( op, e );
00537               e = NULL;
00538               was_dynamicObject = is_dynamicObject = 1;
00539        }
00540        op->o_bd->bd_info = bi;
00541 
00542        rs->sr_err = LDAP_SUCCESS;
00543        for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) {
00544               if ( mod->sml_desc == slap_schema.si_ad_objectClass ) {
00545                      int           i;
00546                      ObjectClass   *oc;
00547 
00548                      switch ( mod->sml_op ) {
00549                      case LDAP_MOD_DELETE:
00550                             if ( mod->sml_values == NULL ) {
00551                                    is_dynamicObject = 0;
00552                                    break;
00553                             }
00554        
00555                             for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) {
00556                                    oc = oc_bvfind( &mod->sml_values[ i ] );
00557                                    if ( oc == slap_schema.si_oc_dynamicObject ) {
00558                                           is_dynamicObject = 0;
00559                                           break;
00560                                    }
00561                             }
00562        
00563                             break;
00564        
00565                      case LDAP_MOD_REPLACE:
00566                             if ( mod->sml_values == NULL ) {
00567                                    is_dynamicObject = 0;
00568                                    break;
00569                             }
00570                             /* fallthru */
00571        
00572                      case LDAP_MOD_ADD:
00573                             for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) {
00574                                    oc = oc_bvfind( &mod->sml_values[ i ] );
00575                                    if ( oc == slap_schema.si_oc_dynamicObject ) {
00576                                           is_dynamicObject = 1;
00577                                           break;
00578                                    }
00579                             }
00580                             break;
00581                      }
00582 
00583               } else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) {
00584                      unsigned long uttl;
00585                      time_t        ttl;
00586                      int           rc;
00587 
00588                      switch ( mod->sml_op ) {
00589                      case LDAP_MOD_DELETE:
00590                      case SLAP_MOD_SOFTDEL: /* FIXME? */
00591                             if ( mod->sml_values != NULL ) {
00592                                    if ( BER_BVISEMPTY( &bv_entryTtl ) 
00593                                           || !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) )
00594                                    {
00595                                           rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, 
00596                                                  slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
00597                                           if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
00598                                                  rs->sr_err = LDAP_NO_SUCH_OBJECT;
00599 
00600                                           } else {
00601                                                  rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
00602                                           }
00603                                           goto done;
00604                                    }
00605                             }
00606                             bv_entryTtl.bv_len = 0;
00607                             entryTtl = -1;
00608                             break;
00609 
00610                      case LDAP_MOD_REPLACE:
00611                             bv_entryTtl.bv_len = 0;
00612                             entryTtl = -1;
00613                             /* fallthru */
00614 
00615                      case LDAP_MOD_ADD:
00616                      case SLAP_MOD_SOFTADD: /* FIXME? */
00617                      case SLAP_MOD_ADD_IF_NOT_PRESENT: /* FIXME? */
00618                             assert( mod->sml_values != NULL );
00619                             assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) );
00620 
00621                             if ( !BER_BVISEMPTY( &bv_entryTtl ) ) {
00622                                    rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, 
00623                                           slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
00624                                    if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
00625                                           rs->sr_err = LDAP_NO_SUCH_OBJECT;
00626 
00627                                    } else {
00628                                           rs->sr_text = "attribute 'entryTtl' cannot have multiple values";
00629                                           rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
00630                                    }
00631                                    goto done;
00632                             }
00633 
00634                             rc = lutil_atoul( &uttl, mod->sml_values[ 0 ].bv_val );
00635                             ttl = (time_t)uttl;
00636                             assert( rc == 0 );
00637                             if ( ttl > DDS_RF2589_MAX_TTL ) {
00638                                    rs->sr_err = LDAP_PROTOCOL_ERROR;
00639                                    rs->sr_text = "invalid time-to-live for dynamicObject";
00640                                    goto done;
00641                             }
00642 
00643                             if ( ttl <= 0 || ttl > di->di_max_ttl ) {
00644                                    /* FIXME: I don't understand if this has to be an error,
00645                                     * or an indication that the requested Ttl has been
00646                                     * shortened to di->di_max_ttl >= 1 day */
00647                                    rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
00648                                    rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit";
00649                                    goto done;
00650                             }
00651 
00652                             entryTtl = ttl;
00653                             bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len;
00654                             AC_MEMCPY( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len );
00655                             bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
00656                             break;
00657 
00658                      case LDAP_MOD_INCREMENT:
00659                             if ( BER_BVISEMPTY( &bv_entryTtl ) ) {
00660                                    rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, 
00661                                           slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
00662                                    if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
00663                                           rs->sr_err = LDAP_NO_SUCH_OBJECT;
00664 
00665                                    } else {
00666                                           rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
00667                                           rs->sr_text = "modify/increment: entryTtl: no such attribute";
00668                                    }
00669                                    goto done;
00670                             }
00671 
00672                             entryTtl++;
00673                             if ( entryTtl > DDS_RF2589_MAX_TTL ) {
00674                                    rs->sr_err = LDAP_PROTOCOL_ERROR;
00675                                    rs->sr_text = "invalid time-to-live for dynamicObject";
00676 
00677                             } else if ( entryTtl <= 0 || entryTtl > di->di_max_ttl ) {
00678                                    /* FIXME: I don't understand if this has to be an error,
00679                                     * or an indication that the requested Ttl has been
00680                                     * shortened to di->di_max_ttl >= 1 day */
00681                                    rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
00682                                    rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit";
00683                             }
00684 
00685                             if ( rs->sr_err != LDAP_SUCCESS ) {
00686                                    rc = backend_attribute( op, NULL, &op->o_req_ndn, 
00687                                           slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
00688                                    if ( rc == LDAP_INSUFFICIENT_ACCESS ) {
00689                                           rs->sr_text = NULL;
00690                                           rs->sr_err = LDAP_NO_SUCH_OBJECT;
00691 
00692                                    }
00693                                    goto done;
00694                             }
00695 
00696                             bv_entryTtl.bv_len = snprintf( textbuf, sizeof( textbuf ), "%ld", entryTtl );
00697                             break;
00698 
00699                      default:
00700                             assert( 0 );
00701                             break;
00702                      }
00703 
00704               } else if ( mod->sml_desc == ad_entryExpireTimestamp ) {
00705                      /* should have been trapped earlier */
00706                      assert( mod->sml_flags & SLAP_MOD_INTERNAL );
00707               }
00708        }
00709 
00710 done:;
00711        if ( rs->sr_err == LDAP_SUCCESS ) {
00712               int    rc;
00713 
00714               /* FIXME: this could be allowed when the Relax control is used...
00715                * in that case:
00716                *
00717                * TODO
00718                * 
00719                *     static => dynamic:
00720                *            entryTtl must be provided; add
00721                *            entryExpireTimestamp accordingly
00722                *
00723                *     dynamic => static:
00724                *            entryTtl must be removed; remove
00725                *            entryTimestamp accordingly
00726                *
00727                * ... but we need to make sure that there are no subordinate 
00728                * issues...
00729                */
00730               rc = is_dynamicObject - was_dynamicObject;
00731               if ( rc ) {
00732 #if 0 /* fix subordinate issues first */
00733                      if ( get_relax( op ) ) {
00734                             switch ( rc ) {
00735                             case -1:
00736                                    /* need to delete entryTtl to have a consistent entry */
00737                                    if ( entryTtl != -1 ) {
00738                                           rs->sr_text = "objectClass modification from dynamicObject to static entry requires entryTtl deletion";
00739                                           rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
00740                                    }
00741                                    break;
00742 
00743                             case 1:
00744                                    /* need to add entryTtl to have a consistent entry */
00745                                    if ( entryTtl <= 0 ) {
00746                                           rs->sr_text = "objectClass modification from static entry to dynamicObject requires entryTtl addition";
00747                                           rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
00748                                    }
00749                                    break;
00750                             }
00751 
00752                      } else
00753 #endif
00754                      {
00755                             switch ( rc ) {
00756                             case -1:
00757                                    rs->sr_text = "objectClass modification cannot turn dynamicObject into static entry";
00758                                    break;
00759 
00760                             case 1:
00761                                    rs->sr_text = "objectClass modification cannot turn static entry into dynamicObject";
00762                                    break;
00763                             }
00764                             rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
00765                      }
00766 
00767                      if ( rc != LDAP_SUCCESS ) {
00768                             rc = backend_attribute( op, NULL, &op->o_req_ndn, 
00769                                    slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
00770                             if ( rc == LDAP_INSUFFICIENT_ACCESS ) {
00771                                    rs->sr_text = NULL;
00772                                    rs->sr_err = LDAP_NO_SUCH_OBJECT;
00773                             }
00774                      }
00775               }
00776        }
00777 
00778        if ( rs->sr_err == LDAP_SUCCESS && entryTtl != 0 ) {
00779               Modifications *tmpmod = NULL, **modp;
00780 
00781               for ( modp = &op->orm_modlist; *modp; modp = &(*modp)->sml_next )
00782                      ;
00783        
00784               tmpmod = ch_calloc( 1, sizeof( Modifications ) );
00785               tmpmod->sml_flags = SLAP_MOD_INTERNAL;
00786               tmpmod->sml_type = ad_entryExpireTimestamp->ad_cname;
00787               tmpmod->sml_desc = ad_entryExpireTimestamp;
00788 
00789               *modp = tmpmod;
00790 
00791               if ( entryTtl == -1 ) {
00792                      /* delete entryExpireTimestamp */
00793                      tmpmod->sml_op = LDAP_MOD_DELETE;
00794 
00795               } else {
00796                      time_t        expire;
00797                      char          tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
00798                      struct berval bv;
00799 
00800                      /* keep entryExpireTimestamp consistent
00801                       * with entryTtl */
00802                      expire = slap_get_time() + entryTtl;
00803                      bv.bv_val = tsbuf;
00804                      bv.bv_len = sizeof( tsbuf );
00805                      slap_timestamp( &expire, &bv );
00806 
00807                      tmpmod->sml_op = LDAP_MOD_REPLACE;
00808                      value_add_one( &tmpmod->sml_values, &bv );
00809                      value_add_one( &tmpmod->sml_nvalues, &bv );
00810                      tmpmod->sml_numvals = 1;
00811               }
00812        }
00813 
00814        if ( rs->sr_err ) {
00815               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00816               send_ldap_result( op, rs );
00817               return rs->sr_err;
00818        }
00819 
00820        return SLAP_CB_CONTINUE;
00821 }
00822 
00823 static int
00824 dds_op_rename( Operation *op, SlapReply *rs )
00825 {
00826        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00827        dds_info_t    *di = on->on_bi.bi_private;
00828 
00829        if ( DDS_OFF( di ) ) {
00830               return SLAP_CB_CONTINUE;
00831        }
00832 
00833        /* we don't allow dynamicObjects to have static subordinates */
00834        if ( op->orr_nnewSup != NULL ) {
00835               Entry         *e = NULL;
00836               BackendInfo   *bi = op->o_bd->bd_info;
00837               int           is_dynamicObject = 0,
00838                             rc;
00839 
00840               rs->sr_err = LDAP_SUCCESS;
00841 
00842               op->o_bd->bd_info = (BackendInfo *)on->on_info;
00843               rc = be_entry_get_rw( op, &op->o_req_ndn,
00844                      slap_schema.si_oc_dynamicObject, NULL, 0, &e );
00845               if ( rc == LDAP_SUCCESS && e != NULL ) {
00846                      be_entry_release_r( op, e );
00847                      e = NULL;
00848                      is_dynamicObject = 1;
00849               }
00850 
00851               rc = be_entry_get_rw( op, op->orr_nnewSup,
00852                      slap_schema.si_oc_dynamicObject, NULL, 0, &e );
00853               if ( rc == LDAP_SUCCESS && e != NULL ) {
00854                      if ( !is_dynamicObject ) {
00855                             /* return referral only if "disclose"
00856                              * is granted on the object */
00857                             if ( ! access_allowed( op, e,
00858                                           slap_schema.si_ad_entry,
00859                                           NULL, ACL_DISCLOSE, NULL ) )
00860                             {
00861                                    rs->sr_err = LDAP_NO_SUCH_OBJECT;
00862                                    send_ldap_result( op, rs );
00863 
00864                             } else {
00865                                    send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION,
00866                                           "static entry cannot have dynamicObject as newSuperior" );
00867                             }
00868                      }
00869                      be_entry_release_r( op, e );
00870               }
00871               op->o_bd->bd_info = bi;
00872               if ( rs->sr_err != LDAP_SUCCESS ) {
00873                      return rs->sr_err;
00874               }
00875        }
00876 
00877        return SLAP_CB_CONTINUE;
00878 }
00879 
00880 static int
00881 slap_parse_refresh(
00882        struct berval *in,
00883        struct berval *ndn,
00884        time_t        *ttl,
00885        const char    **text,
00886        void          *ctx )
00887 {
00888        int                  rc = LDAP_SUCCESS;
00889        ber_tag_t            tag;
00890        ber_len_t            len = -1;
00891        BerElementBuffer     berbuf;
00892        BerElement           *ber = (BerElement *)&berbuf;
00893        struct berval        reqdata = BER_BVNULL;
00894        int                  tmp;
00895 
00896        *text = NULL;
00897 
00898        if ( ndn ) {
00899               BER_BVZERO( ndn );
00900        }
00901 
00902        if ( in == NULL || in->bv_len == 0 ) {
00903               *text = "empty request data field in refresh exop";
00904               return LDAP_PROTOCOL_ERROR;
00905        }
00906 
00907        ber_dupbv_x( &reqdata, in, ctx );
00908 
00909        /* ber_init2 uses reqdata directly, doesn't allocate new buffers */
00910        ber_init2( ber, &reqdata, 0 );
00911 
00912        tag = ber_scanf( ber, "{" /*}*/ );
00913 
00914        if ( tag == LBER_ERROR ) {
00915               Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
00916                      "slap_parse_refresh: decoding error.\n" );
00917               goto decoding_error;
00918        }
00919 
00920        tag = ber_peek_tag( ber, &len );
00921        if ( tag != LDAP_TAG_EXOP_REFRESH_REQ_DN ) {
00922               Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
00923                      "slap_parse_refresh: decoding error.\n" );
00924               goto decoding_error;
00925        }
00926 
00927        if ( ndn ) {
00928               struct berval dn;
00929 
00930               tag = ber_scanf( ber, "m", &dn );
00931               if ( tag == LBER_ERROR ) {
00932                      Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
00933                             "slap_parse_refresh: DN parse failed.\n" );
00934                      goto decoding_error;
00935               }
00936 
00937               rc = dnNormalize( 0, NULL, NULL, &dn, ndn, ctx );
00938               if ( rc != LDAP_SUCCESS ) {
00939                      *text = "invalid DN in refresh exop request data";
00940                      goto done;
00941               }
00942 
00943        } else {
00944               tag = ber_scanf( ber, "x" /* "m" */ );
00945               if ( tag == LBER_DEFAULT ) {
00946                      goto decoding_error;
00947               }
00948        }
00949 
00950        tag = ber_peek_tag( ber, &len );
00951 
00952        if ( tag != LDAP_TAG_EXOP_REFRESH_REQ_TTL ) {
00953               Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
00954                      "slap_parse_refresh: decoding error.\n" );
00955               goto decoding_error;
00956        }
00957 
00958        tag = ber_scanf( ber, "i", &tmp );
00959        if ( tag == LBER_ERROR ) {
00960               Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
00961                      "slap_parse_refresh: TTL parse failed.\n" );
00962               goto decoding_error;
00963        }
00964 
00965        if ( ttl ) {
00966               *ttl = tmp;
00967        }
00968 
00969        tag = ber_peek_tag( ber, &len );
00970 
00971        if ( tag != LBER_DEFAULT || len != 0 ) {
00972 decoding_error:;
00973               Log1( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
00974                      "slap_parse_refresh: decoding error, len=%ld\n",
00975                      (long)len );
00976               rc = LDAP_PROTOCOL_ERROR;
00977               *text = "data decoding error";
00978 
00979 done:;
00980               if ( ndn && !BER_BVISNULL( ndn ) ) {
00981                      slap_sl_free( ndn->bv_val, ctx );
00982                      BER_BVZERO( ndn );
00983               }
00984        }
00985 
00986        if ( !BER_BVISNULL( &reqdata ) ) {
00987               ber_memfree_x( reqdata.bv_val, ctx );
00988        }
00989 
00990        return rc;
00991 }
00992 
00993 static int
00994 dds_op_extended( Operation *op, SlapReply *rs )
00995 {
00996        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
00997        dds_info_t    *di = on->on_bi.bi_private;
00998 
00999        if ( DDS_OFF( di ) ) {
01000               return SLAP_CB_CONTINUE;
01001        }
01002 
01003        if ( bvmatch( &op->ore_reqoid, &slap_EXOP_REFRESH ) ) {
01004               Entry         *e = NULL;
01005               time_t        ttl;
01006               BackendDB     db = *op->o_bd;
01007               SlapReply     rs2 = { REP_RESULT };
01008               Operation     op2 = *op;
01009               slap_callback sc = { 0 };
01010               Modifications ttlmod = { { 0 } };
01011               struct berval ttlvalues[ 2 ];
01012               char          ttlbuf[STRLENOF("31557600") + 1];
01013 
01014               rs->sr_err = slap_parse_refresh( op->ore_reqdata, NULL, &ttl,
01015                      &rs->sr_text, NULL );
01016               assert( rs->sr_err == LDAP_SUCCESS );
01017 
01018               if ( ttl <= 0 || ttl > DDS_RF2589_MAX_TTL ) {
01019                      rs->sr_err = LDAP_PROTOCOL_ERROR;
01020                      rs->sr_text = "invalid time-to-live for dynamicObject";
01021                      return rs->sr_err;
01022               }
01023 
01024               if ( ttl > di->di_max_ttl ) {
01025                      /* FIXME: I don't understand if this has to be an error,
01026                       * or an indication that the requested Ttl has been
01027                       * shortened to di->di_max_ttl >= 1 day */
01028                      rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
01029                      rs->sr_text = "time-to-live for dynamicObject exceeds limit";
01030                      return rs->sr_err;
01031               }
01032 
01033               if ( di->di_min_ttl && ttl < di->di_min_ttl ) {
01034                      ttl = di->di_min_ttl;
01035               }
01036 
01037               /* This does not apply to multi-master case */
01038               if ( !( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ) ) ) {
01039                      /* we SHOULD return a referral in this case */
01040                      BerVarray defref = op->o_bd->be_update_refs
01041                             ? op->o_bd->be_update_refs : default_referral; 
01042 
01043                      if ( defref != NULL ) {
01044                             rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs,
01045                                    NULL, NULL, LDAP_SCOPE_DEFAULT );
01046                             if ( rs->sr_ref ) {
01047                                    rs->sr_flags |= REP_REF_MUSTBEFREED;
01048                             } else {
01049                                    rs->sr_ref = defref;
01050                             }
01051                             rs->sr_err = LDAP_REFERRAL;
01052 
01053                      } else {
01054                             rs->sr_text = "shadow context; no update referral";
01055                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01056                      }
01057 
01058                      return rs->sr_err;
01059               }
01060 
01061               assert( !BER_BVISNULL( &op->o_req_ndn ) );
01062 
01063 
01064 
01065               /* check if exists but not dynamicObject */
01066               op->o_bd->bd_info = (BackendInfo *)on->on_info;
01067               rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
01068                      slap_schema.si_oc_dynamicObject, NULL, 0, &e );
01069               if ( rs->sr_err != LDAP_SUCCESS ) {
01070                      rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
01071                             NULL, NULL, 0, &e );
01072                      if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
01073                             /* return referral only if "disclose"
01074                              * is granted on the object */
01075                             if ( ! access_allowed( op, e,
01076                                           slap_schema.si_ad_entry,
01077                                           NULL, ACL_DISCLOSE, NULL ) )
01078                             {
01079                                    rs->sr_err = LDAP_NO_SUCH_OBJECT;
01080 
01081                             } else {
01082                                    rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
01083                                    rs->sr_text = "refresh operation only applies to dynamic objects";
01084                             }
01085                             be_entry_release_r( op, e );
01086 
01087                      } else {
01088                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
01089                      }
01090                      return rs->sr_err;
01091 
01092               } else if ( e != NULL ) {
01093                      be_entry_release_r( op, e );
01094               }
01095 
01096               /* we require manage privileges on the entryTtl,
01097                * and fake a Relax control */
01098               op2.o_tag = LDAP_REQ_MODIFY;
01099               op2.o_bd = &db;
01100               db.bd_info = (BackendInfo *)on->on_info;
01101               op2.o_callback = &sc;
01102               sc.sc_response = slap_null_cb;
01103               op2.o_relax = SLAP_CONTROL_CRITICAL;
01104               op2.orm_modlist = &ttlmod;
01105 
01106               ttlmod.sml_op = LDAP_MOD_REPLACE;
01107               ttlmod.sml_flags = SLAP_MOD_MANAGING;
01108               ttlmod.sml_desc = slap_schema.si_ad_entryTtl;
01109               ttlmod.sml_values = ttlvalues;
01110               ttlmod.sml_numvals = 1;
01111               ttlvalues[ 0 ].bv_val = ttlbuf;
01112               ttlvalues[ 0 ].bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl );
01113               BER_BVZERO( &ttlvalues[ 1 ] );
01114 
01115               /* the entryExpireTimestamp is added by modify */
01116               rs->sr_err = op2.o_bd->be_modify( &op2, &rs2 );
01117 
01118               if ( ttlmod.sml_next != NULL ) {
01119                      slap_mods_free( ttlmod.sml_next, 1 );
01120               }
01121 
01122               if ( rs->sr_err == LDAP_SUCCESS ) {
01123                      int                  rc;
01124                      BerElementBuffer     berbuf;
01125                      BerElement           *ber = (BerElement *)&berbuf;
01126 
01127                      ber_init_w_nullc( ber, LBER_USE_DER );
01128 
01129                      rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl );
01130 
01131                      if ( rc < 0 ) {
01132                             rs->sr_err = LDAP_OTHER;
01133                             rs->sr_text = "internal error";
01134 
01135                      } else {
01136                             (void)ber_flatten( ber, &rs->sr_rspdata );
01137                             rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val );
01138 
01139                             Log3( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO,
01140                                    "%s REFRESH dn=\"%s\" TTL=%ld\n",
01141                                    op->o_log_prefix, op->o_req_ndn.bv_val, ttl );
01142                      }
01143 
01144                      ber_free_buf( ber );
01145               }
01146 
01147               return rs->sr_err;
01148        }
01149 
01150        return SLAP_CB_CONTINUE;
01151 }
01152 
01153 enum {
01154        DDS_STATE = 1,
01155        DDS_MAXTTL,
01156        DDS_MINTTL,
01157        DDS_DEFAULTTTL,
01158        DDS_INTERVAL,
01159        DDS_TOLERANCE,
01160        DDS_MAXDYNAMICOBJS,
01161 
01162        DDS_LAST
01163 };
01164 
01165 static ConfigDriver dds_cfgen;
01166 #if 0
01167 static ConfigLDAPadd dds_ldadd;
01168 static ConfigCfAdd dds_cfadd;
01169 #endif
01170 
01171 static ConfigTable dds_cfg[] = {
01172        { "dds-state", "on|off",
01173               2, 2, 0, ARG_MAGIC|ARG_ON_OFF|DDS_STATE, dds_cfgen,
01174               "( OLcfgOvAt:9.1 NAME 'olcDDSstate' "
01175                      "DESC 'RFC2589 Dynamic directory services state' "
01176                      "SYNTAX OMsBoolean "
01177                      "SINGLE-VALUE )", NULL, NULL },
01178        { "dds-max-ttl", "ttl",
01179               2, 2, 0, ARG_MAGIC|DDS_MAXTTL, dds_cfgen,
01180               "( OLcfgOvAt:9.2 NAME 'olcDDSmaxTtl' "
01181                      "DESC 'RFC2589 Dynamic directory services max TTL' "
01182                      "SYNTAX OMsDirectoryString "
01183                      "SINGLE-VALUE )", NULL, NULL },
01184        { "dds-min-ttl", "ttl",
01185               2, 2, 0, ARG_MAGIC|DDS_MINTTL, dds_cfgen,
01186               "( OLcfgOvAt:9.3 NAME 'olcDDSminTtl' "
01187                      "DESC 'RFC2589 Dynamic directory services min TTL' "
01188                      "SYNTAX OMsDirectoryString "
01189                      "SINGLE-VALUE )", NULL, NULL },
01190        { "dds-default-ttl", "ttl",
01191               2, 2, 0, ARG_MAGIC|DDS_DEFAULTTTL, dds_cfgen,
01192               "( OLcfgOvAt:9.4 NAME 'olcDDSdefaultTtl' "
01193                      "DESC 'RFC2589 Dynamic directory services default TTL' "
01194                      "SYNTAX OMsDirectoryString "
01195                      "SINGLE-VALUE )", NULL, NULL },
01196        { "dds-interval", "interval",
01197               2, 2, 0, ARG_MAGIC|DDS_INTERVAL, dds_cfgen,
01198               "( OLcfgOvAt:9.5 NAME 'olcDDSinterval' "
01199                      "DESC 'RFC2589 Dynamic directory services expiration "
01200                             "task run interval' "
01201                      "SYNTAX OMsDirectoryString "
01202                      "SINGLE-VALUE )", NULL, NULL },
01203        { "dds-tolerance", "ttl",
01204               2, 2, 0, ARG_MAGIC|DDS_TOLERANCE, dds_cfgen,
01205               "( OLcfgOvAt:9.6 NAME 'olcDDStolerance' "
01206                      "DESC 'RFC2589 Dynamic directory services additional "
01207                             "TTL in expiration scheduling' "
01208                      "SYNTAX OMsDirectoryString "
01209                      "SINGLE-VALUE )", NULL, NULL },
01210        { "dds-max-dynamicObjects", "num",
01211               2, 2, 0, ARG_MAGIC|ARG_INT|DDS_MAXDYNAMICOBJS, dds_cfgen,
01212               "( OLcfgOvAt:9.7 NAME 'olcDDSmaxDynamicObjects' "
01213                      "DESC 'RFC2589 Dynamic directory services max number of dynamic objects' "
01214                      "SYNTAX OMsInteger "
01215                      "SINGLE-VALUE )", NULL, NULL },
01216        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
01217 };
01218 
01219 static ConfigOCs dds_ocs[] = {
01220        { "( OLcfgOvOc:9.1 "
01221               "NAME 'olcDDSConfig' "
01222               "DESC 'RFC2589 Dynamic directory services configuration' "
01223               "SUP olcOverlayConfig "
01224               "MAY ( "
01225                      "olcDDSstate "
01226                      "$ olcDDSmaxTtl "
01227                      "$ olcDDSminTtl "
01228                      "$ olcDDSdefaultTtl "
01229                      "$ olcDDSinterval "
01230                      "$ olcDDStolerance "
01231                      "$ olcDDSmaxDynamicObjects "
01232               " ) "
01233               ")", Cft_Overlay, dds_cfg, NULL, NULL /* dds_cfadd */ },
01234        { NULL, 0, NULL }
01235 };
01236 
01237 #if 0
01238 static int
01239 dds_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
01240 {
01241        return LDAP_SUCCESS;
01242 }
01243 
01244 static int
01245 dds_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
01246 {
01247        return 0;
01248 }
01249 #endif
01250 
01251 static int
01252 dds_cfgen( ConfigArgs *c )
01253 {
01254        slap_overinst *on = (slap_overinst *)c->bi;
01255        dds_info_t    *di = on->on_bi.bi_private;
01256        int           rc = 0;
01257        unsigned long t;
01258 
01259 
01260        if ( c->op == SLAP_CONFIG_EMIT ) {
01261               char          buf[ SLAP_TEXT_BUFLEN ];
01262               struct berval bv;
01263 
01264               switch( c->type ) {
01265               case DDS_STATE: 
01266                      c->value_int = !DDS_OFF( di );
01267                      break;
01268 
01269               case DDS_MAXTTL: 
01270                      lutil_unparse_time( buf, sizeof( buf ), di->di_max_ttl );
01271                      ber_str2bv( buf, 0, 0, &bv );
01272                      value_add_one( &c->rvalue_vals, &bv );
01273                      break;
01274 
01275               case DDS_MINTTL:
01276                      if ( di->di_min_ttl ) {
01277                             lutil_unparse_time( buf, sizeof( buf ), di->di_min_ttl );
01278                             ber_str2bv( buf, 0, 0, &bv );
01279                             value_add_one( &c->rvalue_vals, &bv );
01280 
01281                      } else {
01282                             rc = 1;
01283                      }
01284                      break;
01285 
01286               case DDS_DEFAULTTTL:
01287                      if ( di->di_default_ttl ) {
01288                             lutil_unparse_time( buf, sizeof( buf ), di->di_default_ttl );
01289                             ber_str2bv( buf, 0, 0, &bv );
01290                             value_add_one( &c->rvalue_vals, &bv );
01291 
01292                      } else {
01293                             rc = 1;
01294                      }
01295                      break;
01296 
01297               case DDS_INTERVAL:
01298                      if ( di->di_interval ) {
01299                             lutil_unparse_time( buf, sizeof( buf ), di->di_interval );
01300                             ber_str2bv( buf, 0, 0, &bv );
01301                             value_add_one( &c->rvalue_vals, &bv );
01302 
01303                      } else {
01304                             rc = 1;
01305                      }
01306                      break;
01307 
01308               case DDS_TOLERANCE:
01309                      if ( di->di_tolerance ) {
01310                             lutil_unparse_time( buf, sizeof( buf ), di->di_tolerance );
01311                             ber_str2bv( buf, 0, 0, &bv );
01312                             value_add_one( &c->rvalue_vals, &bv );
01313 
01314                      } else {
01315                             rc = 1;
01316                      }
01317                      break;
01318 
01319               case DDS_MAXDYNAMICOBJS:
01320                      if ( di->di_max_dynamicObjects > 0 ) {
01321                             c->value_int = di->di_max_dynamicObjects;
01322 
01323                      } else {
01324                             rc = 1;
01325                      }
01326                      break;
01327 
01328               default:
01329                      rc = 1;
01330                      break;
01331               }
01332 
01333               return rc;
01334 
01335        } else if ( c->op == LDAP_MOD_DELETE ) {
01336               switch( c->type ) {
01337               case DDS_STATE:
01338                      di->di_flags &= ~DDS_FOFF;
01339                      break;
01340 
01341               case DDS_MAXTTL:
01342                      di->di_min_ttl = DDS_RF2589_DEFAULT_TTL;
01343                      break;
01344 
01345               case DDS_MINTTL:
01346                      di->di_min_ttl = 0;
01347                      break;
01348 
01349               case DDS_DEFAULTTTL:
01350                      di->di_default_ttl = 0;
01351                      break;
01352 
01353               case DDS_INTERVAL:
01354                      di->di_interval = 0;
01355                      break;
01356 
01357               case DDS_TOLERANCE:
01358                      di->di_tolerance = 0;
01359                      break;
01360 
01361               case DDS_MAXDYNAMICOBJS:
01362                      di->di_max_dynamicObjects = 0;
01363                      break;
01364 
01365               default:
01366                      rc = 1;
01367                      break;
01368               }
01369 
01370               return rc;
01371        }
01372 
01373        switch ( c->type ) {
01374        case DDS_STATE:
01375               if ( c->value_int ) {
01376                      di->di_flags &= ~DDS_FOFF;
01377 
01378               } else {
01379                      di->di_flags |= DDS_FOFF;
01380               }
01381               break;
01382 
01383        case DDS_MAXTTL:
01384               if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
01385                      snprintf( c->cr_msg, sizeof( c->cr_msg),
01386                             "DDS unable to parse dds-max-ttl \"%s\"",
01387                             c->argv[ 1 ] );
01388                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01389                             "%s: %s.\n", c->log, c->cr_msg );
01390                      return 1;
01391               }
01392 
01393               if ( t < DDS_RF2589_DEFAULT_TTL || t > DDS_RF2589_MAX_TTL ) {
01394                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
01395                             "DDS invalid dds-max-ttl=%lu; must be between %d and %d",
01396                             t, DDS_RF2589_DEFAULT_TTL, DDS_RF2589_MAX_TTL );
01397                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01398                             "%s: %s.\n", c->log, c->cr_msg );
01399                      return 1;
01400               }
01401 
01402               di->di_max_ttl = (time_t)t;
01403               break;
01404 
01405        case DDS_MINTTL:
01406               if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
01407                      snprintf( c->cr_msg, sizeof( c->cr_msg),
01408                             "DDS unable to parse dds-min-ttl \"%s\"",
01409                             c->argv[ 1 ] );
01410                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01411                             "%s: %s.\n", c->log, c->cr_msg );
01412                      return 1;
01413               }
01414 
01415               if ( t > DDS_RF2589_MAX_TTL ) {
01416                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
01417                             "DDS invalid dds-min-ttl=%lu",
01418                             t );
01419                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01420                             "%s: %s.\n", c->log, c->cr_msg );
01421                      return 1;
01422               }
01423 
01424               if ( t == 0 ) {
01425                      di->di_min_ttl = DDS_RF2589_DEFAULT_TTL;
01426 
01427               } else {
01428                      di->di_min_ttl = (time_t)t;
01429               }
01430               break;
01431 
01432        case DDS_DEFAULTTTL:
01433               if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
01434                      snprintf( c->cr_msg, sizeof( c->cr_msg),
01435                             "DDS unable to parse dds-default-ttl \"%s\"",
01436                             c->argv[ 1 ] );
01437                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01438                             "%s: %s.\n", c->log, c->cr_msg );
01439                      return 1;
01440               }
01441 
01442               if ( t > DDS_RF2589_MAX_TTL ) {
01443                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
01444                             "DDS invalid dds-default-ttl=%lu",
01445                             t );
01446                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01447                             "%s: %s.\n", c->log, c->cr_msg );
01448                      return 1;
01449               }
01450 
01451               if ( t == 0 ) {
01452                      di->di_default_ttl = DDS_RF2589_DEFAULT_TTL;
01453 
01454               } else {
01455                      di->di_default_ttl = (time_t)t;
01456               }
01457               break;
01458 
01459        case DDS_INTERVAL:
01460               if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
01461                      snprintf( c->cr_msg, sizeof( c->cr_msg),
01462                             "DDS unable to parse dds-interval \"%s\"",
01463                             c->argv[ 1 ] );
01464                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01465                             "%s: %s.\n", c->log, c->cr_msg );
01466                      return 1;
01467               }
01468 
01469               if ( t <= 0 ) {
01470                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
01471                             "DDS invalid dds-interval=%lu",
01472                             t );
01473                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01474                             "%s: %s.\n", c->log, c->cr_msg );
01475                      return 1;
01476               }
01477 
01478               if ( t < 60 ) {
01479                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
01480                             "%s: dds-interval=%lu may be too small.\n",
01481                             c->log, t );
01482               }
01483 
01484               di->di_interval = (time_t)t;
01485               if ( di->di_expire_task ) {
01486                      ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
01487                      if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) {
01488                             ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task );
01489                      }
01490                      di->di_expire_task->interval.tv_sec = DDS_INTERVAL( di );
01491                      ldap_pvt_runqueue_resched( &slapd_rq, di->di_expire_task, 0 );
01492                      ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
01493               }
01494               break;
01495 
01496        case DDS_TOLERANCE:
01497               if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
01498                      snprintf( c->cr_msg, sizeof( c->cr_msg),
01499                             "DDS unable to parse dds-tolerance \"%s\"",
01500                             c->argv[ 1 ] );
01501                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01502                             "%s: %s.\n", c->log, c->cr_msg );
01503                      return 1;
01504               }
01505 
01506               if ( t > DDS_RF2589_MAX_TTL ) {
01507                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
01508                             "DDS invalid dds-tolerance=%lu",
01509                             t );
01510                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01511                             "%s: %s.\n", c->log, c->cr_msg );
01512                      return 1;
01513               }
01514 
01515               di->di_tolerance = (time_t)t;
01516               break;
01517 
01518        case DDS_MAXDYNAMICOBJS:
01519               if ( c->value_int < 0 ) {
01520                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
01521                             "DDS invalid dds-max-dynamicObjects=%d", c->value_int );
01522                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01523                             "%s: %s.\n", c->log, c->cr_msg );
01524                      return 1;
01525               }
01526               di->di_max_dynamicObjects = c->value_int;
01527               break;
01528 
01529        default:
01530               rc = 1;
01531               break;
01532        }
01533 
01534        return rc;
01535 }
01536 
01537 static int
01538 dds_db_init(
01539        BackendDB     *be,
01540        ConfigReply   *cr)
01541 {
01542        slap_overinst *on = (slap_overinst *)be->bd_info;
01543        dds_info_t    *di;
01544        BackendInfo   *bi = on->on_info->oi_orig;
01545 
01546        if ( SLAP_ISGLOBALOVERLAY( be ) ) {
01547               Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01548                      "DDS cannot be used as global overlay.\n" );
01549               return 1;
01550        }
01551 
01552        /* check support for required functions */
01553        /* FIXME: some could be provided by other overlays in between */
01554        if ( bi->bi_op_add == NULL                /* object creation */
01555               || bi->bi_op_delete == NULL        /* object deletion */
01556               || bi->bi_op_modify == NULL        /* object refresh */
01557               || bi->bi_op_search == NULL        /* object expiration */
01558               || bi->bi_entry_get_rw == NULL )   /* object type/existence checking */
01559        {
01560               Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01561                      "DDS backend \"%s\" does not provide "
01562                      "required functionality.\n",
01563                      bi->bi_type );
01564               return 1;
01565        }
01566 
01567        di = (dds_info_t *)ch_calloc( 1, sizeof( dds_info_t ) );
01568        on->on_bi.bi_private = di;
01569 
01570        di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
01571        di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
01572 
01573        ldap_pvt_thread_mutex_init( &di->di_mutex );
01574 
01575        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_DYNAMIC;
01576 
01577        return 0;
01578 }
01579 
01580 /* adds dynamicSubtrees to root DSE */
01581 static int
01582 dds_entry_info( void *arg, Entry *e )
01583 {
01584        dds_info_t    *di = (dds_info_t *)arg;
01585 
01586        attr_merge( e, slap_schema.si_ad_dynamicSubtrees,
01587               di->di_suffix, di->di_nsuffix );
01588 
01589        return 0;
01590 }
01591 
01592 /* callback that counts the returned entries, since the search
01593  * does not get to the point in slap_send_search_entries where
01594  * the actual count occurs */
01595 static int
01596 dds_count_cb( Operation *op, SlapReply *rs )
01597 {
01598        int    *nump = (int *)op->o_callback->sc_private;
01599 
01600        switch ( rs->sr_type ) {
01601        case REP_SEARCH:
01602               (*nump)++;
01603               break;
01604 
01605        case REP_SEARCHREF:
01606        case REP_RESULT:
01607               break;
01608 
01609        default:
01610               assert( 0 );
01611        }
01612 
01613        return 0;
01614 }
01615 
01616 /* count dynamic objects existing in the database at startup */
01617 static int
01618 dds_count( void *ctx, BackendDB *be )
01619 {
01620        slap_overinst *on = (slap_overinst *)be->bd_info;
01621        dds_info_t    *di = (dds_info_t *)on->on_bi.bi_private;
01622        
01623        Connection    conn = { 0 };
01624        OperationBuffer opbuf;
01625        Operation     *op;
01626        slap_callback sc = { 0 };
01627        SlapReply     rs = { REP_RESULT };
01628 
01629        int           rc;
01630        char          *extra = "";
01631 
01632        connection_fake_init2( &conn, &opbuf, ctx, 0 );
01633        op = &opbuf.ob_op;
01634 
01635        op->o_tag = LDAP_REQ_SEARCH;
01636        memset( &op->oq_search, 0, sizeof( op->oq_search ) );
01637 
01638        op->o_bd = be;
01639 
01640        op->o_req_dn = op->o_bd->be_suffix[ 0 ];
01641        op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ];
01642 
01643        op->o_dn = op->o_bd->be_rootdn;
01644        op->o_ndn = op->o_bd->be_rootndn;
01645 
01646        op->ors_scope = LDAP_SCOPE_SUBTREE;
01647        op->ors_tlimit = SLAP_NO_LIMIT;
01648        op->ors_slimit = SLAP_NO_LIMIT;
01649        op->ors_attrs = slap_anlist_no_attrs;
01650 
01651        op->ors_filterstr.bv_len = STRLENOF( "(objectClass=" ")" )
01652               + slap_schema.si_oc_dynamicObject->soc_cname.bv_len;
01653        op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
01654        snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1,
01655               "(objectClass=%s)",
01656               slap_schema.si_oc_dynamicObject->soc_cname.bv_val );
01657 
01658        op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
01659        if ( op->ors_filter == NULL ) {
01660               rs.sr_err = LDAP_OTHER;
01661               goto done_search;
01662        }
01663        
01664        op->o_callback = &sc;
01665        sc.sc_response = dds_count_cb;
01666        sc.sc_private = &di->di_num_dynamicObjects;
01667        di->di_num_dynamicObjects = 0;
01668 
01669        op->o_bd->bd_info = (BackendInfo *)on->on_info;
01670        (void)op->o_bd->bd_info->bi_op_search( op, &rs );
01671        op->o_bd->bd_info = (BackendInfo *)on;
01672 
01673 done_search:;
01674        op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
01675        filter_free_x( op, op->ors_filter, 1 );
01676 
01677        rc = rs.sr_err;
01678        switch ( rs.sr_err ) {
01679        case LDAP_SUCCESS:
01680               Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
01681                      "DDS non-expired=%d\n",
01682                      di->di_num_dynamicObjects );
01683               break;
01684 
01685        case LDAP_NO_SUCH_OBJECT:
01686               /* (ITS#5267) database not created yet? */
01687               rs.sr_err = LDAP_SUCCESS;
01688               extra = " (ignored)";
01689               /* fallthru */
01690 
01691        default:
01692               Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01693                      "DDS non-expired objects lookup failed err=%d%s\n",
01694                      rc, extra );
01695               break;
01696        }
01697 
01698        return rs.sr_err;
01699 }
01700 
01701 static int
01702 dds_db_open(
01703        BackendDB     *be,
01704        ConfigReply   *cr )
01705 {
01706        slap_overinst *on = (slap_overinst *)be->bd_info;
01707        dds_info_t    *di = on->on_bi.bi_private;
01708        int           rc = 0;
01709        void          *thrctx = ldap_pvt_thread_pool_context();
01710 
01711        if ( slapMode & SLAP_TOOL_MODE )
01712               return 0;
01713 
01714        if ( DDS_OFF( di ) ) {
01715               goto done;
01716        }
01717 
01718        if ( SLAP_SINGLE_SHADOW( be ) ) {
01719               Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01720                      "DDS incompatible with shadow database \"%s\".\n",
01721                      be->be_suffix[ 0 ].bv_val );
01722               return 1;
01723        }
01724 
01725        if ( di->di_max_ttl == 0 ) {
01726               di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
01727        }
01728 
01729        if ( di->di_min_ttl == 0 ) {
01730               di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
01731        }
01732 
01733        di->di_suffix = be->be_suffix;
01734        di->di_nsuffix = be->be_nsuffix;
01735 
01736        /* ... so that count, if required, is accurate */
01737        if ( di->di_max_dynamicObjects > 0 ) {
01738               /* force deletion of expired entries... */
01739               be->bd_info = (BackendInfo *)on->on_info;
01740               rc = dds_expire( thrctx, di );
01741               be->bd_info = (BackendInfo *)on;
01742               if ( rc != LDAP_SUCCESS ) {
01743                      rc = 1;
01744                      goto done;
01745               }
01746 
01747               rc = dds_count( thrctx, be );
01748               if ( rc != LDAP_SUCCESS ) {
01749                      rc = 1;
01750                      goto done;
01751               }
01752        }
01753 
01754        /* start expire task */
01755        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
01756        di->di_expire_task = ldap_pvt_runqueue_insert( &slapd_rq,
01757               DDS_INTERVAL( di ),
01758               dds_expire_fn, di, "dds_expire_fn",
01759               be->be_suffix[ 0 ].bv_val );
01760        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
01761 
01762        /* register dinamicSubtrees root DSE info support */
01763        rc = entry_info_register( dds_entry_info, (void *)di );
01764 
01765 done:;
01766 
01767        return rc;
01768 }
01769 
01770 static int
01771 dds_db_close(
01772        BackendDB     *be,
01773        ConfigReply   *cr )
01774 {
01775        slap_overinst *on = (slap_overinst *)be->bd_info;
01776        dds_info_t    *di = on->on_bi.bi_private;
01777 
01778        /* stop expire task */
01779        if ( di && di->di_expire_task ) {
01780               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
01781               if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) {
01782                      ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task );
01783               }
01784               ldap_pvt_runqueue_remove( &slapd_rq, di->di_expire_task );
01785               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
01786        }
01787 
01788        (void)entry_info_unregister( dds_entry_info, (void *)di );
01789 
01790        return 0;
01791 }
01792 
01793 static int
01794 dds_db_destroy(
01795        BackendDB     *be,
01796        ConfigReply   *cr )
01797 {
01798        slap_overinst *on = (slap_overinst *)be->bd_info;
01799        dds_info_t    *di = on->on_bi.bi_private;
01800 
01801        if ( di != NULL ) {
01802               ldap_pvt_thread_mutex_destroy( &di->di_mutex );
01803 
01804               free( di );
01805        }
01806 
01807        return 0;
01808 }
01809 
01810 static int
01811 slap_exop_refresh(
01812               Operation     *op,
01813               SlapReply     *rs )
01814 {
01815        BackendDB            *bd = op->o_bd;
01816 
01817        rs->sr_err = slap_parse_refresh( op->ore_reqdata, &op->o_req_ndn, NULL,
01818               &rs->sr_text, op->o_tmpmemctx );
01819        if ( rs->sr_err != LDAP_SUCCESS ) {
01820               return rs->sr_err;
01821        }
01822 
01823        Log2( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
01824               "%s REFRESH dn=\"%s\"\n",
01825               op->o_log_prefix, op->o_req_ndn.bv_val );
01826        op->o_req_dn = op->o_req_ndn;
01827 
01828        op->o_bd = select_backend( &op->o_req_ndn, 0 );
01829        if ( op->o_bd == NULL ) {
01830               send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT,
01831                      "no global superior knowledge" );
01832               goto done;
01833        }
01834 
01835        if ( !SLAP_DYNAMIC( op->o_bd ) ) {
01836               send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
01837                      "backend does not support dynamic directory services" );
01838               goto done;
01839        }
01840 
01841        rs->sr_err = backend_check_restrictions( op, rs,
01842               (struct berval *)&slap_EXOP_REFRESH );
01843        if ( rs->sr_err != LDAP_SUCCESS ) {
01844               goto done;
01845        }
01846 
01847        if ( op->o_bd->be_extended == NULL ) {
01848               send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
01849                      "backend does not support extended operations" );
01850               goto done;
01851        }
01852 
01853        op->o_bd->be_extended( op, rs );
01854 
01855 done:;
01856        if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
01857               op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
01858               BER_BVZERO( &op->o_req_ndn );
01859               BER_BVZERO( &op->o_req_dn );
01860        }
01861        op->o_bd = bd;
01862 
01863         return rs->sr_err;
01864 }
01865 
01866 static slap_overinst dds;
01867 
01868 static int do_not_load_exop;
01869 static int do_not_replace_exop;
01870 static int do_not_load_schema;
01871 
01872 #if SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC
01873 static
01874 #endif /* SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC */
01875 int
01876 dds_initialize()
01877 {
01878        int           rc = 0;
01879        int           i, code;
01880 
01881        /* Make sure we don't exceed the bits reserved for userland */
01882        config_check_userland( DDS_LAST );
01883 
01884        if ( !do_not_load_schema ) {
01885               static struct {
01886                      char                 *desc;
01887                      slap_mask_t          flags;
01888                      AttributeDescription **ad;
01889               }             s_at[] = {
01890                      { "( 1.3.6.1.4.1.4203.666.1.57 "
01891                             "NAME ( 'entryExpireTimestamp' ) "
01892                             "DESC 'RFC2589 OpenLDAP extension: expire time of a dynamic object, "
01893                                    "computed as now + entryTtl' "
01894                             "EQUALITY generalizedTimeMatch "
01895                             "ORDERING generalizedTimeOrderingMatch "
01896                             "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
01897                             "SINGLE-VALUE "
01898                             "NO-USER-MODIFICATION "
01899                             "USAGE dSAOperation )",
01900                             SLAP_AT_HIDE,
01901                             &ad_entryExpireTimestamp },
01902                      { NULL }
01903               };
01904 
01905               for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
01906                      code = register_at( s_at[ i ].desc, s_at[ i ].ad, 0 );
01907                      if ( code ) {
01908                             Debug( LDAP_DEBUG_ANY,
01909                                    "dds_initialize: register_at failed\n", 0, 0, 0 );
01910                             return code;
01911                      }
01912                      (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
01913               }
01914        }
01915 
01916        if ( !do_not_load_exop ) {
01917               rc = load_extop2( (struct berval *)&slap_EXOP_REFRESH,
01918                      SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, slap_exop_refresh,
01919                      !do_not_replace_exop );
01920               if ( rc != LDAP_SUCCESS ) {
01921                      Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01922                             "DDS unable to register refresh exop: %d.\n",
01923                             rc );
01924                      return rc;
01925               }
01926        }
01927 
01928        dds.on_bi.bi_type = "dds";
01929 
01930        dds.on_bi.bi_db_init = dds_db_init;
01931        dds.on_bi.bi_db_open = dds_db_open;
01932        dds.on_bi.bi_db_close = dds_db_close;
01933        dds.on_bi.bi_db_destroy = dds_db_destroy;
01934 
01935        dds.on_bi.bi_op_add = dds_op_add;
01936        dds.on_bi.bi_op_delete = dds_op_delete;
01937        dds.on_bi.bi_op_modify = dds_op_modify;
01938        dds.on_bi.bi_op_modrdn = dds_op_rename;
01939        dds.on_bi.bi_extended = dds_op_extended;
01940 
01941        dds.on_bi.bi_cf_ocs = dds_ocs;
01942 
01943        rc = config_register_schema( dds_cfg, dds_ocs );
01944        if ( rc ) {
01945               return rc;
01946        }
01947 
01948        return overlay_register( &dds );
01949 }
01950 
01951 #if SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC
01952 int
01953 init_module( int argc, char *argv[] )
01954 {
01955        int    i;
01956 
01957        for ( i = 0; i < argc; i++ ) {
01958               char   *arg = argv[ i ];
01959               int    no = 0;
01960 
01961               if ( strncasecmp( arg, "no-", STRLENOF( "no-" ) ) == 0 ) {
01962                      arg += STRLENOF( "no-" );
01963                      no = 1;
01964               }
01965 
01966               if ( strcasecmp( arg, "exop" ) == 0 ) {
01967                      do_not_load_exop = no;
01968 
01969               } else if ( strcasecmp( arg, "replace" ) == 0 ) {
01970                      do_not_replace_exop = no;
01971 
01972               } else if ( strcasecmp( arg, "schema" ) == 0 ) {
01973                      do_not_load_schema = no;
01974 
01975               } else {
01976                      Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
01977                             "DDS unknown module arg[#%d]=\"%s\".\n",
01978                             i, argv[ i ] );
01979                      return 1;
01980               }
01981        }
01982 
01983        return dds_initialize();
01984 }
01985 #endif /* SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC */
01986 
01987 #endif /* defined(SLAPD_OVER_DDS) */