1 /* translucent.c - translucent proxy module */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/translucent.c,v 1.13.2.16 2008/04/14 21:13:44 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2005 Symas Corporation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by Symas Corp. for inclusion in
19 * OpenLDAP Software. This work was sponsored by Hewlett-Packard.
24 #ifdef SLAPD_OVER_TRANSLUCENT
28 #include <ac/string.h>
29 #include <ac/socket.h>
37 typedef struct translucent_info
{
38 BackendDB db
; /* captive backend */
39 AttributeName
*local
; /* valid attrs for local filters */
40 AttributeName
*remote
; /* valid attrs for remote filters */
46 static ConfigLDAPadd translucent_ldadd
;
47 static ConfigCfAdd translucent_cfadd
;
49 static ConfigDriver translucent_cf_gen
;
56 static ConfigTable translucentcfg
[] = {
57 { "translucent_strict", "on|off", 1, 2, 0,
58 ARG_ON_OFF
|ARG_OFFSET
,
59 (void *)offsetof(translucent_info
, strict
),
60 "( OLcfgOvAt:14.1 NAME 'olcTranslucentStrict' "
61 "DESC 'Reveal attribute deletion constraint violations' "
62 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL
, NULL
},
63 { "translucent_no_glue", "on|off", 1, 2, 0,
64 ARG_ON_OFF
|ARG_OFFSET
,
65 (void *)offsetof(translucent_info
, no_glue
),
66 "( OLcfgOvAt:14.2 NAME 'olcTranslucentNoGlue' "
67 "DESC 'Disable automatic glue records for ADD and MODRDN' "
68 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL
, NULL
},
69 { "translucent_local", "attr[,attr...]", 1, 2, 0,
70 ARG_STRING
|ARG_MAGIC
|TRANS_LOCAL
,
72 "( OLcfgOvAt:14.3 NAME 'olcTranslucentLocal' "
73 "DESC 'Attributes to use in local search filter' "
74 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
75 { "translucent_remote", "attr[,attr...]", 1, 2, 0,
76 ARG_STRING
|ARG_MAGIC
|TRANS_REMOTE
,
78 "( OLcfgOvAt:14.4 NAME 'olcTranslucentRemote' "
79 "DESC 'Attributes to use in remote search filter' "
80 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
81 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
}
84 static ConfigTable transdummy
[] = {
85 { "", "", 0, 0, 0, ARG_IGNORED
,
86 NULL
, "( OLcfgGlAt:13 NAME 'olcDatabase' "
87 "DESC 'The backend type for a database instance' "
88 "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL
, NULL
},
89 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
}
92 static ConfigOCs translucentocs
[] = {
94 "NAME 'olcTranslucentConfig' "
95 "DESC 'Translucent configuration' "
96 "SUP olcOverlayConfig "
97 "MAY ( olcTranslucentStrict $ olcTranslucentNoGlue $"
98 " olcTranslucentLocal $ olcTranslucentRemote ) )",
99 Cft_Overlay
, translucentcfg
, NULL
, translucent_cfadd
},
100 { "( OLcfgOvOc:14.2 "
101 "NAME 'olcTranslucentDatabase' "
102 "DESC 'Translucent target database configuration' "
103 "AUXILIARY )", Cft_Misc
, transdummy
, translucent_ldadd
},
106 /* for translucent_init() */
109 translucent_ldadd_cleanup( ConfigArgs
*ca
)
111 slap_overinst
*on
= ca
->ca_private
;
112 translucent_info
*ov
= on
->on_bi
.bi_private
;
114 ov
->defer_db_open
= 0;
115 return backend_startup_one( ca
->be
, &ca
->reply
);
119 translucent_ldadd( CfEntryInfo
*cei
, Entry
*e
, ConfigArgs
*ca
)
122 translucent_info
*ov
;
124 Debug(LDAP_DEBUG_TRACE
, "==> translucent_ldadd\n", 0, 0, 0);
126 if ( cei
->ce_type
!= Cft_Overlay
|| !cei
->ce_bi
||
127 cei
->ce_bi
->bi_cf_ocs
!= translucentocs
)
128 return LDAP_CONSTRAINT_VIOLATION
;
130 on
= (slap_overinst
*)cei
->ce_bi
;
131 ov
= on
->on_bi
.bi_private
;
134 if ( CONFIG_ONLINE_ADD( ca
))
135 ca
->cleanup
= translucent_ldadd_cleanup
;
137 ov
->defer_db_open
= 0;
143 translucent_cfadd( Operation
*op
, SlapReply
*rs
, Entry
*e
, ConfigArgs
*ca
)
145 CfEntryInfo
*cei
= e
->e_private
;
146 slap_overinst
*on
= (slap_overinst
*)cei
->ce_bi
;
147 translucent_info
*ov
= on
->on_bi
.bi_private
;
150 Debug(LDAP_DEBUG_TRACE
, "==> translucent_cfadd\n", 0, 0, 0);
152 /* FIXME: should not hardcode "olcDatabase" here */
153 bv
.bv_len
= snprintf( ca
->cr_msg
, sizeof( ca
->cr_msg
),
154 "olcDatabase=%s", ov
->db
.bd_info
->bi_type
);
155 if ( bv
.bv_len
< 0 || bv
.bv_len
>= sizeof( ca
->cr_msg
) ) {
158 bv
.bv_val
= ca
->cr_msg
;
160 ov
->defer_db_open
= 0;
162 /* We can only create this entry if the database is table-driven
164 if ( ov
->db
.bd_info
->bi_cf_ocs
)
165 config_build_entry( op
, rs
, cei
, ca
, &bv
,
166 ov
->db
.bd_info
->bi_cf_ocs
,
167 &translucentocs
[1] );
173 translucent_cf_gen( ConfigArgs
*c
)
175 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
176 translucent_info
*ov
= on
->on_bi
.bi_private
;
177 AttributeName
**an
, *a2
;
180 if ( c
->type
== TRANS_LOCAL
)
185 if ( c
->op
== SLAP_CONFIG_EMIT
) {
188 for ( i
= 0; !BER_BVISNULL(&(*an
)[i
].an_name
); i
++ ) {
189 value_add_one( &c
->rvalue_vals
, &(*an
)[i
].an_name
);
192 } else if ( c
->op
== LDAP_MOD_DELETE
) {
194 anlist_free( *an
, 1, NULL
);
198 ch_free( (*an
)[i
].an_name
.bv_val
);
200 (*an
)[i
] = (*an
)[i
+1];
201 } while ( !BER_BVISNULL( &(*an
)[i
].an_name
));
205 a2
= str2anlist( *an
, c
->argv
[1], "," );
207 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
), "%s unable to parse attribute %s",
208 c
->argv
[0], c
->argv
[1] );
209 Debug( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
210 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
217 static slap_overinst translucent
;
221 ** call syncrepl_add_glue() with the parent suffix;
225 static struct berval glue
[] = { BER_BVC("top"), BER_BVC("glue"), BER_BVNULL
};
227 void glue_parent(Operation
*op
) {
229 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
230 struct berval ndn
= BER_BVNULL
;
235 dnParent( &op
->o_req_ndn
, &pdn
);
236 ber_dupbv_x( &ndn
, &pdn
, op
->o_tmpmemctx
);
238 Debug(LDAP_DEBUG_TRACE
, "=> glue_parent: fabricating glue for <%s>\n", ndn
.bv_val
, 0, 0);
242 ber_dupbv(&e
->e_name
, &ndn
);
243 ber_dupbv(&e
->e_nname
, &ndn
);
245 a
= attr_alloc( slap_schema
.si_ad_objectClass
);
247 a
->a_vals
= ch_malloc(sizeof(struct berval
) * 3);
248 ber_dupbv(&a
->a_vals
[0], &glue
[0]);
249 ber_dupbv(&a
->a_vals
[1], &glue
[1]);
250 ber_dupbv(&a
->a_vals
[2], &glue
[2]);
251 a
->a_nvals
= a
->a_vals
;
252 a
->a_next
= e
->e_attrs
;
255 a
= attr_alloc( slap_schema
.si_ad_structuralObjectClass
);
257 a
->a_vals
= ch_malloc(sizeof(struct berval
) * 2);
258 ber_dupbv(&a
->a_vals
[0], &glue
[1]);
259 ber_dupbv(&a
->a_vals
[1], &glue
[2]);
260 a
->a_nvals
= a
->a_vals
;
261 a
->a_next
= e
->e_attrs
;
268 nop
.o_bd
->bd_info
= (BackendInfo
*) on
->on_info
->oi_orig
;
269 syncrepl_add_glue(&nop
, e
);
270 nop
.o_bd
->bd_info
= (BackendInfo
*) on
;
272 op
->o_tmpfree( ndn
.bv_val
, op
->o_tmpmemctx
);
282 BerVarray
dup_bervarray(BerVarray b
) {
285 for(len
= 0; b
[len
].bv_val
; len
++);
286 nb
= ch_malloc((len
+1) * sizeof(BerValue
));
287 for(i
= 0; i
< len
; i
++) ber_dupbv(&nb
[i
], &b
[i
]);
288 nb
[len
].bv_val
= NULL
;
295 ** free only the Attribute*, not the contents;
298 void free_attr_chain(Attribute
*b
) {
300 for(a
=b
; a
; a
=a
->a_next
) {
310 ** if not bound as root, send ACCESS error;
311 ** if glue, glue_parent();
316 static int translucent_add(Operation
*op
, SlapReply
*rs
) {
317 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
318 translucent_info
*ov
= on
->on_bi
.bi_private
;
319 Debug(LDAP_DEBUG_TRACE
, "==> translucent_add: %s\n",
320 op
->o_req_dn
.bv_val
, 0, 0);
322 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
323 send_ldap_error(op
, rs
, LDAP_INSUFFICIENT_ACCESS
,
324 "user modification of overlay database not permitted");
325 op
->o_bd
->bd_info
= (BackendInfo
*) on
;
328 if(!ov
->no_glue
) glue_parent(op
);
329 return(SLAP_CB_CONTINUE
);
333 ** translucent_modrdn()
334 ** if not bound as root, send ACCESS error;
335 ** if !glue, glue_parent();
336 ** else return CONTINUE;
340 static int translucent_modrdn(Operation
*op
, SlapReply
*rs
) {
341 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
342 translucent_info
*ov
= on
->on_bi
.bi_private
;
343 Debug(LDAP_DEBUG_TRACE
, "==> translucent_modrdn: %s -> %s\n",
344 op
->o_req_dn
.bv_val
, op
->orr_newrdn
.bv_val
, 0);
346 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
347 send_ldap_error(op
, rs
, LDAP_INSUFFICIENT_ACCESS
,
348 "user modification of overlay database not permitted");
349 op
->o_bd
->bd_info
= (BackendInfo
*) on
;
353 op
->o_tag
= LDAP_REQ_ADD
;
355 op
->o_tag
= LDAP_REQ_MODRDN
;
357 return(SLAP_CB_CONTINUE
);
361 ** translucent_delete()
362 ** if not bound as root, send ACCESS error;
363 ** else return CONTINUE;
367 static int translucent_delete(Operation
*op
, SlapReply
*rs
) {
368 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
369 Debug(LDAP_DEBUG_TRACE
, "==> translucent_delete: %s\n",
370 op
->o_req_dn
.bv_val
, 0, 0);
372 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
373 send_ldap_error(op
, rs
, LDAP_INSUFFICIENT_ACCESS
,
374 "user modification of overlay database not permitted");
375 op
->o_bd
->bd_info
= (BackendInfo
*) on
;
378 return(SLAP_CB_CONTINUE
);
382 translucent_tag_cb( Operation
*op
, SlapReply
*rs
)
384 op
->o_tag
= LDAP_REQ_MODIFY
;
385 op
->orm_modlist
= op
->o_callback
->sc_private
;
386 rs
->sr_tag
= slap_req2res( op
->o_tag
);
388 return SLAP_CB_CONTINUE
;
392 ** translucent_modify()
393 ** modify in local backend if exists in both;
394 ** otherwise, add to local backend;
395 ** fail if not defined in captive backend;
399 static int translucent_modify(Operation
*op
, SlapReply
*rs
) {
400 SlapReply nrs
= { REP_RESULT
};
402 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
403 translucent_info
*ov
= on
->on_bi
.bi_private
;
404 Entry
*e
= NULL
, *re
= NULL
;
406 Modifications
*m
, **mm
;
408 int del
, rc
, erc
= 0;
409 slap_callback cb
= { 0 };
411 Debug(LDAP_DEBUG_TRACE
, "==> translucent_modify: %s\n",
412 op
->o_req_dn
.bv_val
, 0, 0);
414 if(ov
->defer_db_open
) {
415 send_ldap_error(op
, rs
, LDAP_UNAVAILABLE
,
416 "remote DB not available");
420 ** fetch entry from the captive backend;
421 ** if it did not exist, fail;
422 ** release it, if captive backend supports this;
428 rc
= ov
->db
.bd_info
->bi_entry_get_rw(op
, &op
->o_req_ndn
, NULL
, NULL
, 0, &re
);
429 if(rc
!= LDAP_SUCCESS
|| re
== NULL
) {
430 send_ldap_error((op
), rs
, LDAP_NO_SUCH_OBJECT
,
431 "attempt to modify nonexistent local record");
436 ** fetch entry from local backend;
438 ** foreach Modification:
439 ** if attr not present in local:
440 ** if Mod == LDAP_MOD_DELETE:
441 ** if remote attr not present, return NO_SUCH;
442 ** if remote attr present, drop this Mod;
443 ** else force this Mod to LDAP_MOD_ADD;
448 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
449 rc
= be_entry_get_rw(op
, &op
->o_req_ndn
, NULL
, NULL
, 0, &e
);
450 op
->o_bd
->bd_info
= (BackendInfo
*) on
;
452 if(e
&& rc
== LDAP_SUCCESS
) {
453 Debug(LDAP_DEBUG_TRACE
, "=> translucent_modify: found local entry\n", 0, 0, 0);
454 for(mm
= &op
->orm_modlist
; *mm
; ) {
456 for(a
= e
->e_attrs
; a
; a
= a
->a_next
)
457 if(a
->a_desc
== m
->sml_desc
) break;
460 continue; /* found local attr */
462 if(m
->sml_op
== LDAP_MOD_DELETE
) {
463 for(a
= re
->e_attrs
; a
; a
= a
->a_next
)
464 if(a
->a_desc
== m
->sml_desc
) break;
465 /* not found remote attr */
467 erc
= LDAP_NO_SUCH_ATTRIBUTE
;
471 erc
= LDAP_CONSTRAINT_VIOLATION
;
474 Debug(LDAP_DEBUG_TRACE
,
475 "=> translucent_modify: silently dropping delete: %s\n",
476 m
->sml_desc
->ad_cname
.bv_val
, 0, 0);
479 slap_mods_free(m
, 1);
482 m
->sml_op
= LDAP_MOD_ADD
;
485 erc
= SLAP_CB_CONTINUE
;
488 if(ov
->db
.bd_info
->bi_entry_release_rw
) {
490 ov
->db
.bd_info
->bi_entry_release_rw(op
, re
, 0);
495 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
496 be_entry_release_r(op
, e
);
497 op
->o_bd
->bd_info
= (BackendInfo
*) on
;
498 if(erc
== SLAP_CB_CONTINUE
) {
501 send_ldap_error(op
, rs
, erc
,
502 "attempt to delete nonexistent attribute");
507 /* don't leak remote entry copy */
509 if(ov
->db
.bd_info
->bi_entry_release_rw
) {
511 ov
->db
.bd_info
->bi_entry_release_rw(op
, re
, 0);
517 ** foreach Modification:
518 ** if MOD_ADD or MOD_REPLACE, add Attribute;
519 ** if no Modifications were suitable:
520 ** if strict, throw CONSTRAINT_VIOLATION;
521 ** else, return early SUCCESS;
522 ** fabricate Entry with new Attribute chain;
523 ** glue_parent() for this Entry;
524 ** call bi_op_add() in local backend;
528 Debug(LDAP_DEBUG_TRACE
, "=> translucent_modify: fabricating local add\n", 0, 0, 0);
530 for(del
= 0, ax
= NULL
, m
= op
->orm_modlist
; m
; m
= m
->sml_next
) {
532 if(((m
->sml_op
& LDAP_MOD_OP
) != LDAP_MOD_ADD
) &&
533 ((m
->sml_op
& LDAP_MOD_OP
) != LDAP_MOD_REPLACE
)) {
534 Debug(LDAP_DEBUG_ANY
,
535 "=> translucent_modify: silently dropped modification(%d): %s\n",
536 m
->sml_op
, m
->sml_desc
->ad_cname
.bv_val
, 0);
537 if((m
->sml_op
& LDAP_MOD_OP
) == LDAP_MOD_DELETE
) del
++;
540 atmp
.a_desc
= m
->sml_desc
;
541 atmp
.a_vals
= m
->sml_values
;
542 atmp
.a_nvals
= m
->sml_nvalues
? m
->sml_nvalues
: atmp
.a_vals
;
543 atmp
.a_numvals
= m
->sml_numvals
;
545 a
= attr_dup( &atmp
);
550 if(del
&& ov
->strict
) {
552 send_ldap_error(op
, rs
, LDAP_CONSTRAINT_VIOLATION
,
553 "attempt to delete attributes from local database");
559 send_ldap_error(op
, rs
, LDAP_CONSTRAINT_VIOLATION
,
560 "modification contained other than ADD or REPLACE");
563 /* rs->sr_text = "no valid modification found"; */
564 rs
->sr_err
= LDAP_SUCCESS
;
565 send_ldap_result(op
, rs
);
570 ber_dupbv( &e
->e_name
, &op
->o_req_dn
);
571 ber_dupbv( &e
->e_nname
, &op
->o_req_ndn
);
574 op
->o_tag
= LDAP_REQ_ADD
;
575 cb
.sc_response
= translucent_tag_cb
;
576 cb
.sc_private
= op
->orm_modlist
;
581 cb
.sc_next
= op
->o_callback
;
582 op
->o_callback
= &cb
;
583 rc
= on
->on_info
->oi_orig
->bi_op_add(op
, &nrs
);
584 if ( op
->ora_e
== e
)
586 op
->o_callback
= cb
.sc_next
;
591 static int translucent_compare(Operation
*op
, SlapReply
*rs
) {
592 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
593 translucent_info
*ov
= on
->on_bi
.bi_private
;
594 AttributeAssertion
*ava
= op
->orc_ava
;
599 Debug(LDAP_DEBUG_TRACE
, "==> translucent_compare: <%s> %s:%s\n",
600 op
->o_req_dn
.bv_val
, ava
->aa_desc
->ad_cname
.bv_val
, ava
->aa_value
.bv_val
);
603 ** if the local backend has an entry for this attribute:
604 ** CONTINUE and let it do the compare;
607 rc
= overlay_entry_get_ov(op
, &op
->o_req_ndn
, NULL
, ava
->aa_desc
, 0, &e
, on
);
608 if(rc
== LDAP_SUCCESS
&& e
) {
609 overlay_entry_release_ov(op
, e
, 0, on
);
610 return(SLAP_CB_CONTINUE
);
613 if(ov
->defer_db_open
) {
614 send_ldap_error(op
, rs
, LDAP_UNAVAILABLE
,
615 "remote DB not available");
619 ** call compare() in the captive backend;
620 ** return the result;
625 rc
= ov
->db
.bd_info
->bi_op_compare(op
, rs
);
632 ** translucent_search_cb()
633 ** merge local data with remote data
636 ** 1: remote search, no local filter
637 ** merge data and send immediately
638 ** 2: remote search, with local filter
639 ** merge data and save
640 ** 3: local search, no remote filter
641 ** merge data and send immediately
642 ** 4: local search, with remote filter
643 ** check list, merge, send, delete
650 typedef struct trans_ctx
{
658 static int translucent_search_cb(Operation
*op
, SlapReply
*rs
) {
662 translucent_info
*ov
;
664 Attribute
*a
, *ax
, *an
, *as
= NULL
;
667 tc
= op
->o_callback
->sc_private
;
669 /* Don't let the op complete while we're gathering data */
670 if ( rs
->sr_type
== REP_RESULT
&& ( tc
->step
& USE_LIST
))
673 if(!op
|| !rs
|| rs
->sr_type
!= REP_SEARCH
|| !rs
->sr_entry
)
674 return(SLAP_CB_CONTINUE
);
676 Debug(LDAP_DEBUG_TRACE
, "==> translucent_search_cb: %s\n",
677 rs
->sr_entry
->e_name
.bv_val
, 0, 0);
680 ov
= on
->on_bi
.bi_private
;
685 /* If we have local, get remote */
686 if ( tc
->step
& LCL_SIDE
) {
688 /* If entry is already on list, use it */
689 if ( tc
->step
& USE_LIST
) {
690 re
= tavl_delete( &tc
->list
, le
, entry_dn_cmp
);
692 if ( rs
->sr_flags
& REP_ENTRY_MUSTRELEASE
) {
693 rs
->sr_flags
^= REP_ENTRY_MUSTRELEASE
;
694 be_entry_release_r( op
, rs
->sr_entry
);
696 if ( rs
->sr_flags
& REP_ENTRY_MUSTBEFREED
) {
697 rs
->sr_flags
^= REP_ENTRY_MUSTBEFREED
;
698 entry_free( rs
->sr_entry
);
700 rc
= test_filter( op
, re
, tc
->orig
);
701 if ( rc
== LDAP_COMPARE_TRUE
) {
702 rs
->sr_flags
|= REP_ENTRY_MUSTBEFREED
;
704 return SLAP_CB_CONTINUE
;
713 rc
= be_entry_get_rw( op
, &rs
->sr_entry
->e_nname
, NULL
, NULL
, 0, &re
);
714 if ( rc
== LDAP_SUCCESS
&& re
) {
715 Entry
*tmp
= entry_dup( re
);
716 be_entry_release_r( op
, re
);
720 /* Else we have remote, get local */
722 rc
= overlay_entry_get_ov(op
, &rs
->sr_entry
->e_nname
, NULL
, NULL
, 0, &le
, on
);
723 if ( rc
== LDAP_SUCCESS
&& le
) {
724 re
= entry_dup( rs
->sr_entry
);
725 if ( rs
->sr_flags
& REP_ENTRY_MUSTRELEASE
) {
726 rs
->sr_flags
^= REP_ENTRY_MUSTRELEASE
;
727 be_entry_release_r( op
, rs
->sr_entry
);
729 if ( rs
->sr_flags
& REP_ENTRY_MUSTBEFREED
) {
730 rs
->sr_flags
^= REP_ENTRY_MUSTBEFREED
;
731 entry_free( rs
->sr_entry
);
739 ** if we got remote and local entry:
740 ** foreach local attr:
741 ** foreach remote attr:
742 ** if match, remote attr with local attr;
743 ** if new local, add to list;
744 ** append new local attrs to remote;
749 for(ax
= le
->e_attrs
; ax
; ax
= ax
->a_next
) {
750 for(a
= re
->e_attrs
; a
; a
= a
->a_next
) {
751 if(a
->a_desc
== ax
->a_desc
) {
752 if(a
->a_vals
!= a
->a_nvals
)
753 ber_bvarray_free(a
->a_nvals
);
754 ber_bvarray_free(a
->a_vals
);
755 a
->a_vals
= dup_bervarray(ax
->a_vals
);
756 a
->a_nvals
= (ax
->a_vals
== ax
->a_nvals
) ?
757 a
->a_vals
: dup_bervarray(ax
->a_nvals
);
766 /* Dispose of local entry */
767 if ( tc
->step
& LCL_SIDE
) {
768 if ( rs
->sr_flags
& REP_ENTRY_MUSTRELEASE
) {
769 rs
->sr_flags
^= REP_ENTRY_MUSTRELEASE
;
770 be_entry_release_r( op
, rs
->sr_entry
);
772 if ( rs
->sr_flags
& REP_ENTRY_MUSTBEFREED
) {
773 rs
->sr_flags
^= REP_ENTRY_MUSTBEFREED
;
774 entry_free( rs
->sr_entry
);
777 overlay_entry_release_ov(op
, le
, 0, on
);
780 /* literally append, so locals are always last */
783 for(ax
= re
->e_attrs
; ax
->a_next
; ax
= ax
->a_next
);
789 /* If both filters, save entry for later */
790 if ( tc
->step
== (USE_LIST
|RMT_SIDE
) ) {
791 tavl_insert( &tc
->list
, re
, entry_dn_cmp
, avl_dup_error
);
797 rs
->sr_flags
|= REP_ENTRY_MUSTBEFREED
;
798 rc
= SLAP_CB_CONTINUE
;
801 /* Only a local entry: remote was deleted
802 * Ought to delete the local too...
805 } else if ( tc
->step
& USE_LIST
) {
806 /* Only a remote entry, but both filters:
807 * Test the complete filter
809 rc
= test_filter( op
, rs
->sr_entry
, tc
->orig
);
810 if ( rc
== LDAP_COMPARE_TRUE
) {
811 rc
= SLAP_CB_CONTINUE
;
816 /* Only a remote entry, only remote filter:
819 rc
= SLAP_CB_CONTINUE
;
826 /* Dup the filter, excluding invalid elements */
828 trans_filter_dup(Operation
*op
, Filter
*f
, AttributeName
*an
)
835 switch( f
->f_choice
& SLAPD_FILTER_MASK
) {
836 case SLAPD_FILTER_COMPUTED
:
837 n
= op
->o_tmpalloc( sizeof(Filter
), op
->o_tmpmemctx
);
838 n
->f_choice
= f
->f_choice
;
839 n
->f_result
= f
->f_result
;
843 case LDAP_FILTER_PRESENT
:
844 if ( ad_inlist( f
->f_desc
, an
)) {
845 n
= op
->o_tmpalloc( sizeof(Filter
), op
->o_tmpmemctx
);
846 n
->f_choice
= f
->f_choice
;
847 n
->f_desc
= f
->f_desc
;
852 case LDAP_FILTER_EQUALITY
:
855 case LDAP_FILTER_APPROX
:
856 case LDAP_FILTER_SUBSTRINGS
:
857 case LDAP_FILTER_EXT
:
858 if ( !f
->f_av_desc
|| ad_inlist( f
->f_av_desc
, an
)) {
859 n
= op
->o_tmpalloc( sizeof(Filter
), op
->o_tmpmemctx
);
860 n
->f_choice
= f
->f_choice
;
866 case LDAP_FILTER_AND
:
868 case LDAP_FILTER_NOT
: {
871 n
= op
->o_tmpalloc( sizeof(Filter
), op
->o_tmpmemctx
);
872 n
->f_choice
= f
->f_choice
;
875 for ( p
= &n
->f_list
, f
= f
->f_list
; f
; f
= f
->f_next
) {
876 *p
= trans_filter_dup( op
, f
, an
);
881 /* nothing valid in this list */
883 op
->o_tmpfree( n
, op
->o_tmpmemctx
);
886 /* Only 1 element in this list */
887 if ((n
->f_choice
& SLAPD_FILTER_MASK
) != LDAP_FILTER_NOT
&&
888 !n
->f_list
->f_next
) {
891 op
->o_tmpfree( f
, op
->o_tmpmemctx
);
900 trans_filter_free( Operation
*op
, Filter
*f
)
902 Filter
*n
, *p
, *next
;
904 f
->f_choice
&= SLAPD_FILTER_MASK
;
906 switch( f
->f_choice
) {
907 case LDAP_FILTER_AND
:
909 case LDAP_FILTER_NOT
:
910 /* Free in reverse order */
912 for ( p
= f
->f_list
; p
; p
= next
) {
917 for ( p
= n
; p
; p
= next
) {
919 trans_filter_free( op
, p
);
925 op
->o_tmpfree( f
, op
->o_tmpmemctx
);
929 ** translucent_search()
930 ** search via captive backend;
931 ** override results with any local data;
935 static int translucent_search(Operation
*op
, SlapReply
*rs
) {
936 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
937 translucent_info
*ov
= on
->on_bi
.bi_private
;
938 slap_callback cb
= { NULL
, NULL
, NULL
, NULL
};
944 Debug(LDAP_DEBUG_TRACE
, "==> translucent_search: <%s> %s\n",
945 op
->o_req_dn
.bv_val
, op
->ors_filterstr
.bv_val
, 0);
947 if(ov
->defer_db_open
) {
948 send_ldap_error(op
, rs
, LDAP_UNAVAILABLE
,
949 "remote DB not available");
953 fr
= ov
->remote
? trans_filter_dup( op
, op
->ors_filter
, ov
->remote
) : NULL
;
954 fl
= ov
->local
? trans_filter_dup( op
, op
->ors_filter
, ov
->local
) : NULL
;
955 cb
.sc_response
= (slap_response
*) translucent_search_cb
;
957 cb
.sc_next
= op
->o_callback
;
961 tc
.orig
= op
->ors_filter
;
964 fbv
= op
->ors_filterstr
;
966 op
->o_callback
= &cb
;
974 filter2bv_x( op
, fr
, &op
->ors_filterstr
);
976 rc
= ov
->db
.bd_info
->bi_op_search(op
, rs
);
979 op
->o_tmpfree( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
985 filter2bv_x( op
, fl
, &op
->ors_filterstr
);
986 rc
= overlay_op_walk( op
, rs
, op_search
, on
->on_info
, on
->on_next
);
987 op
->o_tmpfree( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
989 op
->ors_filterstr
= fbv
;
990 op
->ors_filter
= tc
.orig
;
991 op
->o_callback
= cb
.sc_next
;
992 /* Send out anything remaining on the list and finish */
993 if ( tc
.step
& USE_LIST
) {
997 av
= tavl_end( tc
.list
, TAVL_DIR_LEFT
);
999 rs
->sr_entry
= av
->avl_data
;
1000 rc
= test_filter( op
, rs
->sr_entry
, op
->ors_filter
);
1001 if ( rc
== LDAP_COMPARE_TRUE
) {
1002 rs
->sr_flags
= REP_ENTRY_MUSTBEFREED
;
1003 rc
= send_search_entry( op
, rs
);
1006 entry_free( rs
->sr_entry
);
1008 av
= tavl_next( av
, TAVL_DIR_RIGHT
);
1010 tavl_free( tc
.list
, NULL
);
1011 rs
->sr_entry
= NULL
;
1013 send_ldap_result( op
, rs
);
1016 /* Free in reverse order */
1018 trans_filter_free( op
, fl
);
1020 trans_filter_free( op
, fr
);
1027 ** translucent_bind()
1028 ** pass bind request to captive backend;
1032 static int translucent_bind(Operation
*op
, SlapReply
*rs
) {
1033 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
1034 translucent_info
*ov
= on
->on_bi
.bi_private
;
1038 Debug(LDAP_DEBUG_TRACE
, "translucent_bind: <%s> method %d\n",
1039 op
->o_req_dn
.bv_val
, op
->orb_method
, 0);
1041 if(ov
->defer_db_open
) {
1042 send_ldap_error(op
, rs
, LDAP_UNAVAILABLE
,
1043 "remote DB not available");
1048 rc
= ov
->db
.bd_info
->bi_op_bind(op
, rs
);
1054 ** translucent_connection_destroy()
1055 ** pass disconnect notification to captive backend;
1059 static int translucent_connection_destroy(BackendDB
*be
, Connection
*conn
) {
1060 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
1061 translucent_info
*ov
= on
->on_bi
.bi_private
;
1064 Debug(LDAP_DEBUG_TRACE
, "translucent_connection_destroy\n", 0, 0, 0);
1066 rc
= ov
->db
.bd_info
->bi_connection_destroy(&ov
->db
, conn
);
1072 ** translucent_db_config()
1073 ** pass config directives to captive backend;
1074 ** parse unrecognized directives ourselves;
1078 static int translucent_db_config(
1086 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
1087 translucent_info
*ov
= on
->on_bi
.bi_private
;
1089 Debug(LDAP_DEBUG_TRACE
, "==> translucent_db_config: %s\n",
1090 argc
? argv
[0] : "", 0, 0);
1092 /* Something for the captive database? */
1093 if ( ov
->db
.bd_info
&& ov
->db
.bd_info
->bi_db_config
)
1094 return ov
->db
.bd_info
->bi_db_config( &ov
->db
, fname
, lineno
,
1096 return SLAP_CONF_UNKNOWN
;
1100 ** translucent_db_init()
1101 ** initialize the captive backend;
1105 static int translucent_db_init(BackendDB
*be
, ConfigReply
*cr
) {
1106 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
1107 translucent_info
*ov
;
1109 Debug(LDAP_DEBUG_TRACE
, "==> translucent_db_init\n", 0, 0, 0);
1111 ov
= ch_calloc(1, sizeof(translucent_info
));
1112 on
->on_bi
.bi_private
= ov
;
1114 ov
->db
.be_private
= NULL
;
1115 ov
->db
.be_pcl_mutexp
= &ov
->db
.be_pcl_mutex
;
1116 ov
->defer_db_open
= 1;
1118 if ( !backend_db_init( "ldap", &ov
->db
, -1, NULL
)) {
1119 Debug( LDAP_DEBUG_CONFIG
, "translucent: unable to open captive back-ldap\n", 0, 0, 0);
1122 SLAP_DBFLAGS(be
) |= SLAP_DBFLAG_NO_SCHEMA_CHECK
;
1123 SLAP_DBFLAGS(be
) |= SLAP_DBFLAG_NOLASTMOD
;
1129 ** translucent_db_open()
1130 ** if the captive backend has an open() method, call it;
1134 static int translucent_db_open(BackendDB
*be
, ConfigReply
*cr
) {
1135 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
1136 translucent_info
*ov
= on
->on_bi
.bi_private
;
1139 Debug(LDAP_DEBUG_TRACE
, "==> translucent_db_open\n", 0, 0, 0);
1141 /* need to inherit something from the original database... */
1142 ov
->db
.be_def_limit
= be
->be_def_limit
;
1143 ov
->db
.be_limits
= be
->be_limits
;
1144 ov
->db
.be_acl
= be
->be_acl
;
1145 ov
->db
.be_dfltaccess
= be
->be_dfltaccess
;
1147 if ( ov
->defer_db_open
)
1150 rc
= backend_startup_one( &ov
->db
, cr
);
1152 if(rc
) Debug(LDAP_DEBUG_TRACE
,
1153 "translucent: bi_db_open() returned error %d\n", rc
, 0, 0);
1159 ** translucent_db_close()
1160 ** if the captive backend has a close() method, call it
1165 translucent_db_close( BackendDB
*be
, ConfigReply
*cr
)
1167 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
1168 translucent_info
*ov
= on
->on_bi
.bi_private
;
1171 Debug(LDAP_DEBUG_TRACE
, "==> translucent_db_close\n", 0, 0, 0);
1173 if ( ov
&& ov
->db
.bd_info
&& ov
->db
.bd_info
->bi_db_close
) {
1174 rc
= ov
->db
.bd_info
->bi_db_close(&ov
->db
, NULL
);
1181 ** translucent_db_destroy()
1182 ** if the captive backend has a db_destroy() method, call it;
1183 ** free any config data
1188 translucent_db_destroy( BackendDB
*be
, ConfigReply
*cr
)
1190 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
1191 translucent_info
*ov
= on
->on_bi
.bi_private
;
1194 Debug(LDAP_DEBUG_TRACE
, "==> translucent_db_destroy\n", 0, 0, 0);
1198 anlist_free( ov
->remote
, 1, NULL
);
1200 anlist_free( ov
->local
, 1, NULL
);
1201 if ( ov
->db
.be_private
!= NULL
) {
1202 backend_stopdown_one( &ov
->db
);
1206 on
->on_bi
.bi_private
= NULL
;
1213 ** translucent_initialize()
1214 ** initialize the slap_overinst with our entry points;
1218 int translucent_initialize() {
1222 Debug(LDAP_DEBUG_TRACE
, "==> translucent_initialize\n", 0, 0, 0);
1224 translucent
.on_bi
.bi_type
= "translucent";
1225 translucent
.on_bi
.bi_db_init
= translucent_db_init
;
1226 translucent
.on_bi
.bi_db_config
= translucent_db_config
;
1227 translucent
.on_bi
.bi_db_open
= translucent_db_open
;
1228 translucent
.on_bi
.bi_db_close
= translucent_db_close
;
1229 translucent
.on_bi
.bi_db_destroy
= translucent_db_destroy
;
1230 translucent
.on_bi
.bi_op_bind
= translucent_bind
;
1231 translucent
.on_bi
.bi_op_add
= translucent_add
;
1232 translucent
.on_bi
.bi_op_modify
= translucent_modify
;
1233 translucent
.on_bi
.bi_op_modrdn
= translucent_modrdn
;
1234 translucent
.on_bi
.bi_op_delete
= translucent_delete
;
1235 translucent
.on_bi
.bi_op_search
= translucent_search
;
1236 translucent
.on_bi
.bi_op_compare
= translucent_compare
;
1237 translucent
.on_bi
.bi_connection_destroy
= translucent_connection_destroy
;
1239 translucent
.on_bi
.bi_cf_ocs
= translucentocs
;
1240 rc
= config_register_schema ( translucentcfg
, translucentocs
);
1241 if ( rc
) return rc
;
1243 return(overlay_register(&translucent
));
1246 #if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC)
1247 int init_module(int argc
, char *argv
[]) {
1248 return translucent_initialize();
1252 #endif /* SLAPD_OVER_TRANSLUCENT */