1 /* $NetBSD: translucent.c,v 1.1.1.3 2010/12/12 15:23:46 adam Exp $ */ 2 3 /* translucent.c - translucent proxy module */ 4 /* OpenLDAP: pkg/ldap/servers/slapd/overlays/translucent.c,v 1.13.2.35 2010/04/15 20:02:30 quanah Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2004-2010 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 const struct berval bv_exop_pwmod = BER_BVC(LDAP_EXOP_MODIFY_PASSWD); 635 Entry *e = NULL, *re = NULL; 636 BackendDB *db; 637 int rc = 0; 638 slap_callback cb = { 0 }; 639 640 if (!ov->pwmod_local) { 641 rs->sr_err = LDAP_CONSTRAINT_VIOLATION, 642 rs->sr_text = "attempt to modify password in local database"; 643 return rs->sr_err; 644 } 645 646 /* 647 ** fetch entry from the captive backend; 648 ** if it did not exist, fail; 649 ** release it, if captive backend supports this; 650 ** 651 */ 652 db = op->o_bd; 653 op->o_bd = &ov->db; 654 ov->db.be_acl = op->o_bd->be_acl; 655 rc = ov->db.bd_info->bi_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &re); 656 if(rc != LDAP_SUCCESS || re == NULL ) { 657 send_ldap_error((op), rs, LDAP_NO_SUCH_OBJECT, 658 "attempt to modify nonexistent local record"); 659 return(rs->sr_err); 660 } 661 op->o_bd = db; 662 /* 663 ** fetch entry from local backend; 664 ** if it exists: 665 ** return CONTINUE; 666 */ 667 668 op->o_bd->bd_info = (BackendInfo *) on->on_info; 669 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e); 670 op->o_bd->bd_info = (BackendInfo *) on; 671 672 if(e && rc == LDAP_SUCCESS) { 673 if(re) { 674 if(ov->db.bd_info->bi_entry_release_rw) { 675 op->o_bd = &ov->db; 676 ov->db.bd_info->bi_entry_release_rw(op, re, 0); 677 op->o_bd = db; 678 } else { 679 entry_free(re); 680 } 681 } 682 op->o_bd->bd_info = (BackendInfo *) on->on_info; 683 be_entry_release_r(op, e); 684 op->o_bd->bd_info = (BackendInfo *) on; 685 return SLAP_CB_CONTINUE; 686 } 687 688 /* don't leak remote entry copy */ 689 if(re) { 690 if(ov->db.bd_info->bi_entry_release_rw) { 691 op->o_bd = &ov->db; 692 ov->db.bd_info->bi_entry_release_rw(op, re, 0); 693 op->o_bd = db; 694 } else { 695 entry_free(re); 696 } 697 } 698 /* 699 ** glue_parent() for this Entry; 700 ** call bi_op_add() in local backend; 701 ** 702 */ 703 e = entry_alloc(); 704 ber_dupbv( &e->e_name, &op->o_req_dn ); 705 ber_dupbv( &e->e_nname, &op->o_req_ndn ); 706 e->e_attrs = NULL; 707 708 nop = *op; 709 nop.o_tag = LDAP_REQ_ADD; 710 cb.sc_response = slap_null_cb; 711 nop.oq_add.rs_e = e; 712 713 glue_parent(&nop); 714 715 nop.o_callback = &cb; 716 rc = on->on_info->oi_orig->bi_op_add(&nop, &nrs); 717 if ( nop.ora_e == e ) { 718 entry_free( e ); 719 } 720 721 if ( rc == LDAP_SUCCESS ) { 722 return SLAP_CB_CONTINUE; 723 } 724 725 return rc; 726 } 727 728 static int translucent_exop(Operation *op, SlapReply *rs) { 729 SlapReply nrs = { REP_RESULT }; 730 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(!op || !rs || 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 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { 823 rs->sr_flags ^= REP_ENTRY_MUSTRELEASE; 824 overlay_entry_release_ov( op, rs->sr_entry, 0, on ); 825 } 826 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) { 827 rs->sr_flags ^= REP_ENTRY_MUSTBEFREED; 828 entry_free( rs->sr_entry ); 829 } 830 rc = test_filter( op, re, tc->orig ); 831 if ( rc == LDAP_COMPARE_TRUE ) { 832 rs->sr_flags |= REP_ENTRY_MUSTBEFREED; 833 rs->sr_entry = re; 834 835 if ( tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) { 836 return LDAP_SIZELIMIT_EXCEEDED; 837 } 838 839 return SLAP_CB_CONTINUE; 840 } else { 841 entry_free( re ); 842 rs->sr_entry = NULL; 843 return 0; 844 } 845 } 846 } 847 op->o_bd = &ov->db; 848 rc = be_entry_get_rw( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &re ); 849 if ( rc == LDAP_SUCCESS && re ) { 850 Entry *tmp = entry_dup( re ); 851 be_entry_release_r( op, re ); 852 re = tmp; 853 test_f = 1; 854 } 855 } else { 856 /* Else we have remote, get local */ 857 op->o_bd = tc->db; 858 le = NULL; 859 rc = overlay_entry_get_ov(op, &rs->sr_entry->e_nname, NULL, NULL, 0, &le, on); 860 if ( rc == LDAP_SUCCESS && le ) { 861 re = entry_dup( rs->sr_entry ); 862 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { 863 rs->sr_flags ^= REP_ENTRY_MUSTRELEASE; 864 overlay_entry_release_ov( op, rs->sr_entry, 0, on ); 865 } 866 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) { 867 rs->sr_flags ^= REP_ENTRY_MUSTBEFREED; 868 entry_free( rs->sr_entry ); 869 } 870 } else { 871 le = NULL; 872 } 873 } 874 875 /* 876 ** if we got remote and local entry: 877 ** foreach local attr: 878 ** foreach remote attr: 879 ** if match, remote attr with local attr; 880 ** if new local, add to list; 881 ** append new local attrs to remote; 882 ** 883 */ 884 885 if ( re && le ) { 886 for(ax = le->e_attrs; ax; ax = ax->a_next) { 887 for(a = re->e_attrs; a; a = a->a_next) { 888 if(a->a_desc == ax->a_desc) { 889 test_f = 1; 890 if(a->a_vals != a->a_nvals) 891 ber_bvarray_free(a->a_nvals); 892 ber_bvarray_free(a->a_vals); 893 ber_bvarray_dup_x( &a->a_vals, ax->a_vals, NULL ); 894 if ( ax->a_vals == ax->a_nvals ) { 895 a->a_nvals = a->a_vals; 896 } else { 897 ber_bvarray_dup_x( &a->a_nvals, ax->a_nvals, NULL ); 898 } 899 break; 900 } 901 } 902 if(a) continue; 903 an = attr_dup(ax); 904 an->a_next = as; 905 as = an; 906 } 907 /* Dispose of local entry */ 908 if ( tc->step & LCL_SIDE ) { 909 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { 910 rs->sr_flags ^= REP_ENTRY_MUSTRELEASE; 911 overlay_entry_release_ov( op, rs->sr_entry, 0, on ); 912 } 913 if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) { 914 rs->sr_flags ^= REP_ENTRY_MUSTBEFREED; 915 entry_free( rs->sr_entry ); 916 } 917 } else { 918 overlay_entry_release_ov(op, le, 0, on); 919 } 920 921 /* literally append, so locals are always last */ 922 if(as) { 923 if(re->e_attrs) { 924 for(ax = re->e_attrs; ax->a_next; ax = ax->a_next); 925 ax->a_next = as; 926 } else { 927 re->e_attrs = as; 928 } 929 } 930 /* If both filters, save entry for later */ 931 if ( tc->step == (USE_LIST|RMT_SIDE) ) { 932 tavl_insert( &tc->list, re, entry_dn_cmp, avl_dup_error ); 933 rs->sr_entry = NULL; 934 rc = 0; 935 } else { 936 /* send it now */ 937 rs->sr_entry = re; 938 rs->sr_flags |= REP_ENTRY_MUSTBEFREED; 939 if ( test_f ) { 940 rc = test_filter( op, rs->sr_entry, tc->orig ); 941 if ( rc == LDAP_COMPARE_TRUE ) { 942 rc = SLAP_CB_CONTINUE; 943 } else { 944 rc = 0; 945 } 946 } else { 947 rc = SLAP_CB_CONTINUE; 948 } 949 } 950 } else if ( le ) { 951 /* Only a local entry: remote was deleted 952 * Ought to delete the local too... 953 */ 954 rc = 0; 955 } else if ( tc->step & USE_LIST ) { 956 /* Only a remote entry, but both filters: 957 * Test the complete filter 958 */ 959 rc = test_filter( op, rs->sr_entry, tc->orig ); 960 if ( rc == LDAP_COMPARE_TRUE ) { 961 rc = SLAP_CB_CONTINUE; 962 } else { 963 rc = 0; 964 } 965 } else { 966 /* Only a remote entry, only remote filter: 967 * just pass thru 968 */ 969 rc = SLAP_CB_CONTINUE; 970 } 971 972 op->o_bd = db; 973 974 if ( rc == SLAP_CB_CONTINUE && tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) { 975 return LDAP_SIZELIMIT_EXCEEDED; 976 } 977 978 return rc; 979 } 980 981 /* Dup the filter, excluding invalid elements */ 982 static Filter * 983 trans_filter_dup(Operation *op, Filter *f, AttributeName *an) 984 { 985 Filter *n = NULL; 986 987 if ( !f ) 988 return NULL; 989 990 switch( f->f_choice & SLAPD_FILTER_MASK ) { 991 case SLAPD_FILTER_COMPUTED: 992 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 993 n->f_choice = f->f_choice; 994 n->f_result = f->f_result; 995 n->f_next = NULL; 996 break; 997 998 case LDAP_FILTER_PRESENT: 999 if ( ad_inlist( f->f_desc, an )) { 1000 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 1001 n->f_choice = f->f_choice; 1002 n->f_desc = f->f_desc; 1003 n->f_next = NULL; 1004 } 1005 break; 1006 1007 case LDAP_FILTER_EQUALITY: 1008 case LDAP_FILTER_GE: 1009 case LDAP_FILTER_LE: 1010 case LDAP_FILTER_APPROX: 1011 case LDAP_FILTER_SUBSTRINGS: 1012 case LDAP_FILTER_EXT: 1013 if ( !f->f_av_desc || ad_inlist( f->f_av_desc, an )) { 1014 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 1015 n->f_choice = f->f_choice; 1016 n->f_ava = f->f_ava; 1017 n->f_next = NULL; 1018 } 1019 break; 1020 1021 case LDAP_FILTER_AND: 1022 case LDAP_FILTER_OR: 1023 case LDAP_FILTER_NOT: { 1024 Filter **p; 1025 1026 n = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 1027 n->f_choice = f->f_choice; 1028 n->f_next = NULL; 1029 1030 for ( p = &n->f_list, f = f->f_list; f; f = f->f_next ) { 1031 *p = trans_filter_dup( op, f, an ); 1032 if ( !*p ) 1033 continue; 1034 p = &(*p)->f_next; 1035 } 1036 /* nothing valid in this list */ 1037 if ( !n->f_list ) { 1038 op->o_tmpfree( n, op->o_tmpmemctx ); 1039 return NULL; 1040 } 1041 /* Only 1 element in this list */ 1042 if ((n->f_choice & SLAPD_FILTER_MASK) != LDAP_FILTER_NOT && 1043 !n->f_list->f_next ) { 1044 f = n->f_list; 1045 *n = *f; 1046 op->o_tmpfree( f, op->o_tmpmemctx ); 1047 } 1048 break; 1049 } 1050 } 1051 return n; 1052 } 1053 1054 static void 1055 trans_filter_free( Operation *op, Filter *f ) 1056 { 1057 Filter *n, *p, *next; 1058 1059 f->f_choice &= SLAPD_FILTER_MASK; 1060 1061 switch( f->f_choice ) { 1062 case LDAP_FILTER_AND: 1063 case LDAP_FILTER_OR: 1064 case LDAP_FILTER_NOT: 1065 /* Free in reverse order */ 1066 n = NULL; 1067 for ( p = f->f_list; p; p = next ) { 1068 next = p->f_next; 1069 p->f_next = n; 1070 n = p; 1071 } 1072 for ( p = n; p; p = next ) { 1073 next = p->f_next; 1074 trans_filter_free( op, p ); 1075 } 1076 break; 1077 default: 1078 break; 1079 } 1080 op->o_tmpfree( f, op->o_tmpmemctx ); 1081 } 1082 1083 /* 1084 ** translucent_search() 1085 ** search via captive backend; 1086 ** override results with any local data; 1087 ** 1088 */ 1089 1090 static int translucent_search(Operation *op, SlapReply *rs) { 1091 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 1092 translucent_info *ov = on->on_bi.bi_private; 1093 slap_callback cb = { NULL, NULL, NULL, NULL }; 1094 trans_ctx tc; 1095 Filter *fl, *fr; 1096 struct berval fbv; 1097 int rc = 0; 1098 1099 Debug(LDAP_DEBUG_TRACE, "==> translucent_search: <%s> %s\n", 1100 op->o_req_dn.bv_val, op->ors_filterstr.bv_val, 0); 1101 1102 if(ov->defer_db_open) { 1103 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 1104 "remote DB not available"); 1105 return(rs->sr_err); 1106 } 1107 1108 fr = ov->remote ? trans_filter_dup( op, op->ors_filter, ov->remote ) : NULL; 1109 fl = ov->local ? trans_filter_dup( op, op->ors_filter, ov->local ) : NULL; 1110 cb.sc_response = (slap_response *) translucent_search_cb; 1111 cb.sc_private = &tc; 1112 cb.sc_next = op->o_callback; 1113 1114 ov->db.be_acl = op->o_bd->be_acl; 1115 tc.db = op->o_bd; 1116 tc.on = on; 1117 tc.orig = op->ors_filter; 1118 tc.list = NULL; 1119 tc.step = 0; 1120 tc.slimit = op->ors_slimit; 1121 tc.attrs = NULL; 1122 fbv = op->ors_filterstr; 1123 1124 op->o_callback = &cb; 1125 1126 if ( fr || !fl ) { 1127 tc.attrs = op->ors_attrs; 1128 op->ors_slimit = SLAP_NO_LIMIT; 1129 op->ors_attrs = slap_anlist_all_attributes; 1130 op->o_bd = &ov->db; 1131 tc.step |= RMT_SIDE; 1132 if ( fl ) { 1133 tc.step |= USE_LIST; 1134 op->ors_filter = fr; 1135 filter2bv_x( op, fr, &op->ors_filterstr ); 1136 } 1137 rc = ov->db.bd_info->bi_op_search(op, rs); 1138 op->ors_attrs = tc.attrs; 1139 op->o_bd = tc.db; 1140 if ( fl ) { 1141 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1142 } 1143 } 1144 if ( fl && !rc ) { 1145 tc.step |= LCL_SIDE; 1146 op->ors_filter = fl; 1147 filter2bv_x( op, fl, &op->ors_filterstr ); 1148 rc = overlay_op_walk( op, rs, op_search, on->on_info, on->on_next ); 1149 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1150 } 1151 op->ors_filterstr = fbv; 1152 op->ors_filter = tc.orig; 1153 op->o_callback = cb.sc_next; 1154 rs->sr_attrs = op->ors_attrs; 1155 rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs ); 1156 1157 /* Send out anything remaining on the list and finish */ 1158 if ( tc.step & USE_LIST ) { 1159 if ( tc.list ) { 1160 Avlnode *av; 1161 1162 av = tavl_end( tc.list, TAVL_DIR_LEFT ); 1163 while ( av ) { 1164 rs->sr_entry = av->avl_data; 1165 rc = test_filter( op, rs->sr_entry, op->ors_filter ); 1166 if ( rc == LDAP_COMPARE_TRUE ) { 1167 rs->sr_flags = REP_ENTRY_MUSTBEFREED; 1168 rc = send_search_entry( op, rs ); 1169 if ( rc ) break; 1170 } else { 1171 entry_free( rs->sr_entry ); 1172 } 1173 av = tavl_next( av, TAVL_DIR_RIGHT ); 1174 } 1175 tavl_free( tc.list, NULL ); 1176 rs->sr_entry = NULL; 1177 } 1178 send_ldap_result( op, rs ); 1179 } 1180 1181 op->ors_slimit = tc.slimit; 1182 1183 /* Free in reverse order */ 1184 if ( fl ) 1185 trans_filter_free( op, fl ); 1186 if ( fr ) 1187 trans_filter_free( op, fr ); 1188 1189 return rc; 1190 } 1191 1192 1193 /* 1194 ** translucent_bind() 1195 ** pass bind request to captive backend; 1196 ** 1197 */ 1198 1199 static int translucent_bind(Operation *op, SlapReply *rs) { 1200 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 1201 translucent_info *ov = on->on_bi.bi_private; 1202 BackendDB *db; 1203 slap_callback sc = { 0 }, *save_cb; 1204 int rc; 1205 1206 Debug(LDAP_DEBUG_TRACE, "translucent_bind: <%s> method %d\n", 1207 op->o_req_dn.bv_val, op->orb_method, 0); 1208 1209 if(ov->defer_db_open) { 1210 send_ldap_error(op, rs, LDAP_UNAVAILABLE, 1211 "remote DB not available"); 1212 return(rs->sr_err); 1213 } 1214 1215 if (ov->bind_local) { 1216 sc.sc_response = slap_null_cb; 1217 save_cb = op->o_callback; 1218 op->o_callback = ≻ 1219 } 1220 1221 db = op->o_bd; 1222 op->o_bd = &ov->db; 1223 ov->db.be_acl = op->o_bd->be_acl; 1224 rc = ov->db.bd_info->bi_op_bind(op, rs); 1225 op->o_bd = db; 1226 1227 if (ov->bind_local) { 1228 op->o_callback = save_cb; 1229 if (rc != LDAP_SUCCESS) { 1230 rc = SLAP_CB_CONTINUE; 1231 } 1232 } 1233 1234 return rc; 1235 } 1236 1237 /* 1238 ** translucent_connection_destroy() 1239 ** pass disconnect notification to captive backend; 1240 ** 1241 */ 1242 1243 static int translucent_connection_destroy(BackendDB *be, Connection *conn) { 1244 slap_overinst *on = (slap_overinst *) be->bd_info; 1245 translucent_info *ov = on->on_bi.bi_private; 1246 int rc = 0; 1247 1248 Debug(LDAP_DEBUG_TRACE, "translucent_connection_destroy\n", 0, 0, 0); 1249 1250 rc = ov->db.bd_info->bi_connection_destroy(&ov->db, conn); 1251 1252 return(rc); 1253 } 1254 1255 /* 1256 ** translucent_db_config() 1257 ** pass config directives to captive backend; 1258 ** parse unrecognized directives ourselves; 1259 ** 1260 */ 1261 1262 static int translucent_db_config( 1263 BackendDB *be, 1264 const char *fname, 1265 int lineno, 1266 int argc, 1267 char **argv 1268 ) 1269 { 1270 slap_overinst *on = (slap_overinst *) be->bd_info; 1271 translucent_info *ov = on->on_bi.bi_private; 1272 1273 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_config: %s\n", 1274 argc ? argv[0] : "", 0, 0); 1275 1276 /* Something for the captive database? */ 1277 if ( ov->db.bd_info && ov->db.bd_info->bi_db_config ) 1278 return ov->db.bd_info->bi_db_config( &ov->db, fname, lineno, 1279 argc, argv ); 1280 return SLAP_CONF_UNKNOWN; 1281 } 1282 1283 /* 1284 ** translucent_db_init() 1285 ** initialize the captive backend; 1286 ** 1287 */ 1288 1289 static int translucent_db_init(BackendDB *be, ConfigReply *cr) { 1290 slap_overinst *on = (slap_overinst *) be->bd_info; 1291 translucent_info *ov; 1292 1293 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_init\n", 0, 0, 0); 1294 1295 ov = ch_calloc(1, sizeof(translucent_info)); 1296 on->on_bi.bi_private = ov; 1297 ov->db = *be; 1298 ov->db.be_private = NULL; 1299 ov->defer_db_open = 1; 1300 1301 if ( !backend_db_init( "ldap", &ov->db, -1, NULL )) { 1302 Debug( LDAP_DEBUG_CONFIG, "translucent: unable to open captive back-ldap\n", 0, 0, 0); 1303 return 1; 1304 } 1305 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK; 1306 SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NOLASTMOD; 1307 1308 return 0; 1309 } 1310 1311 /* 1312 ** translucent_db_open() 1313 ** if the captive backend has an open() method, call it; 1314 ** 1315 */ 1316 1317 static int translucent_db_open(BackendDB *be, ConfigReply *cr) { 1318 slap_overinst *on = (slap_overinst *) be->bd_info; 1319 translucent_info *ov = on->on_bi.bi_private; 1320 int rc; 1321 1322 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_open\n", 0, 0, 0); 1323 1324 /* need to inherit something from the original database... */ 1325 ov->db.be_def_limit = be->be_def_limit; 1326 ov->db.be_limits = be->be_limits; 1327 ov->db.be_acl = be->be_acl; 1328 ov->db.be_dfltaccess = be->be_dfltaccess; 1329 1330 if ( ov->defer_db_open ) 1331 return 0; 1332 1333 rc = backend_startup_one( &ov->db, cr ); 1334 1335 if(rc) Debug(LDAP_DEBUG_TRACE, 1336 "translucent: bi_db_open() returned error %d\n", rc, 0, 0); 1337 1338 return(rc); 1339 } 1340 1341 /* 1342 ** translucent_db_close() 1343 ** if the captive backend has a close() method, call it 1344 ** 1345 */ 1346 1347 static int 1348 translucent_db_close( 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_close\n", 0, 0, 0); 1355 1356 if ( ov && ov->db.bd_info && ov->db.bd_info->bi_db_close ) { 1357 rc = ov->db.bd_info->bi_db_close(&ov->db, NULL); 1358 } 1359 1360 return(rc); 1361 } 1362 1363 /* 1364 ** translucent_db_destroy() 1365 ** if the captive backend has a db_destroy() method, call it; 1366 ** free any config data 1367 ** 1368 */ 1369 1370 static int 1371 translucent_db_destroy( BackendDB *be, ConfigReply *cr ) 1372 { 1373 slap_overinst *on = (slap_overinst *) be->bd_info; 1374 translucent_info *ov = on->on_bi.bi_private; 1375 int rc = 0; 1376 1377 Debug(LDAP_DEBUG_TRACE, "==> translucent_db_destroy\n", 0, 0, 0); 1378 1379 if ( ov ) { 1380 if ( ov->remote ) 1381 anlist_free( ov->remote, 1, NULL ); 1382 if ( ov->local ) 1383 anlist_free( ov->local, 1, NULL ); 1384 if ( ov->db.be_private != NULL ) { 1385 backend_stopdown_one( &ov->db ); 1386 } 1387 1388 ch_free(ov); 1389 on->on_bi.bi_private = NULL; 1390 } 1391 1392 return(rc); 1393 } 1394 1395 /* 1396 ** translucent_initialize() 1397 ** initialize the slap_overinst with our entry points; 1398 ** 1399 */ 1400 1401 int translucent_initialize() { 1402 1403 int rc; 1404 1405 Debug(LDAP_DEBUG_TRACE, "==> translucent_initialize\n", 0, 0, 0); 1406 1407 translucent.on_bi.bi_type = "translucent"; 1408 translucent.on_bi.bi_db_init = translucent_db_init; 1409 translucent.on_bi.bi_db_config = translucent_db_config; 1410 translucent.on_bi.bi_db_open = translucent_db_open; 1411 translucent.on_bi.bi_db_close = translucent_db_close; 1412 translucent.on_bi.bi_db_destroy = translucent_db_destroy; 1413 translucent.on_bi.bi_op_bind = translucent_bind; 1414 translucent.on_bi.bi_op_add = translucent_add; 1415 translucent.on_bi.bi_op_modify = translucent_modify; 1416 translucent.on_bi.bi_op_modrdn = translucent_modrdn; 1417 translucent.on_bi.bi_op_delete = translucent_delete; 1418 translucent.on_bi.bi_op_search = translucent_search; 1419 translucent.on_bi.bi_op_compare = translucent_compare; 1420 translucent.on_bi.bi_connection_destroy = translucent_connection_destroy; 1421 translucent.on_bi.bi_extended = translucent_exop; 1422 1423 translucent.on_bi.bi_cf_ocs = translucentocs; 1424 rc = config_register_schema ( translucentcfg, translucentocs ); 1425 if ( rc ) return rc; 1426 1427 return(overlay_register(&translucent)); 1428 } 1429 1430 #if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC) 1431 int init_module(int argc, char *argv[]) { 1432 return translucent_initialize(); 1433 } 1434 #endif 1435 1436 #endif /* SLAPD_OVER_TRANSLUCENT */ 1437