1 /* $NetBSD: translucent.c,v 1.1.1.4 2014/05/28 09:58:53 tron Exp $ */ 2 3 /* translucent.c - translucent proxy module */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2004-2014 The OpenLDAP Foundation. 8 * Portions Copyright 2005 Symas Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Symas Corp. for inclusion in 21 * OpenLDAP Software. This work was sponsored by Hewlett-Packard. 22 */ 23 24 #include "portable.h" 25 26 #ifdef SLAPD_OVER_TRANSLUCENT 27 28 #include <stdio.h> 29 30 #include <ac/string.h> 31 #include <ac/socket.h> 32 33 #include "slap.h" 34 #include "lutil.h" 35 36 #include "config.h" 37 38 /* config block */ 39 typedef struct translucent_info { 40 BackendDB db; /* captive backend */ 41 AttributeName *local; /* valid attrs for local filters */ 42 AttributeName *remote; /* valid attrs for remote filters */ 43 int strict; 44 int no_glue; 45 int defer_db_open; 46 int bind_local; 47 int pwmod_local; 48 } translucent_info; 49 50 static ConfigLDAPadd translucent_ldadd; 51 static ConfigCfAdd translucent_cfadd; 52 53 static ConfigDriver translucent_cf_gen; 54 55 enum { 56 TRANS_LOCAL = 1, 57 TRANS_REMOTE 58 }; 59 60 static ConfigTable translucentcfg[] = { 61 { "translucent_strict", "on|off", 1, 2, 0, 62 ARG_ON_OFF|ARG_OFFSET, 63 (void *)offsetof(translucent_info, strict), 64 "( OLcfgOvAt:14.1 NAME 'olcTranslucentStrict' " 65 "DESC 'Reveal attribute deletion constraint violations' " 66 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 67 { "translucent_no_glue", "on|off", 1, 2, 0, 68 ARG_ON_OFF|ARG_OFFSET, 69 (void *)offsetof(translucent_info, no_glue), 70 "( OLcfgOvAt:14.2 NAME 'olcTranslucentNoGlue' " 71 "DESC 'Disable automatic glue records for ADD and MODRDN' " 72 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 73 { "translucent_local", "attr[,attr...]", 1, 2, 0, 74 ARG_MAGIC|TRANS_LOCAL, 75 translucent_cf_gen, 76 "( OLcfgOvAt:14.3 NAME 'olcTranslucentLocal' " 77 "DESC 'Attributes to use in local search filter' " 78 "SYNTAX OMsDirectoryString )", NULL, NULL }, 79 { "translucent_remote", "attr[,attr...]", 1, 2, 0, 80 ARG_MAGIC|TRANS_REMOTE, 81 translucent_cf_gen, 82 "( OLcfgOvAt:14.4 NAME 'olcTranslucentRemote' " 83 "DESC 'Attributes to use in remote search filter' " 84 "SYNTAX OMsDirectoryString )", NULL, NULL }, 85 { "translucent_bind_local", "on|off", 1, 2, 0, 86 ARG_ON_OFF|ARG_OFFSET, 87 (void *)offsetof(translucent_info, bind_local), 88 "( OLcfgOvAt:14.5 NAME 'olcTranslucentBindLocal' " 89 "DESC 'Enable local bind' " 90 "SYNTAX OMsBoolean SINGLE-VALUE)", NULL, NULL }, 91 { "translucent_pwmod_local", "on|off", 1, 2, 0, 92 ARG_ON_OFF|ARG_OFFSET, 93 (void *)offsetof(translucent_info, pwmod_local), 94 "( OLcfgOvAt:14.6 NAME 'olcTranslucentPwModLocal' " 95 "DESC 'Enable local RFC 3062 Password Modify extended operation' " 96 "SYNTAX OMsBoolean SINGLE-VALUE)", NULL, NULL }, 97 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 98 }; 99 100 static ConfigOCs translucentocs[] = { 101 { "( OLcfgOvOc:14.1 " 102 "NAME 'olcTranslucentConfig' " 103 "DESC 'Translucent configuration' " 104 "SUP olcOverlayConfig " 105 "MAY ( olcTranslucentStrict $ olcTranslucentNoGlue $" 106 " olcTranslucentLocal $ olcTranslucentRemote $" 107 " olcTranslucentBindLocal $ olcTranslucentPwModLocal ) )", 108 Cft_Overlay, translucentcfg, NULL, translucent_cfadd }, 109 { "( OLcfgOvOc:14.2 " 110 "NAME 'olcTranslucentDatabase' " 111 "DESC 'Translucent target database configuration' " 112 "AUXILIARY )", Cft_Misc, olcDatabaseDummy, translucent_ldadd }, 113 { NULL, 0, NULL } 114 }; 115 /* for translucent_init() */ 116 117 static int 118 translucent_ldadd_cleanup( ConfigArgs *ca ) 119 { 120 slap_overinst *on = ca->ca_private; 121 translucent_info *ov = on->on_bi.bi_private; 122 123 ov->defer_db_open = 0; 124 return backend_startup_one( ca->be, &ca->reply ); 125 } 126 127 static int 128 translucent_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 129 { 130 slap_overinst *on; 131 translucent_info *ov; 132 133 Debug(LDAP_DEBUG_TRACE, "==> translucent_ldadd\n", 0, 0, 0); 134 135 if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || 136 cei->ce_bi->bi_cf_ocs != translucentocs ) 137 return LDAP_CONSTRAINT_VIOLATION; 138 139 on = (slap_overinst *)cei->ce_bi; 140 ov = on->on_bi.bi_private; 141 ca->be = &ov->db; 142 ca->ca_private = on; 143 if ( CONFIG_ONLINE_ADD( ca )) 144 ca->cleanup = translucent_ldadd_cleanup; 145 else 146 ov->defer_db_open = 0; 147 148 return LDAP_SUCCESS; 149 } 150 151 static int 152 translucent_cfadd( Operation *op, SlapReply *rs, Entry *e, ConfigArgs *ca ) 153 { 154 CfEntryInfo *cei = e->e_private; 155 slap_overinst *on = (slap_overinst *)cei->ce_bi; 156 translucent_info *ov = on->on_bi.bi_private; 157 struct berval bv; 158 159 Debug(LDAP_DEBUG_TRACE, "==> translucent_cfadd\n", 0, 0, 0); 160 161 /* FIXME: should not hardcode "olcDatabase" here */ 162 bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ), 163 "olcDatabase=" SLAP_X_ORDERED_FMT "%s", 164 0, ov->db.bd_info->bi_type ); 165 if ( bv.bv_len >= sizeof( ca->cr_msg ) ) { 166 return -1; 167 } 168 bv.bv_val = ca->cr_msg; 169 ca->be = &ov->db; 170 ov->defer_db_open = 0; 171 172 /* We can only create this entry if the database is table-driven 173 */ 174 if ( ov->db.bd_info->bi_cf_ocs ) 175 config_build_entry( op, rs, cei, ca, &bv, 176 ov->db.bd_info->bi_cf_ocs, 177 &translucentocs[1] ); 178 179 return 0; 180 } 181 182 static int 183 translucent_cf_gen( ConfigArgs *c ) 184 { 185 slap_overinst *on = (slap_overinst *)c->bi; 186 translucent_info *ov = on->on_bi.bi_private; 187 AttributeName **an, *a2; 188 int i; 189 190 if ( c->type == TRANS_LOCAL ) 191 an = &ov->local; 192 else 193 an = &ov->remote; 194 195 if ( c->op == SLAP_CONFIG_EMIT ) { 196 if ( !*an ) 197 return 1; 198 for ( i = 0; !BER_BVISNULL(&(*an)[i].an_name); i++ ) { 199 value_add_one( &c->rvalue_vals, &(*an)[i].an_name ); 200 } 201 return ( i < 1 ); 202 } else if ( c->op == LDAP_MOD_DELETE ) { 203 if ( c->valx < 0 ) { 204 anlist_free( *an, 1, NULL ); 205 *an = NULL; 206 } else { 207 i = c->valx; 208 ch_free( (*an)[i].an_name.bv_val ); 209 do { 210 (*an)[i] = (*an)[i+1]; 211 i++; 212 } while ( !BER_BVISNULL( &(*an)[i].an_name )); 213 } 214 return 0; 215 } 216 a2 = str2anlist( *an, c->argv[1], "," ); 217 if ( !a2 ) { 218 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s unable to parse attribute %s", 219 c->argv[0], c->argv[1] ); 220 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 221 "%s: %s\n", c->log, c->cr_msg, 0 ); 222 return ARG_BAD_CONF; 223 } 224 *an = a2; 225 return 0; 226 } 227 228 static slap_overinst translucent; 229 230 /* 231 ** glue_parent() 232 ** call syncrepl_add_glue() with the parent suffix; 233 ** 234 */ 235 236 static struct berval glue[] = { BER_BVC("top"), BER_BVC("glue"), BER_BVNULL }; 237 238 void glue_parent(Operation *op) { 239 Operation nop = *op; 240 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 241 struct berval ndn = BER_BVNULL; 242 Attribute *a; 243 Entry *e; 244 struct berval pdn; 245 246 dnParent( &op->o_req_ndn, &pdn ); 247 ber_dupbv_x( &ndn, &pdn, op->o_tmpmemctx ); 248 249 Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", ndn.bv_val, 0, 0); 250 251 e = entry_alloc(); 252 e->e_id = NOID; 253 ber_dupbv(&e->e_name, &ndn); 254 ber_dupbv(&e->e_nname, &ndn); 255 256 a = attr_alloc( slap_schema.si_ad_objectClass ); 257 a->a_numvals = 2; 258 a->a_vals = ch_malloc(sizeof(struct berval) * 3); 259 ber_dupbv(&a->a_vals[0], &glue[0]); 260 ber_dupbv(&a->a_vals[1], &glue[1]); 261 ber_dupbv(&a->a_vals[2], &glue[2]); 262 a->a_nvals = a->a_vals; 263 a->a_next = e->e_attrs; 264 e->e_attrs = a; 265 266 a = attr_alloc( slap_schema.si_ad_structuralObjectClass ); 267 a->a_numvals = 1; 268 a->a_vals = ch_malloc(sizeof(struct berval) * 2); 269 ber_dupbv(&a->a_vals[0], &glue[1]); 270 ber_dupbv(&a->a_vals[1], &glue[2]); 271 a->a_nvals = a->a_vals; 272 a->a_next = e->e_attrs; 273 e->e_attrs = a; 274 275 nop.o_req_dn = ndn; 276 nop.o_req_ndn = ndn; 277 nop.ora_e = e; 278 279 nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig; 280 syncrepl_add_glue(&nop, e); 281 nop.o_bd->bd_info = (BackendInfo *) on; 282 283 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); 284 285 return; 286 } 287 288 /* 289 ** free_attr_chain() 290 ** free only the Attribute*, not the contents; 291 ** 292 */ 293 void free_attr_chain(Attribute *b) { 294 Attribute *a; 295 for(a=b; a; a=a->a_next) { 296 a->a_vals = NULL; 297 a->a_nvals = NULL; 298 } 299 attrs_free( b ); 300 return; 301 } 302 303 /* 304 ** translucent_add() 305 ** if not bound as root, send ACCESS error; 306 ** if glue, glue_parent(); 307 ** return CONTINUE; 308 ** 309 */ 310 311 static int translucent_add(Operation *op, SlapReply *rs) { 312 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 313 translucent_info *ov = on->on_bi.bi_private; 314 Debug(LDAP_DEBUG_TRACE, "==> translucent_add: %s\n", 315 op->o_req_dn.bv_val, 0, 0); 316 if(!be_isroot(op)) { 317 op->o_bd->bd_info = (BackendInfo *) on->on_info; 318 send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS, 319 "user modification of overlay database not permitted"); 320 op->o_bd->bd_info = (BackendInfo *) on; 321 return(rs->sr_err); 322 } 323 if(!ov->no_glue) glue_parent(op); 324 return(SLAP_CB_CONTINUE); 325 } 326 327 /* 328 ** translucent_modrdn() 329 ** if not bound as root, send ACCESS error; 330 ** if !glue, glue_parent(); 331 ** else return CONTINUE; 332 ** 333 */ 334 335 static int translucent_modrdn(Operation *op, SlapReply *rs) { 336 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 337 translucent_info *ov = on->on_bi.bi_private; 338 Debug(LDAP_DEBUG_TRACE, "==> translucent_modrdn: %s -> %s\n", 339 op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0); 340 if(!be_isroot(op)) { 341 op->o_bd->bd_info = (BackendInfo *) on->on_info; 342 send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS, 343 "user modification of overlay database not permitted"); 344 op->o_bd->bd_info = (BackendInfo *) on; 345 return(rs->sr_err); 346 } 347 if(!ov->no_glue) { 348 op->o_tag = LDAP_REQ_ADD; 349 glue_parent(op); 350 op->o_tag = LDAP_REQ_MODRDN; 351 } 352 return(SLAP_CB_CONTINUE); 353 } 354 355 /* 356 ** translucent_delete() 357 ** if not bound as root, send ACCESS error; 358 ** else return CONTINUE; 359 ** 360 */ 361 362 static int translucent_delete(Operation *op, SlapReply *rs) { 363 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 364 Debug(LDAP_DEBUG_TRACE, "==> translucent_delete: %s\n", 365 op->o_req_dn.bv_val, 0, 0); 366 if(!be_isroot(op)) { 367 op->o_bd->bd_info = (BackendInfo *) on->on_info; 368 send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS, 369 "user modification of overlay database not permitted"); 370 op->o_bd->bd_info = (BackendInfo *) on; 371 return(rs->sr_err); 372 } 373 return(SLAP_CB_CONTINUE); 374 } 375 376 static int 377 translucent_tag_cb( Operation *op, SlapReply *rs ) 378 { 379 op->o_tag = LDAP_REQ_MODIFY; 380 op->orm_modlist = op->o_callback->sc_private; 381 rs->sr_tag = slap_req2res( op->o_tag ); 382 383 return SLAP_CB_CONTINUE; 384 } 385 386 /* 387 ** translucent_modify() 388 ** modify in local backend if exists in both; 389 ** otherwise, add to local backend; 390 ** fail if not defined in captive backend; 391 ** 392 */ 393 394 static int translucent_modify(Operation *op, SlapReply *rs) { 395 SlapReply nrs = { REP_RESULT }; 396 397 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 398 translucent_info *ov = on->on_bi.bi_private; 399 Entry *e = NULL, *re = NULL; 400 Attribute *a, *ax; 401 Modifications *m, **mm; 402 BackendDB *db; 403 int del, rc, erc = 0; 404 slap_callback cb = { 0 }; 405 406 Debug(LDAP_DEBUG_TRACE, "==> translucent_modify: %s\n", 407 op->o_req_dn.bv_val, 0, 0); 408 409 if(ov->defer_db_open) { 410 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 411 "remote DB not available"); 412 return(rs->sr_err); 413 } 414 /* 415 ** fetch entry from the captive backend; 416 ** if it did not exist, fail; 417 ** release it, if captive backend supports this; 418 ** 419 */ 420 421 db = op->o_bd; 422 op->o_bd = &ov->db; 423 ov->db.be_acl = op->o_bd->be_acl; 424 rc = ov->db.bd_info->bi_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &re); 425 if(rc != LDAP_SUCCESS || re == NULL ) { 426 send_ldap_error((op), rs, LDAP_NO_SUCH_OBJECT, 427 "attempt to modify nonexistent local record"); 428 return(rs->sr_err); 429 } 430 op->o_bd = db; 431 /* 432 ** fetch entry from local backend; 433 ** if it exists: 434 ** foreach Modification: 435 ** if attr not present in local: 436 ** if Mod == LDAP_MOD_DELETE: 437 ** if remote attr not present, return NO_SUCH; 438 ** if remote attr present, drop this Mod; 439 ** else force this Mod to LDAP_MOD_ADD; 440 ** return CONTINUE; 441 ** 442 */ 443 444 op->o_bd->bd_info = (BackendInfo *) on->on_info; 445 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e); 446 op->o_bd->bd_info = (BackendInfo *) on; 447 448 if(e && rc == LDAP_SUCCESS) { 449 Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: found local entry\n", 0, 0, 0); 450 for(mm = &op->orm_modlist; *mm; ) { 451 m = *mm; 452 for(a = e->e_attrs; a; a = a->a_next) 453 if(a->a_desc == m->sml_desc) break; 454 if(a) { 455 mm = &m->sml_next; 456 continue; /* found local attr */ 457 } 458 if(m->sml_op == LDAP_MOD_DELETE) { 459 for(a = re->e_attrs; a; a = a->a_next) 460 if(a->a_desc == m->sml_desc) break; 461 /* not found remote attr */ 462 if(!a) { 463 erc = LDAP_NO_SUCH_ATTRIBUTE; 464 goto release; 465 } 466 if(ov->strict) { 467 erc = LDAP_CONSTRAINT_VIOLATION; 468 goto release; 469 } 470 Debug(LDAP_DEBUG_TRACE, 471 "=> translucent_modify: silently dropping delete: %s\n", 472 m->sml_desc->ad_cname.bv_val, 0, 0); 473 *mm = m->sml_next; 474 m->sml_next = NULL; 475 slap_mods_free(m, 1); 476 continue; 477 } 478 m->sml_op = LDAP_MOD_ADD; 479 mm = &m->sml_next; 480 } 481 erc = SLAP_CB_CONTINUE; 482 release: 483 if(re) { 484 if(ov->db.bd_info->bi_entry_release_rw) { 485 op->o_bd = &ov->db; 486 ov->db.bd_info->bi_entry_release_rw(op, re, 0); 487 op->o_bd = db; 488 } else 489 entry_free(re); 490 } 491 op->o_bd->bd_info = (BackendInfo *) on->on_info; 492 be_entry_release_r(op, e); 493 op->o_bd->bd_info = (BackendInfo *) on; 494 if(erc == SLAP_CB_CONTINUE) { 495 return(erc); 496 } else if(erc) { 497 send_ldap_error(op, rs, erc, 498 "attempt to delete nonexistent attribute"); 499 return(erc); 500 } 501 } 502 503 /* don't leak remote entry copy */ 504 if(re) { 505 if(ov->db.bd_info->bi_entry_release_rw) { 506 op->o_bd = &ov->db; 507 ov->db.bd_info->bi_entry_release_rw(op, re, 0); 508 op->o_bd = db; 509 } else 510 entry_free(re); 511 } 512 /* 513 ** foreach Modification: 514 ** if MOD_ADD or MOD_REPLACE, add Attribute; 515 ** if no Modifications were suitable: 516 ** if strict, throw CONSTRAINT_VIOLATION; 517 ** else, return early SUCCESS; 518 ** fabricate Entry with new Attribute chain; 519 ** glue_parent() for this Entry; 520 ** call bi_op_add() in local backend; 521 ** 522 */ 523 524 Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: fabricating local add\n", 0, 0, 0); 525 a = NULL; 526 for(del = 0, ax = NULL, m = op->orm_modlist; m; m = m->sml_next) { 527 Attribute atmp; 528 if(((m->sml_op & LDAP_MOD_OP) != LDAP_MOD_ADD) && 529 ((m->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE)) { 530 Debug(LDAP_DEBUG_ANY, 531 "=> translucent_modify: silently dropped modification(%d): %s\n", 532 m->sml_op, m->sml_desc->ad_cname.bv_val, 0); 533 if((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE) del++; 534 continue; 535 } 536 atmp.a_desc = m->sml_desc; 537 atmp.a_vals = m->sml_values; 538 atmp.a_nvals = m->sml_nvalues ? m->sml_nvalues : atmp.a_vals; 539 atmp.a_numvals = m->sml_numvals; 540 atmp.a_flags = 0; 541 a = attr_dup( &atmp ); 542 a->a_next = ax; 543 ax = a; 544 } 545 546 if(del && ov->strict) { 547 attrs_free( a ); 548 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, 549 "attempt to delete attributes from local database"); 550 return(rs->sr_err); 551 } 552 553 if(!ax) { 554 if(ov->strict) { 555 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, 556 "modification contained other than ADD or REPLACE"); 557 return(rs->sr_err); 558 } 559 /* rs->sr_text = "no valid modification found"; */ 560 rs->sr_err = LDAP_SUCCESS; 561 send_ldap_result(op, rs); 562 return(rs->sr_err); 563 } 564 565 e = entry_alloc(); 566 ber_dupbv( &e->e_name, &op->o_req_dn ); 567 ber_dupbv( &e->e_nname, &op->o_req_ndn ); 568 e->e_attrs = a; 569 570 op->o_tag = LDAP_REQ_ADD; 571 cb.sc_response = translucent_tag_cb; 572 cb.sc_private = op->orm_modlist; 573 op->oq_add.rs_e = e; 574 575 glue_parent(op); 576 577 cb.sc_next = op->o_callback; 578 op->o_callback = &cb; 579 rc = on->on_info->oi_orig->bi_op_add(op, &nrs); 580 if ( op->ora_e == e ) 581 entry_free( e ); 582 op->o_callback = cb.sc_next; 583 584 return(rc); 585 } 586 587 static int translucent_compare(Operation *op, SlapReply *rs) { 588 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 589 translucent_info *ov = on->on_bi.bi_private; 590 AttributeAssertion *ava = op->orc_ava; 591 Entry *e = NULL; 592 BackendDB *db; 593 int rc; 594 595 Debug(LDAP_DEBUG_TRACE, "==> translucent_compare: <%s> %s:%s\n", 596 op->o_req_dn.bv_val, ava->aa_desc->ad_cname.bv_val, ava->aa_value.bv_val); 597 598 /* 599 ** if the local backend has an entry for this attribute: 600 ** CONTINUE and let it do the compare; 601 ** 602 */ 603 rc = overlay_entry_get_ov(op, &op->o_req_ndn, NULL, ava->aa_desc, 0, &e, on); 604 if(rc == LDAP_SUCCESS && e) { 605 overlay_entry_release_ov(op, e, 0, on); 606 return(SLAP_CB_CONTINUE); 607 } 608 609 if(ov->defer_db_open) { 610 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 611 "remote DB not available"); 612 return(rs->sr_err); 613 } 614 /* 615 ** call compare() in the captive backend; 616 ** return the result; 617 ** 618 */ 619 db = op->o_bd; 620 op->o_bd = &ov->db; 621 ov->db.be_acl = op->o_bd->be_acl; 622 rc = ov->db.bd_info->bi_op_compare(op, rs); 623 op->o_bd = db; 624 625 return(rc); 626 } 627 628 static int translucent_pwmod(Operation *op, SlapReply *rs) { 629 SlapReply nrs = { REP_RESULT }; 630 Operation nop; 631 632 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 633 translucent_info *ov = on->on_bi.bi_private; 634 Entry *e = NULL, *re = NULL; 635 BackendDB *db; 636 int rc = 0; 637 slap_callback cb = { 0 }; 638 639 if (!ov->pwmod_local) { 640 rs->sr_err = LDAP_CONSTRAINT_VIOLATION, 641 rs->sr_text = "attempt to modify password in local database"; 642 return rs->sr_err; 643 } 644 645 /* 646 ** fetch entry from the captive backend; 647 ** if it did not exist, fail; 648 ** release it, if captive backend supports this; 649 ** 650 */ 651 db = op->o_bd; 652 op->o_bd = &ov->db; 653 ov->db.be_acl = op->o_bd->be_acl; 654 rc = ov->db.bd_info->bi_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &re); 655 if(rc != LDAP_SUCCESS || re == NULL ) { 656 send_ldap_error((op), rs, LDAP_NO_SUCH_OBJECT, 657 "attempt to modify nonexistent local record"); 658 return(rs->sr_err); 659 } 660 op->o_bd = db; 661 /* 662 ** fetch entry from local backend; 663 ** if it exists: 664 ** return CONTINUE; 665 */ 666 667 op->o_bd->bd_info = (BackendInfo *) on->on_info; 668 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e); 669 op->o_bd->bd_info = (BackendInfo *) on; 670 671 if(e && rc == LDAP_SUCCESS) { 672 if(re) { 673 if(ov->db.bd_info->bi_entry_release_rw) { 674 op->o_bd = &ov->db; 675 ov->db.bd_info->bi_entry_release_rw(op, re, 0); 676 op->o_bd = db; 677 } else { 678 entry_free(re); 679 } 680 } 681 op->o_bd->bd_info = (BackendInfo *) on->on_info; 682 be_entry_release_r(op, e); 683 op->o_bd->bd_info = (BackendInfo *) on; 684 return SLAP_CB_CONTINUE; 685 } 686 687 /* don't leak remote entry copy */ 688 if(re) { 689 if(ov->db.bd_info->bi_entry_release_rw) { 690 op->o_bd = &ov->db; 691 ov->db.bd_info->bi_entry_release_rw(op, re, 0); 692 op->o_bd = db; 693 } else { 694 entry_free(re); 695 } 696 } 697 /* 698 ** glue_parent() for this Entry; 699 ** call bi_op_add() in local backend; 700 ** 701 */ 702 e = entry_alloc(); 703 ber_dupbv( &e->e_name, &op->o_req_dn ); 704 ber_dupbv( &e->e_nname, &op->o_req_ndn ); 705 e->e_attrs = NULL; 706 707 nop = *op; 708 nop.o_tag = LDAP_REQ_ADD; 709 cb.sc_response = slap_null_cb; 710 nop.oq_add.rs_e = e; 711 712 glue_parent(&nop); 713 714 nop.o_callback = &cb; 715 rc = on->on_info->oi_orig->bi_op_add(&nop, &nrs); 716 if ( nop.ora_e == e ) { 717 entry_free( e ); 718 } 719 720 if ( rc == LDAP_SUCCESS ) { 721 return SLAP_CB_CONTINUE; 722 } 723 724 return rc; 725 } 726 727 static int translucent_exop(Operation *op, SlapReply *rs) { 728 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 729 translucent_info *ov = on->on_bi.bi_private; 730 const struct berval bv_exop_pwmod = BER_BVC(LDAP_EXOP_MODIFY_PASSWD); 731 732 Debug(LDAP_DEBUG_TRACE, "==> translucent_exop: %s\n", 733 op->o_req_dn.bv_val, 0, 0); 734 735 if(ov->defer_db_open) { 736 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 737 "remote DB not available"); 738 return(rs->sr_err); 739 } 740 741 if ( bvmatch( &bv_exop_pwmod, &op->ore_reqoid ) ) { 742 return translucent_pwmod( op, rs ); 743 } 744 745 return SLAP_CB_CONTINUE; 746 } 747 748 /* 749 ** translucent_search_cb() 750 ** merge local data with remote data 751 ** 752 ** Four cases: 753 ** 1: remote search, no local filter 754 ** merge data and send immediately 755 ** 2: remote search, with local filter 756 ** merge data and save 757 ** 3: local search, no remote filter 758 ** merge data and send immediately 759 ** 4: local search, with remote filter 760 ** check list, merge, send, delete 761 */ 762 763 #define RMT_SIDE 0 764 #define LCL_SIDE 1 765 #define USE_LIST 2 766 767 typedef struct trans_ctx { 768 BackendDB *db; 769 slap_overinst *on; 770 Filter *orig; 771 Avlnode *list; 772 int step; 773 int slimit; 774 AttributeName *attrs; 775 } trans_ctx; 776 777 static int translucent_search_cb(Operation *op, SlapReply *rs) { 778 trans_ctx *tc; 779 BackendDB *db; 780 slap_overinst *on; 781 translucent_info *ov; 782 Entry *le, *re; 783 Attribute *a, *ax, *an, *as = NULL; 784 int rc; 785 int test_f = 0; 786 787 tc = op->o_callback->sc_private; 788 789 /* Don't let the op complete while we're gathering data */ 790 if ( rs->sr_type == REP_RESULT && ( tc->step & USE_LIST )) 791 return 0; 792 793 if(!op || !rs || rs->sr_type != REP_SEARCH || !rs->sr_entry) 794 return(SLAP_CB_CONTINUE); 795 796 Debug(LDAP_DEBUG_TRACE, "==> translucent_search_cb: %s\n", 797 rs->sr_entry->e_name.bv_val, 0, 0); 798 799 op->ors_slimit = tc->slimit + ( tc->slimit > 0 ? 1 : 0 ); 800 if ( op->ors_attrs == slap_anlist_all_attributes ) { 801 op->ors_attrs = tc->attrs; 802 rs->sr_attrs = tc->attrs; 803 rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs ); 804 } 805 806 on = tc->on; 807 ov = on->on_bi.bi_private; 808 809 db = op->o_bd; 810 re = NULL; 811 812 /* If we have local, get remote */ 813 if ( tc->step & LCL_SIDE ) { 814 le = rs->sr_entry; 815 /* If entry is already on list, use it */ 816 if ( tc->step & USE_LIST ) { 817 re = tavl_delete( &tc->list, le, entry_dn_cmp ); 818 if ( re ) { 819 rs_flush_entry( op, rs, on ); 820 rc = test_filter( op, re, tc->orig ); 821 if ( rc == LDAP_COMPARE_TRUE ) { 822 rs->sr_flags |= REP_ENTRY_MUSTBEFREED; 823 rs->sr_entry = re; 824 825 if ( tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) { 826 return LDAP_SIZELIMIT_EXCEEDED; 827 } 828 829 return SLAP_CB_CONTINUE; 830 } else { 831 entry_free( re ); 832 rs->sr_entry = NULL; 833 return 0; 834 } 835 } 836 } 837 op->o_bd = &ov->db; 838 rc = be_entry_get_rw( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &re ); 839 if ( rc == LDAP_SUCCESS && re ) { 840 Entry *tmp = entry_dup( re ); 841 be_entry_release_r( op, re ); 842 re = tmp; 843 test_f = 1; 844 } 845 } else { 846 /* Else we have remote, get local */ 847 op->o_bd = tc->db; 848 le = NULL; 849 rc = overlay_entry_get_ov(op, &rs->sr_entry->e_nname, NULL, NULL, 0, &le, on); 850 if ( rc == LDAP_SUCCESS && le ) { 851 re = entry_dup( rs->sr_entry ); 852 rs_flush_entry( op, rs, on ); 853 } else { 854 le = NULL; 855 } 856 } 857 858 /* 859 ** if we got remote and local entry: 860 ** foreach local attr: 861 ** foreach remote attr: 862 ** if match, remote attr with local attr; 863 ** if new local, add to list; 864 ** append new local attrs to remote; 865 ** 866 */ 867 868 if ( re && le ) { 869 for(ax = le->e_attrs; ax; ax = ax->a_next) { 870 for(a = re->e_attrs; a; a = a->a_next) { 871 if(a->a_desc == ax->a_desc) { 872 test_f = 1; 873 if(a->a_vals != a->a_nvals) 874 ber_bvarray_free(a->a_nvals); 875 ber_bvarray_free(a->a_vals); 876 ber_bvarray_dup_x( &a->a_vals, ax->a_vals, NULL ); 877 if ( ax->a_vals == ax->a_nvals ) { 878 a->a_nvals = a->a_vals; 879 } else { 880 ber_bvarray_dup_x( &a->a_nvals, ax->a_nvals, NULL ); 881 } 882 break; 883 } 884 } 885 if(a) continue; 886 an = attr_dup(ax); 887 an->a_next = as; 888 as = an; 889 } 890 /* Dispose of local entry */ 891 if ( tc->step & LCL_SIDE ) { 892 rs_flush_entry(op, rs, on); 893 } else { 894 overlay_entry_release_ov(op, le, 0, on); 895 } 896 897 /* literally append, so locals are always last */ 898 if(as) { 899 if(re->e_attrs) { 900 for(ax = re->e_attrs; ax->a_next; ax = ax->a_next); 901 ax->a_next = as; 902 } else { 903 re->e_attrs = as; 904 } 905 } 906 /* If both filters, save entry for later */ 907 if ( tc->step == (USE_LIST|RMT_SIDE) ) { 908 tavl_insert( &tc->list, re, entry_dn_cmp, avl_dup_error ); 909 rs->sr_entry = NULL; 910 rc = 0; 911 } else { 912 /* send it now */ 913 rs->sr_entry = re; 914 rs->sr_flags |= REP_ENTRY_MUSTBEFREED; 915 if ( test_f ) { 916 rc = test_filter( op, rs->sr_entry, tc->orig ); 917 if ( rc == LDAP_COMPARE_TRUE ) { 918 rc = SLAP_CB_CONTINUE; 919 } else { 920 rc = 0; 921 } 922 } else { 923 rc = SLAP_CB_CONTINUE; 924 } 925 } 926 } else if ( le ) { 927 /* Only a local entry: remote was deleted 928 * Ought to delete the local too... 929 */ 930 rc = 0; 931 } else if ( tc->step & USE_LIST ) { 932 /* Only a remote entry, but both filters: 933 * Test the complete filter 934 */ 935 rc = test_filter( op, rs->sr_entry, tc->orig ); 936 if ( rc == LDAP_COMPARE_TRUE ) { 937 rc = SLAP_CB_CONTINUE; 938 } else { 939 rc = 0; 940 } 941 } else { 942 /* Only a remote entry, only remote filter: 943 * just pass thru 944 */ 945 rc = SLAP_CB_CONTINUE; 946 } 947 948 op->o_bd = db; 949 950 if ( rc == SLAP_CB_CONTINUE && tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) { 951 return LDAP_SIZELIMIT_EXCEEDED; 952 } 953 954 return rc; 955 } 956 957 /* Dup the filter, excluding invalid elements */ 958 static Filter * 959 trans_filter_dup(Operation *op, Filter *f, AttributeName *an) 960 { 961 Filter *n = NULL; 962 963 if ( !f ) 964 return NULL; 965 966 switch( f->f_choice & SLAPD_FILTER_MASK ) { 967 case SLAPD_FILTER_COMPUTED: 968 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 969 n->f_choice = f->f_choice; 970 n->f_result = f->f_result; 971 n->f_next = NULL; 972 break; 973 974 case LDAP_FILTER_PRESENT: 975 if ( ad_inlist( f->f_desc, an )) { 976 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 977 n->f_choice = f->f_choice; 978 n->f_desc = f->f_desc; 979 n->f_next = NULL; 980 } 981 break; 982 983 case LDAP_FILTER_EQUALITY: 984 case LDAP_FILTER_GE: 985 case LDAP_FILTER_LE: 986 case LDAP_FILTER_APPROX: 987 case LDAP_FILTER_SUBSTRINGS: 988 case LDAP_FILTER_EXT: 989 if ( !f->f_av_desc || ad_inlist( f->f_av_desc, an )) { 990 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 991 n->f_choice = f->f_choice; 992 n->f_ava = f->f_ava; 993 n->f_next = NULL; 994 } 995 break; 996 997 case LDAP_FILTER_AND: 998 case LDAP_FILTER_OR: 999 case LDAP_FILTER_NOT: { 1000 Filter **p; 1001 1002 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 1003 n->f_choice = f->f_choice; 1004 n->f_next = NULL; 1005 1006 for ( p = &n->f_list, f = f->f_list; f; f = f->f_next ) { 1007 *p = trans_filter_dup( op, f, an ); 1008 if ( !*p ) 1009 continue; 1010 p = &(*p)->f_next; 1011 } 1012 /* nothing valid in this list */ 1013 if ( !n->f_list ) { 1014 op->o_tmpfree( n, op->o_tmpmemctx ); 1015 return NULL; 1016 } 1017 /* Only 1 element in this list */ 1018 if ((n->f_choice & SLAPD_FILTER_MASK) != LDAP_FILTER_NOT && 1019 !n->f_list->f_next ) { 1020 f = n->f_list; 1021 *n = *f; 1022 op->o_tmpfree( f, op->o_tmpmemctx ); 1023 } 1024 break; 1025 } 1026 } 1027 return n; 1028 } 1029 1030 static void 1031 trans_filter_free( Operation *op, Filter *f ) 1032 { 1033 Filter *n, *p, *next; 1034 1035 f->f_choice &= SLAPD_FILTER_MASK; 1036 1037 switch( f->f_choice ) { 1038 case LDAP_FILTER_AND: 1039 case LDAP_FILTER_OR: 1040 case LDAP_FILTER_NOT: 1041 /* Free in reverse order */ 1042 n = NULL; 1043 for ( p = f->f_list; p; p = next ) { 1044 next = p->f_next; 1045 p->f_next = n; 1046 n = p; 1047 } 1048 for ( p = n; p; p = next ) { 1049 next = p->f_next; 1050 trans_filter_free( op, p ); 1051 } 1052 break; 1053 default: 1054 break; 1055 } 1056 op->o_tmpfree( f, op->o_tmpmemctx ); 1057 } 1058 1059 /* 1060 ** translucent_search() 1061 ** search via captive backend; 1062 ** override results with any local data; 1063 ** 1064 */ 1065 1066 static int translucent_search(Operation *op, SlapReply *rs) { 1067 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 1068 translucent_info *ov = on->on_bi.bi_private; 1069 slap_callback cb = { NULL, NULL, NULL, NULL }; 1070 trans_ctx tc; 1071 Filter *fl, *fr; 1072 struct berval fbv; 1073 int rc = 0; 1074 1075 Debug(LDAP_DEBUG_TRACE, "==> translucent_search: <%s> %s\n", 1076 op->o_req_dn.bv_val, op->ors_filterstr.bv_val, 0); 1077 1078 if(ov->defer_db_open) { 1079 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 1080 "remote DB not available"); 1081 return(rs->sr_err); 1082 } 1083 1084 fr = ov->remote ? trans_filter_dup( op, op->ors_filter, ov->remote ) : NULL; 1085 fl = ov->local ? trans_filter_dup( op, op->ors_filter, ov->local ) : NULL; 1086 cb.sc_response = (slap_response *) translucent_search_cb; 1087 cb.sc_private = &tc; 1088 cb.sc_next = op->o_callback; 1089 1090 ov->db.be_acl = op->o_bd->be_acl; 1091 tc.db = op->o_bd; 1092 tc.on = on; 1093 tc.orig = op->ors_filter; 1094 tc.list = NULL; 1095 tc.step = 0; 1096 tc.slimit = op->ors_slimit; 1097 tc.attrs = NULL; 1098 fbv = op->ors_filterstr; 1099 1100 op->o_callback = &cb; 1101 1102 if ( fr || !fl ) { 1103 tc.attrs = op->ors_attrs; 1104 op->ors_slimit = SLAP_NO_LIMIT; 1105 op->ors_attrs = slap_anlist_all_attributes; 1106 op->o_bd = &ov->db; 1107 tc.step |= RMT_SIDE; 1108 if ( fl ) { 1109 tc.step |= USE_LIST; 1110 op->ors_filter = fr; 1111 filter2bv_x( op, fr, &op->ors_filterstr ); 1112 } 1113 rc = ov->db.bd_info->bi_op_search(op, rs); 1114 op->ors_attrs = tc.attrs; 1115 op->o_bd = tc.db; 1116 if ( fl ) { 1117 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1118 } 1119 } 1120 if ( fl && !rc ) { 1121 tc.step |= LCL_SIDE; 1122 op->ors_filter = fl; 1123 filter2bv_x( op, fl, &op->ors_filterstr ); 1124 rc = overlay_op_walk( op, rs, op_search, on->on_info, on->on_next ); 1125 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1126 } 1127 op->ors_filterstr = fbv; 1128 op->ors_filter = tc.orig; 1129 op->o_callback = cb.sc_next; 1130 rs->sr_attrs = op->ors_attrs; 1131 rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs ); 1132 1133 /* Send out anything remaining on the list and finish */ 1134 if ( tc.step & USE_LIST ) { 1135 if ( tc.list ) { 1136 Avlnode *av; 1137 1138 av = tavl_end( tc.list, TAVL_DIR_LEFT ); 1139 while ( av ) { 1140 rs->sr_entry = av->avl_data; 1141 if ( rc == LDAP_SUCCESS && LDAP_COMPARE_TRUE == 1142 test_filter( op, rs->sr_entry, op->ors_filter )) 1143 { 1144 rs->sr_flags = REP_ENTRY_MUSTBEFREED; 1145 rc = send_search_entry( op, rs ); 1146 } else { 1147 entry_free( rs->sr_entry ); 1148 } 1149 av = tavl_next( av, TAVL_DIR_RIGHT ); 1150 } 1151 tavl_free( tc.list, NULL ); 1152 rs->sr_flags = 0; 1153 rs->sr_entry = NULL; 1154 } 1155 send_ldap_result( op, rs ); 1156 } 1157 1158 op->ors_slimit = tc.slimit; 1159 1160 /* Free in reverse order */ 1161 if ( fl ) 1162 trans_filter_free( op, fl ); 1163 if ( fr ) 1164 trans_filter_free( op, fr ); 1165 1166 return rc; 1167 } 1168 1169 1170 /* 1171 ** translucent_bind() 1172 ** pass bind request to captive backend; 1173 ** 1174 */ 1175 1176 static int translucent_bind(Operation *op, SlapReply *rs) { 1177 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 1178 translucent_info *ov = on->on_bi.bi_private; 1179 BackendDB *db; 1180 slap_callback sc = { 0 }, *save_cb; 1181 int rc; 1182 1183 Debug(LDAP_DEBUG_TRACE, "translucent_bind: <%s> method %d\n", 1184 op->o_req_dn.bv_val, op->orb_method, 0); 1185 1186 if(ov->defer_db_open) { 1187 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 1188 "remote DB not available"); 1189 return(rs->sr_err); 1190 } 1191 1192 if (ov->bind_local) { 1193 sc.sc_response = slap_null_cb; 1194 save_cb = op->o_callback; 1195 op->o_callback = ≻ 1196 } 1197 1198 db = op->o_bd; 1199 op->o_bd = &ov->db; 1200 ov->db.be_acl = op->o_bd->be_acl; 1201 rc = ov->db.bd_info->bi_op_bind(op, rs); 1202 op->o_bd = db; 1203 1204 if (ov->bind_local) { 1205 op->o_callback = save_cb; 1206 if (rc != LDAP_SUCCESS) { 1207 rc = SLAP_CB_CONTINUE; 1208 } 1209 } 1210 1211 return rc; 1212 } 1213 1214 /* 1215 ** translucent_connection_destroy() 1216 ** pass disconnect notification to captive backend; 1217 ** 1218 */ 1219 1220 static int translucent_connection_destroy(BackendDB *be, Connection *conn) { 1221 slap_overinst *on = (slap_overinst *) be->bd_info; 1222 translucent_info *ov = on->on_bi.bi_private; 1223 int rc = 0; 1224 1225 Debug(LDAP_DEBUG_TRACE, "translucent_connection_destroy\n", 0, 0, 0); 1226 1227 rc = ov->db.bd_info->bi_connection_destroy(&ov->db, conn); 1228 1229 return(rc); 1230 } 1231 1232 /* 1233 ** translucent_db_config() 1234 ** pass config directives to captive backend; 1235 ** parse unrecognized directives ourselves; 1236 ** 1237 */ 1238 1239 static int translucent_db_config( 1240 BackendDB *be, 1241 const char *fname, 1242 int lineno, 1243 int argc, 1244 char **argv 1245 ) 1246 { 1247 slap_overinst *on = (slap_overinst *) be->bd_info; 1248 translucent_info *ov = on->on_bi.bi_private; 1249 1250 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_config: %s\n", 1251 argc ? argv[0] : "", 0, 0); 1252 1253 /* Something for the captive database? */ 1254 if ( ov->db.bd_info && ov->db.bd_info->bi_db_config ) 1255 return ov->db.bd_info->bi_db_config( &ov->db, fname, lineno, 1256 argc, argv ); 1257 return SLAP_CONF_UNKNOWN; 1258 } 1259 1260 /* 1261 ** translucent_db_init() 1262 ** initialize the captive backend; 1263 ** 1264 */ 1265 1266 static int translucent_db_init(BackendDB *be, ConfigReply *cr) { 1267 slap_overinst *on = (slap_overinst *) be->bd_info; 1268 translucent_info *ov; 1269 1270 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_init\n", 0, 0, 0); 1271 1272 ov = ch_calloc(1, sizeof(translucent_info)); 1273 on->on_bi.bi_private = ov; 1274 ov->db = *be; 1275 ov->db.be_private = NULL; 1276 ov->defer_db_open = 1; 1277 1278 if ( !backend_db_init( "ldap", &ov->db, -1, NULL )) { 1279 Debug( LDAP_DEBUG_CONFIG, "translucent: unable to open captive back-ldap\n", 0, 0, 0); 1280 return 1; 1281 } 1282 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK; 1283 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NOLASTMOD; 1284 1285 return 0; 1286 } 1287 1288 /* 1289 ** translucent_db_open() 1290 ** if the captive backend has an open() method, call it; 1291 ** 1292 */ 1293 1294 static int translucent_db_open(BackendDB *be, ConfigReply *cr) { 1295 slap_overinst *on = (slap_overinst *) be->bd_info; 1296 translucent_info *ov = on->on_bi.bi_private; 1297 int rc; 1298 1299 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_open\n", 0, 0, 0); 1300 1301 /* need to inherit something from the original database... */ 1302 ov->db.be_def_limit = be->be_def_limit; 1303 ov->db.be_limits = be->be_limits; 1304 ov->db.be_acl = be->be_acl; 1305 ov->db.be_dfltaccess = be->be_dfltaccess; 1306 1307 if ( ov->defer_db_open ) 1308 return 0; 1309 1310 rc = backend_startup_one( &ov->db, cr ); 1311 1312 if(rc) Debug(LDAP_DEBUG_TRACE, 1313 "translucent: bi_db_open() returned error %d\n", rc, 0, 0); 1314 1315 return(rc); 1316 } 1317 1318 /* 1319 ** translucent_db_close() 1320 ** if the captive backend has a close() method, call it 1321 ** 1322 */ 1323 1324 static int 1325 translucent_db_close( BackendDB *be, ConfigReply *cr ) 1326 { 1327 slap_overinst *on = (slap_overinst *) be->bd_info; 1328 translucent_info *ov = on->on_bi.bi_private; 1329 int rc = 0; 1330 1331 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_close\n", 0, 0, 0); 1332 1333 if ( ov && ov->db.bd_info && ov->db.bd_info->bi_db_close ) { 1334 rc = ov->db.bd_info->bi_db_close(&ov->db, NULL); 1335 } 1336 1337 return(rc); 1338 } 1339 1340 /* 1341 ** translucent_db_destroy() 1342 ** if the captive backend has a db_destroy() method, call it; 1343 ** free any config data 1344 ** 1345 */ 1346 1347 static int 1348 translucent_db_destroy( BackendDB *be, ConfigReply *cr ) 1349 { 1350 slap_overinst *on = (slap_overinst *) be->bd_info; 1351 translucent_info *ov = on->on_bi.bi_private; 1352 int rc = 0; 1353 1354 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_destroy\n", 0, 0, 0); 1355 1356 if ( ov ) { 1357 if ( ov->remote ) 1358 anlist_free( ov->remote, 1, NULL ); 1359 if ( ov->local ) 1360 anlist_free( ov->local, 1, NULL ); 1361 if ( ov->db.be_private != NULL ) { 1362 backend_stopdown_one( &ov->db ); 1363 } 1364 1365 ldap_pvt_thread_mutex_destroy( &ov->db.be_pcl_mutex ); 1366 ch_free(ov); 1367 on->on_bi.bi_private = NULL; 1368 } 1369 1370 return(rc); 1371 } 1372 1373 /* 1374 ** translucent_initialize() 1375 ** initialize the slap_overinst with our entry points; 1376 ** 1377 */ 1378 1379 int translucent_initialize() { 1380 1381 int rc; 1382 1383 Debug(LDAP_DEBUG_TRACE, "==> translucent_initialize\n", 0, 0, 0); 1384 1385 translucent.on_bi.bi_type = "translucent"; 1386 translucent.on_bi.bi_db_init = translucent_db_init; 1387 translucent.on_bi.bi_db_config = translucent_db_config; 1388 translucent.on_bi.bi_db_open = translucent_db_open; 1389 translucent.on_bi.bi_db_close = translucent_db_close; 1390 translucent.on_bi.bi_db_destroy = translucent_db_destroy; 1391 translucent.on_bi.bi_op_bind = translucent_bind; 1392 translucent.on_bi.bi_op_add = translucent_add; 1393 translucent.on_bi.bi_op_modify = translucent_modify; 1394 translucent.on_bi.bi_op_modrdn = translucent_modrdn; 1395 translucent.on_bi.bi_op_delete = translucent_delete; 1396 translucent.on_bi.bi_op_search = translucent_search; 1397 translucent.on_bi.bi_op_compare = translucent_compare; 1398 translucent.on_bi.bi_connection_destroy = translucent_connection_destroy; 1399 translucent.on_bi.bi_extended = translucent_exop; 1400 1401 translucent.on_bi.bi_cf_ocs = translucentocs; 1402 rc = config_register_schema ( translucentcfg, translucentocs ); 1403 if ( rc ) return rc; 1404 1405 return(overlay_register(&translucent)); 1406 } 1407 1408 #if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC) 1409 int init_module(int argc, char *argv[]) { 1410 return translucent_initialize(); 1411 } 1412 #endif 1413 1414 #endif /* SLAPD_OVER_TRANSLUCENT */ 1415