1 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/dds.c,v 1.7.2.9 2008/02/11 23:26:48 kurt Exp $ */ 2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 2005-2008 The OpenLDAP Foundation. 5 * Portions Copyright 2005-2006 SysNet s.n.c. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 /* ACKNOWLEDGEMENTS: 17 * This work was initially developed by Pierangelo Masarati for inclusion 18 * in OpenLDAP Software, sponsored by SysNet s.n.c. 19 */ 20 21 #include "portable.h" 22 23 #ifdef SLAPD_OVER_DDS 24 25 #include <stdio.h> 26 27 #include <ac/string.h> 28 #include <ac/time.h> 29 30 #include "slap.h" 31 #include "lutil.h" 32 #include "ldap_rq.h" 33 34 #include "config.h" 35 36 #define DDS_RF2589_MAX_TTL (31557600) /* 1 year + 6 hours */ 37 #define DDS_RF2589_DEFAULT_TTL (86400) /* 1 day */ 38 #define DDS_DEFAULT_INTERVAL (3600) /* 1 hour */ 39 40 typedef struct dds_info_t { 41 unsigned di_flags; 42 #define DDS_FOFF (0x1U) /* is this really needed? */ 43 #define DDS_SET(di, f) ( (di)->di_flags & (f) ) 44 45 #define DDS_OFF(di) DDS_SET( (di), DDS_FOFF ) 46 47 time_t di_max_ttl; 48 time_t di_min_ttl; 49 time_t di_default_ttl; 50 #define DDS_DEFAULT_TTL(di) \ 51 ( (di)->di_default_ttl ? (di)->di_default_ttl : (di)->di_max_ttl ) 52 53 time_t di_tolerance; 54 55 /* expire check interval and task */ 56 time_t di_interval; 57 #define DDS_INTERVAL(di) \ 58 ( (di)->di_interval ? (di)->di_interval : DDS_DEFAULT_INTERVAL ) 59 struct re_s *di_expire_task; 60 61 /* allows to limit the maximum number of dynamic objects */ 62 ldap_pvt_thread_mutex_t di_mutex; 63 int di_num_dynamicObjects; 64 int di_max_dynamicObjects; 65 66 /* used to advertize the dynamicSubtrees in the root DSE, 67 * and to select the database in the expiration task */ 68 BerVarray di_suffix; 69 BerVarray di_nsuffix; 70 } dds_info_t; 71 72 static struct berval slap_EXOP_REFRESH = BER_BVC( LDAP_EXOP_REFRESH ); 73 static AttributeDescription *ad_entryExpireTimestamp; 74 75 /* list of expired DNs */ 76 typedef struct dds_expire_t { 77 struct berval de_ndn; 78 struct dds_expire_t *de_next; 79 } dds_expire_t; 80 81 typedef struct dds_cb_t { 82 dds_expire_t *dc_ndnlist; 83 } dds_cb_t; 84 85 static int 86 dds_expire_cb( Operation *op, SlapReply *rs ) 87 { 88 dds_cb_t *dc = (dds_cb_t *)op->o_callback->sc_private; 89 dds_expire_t *de; 90 int rc; 91 92 switch ( rs->sr_type ) { 93 case REP_SEARCH: 94 /* alloc list and buffer for berval all in one */ 95 de = op->o_tmpalloc( sizeof( dds_expire_t ) + rs->sr_entry->e_nname.bv_len + 1, 96 op->o_tmpmemctx ); 97 98 de->de_next = dc->dc_ndnlist; 99 dc->dc_ndnlist = de; 100 101 de->de_ndn.bv_len = rs->sr_entry->e_nname.bv_len; 102 de->de_ndn.bv_val = (char *)&de[ 1 ]; 103 AC_MEMCPY( de->de_ndn.bv_val, rs->sr_entry->e_nname.bv_val, 104 rs->sr_entry->e_nname.bv_len + 1 ); 105 rc = 0; 106 break; 107 108 case REP_SEARCHREF: 109 case REP_RESULT: 110 rc = rs->sr_err; 111 break; 112 113 default: 114 assert( 0 ); 115 } 116 117 return rc; 118 } 119 120 static int 121 dds_expire( void *ctx, dds_info_t *di ) 122 { 123 Connection conn = { 0 }; 124 OperationBuffer opbuf; 125 Operation *op; 126 slap_callback sc = { 0 }; 127 dds_cb_t dc = { 0 }; 128 dds_expire_t *de = NULL, **dep; 129 SlapReply rs = { REP_RESULT }; 130 131 time_t expire; 132 char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 133 struct berval ts; 134 135 int ndeletes, ntotdeletes; 136 137 int rc; 138 char *extra = ""; 139 140 connection_fake_init( &conn, &opbuf, ctx ); 141 op = &opbuf.ob_op; 142 143 op->o_tag = LDAP_REQ_SEARCH; 144 memset( &op->oq_search, 0, sizeof( op->oq_search ) ); 145 146 op->o_bd = select_backend( &di->di_nsuffix[ 0 ], 0 ); 147 148 op->o_req_dn = op->o_bd->be_suffix[ 0 ]; 149 op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; 150 151 op->o_dn = op->o_bd->be_rootdn; 152 op->o_ndn = op->o_bd->be_rootndn; 153 154 op->ors_scope = LDAP_SCOPE_SUBTREE; 155 op->ors_tlimit = DDS_INTERVAL( di )/2 + 1; 156 op->ors_slimit = SLAP_NO_LIMIT; 157 op->ors_attrs = slap_anlist_no_attrs; 158 159 expire = slap_get_time() + di->di_tolerance; 160 ts.bv_val = tsbuf; 161 ts.bv_len = sizeof( tsbuf ); 162 slap_timestamp( &expire, &ts ); 163 164 op->ors_filterstr.bv_len = STRLENOF( "(&(objectClass=" ")(" "<=" "))" ) 165 + slap_schema.si_oc_dynamicObject->soc_cname.bv_len 166 + ad_entryExpireTimestamp->ad_cname.bv_len 167 + ts.bv_len; 168 op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 169 snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1, 170 "(&(objectClass=%s)(%s<=%s))", 171 slap_schema.si_oc_dynamicObject->soc_cname.bv_val, 172 ad_entryExpireTimestamp->ad_cname.bv_val, ts.bv_val ); 173 174 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); 175 if ( op->ors_filter == NULL ) { 176 rs.sr_err = LDAP_OTHER; 177 goto done_search; 178 } 179 180 op->o_callback = ≻ 181 sc.sc_response = dds_expire_cb; 182 sc.sc_private = &dc; 183 184 (void)op->o_bd->bd_info->bi_op_search( op, &rs ); 185 186 done_search:; 187 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 188 filter_free_x( op, op->ors_filter ); 189 190 rc = rs.sr_err; 191 switch ( rs.sr_err ) { 192 case LDAP_SUCCESS: 193 break; 194 195 case LDAP_NO_SUCH_OBJECT: 196 /* (ITS#5267) database not created yet? */ 197 rs.sr_err = LDAP_SUCCESS; 198 extra = " (ignored)"; 199 /* fallthru */ 200 201 default: 202 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 203 "DDS expired objects lookup failed err=%d%s\n", 204 rc, extra ); 205 goto done; 206 } 207 208 op->o_tag = LDAP_REQ_DELETE; 209 op->o_callback = ≻ 210 sc.sc_response = slap_null_cb; 211 sc.sc_private = NULL; 212 213 for ( ntotdeletes = 0, ndeletes = 1; dc.dc_ndnlist != NULL && ndeletes > 0; ) { 214 ndeletes = 0; 215 216 for ( dep = &dc.dc_ndnlist; *dep != NULL; ) { 217 de = *dep; 218 219 op->o_req_dn = de->de_ndn; 220 op->o_req_ndn = de->de_ndn; 221 (void)op->o_bd->bd_info->bi_op_delete( op, &rs ); 222 switch ( rs.sr_err ) { 223 case LDAP_SUCCESS: 224 Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, 225 "DDS dn=\"%s\" expired.\n", 226 de->de_ndn.bv_val ); 227 ndeletes++; 228 break; 229 230 case LDAP_NOT_ALLOWED_ON_NONLEAF: 231 Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE, 232 "DDS dn=\"%s\" is non-leaf; " 233 "deferring.\n", 234 de->de_ndn.bv_val ); 235 dep = &de->de_next; 236 de = NULL; 237 break; 238 239 default: 240 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE, 241 "DDS dn=\"%s\" err=%d; " 242 "deferring.\n", 243 de->de_ndn.bv_val, rs.sr_err ); 244 break; 245 } 246 247 if ( de != NULL ) { 248 *dep = de->de_next; 249 dep = &de->de_next; 250 op->o_tmpfree( de, op->o_tmpmemctx ); 251 } 252 } 253 254 ntotdeletes += ndeletes; 255 } 256 257 rs.sr_err = LDAP_SUCCESS; 258 259 Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, 260 "DDS expired=%d\n", ntotdeletes ); 261 262 done:; 263 return rs.sr_err; 264 } 265 266 static void * 267 dds_expire_fn( void *ctx, void *arg ) 268 { 269 struct re_s *rtask = arg; 270 dds_info_t *di = rtask->arg; 271 272 assert( di->di_expire_task == rtask ); 273 274 (void)dds_expire( ctx, di ); 275 276 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 277 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { 278 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 279 } 280 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); 281 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 282 283 return NULL; 284 } 285 286 /* frees the callback */ 287 static int 288 dds_freeit_cb( Operation *op, SlapReply *rs ) 289 { 290 op->o_tmpfree( op->o_callback, op->o_tmpmemctx ); 291 op->o_callback = NULL; 292 293 return SLAP_CB_CONTINUE; 294 } 295 296 /* updates counter - installed on add/delete only if required */ 297 static int 298 dds_counter_cb( Operation *op, SlapReply *rs ) 299 { 300 assert( rs->sr_type == REP_RESULT ); 301 302 if ( rs->sr_err == LDAP_SUCCESS ) { 303 dds_info_t *di = op->o_callback->sc_private; 304 305 ldap_pvt_thread_mutex_lock( &di->di_mutex ); 306 switch ( op->o_tag ) { 307 case LDAP_REQ_DELETE: 308 assert( di->di_num_dynamicObjects > 0 ); 309 di->di_num_dynamicObjects--; 310 break; 311 312 case LDAP_REQ_ADD: 313 assert( di->di_num_dynamicObjects < di->di_max_dynamicObjects ); 314 di->di_num_dynamicObjects++; 315 break; 316 317 default: 318 assert( 0 ); 319 } 320 ldap_pvt_thread_mutex_unlock( &di->di_mutex ); 321 } 322 323 return dds_freeit_cb( op, rs ); 324 } 325 326 static int 327 dds_op_add( Operation *op, SlapReply *rs ) 328 { 329 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 330 dds_info_t *di = on->on_bi.bi_private; 331 int is_dynamicObject; 332 333 if ( DDS_OFF( di ) ) { 334 return SLAP_CB_CONTINUE; 335 } 336 337 is_dynamicObject = is_entry_dynamicObject( op->ora_e ); 338 339 /* FIXME: do not allow this right now, pending clarification */ 340 if ( is_dynamicObject ) { 341 rs->sr_err = LDAP_SUCCESS; 342 343 if ( is_entry_referral( op->ora_e ) ) { 344 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 345 rs->sr_text = "a referral cannot be a dynamicObject"; 346 347 } else if ( is_entry_alias( op->ora_e ) ) { 348 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 349 rs->sr_text = "an alias cannot be a dynamicObject"; 350 } 351 352 if ( rs->sr_err != LDAP_SUCCESS ) { 353 op->o_bd->bd_info = (BackendInfo *)on->on_info; 354 send_ldap_result( op, rs ); 355 return rs->sr_err; 356 } 357 } 358 359 /* we don't allow dynamicObjects to have static subordinates */ 360 if ( !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) { 361 struct berval p_ndn; 362 Entry *e = NULL; 363 int rc; 364 BackendInfo *bi = op->o_bd->bd_info; 365 366 dnParent( &op->o_req_ndn, &p_ndn ); 367 op->o_bd->bd_info = (BackendInfo *)on->on_info; 368 rc = be_entry_get_rw( op, &p_ndn, 369 slap_schema.si_oc_dynamicObject, NULL, 0, &e ); 370 if ( rc == LDAP_SUCCESS && e != NULL ) { 371 if ( !is_dynamicObject ) { 372 /* return referral only if "disclose" 373 * is granted on the object */ 374 if ( ! access_allowed( op, e, 375 slap_schema.si_ad_entry, 376 NULL, ACL_DISCLOSE, NULL ) ) 377 { 378 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; 379 send_ldap_result( op, rs ); 380 381 } else { 382 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 383 send_ldap_error( op, rs, rc, "no static subordinate entries allowed for dynamicObject" ); 384 } 385 } 386 387 be_entry_release_r( op, e ); 388 if ( rc != LDAP_SUCCESS ) { 389 return rc; 390 } 391 } 392 op->o_bd->bd_info = bi; 393 } 394 395 /* handle dynamic object operational attr(s) */ 396 if ( is_dynamicObject ) { 397 time_t ttl, expire; 398 char ttlbuf[STRLENOF("31557600") + 1]; 399 char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 400 struct berval bv; 401 402 if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { 403 ldap_pvt_thread_mutex_lock( &di->di_mutex ); 404 rs->sr_err = ( di->di_max_dynamicObjects && 405 di->di_num_dynamicObjects >= di->di_max_dynamicObjects ); 406 ldap_pvt_thread_mutex_unlock( &di->di_mutex ); 407 if ( rs->sr_err ) { 408 op->o_bd->bd_info = (BackendInfo *)on->on_info; 409 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 410 "too many dynamicObjects in context" ); 411 return rs->sr_err; 412 } 413 } 414 415 ttl = DDS_DEFAULT_TTL( di ); 416 417 /* assert because should be checked at configure */ 418 assert( ttl <= DDS_RF2589_MAX_TTL ); 419 420 bv.bv_val = ttlbuf; 421 bv.bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl ); 422 assert( bv.bv_len < sizeof( ttlbuf ) ); 423 424 /* FIXME: apparently, values in op->ora_e are malloc'ed 425 * on the thread's slab; works fine by chance, 426 * only because the attribute doesn't exist yet. */ 427 assert( attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryTtl ) == NULL ); 428 attr_merge_one( op->ora_e, slap_schema.si_ad_entryTtl, &bv, &bv ); 429 430 expire = slap_get_time() + ttl; 431 bv.bv_val = tsbuf; 432 bv.bv_len = sizeof( tsbuf ); 433 slap_timestamp( &expire, &bv ); 434 assert( attr_find( op->ora_e->e_attrs, ad_entryExpireTimestamp ) == NULL ); 435 attr_merge_one( op->ora_e, ad_entryExpireTimestamp, &bv, &bv ); 436 437 /* if required, install counter callback */ 438 if ( di->di_max_dynamicObjects > 0) { 439 slap_callback *sc; 440 441 sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx ); 442 sc->sc_cleanup = dds_freeit_cb; 443 sc->sc_response = dds_counter_cb; 444 sc->sc_private = di; 445 sc->sc_next = op->o_callback; 446 447 op->o_callback = sc; 448 } 449 } 450 451 return SLAP_CB_CONTINUE; 452 } 453 454 static int 455 dds_op_delete( Operation *op, SlapReply *rs ) 456 { 457 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 458 dds_info_t *di = on->on_bi.bi_private; 459 460 /* if required, install counter callback */ 461 if ( !DDS_OFF( di ) && di->di_max_dynamicObjects > 0 ) { 462 Entry *e = NULL; 463 BackendInfo *bi = op->o_bd->bd_info; 464 465 op->o_bd->bd_info = (BackendInfo *)on->on_info; 466 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, 467 slap_schema.si_oc_dynamicObject, NULL, 0, &e ); 468 469 /* FIXME: couldn't the entry be added before deletion? */ 470 if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) { 471 slap_callback *sc; 472 473 be_entry_release_r( op, e ); 474 e = NULL; 475 476 sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx ); 477 sc->sc_cleanup = dds_freeit_cb; 478 sc->sc_response = dds_counter_cb; 479 sc->sc_private = di; 480 sc->sc_next = op->o_callback; 481 482 op->o_callback = sc; 483 } 484 op->o_bd->bd_info = bi; 485 } 486 487 return SLAP_CB_CONTINUE; 488 } 489 490 static int 491 dds_op_modify( Operation *op, SlapReply *rs ) 492 { 493 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 494 dds_info_t *di = (dds_info_t *)on->on_bi.bi_private; 495 Modifications *mod; 496 Entry *e = NULL; 497 BackendInfo *bi = op->o_bd->bd_info; 498 int was_dynamicObject = 0, 499 is_dynamicObject = 0; 500 struct berval bv_entryTtl = BER_BVNULL; 501 time_t entryTtl = 0; 502 char textbuf[ SLAP_TEXT_BUFLEN ]; 503 504 if ( DDS_OFF( di ) ) { 505 return SLAP_CB_CONTINUE; 506 } 507 508 /* bv_entryTtl stores the string representation of the entryTtl 509 * across modifies for consistency checks of the final value; 510 * the bv_val points to a static buffer; the bv_len is zero when 511 * the attribute is deleted. 512 * entryTtl stores the integer representation of the entryTtl; 513 * its value is -1 when the attribute is deleted; it is 0 only 514 * if no modifications of the entryTtl occurred, as an entryTtl 515 * of 0 is invalid. */ 516 bv_entryTtl.bv_val = textbuf; 517 518 op->o_bd->bd_info = (BackendInfo *)on->on_info; 519 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, 520 slap_schema.si_oc_dynamicObject, slap_schema.si_ad_entryTtl, 0, &e ); 521 if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) { 522 Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryTtl ); 523 524 /* the value of the entryTtl is saved for later checks */ 525 if ( a != NULL ) { 526 unsigned long ttl; 527 int rc; 528 529 bv_entryTtl.bv_len = a->a_nvals[ 0 ].bv_len; 530 AC_MEMCPY( bv_entryTtl.bv_val, a->a_nvals[ 0 ].bv_val, bv_entryTtl.bv_len ); 531 bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0'; 532 rc = lutil_atoul( &ttl, bv_entryTtl.bv_val ); 533 assert( rc == 0 ); 534 entryTtl = (time_t)ttl; 535 } 536 537 be_entry_release_r( op, e ); 538 e = NULL; 539 was_dynamicObject = is_dynamicObject = 1; 540 } 541 op->o_bd->bd_info = bi; 542 543 rs->sr_err = LDAP_SUCCESS; 544 for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) { 545 if ( mod->sml_desc == slap_schema.si_ad_objectClass ) { 546 int i; 547 ObjectClass *oc; 548 549 switch ( mod->sml_op ) { 550 case LDAP_MOD_DELETE: 551 if ( mod->sml_values == NULL ) { 552 is_dynamicObject = 0; 553 break; 554 } 555 556 for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) { 557 oc = oc_bvfind( &mod->sml_values[ i ] ); 558 if ( oc == slap_schema.si_oc_dynamicObject ) { 559 is_dynamicObject = 0; 560 break; 561 } 562 } 563 564 break; 565 566 case LDAP_MOD_REPLACE: 567 if ( mod->sml_values == NULL ) { 568 is_dynamicObject = 0; 569 break; 570 } 571 /* fallthru */ 572 573 case LDAP_MOD_ADD: 574 for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) { 575 oc = oc_bvfind( &mod->sml_values[ i ] ); 576 if ( oc == slap_schema.si_oc_dynamicObject ) { 577 is_dynamicObject = 1; 578 break; 579 } 580 } 581 break; 582 } 583 584 } else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) { 585 unsigned long ttl; 586 int rc; 587 588 switch ( mod->sml_op ) { 589 case LDAP_MOD_DELETE: 590 if ( mod->sml_values != NULL ) { 591 if ( BER_BVISEMPTY( &bv_entryTtl ) 592 || !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) ) 593 { 594 rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, 595 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); 596 if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { 597 rs->sr_err = LDAP_NO_SUCH_OBJECT; 598 599 } else { 600 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; 601 } 602 goto done; 603 } 604 } 605 bv_entryTtl.bv_len = 0; 606 entryTtl = -1; 607 break; 608 609 case LDAP_MOD_REPLACE: 610 bv_entryTtl.bv_len = 0; 611 entryTtl = -1; 612 /* fallthru */ 613 614 case SLAP_MOD_SOFTADD: /* FIXME? */ 615 case LDAP_MOD_ADD: 616 assert( mod->sml_values != NULL ); 617 assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) ); 618 619 if ( !BER_BVISEMPTY( &bv_entryTtl ) ) { 620 rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, 621 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); 622 if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { 623 rs->sr_err = LDAP_NO_SUCH_OBJECT; 624 625 } else { 626 rs->sr_text = "attribute 'entryTtl' cannot have multiple values"; 627 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 628 } 629 goto done; 630 } 631 632 rc = lutil_atoul( &ttl, mod->sml_values[ 0 ].bv_val ); 633 assert( rc == 0 ); 634 if ( ttl > DDS_RF2589_MAX_TTL ) { 635 rs->sr_err = LDAP_PROTOCOL_ERROR; 636 rs->sr_text = "invalid time-to-live for dynamicObject"; 637 goto done; 638 } 639 640 if ( ttl <= 0 || ttl > di->di_max_ttl ) { 641 /* FIXME: I don't understand if this has to be an error, 642 * or an indication that the requested Ttl has been 643 * shortened to di->di_max_ttl >= 1 day */ 644 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; 645 rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit"; 646 goto done; 647 } 648 649 entryTtl = (time_t)ttl; 650 bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len; 651 AC_MEMCPY( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len ); 652 bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0'; 653 break; 654 655 case LDAP_MOD_INCREMENT: 656 if ( BER_BVISEMPTY( &bv_entryTtl ) ) { 657 rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, 658 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); 659 if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { 660 rs->sr_err = LDAP_NO_SUCH_OBJECT; 661 662 } else { 663 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; 664 rs->sr_text = "modify/increment: entryTtl: no such attribute"; 665 } 666 goto done; 667 } 668 669 entryTtl++; 670 if ( entryTtl > DDS_RF2589_MAX_TTL ) { 671 rs->sr_err = LDAP_PROTOCOL_ERROR; 672 rs->sr_text = "invalid time-to-live for dynamicObject"; 673 674 } else if ( entryTtl <= 0 || entryTtl > di->di_max_ttl ) { 675 /* FIXME: I don't understand if this has to be an error, 676 * or an indication that the requested Ttl has been 677 * shortened to di->di_max_ttl >= 1 day */ 678 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; 679 rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit"; 680 } 681 682 if ( rs->sr_err != LDAP_SUCCESS ) { 683 rc = backend_attribute( op, NULL, &op->o_req_ndn, 684 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); 685 if ( rc == LDAP_INSUFFICIENT_ACCESS ) { 686 rs->sr_text = NULL; 687 rs->sr_err = LDAP_NO_SUCH_OBJECT; 688 689 } 690 goto done; 691 } 692 693 bv_entryTtl.bv_len = snprintf( textbuf, sizeof( textbuf ), "%ld", entryTtl ); 694 break; 695 696 default: 697 assert( 0 ); 698 break; 699 } 700 701 } else if ( mod->sml_desc == ad_entryExpireTimestamp ) { 702 /* should have been trapped earlier */ 703 assert( mod->sml_flags & SLAP_MOD_INTERNAL ); 704 } 705 } 706 707 done:; 708 if ( rs->sr_err == LDAP_SUCCESS ) { 709 int rc; 710 711 /* FIXME: this could be allowed when the Relax control is used... 712 * in that case: 713 * 714 * TODO 715 * 716 * static => dynamic: 717 * entryTtl must be provided; add 718 * entryExpireTimestamp accordingly 719 * 720 * dynamic => static: 721 * entryTtl must be removed; remove 722 * entryTimestamp accordingly 723 * 724 * ... but we need to make sure that there are no subordinate 725 * issues... 726 */ 727 rc = is_dynamicObject - was_dynamicObject; 728 if ( rc ) { 729 #if 0 /* fix subordinate issues first */ 730 if ( get_relax( op ) ) { 731 switch ( rc ) { 732 case -1: 733 /* need to delete entryTtl to have a consistent entry */ 734 if ( entryTtl != -1 ) { 735 rs->sr_text = "objectClass modification from dynamicObject to static entry requires entryTtl deletion"; 736 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 737 } 738 break; 739 740 case 1: 741 /* need to add entryTtl to have a consistent entry */ 742 if ( entryTtl <= 0 ) { 743 rs->sr_text = "objectClass modification from static entry to dynamicObject requires entryTtl addition"; 744 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 745 } 746 break; 747 } 748 749 } else 750 #endif 751 { 752 switch ( rc ) { 753 case -1: 754 rs->sr_text = "objectClass modification cannot turn dynamicObject into static entry"; 755 break; 756 757 case 1: 758 rs->sr_text = "objectClass modification cannot turn static entry into dynamicObject"; 759 break; 760 } 761 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 762 } 763 764 if ( rc != LDAP_SUCCESS ) { 765 rc = backend_attribute( op, NULL, &op->o_req_ndn, 766 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); 767 if ( rc == LDAP_INSUFFICIENT_ACCESS ) { 768 rs->sr_text = NULL; 769 rs->sr_err = LDAP_NO_SUCH_OBJECT; 770 } 771 } 772 } 773 } 774 775 if ( rs->sr_err == LDAP_SUCCESS && entryTtl != 0 ) { 776 Modifications *tmpmod = NULL, **modp; 777 778 for ( modp = &op->orm_modlist; *modp; modp = &(*modp)->sml_next ) 779 ; 780 781 tmpmod = ch_calloc( 1, sizeof( Modifications ) ); 782 tmpmod->sml_flags = SLAP_MOD_INTERNAL; 783 tmpmod->sml_type = ad_entryExpireTimestamp->ad_cname; 784 tmpmod->sml_desc = ad_entryExpireTimestamp; 785 786 *modp = tmpmod; 787 788 if ( entryTtl == -1 ) { 789 /* delete entryExpireTimestamp */ 790 tmpmod->sml_op = LDAP_MOD_DELETE; 791 792 } else { 793 time_t expire; 794 char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 795 struct berval bv; 796 797 /* keep entryExpireTimestamp consistent 798 * with entryTtl */ 799 expire = slap_get_time() + entryTtl; 800 bv.bv_val = tsbuf; 801 bv.bv_len = sizeof( tsbuf ); 802 slap_timestamp( &expire, &bv ); 803 804 tmpmod->sml_op = LDAP_MOD_REPLACE; 805 value_add_one( &tmpmod->sml_values, &bv ); 806 value_add_one( &tmpmod->sml_nvalues, &bv ); 807 tmpmod->sml_numvals = 1; 808 } 809 } 810 811 if ( rs->sr_err ) { 812 op->o_bd->bd_info = (BackendInfo *)on->on_info; 813 send_ldap_result( op, rs ); 814 return rs->sr_err; 815 } 816 817 return SLAP_CB_CONTINUE; 818 } 819 820 static int 821 dds_op_rename( Operation *op, SlapReply *rs ) 822 { 823 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 824 dds_info_t *di = on->on_bi.bi_private; 825 826 if ( DDS_OFF( di ) ) { 827 return SLAP_CB_CONTINUE; 828 } 829 830 /* we don't allow dynamicObjects to have static subordinates */ 831 if ( op->orr_nnewSup != NULL ) { 832 Entry *e = NULL; 833 BackendInfo *bi = op->o_bd->bd_info; 834 int is_dynamicObject = 0, 835 rc; 836 837 rs->sr_err = LDAP_SUCCESS; 838 839 op->o_bd->bd_info = (BackendInfo *)on->on_info; 840 rc = be_entry_get_rw( op, &op->o_req_ndn, 841 slap_schema.si_oc_dynamicObject, NULL, 0, &e ); 842 if ( rc == LDAP_SUCCESS && e != NULL ) { 843 be_entry_release_r( op, e ); 844 e = NULL; 845 is_dynamicObject = 1; 846 } 847 848 rc = be_entry_get_rw( op, op->orr_nnewSup, 849 slap_schema.si_oc_dynamicObject, NULL, 0, &e ); 850 if ( rc == LDAP_SUCCESS && e != NULL ) { 851 if ( !is_dynamicObject ) { 852 /* return referral only if "disclose" 853 * is granted on the object */ 854 if ( ! access_allowed( op, e, 855 slap_schema.si_ad_entry, 856 NULL, ACL_DISCLOSE, NULL ) ) 857 { 858 rs->sr_err = LDAP_NO_SUCH_OBJECT; 859 send_ldap_result( op, rs ); 860 861 } else { 862 send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, 863 "static entry cannot have dynamicObject as newSuperior" ); 864 } 865 } 866 be_entry_release_r( op, e ); 867 } 868 op->o_bd->bd_info = bi; 869 if ( rs->sr_err != LDAP_SUCCESS ) { 870 return rs->sr_err; 871 } 872 } 873 874 return SLAP_CB_CONTINUE; 875 } 876 877 static int 878 slap_parse_refresh( 879 struct berval *in, 880 struct berval *ndn, 881 time_t *ttl, 882 const char **text, 883 void *ctx ) 884 { 885 int rc = LDAP_SUCCESS; 886 ber_tag_t tag; 887 ber_len_t len = -1; 888 BerElementBuffer berbuf; 889 BerElement *ber = (BerElement *)&berbuf; 890 struct berval reqdata = BER_BVNULL; 891 int tmp; 892 893 *text = NULL; 894 895 if ( ndn ) { 896 BER_BVZERO( ndn ); 897 } 898 899 if ( in == NULL || in->bv_len == 0 ) { 900 *text = "empty request data field in refresh exop"; 901 return LDAP_PROTOCOL_ERROR; 902 } 903 904 ber_dupbv_x( &reqdata, in, ctx ); 905 906 /* ber_init2 uses reqdata directly, doesn't allocate new buffers */ 907 ber_init2( ber, &reqdata, 0 ); 908 909 tag = ber_scanf( ber, "{" /*}*/ ); 910 911 if ( tag == LBER_ERROR ) { 912 Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, 913 "slap_parse_refresh: decoding error.\n" ); 914 goto decoding_error; 915 } 916 917 tag = ber_peek_tag( ber, &len ); 918 if ( tag != LDAP_TAG_EXOP_REFRESH_REQ_DN ) { 919 Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, 920 "slap_parse_refresh: decoding error.\n" ); 921 goto decoding_error; 922 } 923 924 if ( ndn ) { 925 struct berval dn; 926 927 tag = ber_scanf( ber, "m", &dn ); 928 if ( tag == LBER_ERROR ) { 929 Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, 930 "slap_parse_refresh: DN parse failed.\n" ); 931 goto decoding_error; 932 } 933 934 rc = dnNormalize( 0, NULL, NULL, &dn, ndn, ctx ); 935 if ( rc != LDAP_SUCCESS ) { 936 *text = "invalid DN in refresh exop request data"; 937 goto done; 938 } 939 940 } else { 941 tag = ber_scanf( ber, "x" /* "m" */ ); 942 if ( tag == LBER_DEFAULT ) { 943 goto decoding_error; 944 } 945 } 946 947 tag = ber_peek_tag( ber, &len ); 948 949 if ( tag != LDAP_TAG_EXOP_REFRESH_REQ_TTL ) { 950 Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, 951 "slap_parse_refresh: decoding error.\n" ); 952 goto decoding_error; 953 } 954 955 tag = ber_scanf( ber, "i", &tmp ); 956 if ( tag == LBER_ERROR ) { 957 Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, 958 "slap_parse_refresh: TTL parse failed.\n" ); 959 goto decoding_error; 960 } 961 962 if ( ttl ) { 963 *ttl = tmp; 964 } 965 966 tag = ber_peek_tag( ber, &len ); 967 968 if ( tag != LBER_DEFAULT || len != 0 ) { 969 decoding_error:; 970 Log1( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, 971 "slap_parse_refresh: decoding error, len=%ld\n", 972 (long)len ); 973 rc = LDAP_PROTOCOL_ERROR; 974 *text = "data decoding error"; 975 976 done:; 977 if ( ndn && !BER_BVISNULL( ndn ) ) { 978 slap_sl_free( ndn->bv_val, ctx ); 979 BER_BVZERO( ndn ); 980 } 981 } 982 983 if ( !BER_BVISNULL( &reqdata ) ) { 984 ber_memfree_x( reqdata.bv_val, ctx ); 985 } 986 987 return rc; 988 } 989 990 static int 991 dds_op_extended( Operation *op, SlapReply *rs ) 992 { 993 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 994 dds_info_t *di = on->on_bi.bi_private; 995 996 if ( DDS_OFF( di ) ) { 997 return SLAP_CB_CONTINUE; 998 } 999 1000 if ( bvmatch( &op->ore_reqoid, &slap_EXOP_REFRESH ) ) { 1001 Entry *e = NULL; 1002 time_t ttl; 1003 BackendDB db = *op->o_bd; 1004 SlapReply rs2 = { REP_RESULT }; 1005 Operation op2 = *op; 1006 slap_callback sc = { 0 }; 1007 Modifications ttlmod = { { 0 } }; 1008 struct berval ttlvalues[ 2 ]; 1009 char ttlbuf[STRLENOF("31557600") + 1]; 1010 1011 rs->sr_err = slap_parse_refresh( op->ore_reqdata, NULL, &ttl, 1012 &rs->sr_text, NULL ); 1013 assert( rs->sr_err == LDAP_SUCCESS ); 1014 1015 if ( ttl <= 0 || ttl > DDS_RF2589_MAX_TTL ) { 1016 rs->sr_err = LDAP_PROTOCOL_ERROR; 1017 rs->sr_text = "invalid time-to-live for dynamicObject"; 1018 return rs->sr_err; 1019 } 1020 1021 if ( ttl > di->di_max_ttl ) { 1022 /* FIXME: I don't understand if this has to be an error, 1023 * or an indication that the requested Ttl has been 1024 * shortened to di->di_max_ttl >= 1 day */ 1025 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; 1026 rs->sr_text = "time-to-live for dynamicObject exceeds limit"; 1027 return rs->sr_err; 1028 } 1029 1030 if ( di->di_min_ttl && ttl < di->di_min_ttl ) { 1031 ttl = di->di_min_ttl; 1032 } 1033 1034 /* This does not apply to multi-master case */ 1035 if ( !( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ) ) ) { 1036 /* we SHOULD return a referral in this case */ 1037 BerVarray defref = op->o_bd->be_update_refs 1038 ? op->o_bd->be_update_refs : default_referral; 1039 1040 if ( defref != NULL ) { 1041 rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs, 1042 NULL, NULL, LDAP_SCOPE_DEFAULT ); 1043 if ( rs->sr_ref ) { 1044 rs->sr_flags |= REP_REF_MUSTBEFREED; 1045 } else { 1046 rs->sr_ref = defref; 1047 } 1048 rs->sr_err = LDAP_REFERRAL; 1049 1050 } else { 1051 rs->sr_text = "shadow context; no update referral"; 1052 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1053 } 1054 1055 return rs->sr_err; 1056 } 1057 1058 assert( !BER_BVISNULL( &op->o_req_ndn ) ); 1059 1060 1061 1062 /* check if exists but not dynamicObject */ 1063 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1064 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, 1065 slap_schema.si_oc_dynamicObject, NULL, 0, &e ); 1066 if ( rs->sr_err != LDAP_SUCCESS ) { 1067 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, 1068 NULL, NULL, 0, &e ); 1069 if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) { 1070 /* return referral only if "disclose" 1071 * is granted on the object */ 1072 if ( ! access_allowed( op, e, 1073 slap_schema.si_ad_entry, 1074 NULL, ACL_DISCLOSE, NULL ) ) 1075 { 1076 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1077 1078 } else { 1079 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 1080 rs->sr_text = "refresh operation only applies to dynamic objects"; 1081 } 1082 be_entry_release_r( op, e ); 1083 1084 } else { 1085 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1086 } 1087 return rs->sr_err; 1088 1089 } else if ( e != NULL ) { 1090 be_entry_release_r( op, e ); 1091 } 1092 1093 /* we require manage privileges on the entryTtl, 1094 * and fake a Relax control */ 1095 op2.o_tag = LDAP_REQ_MODIFY; 1096 op2.o_bd = &db; 1097 db.bd_info = (BackendInfo *)on->on_info; 1098 op2.o_callback = ≻ 1099 sc.sc_response = slap_null_cb; 1100 op2.o_relax = SLAP_CONTROL_CRITICAL; 1101 op2.orm_modlist = &ttlmod; 1102 1103 ttlmod.sml_op = LDAP_MOD_REPLACE; 1104 ttlmod.sml_flags = SLAP_MOD_MANAGING; 1105 ttlmod.sml_desc = slap_schema.si_ad_entryTtl; 1106 ttlmod.sml_values = ttlvalues; 1107 ttlmod.sml_numvals = 1; 1108 ttlvalues[ 0 ].bv_val = ttlbuf; 1109 ttlvalues[ 0 ].bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl ); 1110 BER_BVZERO( &ttlvalues[ 1 ] ); 1111 1112 /* the entryExpireTimestamp is added by modify */ 1113 rs->sr_err = op2.o_bd->be_modify( &op2, &rs2 ); 1114 1115 if ( ttlmod.sml_next != NULL ) { 1116 slap_mods_free( ttlmod.sml_next, 1 ); 1117 } 1118 1119 if ( rs->sr_err == LDAP_SUCCESS ) { 1120 int rc; 1121 BerElementBuffer berbuf; 1122 BerElement *ber = (BerElement *)&berbuf; 1123 1124 if ( rs->sr_err == LDAP_SUCCESS ) { 1125 ber_init_w_nullc( ber, LBER_USE_DER ); 1126 1127 rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl ); 1128 1129 if ( rc < 0 ) { 1130 rs->sr_err = LDAP_OTHER; 1131 rs->sr_text = "internal error"; 1132 1133 } else { 1134 (void)ber_flatten( ber, &rs->sr_rspdata ); 1135 rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val ); 1136 1137 Log3( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO, 1138 "%s REFRESH dn=\"%s\" TTL=%ld\n", 1139 op->o_log_prefix, op->o_req_ndn.bv_val, ttl ); 1140 } 1141 1142 ber_free_buf( ber ); 1143 } 1144 } 1145 1146 return rs->sr_err; 1147 } 1148 1149 return SLAP_CB_CONTINUE; 1150 } 1151 1152 enum { 1153 DDS_STATE = 1, 1154 DDS_MAXTTL, 1155 DDS_MINTTL, 1156 DDS_DEFAULTTTL, 1157 DDS_INTERVAL, 1158 DDS_TOLERANCE, 1159 DDS_MAXDYNAMICOBJS, 1160 1161 DDS_LAST 1162 }; 1163 1164 static ConfigDriver dds_cfgen; 1165 #if 0 1166 static ConfigLDAPadd dds_ldadd; 1167 static ConfigCfAdd dds_cfadd; 1168 #endif 1169 1170 static ConfigTable dds_cfg[] = { 1171 { "dds-state", "on|off", 1172 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|DDS_STATE, dds_cfgen, 1173 "( OLcfgOvAt:9.1 NAME 'olcDDSstate' " 1174 "DESC 'RFC2589 Dynamic directory services state' " 1175 "SYNTAX OMsBoolean " 1176 "SINGLE-VALUE )", NULL, NULL }, 1177 { "dds-max-ttl", "ttl", 1178 2, 2, 0, ARG_MAGIC|DDS_MAXTTL, dds_cfgen, 1179 "( OLcfgOvAt:9.2 NAME 'olcDDSmaxTtl' " 1180 "DESC 'RFC2589 Dynamic directory services max TTL' " 1181 "SYNTAX OMsDirectoryString " 1182 "SINGLE-VALUE )", NULL, NULL }, 1183 { "dds-min-ttl", "ttl", 1184 2, 2, 0, ARG_MAGIC|DDS_MINTTL, dds_cfgen, 1185 "( OLcfgOvAt:9.3 NAME 'olcDDSminTtl' " 1186 "DESC 'RFC2589 Dynamic directory services min TTL' " 1187 "SYNTAX OMsDirectoryString " 1188 "SINGLE-VALUE )", NULL, NULL }, 1189 { "dds-default-ttl", "ttl", 1190 2, 2, 0, ARG_MAGIC|DDS_DEFAULTTTL, dds_cfgen, 1191 "( OLcfgOvAt:9.4 NAME 'olcDDSdefaultTtl' " 1192 "DESC 'RFC2589 Dynamic directory services default TTL' " 1193 "SYNTAX OMsDirectoryString " 1194 "SINGLE-VALUE )", NULL, NULL }, 1195 { "dds-interval", "interval", 1196 2, 2, 0, ARG_MAGIC|DDS_INTERVAL, dds_cfgen, 1197 "( OLcfgOvAt:9.5 NAME 'olcDDSinterval' " 1198 "DESC 'RFC2589 Dynamic directory services expiration " 1199 "task run interval' " 1200 "SYNTAX OMsDirectoryString " 1201 "SINGLE-VALUE )", NULL, NULL }, 1202 { "dds-tolerance", "ttl", 1203 2, 2, 0, ARG_MAGIC|DDS_TOLERANCE, dds_cfgen, 1204 "( OLcfgOvAt:9.6 NAME 'olcDDStolerance' " 1205 "DESC 'RFC2589 Dynamic directory services additional " 1206 "TTL in expiration scheduling' " 1207 "SYNTAX OMsDirectoryString " 1208 "SINGLE-VALUE )", NULL, NULL }, 1209 { "dds-max-dynamicObjects", "num", 1210 2, 2, 0, ARG_MAGIC|ARG_INT|DDS_MAXDYNAMICOBJS, dds_cfgen, 1211 "( OLcfgOvAt:9.7 NAME 'olcDDSmaxDynamicObjects' " 1212 "DESC 'RFC2589 Dynamic directory services max number of dynamic objects' " 1213 "SYNTAX OMsInteger " 1214 "SINGLE-VALUE )", NULL, NULL }, 1215 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 1216 }; 1217 1218 static ConfigOCs dds_ocs[] = { 1219 { "( OLcfgOvOc:9.1 " 1220 "NAME 'olcDDSConfig' " 1221 "DESC 'RFC2589 Dynamic directory services configuration' " 1222 "SUP olcOverlayConfig " 1223 "MAY ( " 1224 "olcDDSstate " 1225 "$ olcDDSmaxTtl " 1226 "$ olcDDSminTtl " 1227 "$ olcDDSdefaultTtl " 1228 "$ olcDDSinterval " 1229 "$ olcDDStolerance " 1230 "$ olcDDSmaxDynamicObjects " 1231 " ) " 1232 ")", Cft_Overlay, dds_cfg, NULL, NULL /* dds_cfadd */ }, 1233 { NULL, 0, NULL } 1234 }; 1235 1236 #if 0 1237 static int 1238 dds_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) 1239 { 1240 return LDAP_SUCCESS; 1241 } 1242 1243 static int 1244 dds_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) 1245 { 1246 return 0; 1247 } 1248 #endif 1249 1250 static int 1251 dds_cfgen( ConfigArgs *c ) 1252 { 1253 slap_overinst *on = (slap_overinst *)c->bi; 1254 dds_info_t *di = on->on_bi.bi_private; 1255 int rc = 0; 1256 unsigned long t; 1257 1258 1259 if ( c->op == SLAP_CONFIG_EMIT ) { 1260 char buf[ SLAP_TEXT_BUFLEN ]; 1261 struct berval bv; 1262 1263 switch( c->type ) { 1264 case DDS_STATE: 1265 c->value_int = !DDS_OFF( di ); 1266 break; 1267 1268 case DDS_MAXTTL: 1269 lutil_unparse_time( buf, sizeof( buf ), di->di_max_ttl ); 1270 ber_str2bv( buf, 0, 0, &bv ); 1271 value_add_one( &c->rvalue_vals, &bv ); 1272 break; 1273 1274 case DDS_MINTTL: 1275 if ( di->di_min_ttl ) { 1276 lutil_unparse_time( buf, sizeof( buf ), di->di_min_ttl ); 1277 ber_str2bv( buf, 0, 0, &bv ); 1278 value_add_one( &c->rvalue_vals, &bv ); 1279 1280 } else { 1281 rc = 1; 1282 } 1283 break; 1284 1285 case DDS_DEFAULTTTL: 1286 if ( di->di_default_ttl ) { 1287 lutil_unparse_time( buf, sizeof( buf ), di->di_default_ttl ); 1288 ber_str2bv( buf, 0, 0, &bv ); 1289 value_add_one( &c->rvalue_vals, &bv ); 1290 1291 } else { 1292 rc = 1; 1293 } 1294 break; 1295 1296 case DDS_INTERVAL: 1297 if ( di->di_interval ) { 1298 lutil_unparse_time( buf, sizeof( buf ), di->di_interval ); 1299 ber_str2bv( buf, 0, 0, &bv ); 1300 value_add_one( &c->rvalue_vals, &bv ); 1301 1302 } else { 1303 rc = 1; 1304 } 1305 break; 1306 1307 case DDS_TOLERANCE: 1308 if ( di->di_tolerance ) { 1309 lutil_unparse_time( buf, sizeof( buf ), di->di_tolerance ); 1310 ber_str2bv( buf, 0, 0, &bv ); 1311 value_add_one( &c->rvalue_vals, &bv ); 1312 1313 } else { 1314 rc = 1; 1315 } 1316 break; 1317 1318 case DDS_MAXDYNAMICOBJS: 1319 if ( di->di_max_dynamicObjects > 0 ) { 1320 c->value_int = di->di_max_dynamicObjects; 1321 1322 } else { 1323 rc = 1; 1324 } 1325 break; 1326 1327 default: 1328 rc = 1; 1329 break; 1330 } 1331 1332 return rc; 1333 1334 } else if ( c->op == LDAP_MOD_DELETE ) { 1335 switch( c->type ) { 1336 case DDS_STATE: 1337 di->di_flags &= ~DDS_FOFF; 1338 break; 1339 1340 case DDS_MAXTTL: 1341 di->di_min_ttl = DDS_RF2589_DEFAULT_TTL; 1342 break; 1343 1344 case DDS_MINTTL: 1345 di->di_min_ttl = 0; 1346 break; 1347 1348 case DDS_DEFAULTTTL: 1349 di->di_default_ttl = 0; 1350 break; 1351 1352 case DDS_INTERVAL: 1353 di->di_interval = 0; 1354 break; 1355 1356 case DDS_TOLERANCE: 1357 di->di_tolerance = 0; 1358 break; 1359 1360 case DDS_MAXDYNAMICOBJS: 1361 di->di_max_dynamicObjects = 0; 1362 break; 1363 1364 default: 1365 rc = 1; 1366 break; 1367 } 1368 1369 return rc; 1370 } 1371 1372 switch ( c->type ) { 1373 case DDS_STATE: 1374 if ( c->value_int ) { 1375 di->di_flags &= ~DDS_FOFF; 1376 1377 } else { 1378 di->di_flags |= DDS_FOFF; 1379 } 1380 break; 1381 1382 case DDS_MAXTTL: 1383 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { 1384 snprintf( c->cr_msg, sizeof( c->cr_msg), 1385 "DDS unable to parse dds-max-ttl \"%s\"", 1386 c->argv[ 1 ] ); 1387 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1388 "%s: %s.\n", c->log, c->cr_msg ); 1389 return 1; 1390 } 1391 1392 if ( t < DDS_RF2589_DEFAULT_TTL || t > DDS_RF2589_MAX_TTL ) { 1393 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1394 "DDS invalid dds-max-ttl=%ld; must be between %d and %d", 1395 t, DDS_RF2589_DEFAULT_TTL, DDS_RF2589_MAX_TTL ); 1396 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1397 "%s: %s.\n", c->log, c->cr_msg ); 1398 return 1; 1399 } 1400 1401 di->di_max_ttl = (time_t)t; 1402 break; 1403 1404 case DDS_MINTTL: 1405 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { 1406 snprintf( c->cr_msg, sizeof( c->cr_msg), 1407 "DDS unable to parse dds-min-ttl \"%s\"", 1408 c->argv[ 1 ] ); 1409 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1410 "%s: %s.\n", c->log, c->cr_msg ); 1411 return 1; 1412 } 1413 1414 if ( t < 0 || t > DDS_RF2589_MAX_TTL ) { 1415 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1416 "DDS invalid dds-min-ttl=%ld", 1417 t ); 1418 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1419 "%s: %s.\n", c->log, c->cr_msg ); 1420 return 1; 1421 } 1422 1423 if ( t == 0 ) { 1424 di->di_min_ttl = DDS_RF2589_DEFAULT_TTL; 1425 1426 } else { 1427 di->di_min_ttl = (time_t)t; 1428 } 1429 break; 1430 1431 case DDS_DEFAULTTTL: 1432 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { 1433 snprintf( c->cr_msg, sizeof( c->cr_msg), 1434 "DDS unable to parse dds-default-ttl \"%s\"", 1435 c->argv[ 1 ] ); 1436 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1437 "%s: %s.\n", c->log, c->cr_msg ); 1438 return 1; 1439 } 1440 1441 if ( t < 0 || t > DDS_RF2589_MAX_TTL ) { 1442 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1443 "DDS invalid dds-default-ttl=%ld", 1444 t ); 1445 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1446 "%s: %s.\n", c->log, c->cr_msg ); 1447 return 1; 1448 } 1449 1450 if ( t == 0 ) { 1451 di->di_default_ttl = DDS_RF2589_DEFAULT_TTL; 1452 1453 } else { 1454 di->di_default_ttl = (time_t)t; 1455 } 1456 break; 1457 1458 case DDS_INTERVAL: 1459 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { 1460 snprintf( c->cr_msg, sizeof( c->cr_msg), 1461 "DDS unable to parse dds-interval \"%s\"", 1462 c->argv[ 1 ] ); 1463 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1464 "%s: %s.\n", c->log, c->cr_msg ); 1465 return 1; 1466 } 1467 1468 if ( t <= 0 ) { 1469 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1470 "DDS invalid dds-interval=%ld", 1471 t ); 1472 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1473 "%s: %s.\n", c->log, c->cr_msg ); 1474 return 1; 1475 } 1476 1477 if ( t < 60 ) { 1478 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE, 1479 "%s: dds-interval=%lu may be too small.\n", 1480 c->log, t ); 1481 } 1482 1483 di->di_interval = (time_t)t; 1484 if ( di->di_expire_task ) { 1485 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 1486 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) { 1487 ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task ); 1488 } 1489 di->di_expire_task->interval.tv_sec = DDS_INTERVAL( di ); 1490 ldap_pvt_runqueue_resched( &slapd_rq, di->di_expire_task, 0 ); 1491 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 1492 } 1493 break; 1494 1495 case DDS_TOLERANCE: 1496 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { 1497 snprintf( c->cr_msg, sizeof( c->cr_msg), 1498 "DDS unable to parse dds-tolerance \"%s\"", 1499 c->argv[ 1 ] ); 1500 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1501 "%s: %s.\n", c->log, c->cr_msg ); 1502 return 1; 1503 } 1504 1505 if ( t < 0 || t > DDS_RF2589_MAX_TTL ) { 1506 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1507 "DDS invalid dds-tolerance=%ld", 1508 t ); 1509 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1510 "%s: %s.\n", c->log, c->cr_msg ); 1511 return 1; 1512 } 1513 1514 di->di_tolerance = (time_t)t; 1515 break; 1516 1517 case DDS_MAXDYNAMICOBJS: 1518 if ( c->value_int < 0 ) { 1519 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1520 "DDS invalid dds-max-dynamicObjects=%d", c->value_int ); 1521 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1522 "%s: %s.\n", c->log, c->cr_msg ); 1523 return 1; 1524 } 1525 di->di_max_dynamicObjects = c->value_int; 1526 break; 1527 1528 default: 1529 rc = 1; 1530 break; 1531 } 1532 1533 return rc; 1534 } 1535 1536 static int 1537 dds_db_init( 1538 BackendDB *be, 1539 ConfigReply *cr) 1540 { 1541 slap_overinst *on = (slap_overinst *)be->bd_info; 1542 dds_info_t *di; 1543 BackendInfo *bi = on->on_info->oi_orig; 1544 1545 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 1546 Log0( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1547 "DDS cannot be used as global overlay.\n" ); 1548 return 1; 1549 } 1550 1551 /* check support for required functions */ 1552 /* FIXME: some could be provided by other overlays in between */ 1553 if ( bi->bi_op_add == NULL /* object creation */ 1554 || bi->bi_op_delete == NULL /* object deletion */ 1555 || bi->bi_op_modify == NULL /* object refresh */ 1556 || bi->bi_op_search == NULL /* object expiration */ 1557 || bi->bi_entry_get_rw == NULL ) /* object type/existence checking */ 1558 { 1559 Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1560 "DDS backend \"%s\" does not provide " 1561 "required functionality.\n", 1562 bi->bi_type ); 1563 return 1; 1564 } 1565 1566 di = (dds_info_t *)ch_calloc( 1, sizeof( dds_info_t ) ); 1567 on->on_bi.bi_private = di; 1568 1569 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL; 1570 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL; 1571 1572 ldap_pvt_thread_mutex_init( &di->di_mutex ); 1573 1574 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_DYNAMIC; 1575 1576 return 0; 1577 } 1578 1579 /* adds dynamicSubtrees to root DSE */ 1580 static int 1581 dds_entry_info( void *arg, Entry *e ) 1582 { 1583 dds_info_t *di = (dds_info_t *)arg; 1584 1585 attr_merge( e, slap_schema.si_ad_dynamicSubtrees, 1586 di->di_suffix, di->di_nsuffix ); 1587 1588 return 0; 1589 } 1590 1591 /* callback that counts the returned entries, since the search 1592 * does not get to the point in slap_send_search_entries where 1593 * the actual count occurs */ 1594 static int 1595 dds_count_cb( Operation *op, SlapReply *rs ) 1596 { 1597 int *nump = (int *)op->o_callback->sc_private; 1598 1599 switch ( rs->sr_type ) { 1600 case REP_SEARCH: 1601 (*nump)++; 1602 break; 1603 1604 case REP_SEARCHREF: 1605 case REP_RESULT: 1606 break; 1607 1608 default: 1609 assert( 0 ); 1610 } 1611 1612 return 0; 1613 } 1614 1615 /* count dynamic objects existing in the database at startup */ 1616 static int 1617 dds_count( void *ctx, BackendDB *be ) 1618 { 1619 slap_overinst *on = (slap_overinst *)be->bd_info; 1620 dds_info_t *di = (dds_info_t *)on->on_bi.bi_private; 1621 1622 Connection conn = { 0 }; 1623 OperationBuffer opbuf; 1624 Operation *op; 1625 slap_callback sc = { 0 }; 1626 SlapReply rs = { REP_RESULT }; 1627 1628 int rc; 1629 char *extra = ""; 1630 1631 connection_fake_init( &conn, &opbuf, ctx ); 1632 op = &opbuf.ob_op; 1633 1634 op->o_tag = LDAP_REQ_SEARCH; 1635 memset( &op->oq_search, 0, sizeof( op->oq_search ) ); 1636 1637 op->o_bd = be; 1638 1639 op->o_req_dn = op->o_bd->be_suffix[ 0 ]; 1640 op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; 1641 1642 op->o_dn = op->o_bd->be_rootdn; 1643 op->o_ndn = op->o_bd->be_rootndn; 1644 1645 op->ors_scope = LDAP_SCOPE_SUBTREE; 1646 op->ors_tlimit = SLAP_NO_LIMIT; 1647 op->ors_slimit = SLAP_NO_LIMIT; 1648 op->ors_attrs = slap_anlist_no_attrs; 1649 1650 op->ors_filterstr.bv_len = STRLENOF( "(objectClass=" ")" ) 1651 + slap_schema.si_oc_dynamicObject->soc_cname.bv_len; 1652 op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 1653 snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1, 1654 "(objectClass=%s)", 1655 slap_schema.si_oc_dynamicObject->soc_cname.bv_val ); 1656 1657 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); 1658 if ( op->ors_filter == NULL ) { 1659 rs.sr_err = LDAP_OTHER; 1660 goto done_search; 1661 } 1662 1663 op->o_callback = ≻ 1664 sc.sc_response = dds_count_cb; 1665 sc.sc_private = &di->di_num_dynamicObjects; 1666 di->di_num_dynamicObjects = 0; 1667 1668 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1669 (void)op->o_bd->bd_info->bi_op_search( op, &rs ); 1670 op->o_bd->bd_info = (BackendInfo *)on; 1671 1672 done_search:; 1673 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1674 filter_free_x( op, op->ors_filter ); 1675 1676 rc = rs.sr_err; 1677 switch ( rs.sr_err ) { 1678 case LDAP_SUCCESS: 1679 Log1( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, 1680 "DDS non-expired=%d\n", 1681 di->di_num_dynamicObjects ); 1682 break; 1683 1684 case LDAP_NO_SUCH_OBJECT: 1685 /* (ITS#5267) database not created yet? */ 1686 rs.sr_err = LDAP_SUCCESS; 1687 extra = " (ignored)"; 1688 /* fallthru */ 1689 1690 default: 1691 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1692 "DDS non-expired objects lookup failed err=%d%s\n", 1693 rc, extra ); 1694 break; 1695 } 1696 1697 return rs.sr_err; 1698 } 1699 1700 static int 1701 dds_db_open( 1702 BackendDB *be, 1703 ConfigReply *cr ) 1704 { 1705 slap_overinst *on = (slap_overinst *)be->bd_info; 1706 dds_info_t *di = on->on_bi.bi_private; 1707 int rc = 0; 1708 void *thrctx = ldap_pvt_thread_pool_context(); 1709 1710 if ( DDS_OFF( di ) ) { 1711 goto done; 1712 } 1713 1714 if ( SLAP_SINGLE_SHADOW( be ) ) { 1715 Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1716 "DDS incompatible with shadow database \"%s\".\n", 1717 be->be_suffix[ 0 ].bv_val ); 1718 return 1; 1719 } 1720 1721 if ( di->di_max_ttl == 0 ) { 1722 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL; 1723 } 1724 1725 if ( di->di_min_ttl == 0 ) { 1726 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL; 1727 } 1728 1729 di->di_suffix = be->be_suffix; 1730 di->di_nsuffix = be->be_nsuffix; 1731 1732 /* ... so that count, if required, is accurate */ 1733 if ( di->di_max_dynamicObjects > 0 ) { 1734 /* force deletion of expired entries... */ 1735 be->bd_info = (BackendInfo *)on->on_info; 1736 rc = dds_expire( thrctx, di ); 1737 be->bd_info = (BackendInfo *)on; 1738 if ( rc != LDAP_SUCCESS ) { 1739 rc = 1; 1740 goto done; 1741 } 1742 1743 rc = dds_count( thrctx, be ); 1744 if ( rc != LDAP_SUCCESS ) { 1745 rc = 1; 1746 goto done; 1747 } 1748 } 1749 1750 /* start expire task */ 1751 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 1752 di->di_expire_task = ldap_pvt_runqueue_insert( &slapd_rq, 1753 DDS_INTERVAL( di ), 1754 dds_expire_fn, di, "dds_expire_fn", 1755 be->be_suffix[ 0 ].bv_val ); 1756 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 1757 1758 /* register dinamicSubtrees root DSE info support */ 1759 rc = entry_info_register( dds_entry_info, (void *)di ); 1760 1761 done:; 1762 1763 return rc; 1764 } 1765 1766 static int 1767 dds_db_close( 1768 BackendDB *be, 1769 ConfigReply *cr ) 1770 { 1771 slap_overinst *on = (slap_overinst *)be->bd_info; 1772 dds_info_t *di = on->on_bi.bi_private; 1773 1774 /* stop expire task */ 1775 if ( di && di->di_expire_task ) { 1776 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 1777 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) { 1778 ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task ); 1779 } 1780 ldap_pvt_runqueue_remove( &slapd_rq, di->di_expire_task ); 1781 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 1782 } 1783 1784 (void)entry_info_unregister( dds_entry_info, (void *)di ); 1785 1786 return 0; 1787 } 1788 1789 static int 1790 dds_db_destroy( 1791 BackendDB *be, 1792 ConfigReply *cr ) 1793 { 1794 slap_overinst *on = (slap_overinst *)be->bd_info; 1795 dds_info_t *di = on->on_bi.bi_private; 1796 1797 if ( di != NULL ) { 1798 ldap_pvt_thread_mutex_destroy( &di->di_mutex ); 1799 1800 free( di ); 1801 } 1802 1803 return 0; 1804 } 1805 1806 static int 1807 slap_exop_refresh( 1808 Operation *op, 1809 SlapReply *rs ) 1810 { 1811 BackendDB *bd = op->o_bd; 1812 1813 rs->sr_err = slap_parse_refresh( op->ore_reqdata, &op->o_req_ndn, NULL, 1814 &rs->sr_text, op->o_tmpmemctx ); 1815 if ( rs->sr_err != LDAP_SUCCESS ) { 1816 return rs->sr_err; 1817 } 1818 1819 Log2( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO, 1820 "%s REFRESH dn=\"%s\"\n", 1821 op->o_log_prefix, op->o_req_ndn.bv_val ); 1822 op->o_req_dn = op->o_req_ndn; 1823 1824 op->o_bd = select_backend( &op->o_req_ndn, 0 ); 1825 if ( !SLAP_DYNAMIC( op->o_bd ) ) { 1826 send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION, 1827 "backend does not support dynamic directory services" ); 1828 goto done; 1829 } 1830 1831 rs->sr_err = backend_check_restrictions( op, rs, 1832 (struct berval *)&slap_EXOP_REFRESH ); 1833 if ( rs->sr_err != LDAP_SUCCESS ) { 1834 goto done; 1835 } 1836 1837 if ( op->o_bd->be_extended == NULL ) { 1838 send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION, 1839 "backend does not support extended operations" ); 1840 goto done; 1841 } 1842 1843 op->o_bd->be_extended( op, rs ); 1844 1845 done:; 1846 if ( !BER_BVISNULL( &op->o_req_ndn ) ) { 1847 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); 1848 BER_BVZERO( &op->o_req_ndn ); 1849 BER_BVZERO( &op->o_req_dn ); 1850 } 1851 op->o_bd = bd; 1852 1853 return rs->sr_err; 1854 } 1855 1856 static slap_overinst dds; 1857 1858 static int do_not_load_exop; 1859 static int do_not_replace_exop; 1860 static int do_not_load_schema; 1861 1862 #if SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC 1863 static 1864 #endif /* SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC */ 1865 int 1866 dds_initialize() 1867 { 1868 int rc = 0; 1869 int i, code; 1870 1871 /* Make sure we don't exceed the bits reserved for userland */ 1872 config_check_userland( DDS_LAST ); 1873 1874 if ( !do_not_load_schema ) { 1875 static struct { 1876 char *desc; 1877 slap_mask_t flags; 1878 AttributeDescription **ad; 1879 } s_at[] = { 1880 { "( 1.3.6.1.4.1.4203.666.1.57 " 1881 "NAME ( 'entryExpireTimestamp' ) " 1882 "DESC 'RFC2589 OpenLDAP extension: expire time of a dynamic object, " 1883 "computed as now + entryTtl' " 1884 "EQUALITY generalizedTimeMatch " 1885 "ORDERING generalizedTimeOrderingMatch " 1886 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 1887 "SINGLE-VALUE " 1888 "NO-USER-MODIFICATION " 1889 "USAGE dSAOperation )", 1890 SLAP_AT_HIDE, 1891 &ad_entryExpireTimestamp }, 1892 { NULL } 1893 }; 1894 1895 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 1896 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 0 ); 1897 if ( code ) { 1898 Debug( LDAP_DEBUG_ANY, 1899 "dds_initialize: register_at failed\n", 0, 0, 0 ); 1900 return code; 1901 } 1902 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 1903 } 1904 } 1905 1906 if ( !do_not_load_exop ) { 1907 rc = load_extop2( (struct berval *)&slap_EXOP_REFRESH, 1908 SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, slap_exop_refresh, 1909 !do_not_replace_exop ); 1910 if ( rc != LDAP_SUCCESS ) { 1911 Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1912 "DDS unable to register refresh exop: %d.\n", 1913 rc ); 1914 return rc; 1915 } 1916 } 1917 1918 dds.on_bi.bi_type = "dds"; 1919 1920 dds.on_bi.bi_db_init = dds_db_init; 1921 dds.on_bi.bi_db_open = dds_db_open; 1922 dds.on_bi.bi_db_close = dds_db_close; 1923 dds.on_bi.bi_db_destroy = dds_db_destroy; 1924 1925 dds.on_bi.bi_op_add = dds_op_add; 1926 dds.on_bi.bi_op_delete = dds_op_delete; 1927 dds.on_bi.bi_op_modify = dds_op_modify; 1928 dds.on_bi.bi_op_modrdn = dds_op_rename; 1929 dds.on_bi.bi_extended = dds_op_extended; 1930 1931 dds.on_bi.bi_cf_ocs = dds_ocs; 1932 1933 rc = config_register_schema( dds_cfg, dds_ocs ); 1934 if ( rc ) { 1935 return rc; 1936 } 1937 1938 return overlay_register( &dds ); 1939 } 1940 1941 #if SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC 1942 int 1943 init_module( int argc, char *argv[] ) 1944 { 1945 int i; 1946 1947 for ( i = 0; i < argc; i++ ) { 1948 char *arg = argv[ i ]; 1949 int no = 0; 1950 1951 if ( strncasecmp( arg, "no-", STRLENOF( "no-" ) ) == 0 ) { 1952 arg += STRLENOF( "no-" ); 1953 no = 1; 1954 } 1955 1956 if ( strcasecmp( arg, "exop" ) == 0 ) { 1957 do_not_load_exop = no; 1958 1959 } else if ( strcasecmp( arg, "replace" ) == 0 ) { 1960 do_not_replace_exop = no; 1961 1962 } else if ( strcasecmp( arg, "schema" ) == 0 ) { 1963 do_not_load_schema = no; 1964 1965 } else { 1966 Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, 1967 "DDS unknown module arg[#%d]=\"%s\".\n", 1968 i, argv[ i ] ); 1969 return 1; 1970 } 1971 } 1972 1973 return dds_initialize(); 1974 } 1975 #endif /* SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC */ 1976 1977 #endif /* defined(SLAPD_OVER_DDS) */ 1978