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