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