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