1 /* rwm.c - rewrite/remap operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2006 The OpenLDAP Foundation.
6 * Portions Copyright 2003 Pierangelo Masarati.
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>.
24 #include <ac/string.h>
30 rwm_db_destroy( BackendDB *be );
33 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie )
35 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
36 struct ldaprwmap *rwmap =
37 (struct ldaprwmap *)on->on_bi.bi_private;
39 struct berval dn = BER_BVNULL,
45 * Rewrite the dn if needed
51 dc.ctx = (char *)cookie;
52 #else /* ! ENABLE_REWRITE */
53 dc.tofrom = ((int *)cookie)[0];
55 #endif /* ! ENABLE_REWRITE */
57 /* NOTE: in those cases where only the ndn is available,
58 * and the caller sets op->o_req_dn = op->o_req_ndn,
59 * only rewrite the op->o_req_ndn and use it as
60 * op->o_req_dn as well */
62 if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
64 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
66 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
69 if ( rc != LDAP_SUCCESS ) {
73 if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
74 || ndn.bv_val == op->o_req_ndn.bv_val )
79 if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
80 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
85 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
92 rwm_op_add( Operation *op, SlapReply *rs )
94 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
95 struct ldaprwmap *rwmap =
96 (struct ldaprwmap *)on->on_bi.bi_private;
100 Attribute **ap = NULL;
101 char *olddn = op->o_req_dn.bv_val;
104 #ifdef ENABLE_REWRITE
105 rc = rwm_op_dn_massage( op, rs, "addDN" );
106 #else /* ! ENABLE_REWRITE */
108 rc = rwm_op_dn_massage( op, rs, &rc );
109 #endif /* ! ENABLE_REWRITE */
110 if ( rc != LDAP_SUCCESS ) {
111 op->o_bd->bd_info = (BackendInfo *)on->on_info;
112 send_ldap_error( op, rs, rc, "addDN massage error" );
116 if ( olddn != op->o_req_dn.bv_val ) {
117 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
118 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
121 /* Count number of attributes in entry */
122 isupdate = be_shadow_update( op );
123 for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
126 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
127 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
131 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[ last ] ); last++ )
134 for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
135 struct ldapmapping *mapping = NULL;
137 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
139 if ( mapping == NULL ) {
140 if ( rwmap->rwm_at.drop_missing ) {
141 /* FIXME: we allow to remove objectClasses as well;
142 * if the resulting entry is inconsistent, that's
143 * the relayed database's business...
145 ch_free( (*ap)->a_vals[ j ].bv_val );
147 (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
149 BER_BVZERO( &(*ap)->a_vals[ last ] );
155 ch_free( (*ap)->a_vals[ j ].bv_val );
156 ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
160 } else if ( !isupdate && !get_manageDIT( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
165 struct ldapmapping *mapping = NULL;
167 ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
169 if ( mapping == NULL ) {
170 if ( rwmap->rwm_at.drop_missing ) {
175 if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
176 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
179 * FIXME: rewrite could fail; in this case
180 * the operation should give up, right?
182 #ifdef ENABLE_REWRITE
183 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
185 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
186 #else /* ! ENABLE_REWRITE */
188 rc = rwm_dnattr_rewrite( op, rs, &rc, (*ap)->a_vals,
189 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
190 #endif /* ! ENABLE_REWRITE */
195 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
196 #ifdef ENABLE_REWRITE
197 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
199 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
200 #else /* ! ENABLE_REWRITE */
202 rc = rwm_referral_rewrite( op, rs, &rc, (*ap)->a_vals,
203 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
204 #endif /* ! ENABLE_REWRITE */
205 if ( rc != LDAP_SUCCESS ) {
210 if ( mapping != NULL ) {
211 assert( mapping->m_dst_ad != NULL );
212 (*ap)->a_desc = mapping->m_dst_ad;
221 /* FIXME: leaking attribute/values? */
228 /* TODO: map attribute types, values of DN-valued attributes ... */
229 return SLAP_CB_CONTINUE;
232 #ifdef ENABLE_REWRITE
234 rwm_conn_init( BackendDB *be, Connection *conn )
236 slap_overinst *on = (slap_overinst *) be->bd_info;
237 struct ldaprwmap *rwmap =
238 (struct ldaprwmap *)on->on_bi.bi_private;
240 ( void )rewrite_session_init( rwmap->rwm_rw, conn );
242 return SLAP_CB_CONTINUE;
246 rwm_conn_destroy( BackendDB *be, Connection *conn )
248 slap_overinst *on = (slap_overinst *) be->bd_info;
249 struct ldaprwmap *rwmap =
250 (struct ldaprwmap *)on->on_bi.bi_private;
252 ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
254 return SLAP_CB_CONTINUE;
256 #endif /* ENABLE_REWRITE */
259 rwm_op_bind( Operation *op, SlapReply *rs )
261 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
264 #ifdef ENABLE_REWRITE
265 rc = rwm_op_dn_massage( op, rs, "bindDN" );
266 #else /* ! ENABLE_REWRITE */
268 rc = rwm_op_dn_massage( op, rs, &rc );
269 #endif /* ! ENABLE_REWRITE */
270 if ( rc != LDAP_SUCCESS ) {
271 op->o_bd->bd_info = (BackendInfo *)on->on_info;
272 send_ldap_error( op, rs, rc, "bindDN massage error" );
276 return SLAP_CB_CONTINUE;
280 rwm_op_unbind( Operation *op, SlapReply *rs )
282 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
283 struct ldaprwmap *rwmap =
284 (struct ldaprwmap *)on->on_bi.bi_private;
286 #ifdef ENABLE_REWRITE
287 rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
288 #endif /* ENABLE_REWRITE */
290 return SLAP_CB_CONTINUE;
294 rwm_op_compare( Operation *op, SlapReply *rs )
296 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
297 struct ldaprwmap *rwmap =
298 (struct ldaprwmap *)on->on_bi.bi_private;
301 struct berval mapped_at = BER_BVNULL,
302 mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
304 #ifdef ENABLE_REWRITE
305 rc = rwm_op_dn_massage( op, rs, "compareDN" );
306 #else /* ! ENABLE_REWRITE */
308 rc = rwm_op_dn_massage( op, rs, &rc );
309 #endif /* ! ENABLE_REWRITE */
310 if ( rc != LDAP_SUCCESS ) {
311 op->o_bd->bd_info = (BackendInfo *)on->on_info;
312 send_ldap_error( op, rs, rc, "compareDN massage error" );
316 /* if the attribute is an objectClass, try to remap its value */
317 if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
318 || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
320 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
321 &mapped_vals[0], RWM_MAP );
322 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
324 op->o_bd->bd_info = (BackendInfo *)on->on_info;
325 send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
328 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
329 ber_bvreplace_x( &op->orc_ava->aa_value, &mapped_vals[0], op->o_tmpmemctx );
331 mapped_at = op->orc_ava->aa_desc->ad_cname;
334 struct ldapmapping *mapping = NULL;
335 AttributeDescription *ad = op->orc_ava->aa_desc;
337 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
339 if ( mapping == NULL ) {
340 if ( rwmap->rwm_at.drop_missing ) {
341 op->o_bd->bd_info = (BackendInfo *)on->on_info;
342 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
347 assert( mapping->m_dst_ad != NULL );
348 ad = mapping->m_dst_ad;
351 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
352 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
354 struct berval *mapped_valsp[2];
356 mapped_valsp[0] = &mapped_vals[0];
357 mapped_valsp[1] = &mapped_vals[1];
359 mapped_vals[0] = op->orc_ava->aa_value;
361 #ifdef ENABLE_REWRITE
362 rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
363 #else /* ! ENABLE_REWRITE */
365 rc = rwm_dnattr_rewrite( op, rs, &rc, NULL, mapped_valsp );
366 #endif /* ! ENABLE_REWRITE */
368 if ( rc != LDAP_SUCCESS ) {
369 op->o_bd->bd_info = (BackendInfo *)on->on_info;
370 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
374 if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
375 /* NOTE: if we get here, rwm_dnattr_rewrite()
376 * already freed the old value, so now
378 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
380 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
383 op->orc_ava->aa_desc = ad;
386 return SLAP_CB_CONTINUE;
390 rwm_op_delete( Operation *op, SlapReply *rs )
392 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
395 #ifdef ENABLE_REWRITE
396 rc = rwm_op_dn_massage( op, rs, "deleteDN" );
397 #else /* ! ENABLE_REWRITE */
399 rc = rwm_op_dn_massage( op, rs, &rc );
400 #endif /* ! ENABLE_REWRITE */
401 if ( rc != LDAP_SUCCESS ) {
402 op->o_bd->bd_info = (BackendInfo *)on->on_info;
403 send_ldap_error( op, rs, rc, "deleteDN massage error" );
407 return SLAP_CB_CONTINUE;
411 rwm_op_modify( Operation *op, SlapReply *rs )
413 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
414 struct ldaprwmap *rwmap =
415 (struct ldaprwmap *)on->on_bi.bi_private;
421 #ifdef ENABLE_REWRITE
422 rc = rwm_op_dn_massage( op, rs, "modifyDN" );
423 #else /* ! ENABLE_REWRITE */
425 rc = rwm_op_dn_massage( op, rs, &rc );
426 #endif /* ! ENABLE_REWRITE */
427 if ( rc != LDAP_SUCCESS ) {
428 op->o_bd->bd_info = (BackendInfo *)on->on_info;
429 send_ldap_error( op, rs, rc, "modifyDN massage error" );
433 isupdate = be_shadow_update( op );
434 for ( mlp = &op->oq_modify.rs_modlist; *mlp; ) {
437 struct ldapmapping *mapping = NULL;
439 if ( (*mlp)->sml_desc == slap_schema.si_ad_objectClass
440 || (*mlp)->sml_desc == slap_schema.si_ad_structuralObjectClass )
444 } else if ( !isupdate && !get_manageDIT( op ) && (*mlp)->sml_desc->ad_type->sat_no_user_mod )
451 drop_missing = rwm_mapping( &rwmap->rwm_at,
452 &(*mlp)->sml_desc->ad_cname,
454 if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
460 if ( (*mlp)->sml_values != NULL ) {
464 for ( last = 0; !BER_BVISNULL( &(*mlp)->sml_values[ last ] ); last++ )
468 for ( j = 0; !BER_BVISNULL( &(*mlp)->sml_values[ j ] ); j++ ) {
469 struct ldapmapping *oc_mapping = NULL;
471 ( void )rwm_mapping( &rwmap->rwm_oc, &(*mlp)->sml_values[ j ],
472 &oc_mapping, RWM_MAP );
473 if ( oc_mapping == NULL ) {
474 if ( rwmap->rwm_at.drop_missing ) {
475 /* FIXME: we allow to remove objectClasses as well;
476 * if the resulting entry is inconsistent, that's
477 * the relayed database's business...
479 ch_free( (*mlp)->sml_values[ j ].bv_val );
481 (*mlp)->sml_values[ j ] = (*mlp)->sml_values[ last ];
483 BER_BVZERO( &(*mlp)->sml_values[ last ] );
489 ch_free( (*mlp)->sml_values[ j ].bv_val );
490 ber_dupbv( &(*mlp)->sml_values[ j ], &oc_mapping->m_dst );
495 if ( (*mlp)->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
496 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
498 #ifdef ENABLE_REWRITE
499 rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
501 (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
502 #else /* ! ENABLE_REWRITE */
504 rc = rwm_dnattr_rewrite( op, rs, &rc,
506 (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
507 #endif /* ! ENABLE_REWRITE */
509 } else if ( (*mlp)->sml_desc == slap_schema.si_ad_ref ) {
510 #ifdef ENABLE_REWRITE
511 rc = rwm_referral_rewrite( op, rs,
514 (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
515 #else /* ! ENABLE_REWRITE */
517 rc = rwm_referral_rewrite( op, rs, &rc,
519 (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
520 #endif /* ! ENABLE_REWRITE */
521 if ( rc != LDAP_SUCCESS ) {
526 if ( rc != LDAP_SUCCESS ) {
533 if ( mapping != NULL ) {
534 /* use new attribute description */
535 assert( mapping->m_dst_ad != NULL );
536 (*mlp)->sml_desc = mapping->m_dst_ad;
539 mlp = &(*mlp)->sml_next;
544 *mlp = (*mlp)->sml_next;
545 slap_mod_free( &ml->sml_mod, 0 );
549 return SLAP_CB_CONTINUE;
553 rwm_op_modrdn( Operation *op, SlapReply *rs )
555 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
556 struct ldaprwmap *rwmap =
557 (struct ldaprwmap *)on->on_bi.bi_private;
561 if ( op->orr_newSup ) {
563 struct berval nnewSup = BER_BVNULL;
564 struct berval newSup = BER_BVNULL;
567 * Rewrite the new superior, if defined and required
570 #ifdef ENABLE_REWRITE
571 dc.conn = op->o_conn;
573 dc.ctx = "newSuperiorDN";
574 #else /* ! ENABLE_REWRITE */
577 #endif /* ! ENABLE_REWRITE */
578 newSup = *op->orr_newSup;
579 nnewSup = *op->orr_nnewSup;
580 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
581 if ( rc != LDAP_SUCCESS ) {
582 op->o_bd->bd_info = (BackendInfo *)on->on_info;
583 send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
587 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
588 op->o_tmpfree( op->orr_newSup->bv_val, op->o_tmpmemctx );
589 op->o_tmpfree( op->orr_nnewSup->bv_val, op->o_tmpmemctx );
590 *op->orr_newSup = newSup;
591 *op->orr_nnewSup = nnewSup;
596 * Rewrite the dn, if needed
598 #ifdef ENABLE_REWRITE
599 rc = rwm_op_dn_massage( op, rs, "renameDN" );
600 #else /* ! ENABLE_REWRITE */
602 rc = rwm_op_dn_massage( op, rs, &rc );
603 #endif /* ! ENABLE_REWRITE */
604 if ( rc != LDAP_SUCCESS ) {
605 op->o_bd->bd_info = (BackendInfo *)on->on_info;
606 send_ldap_error( op, rs, rc, "renameDN massage error" );
610 /* TODO: rewrite newRDN, attribute types,
611 * values of DN-valued attributes ... */
612 return SLAP_CB_CONTINUE;
615 static slap_callback rwm_cb;
622 ber_memfree_x( data, NULL );
625 static slap_callback *
626 rwm_callback_get( Operation *op )
630 if ( op->o_threadctx == NULL ) {
634 ldap_pvt_thread_pool_getkey( op->o_threadctx,
635 rwm_keyfree, &data, NULL );
636 if ( data == NULL ) {
637 data = ch_calloc( sizeof( slap_callback ), 1 );
638 ldap_pvt_thread_pool_setkey( op->o_threadctx,
639 rwm_keyfree, data, rwm_keyfree );
642 return (slap_callback *)data;
646 rwm_swap_attrs( Operation *op, SlapReply *rs )
648 slap_callback *cb = op->o_callback;
649 AttributeName *an = (AttributeName *)cb->sc_private;
653 return SLAP_CB_CONTINUE;
657 rwm_op_search( Operation *op, SlapReply *rs )
659 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
660 struct ldaprwmap *rwmap =
661 (struct ldaprwmap *)on->on_bi.bi_private;
666 struct berval fstr = BER_BVNULL;
669 slap_callback *cb = NULL;
670 AttributeName *an = NULL;
674 #ifdef ENABLE_REWRITE
675 rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
676 "searchFilter", op->ors_filterstr.bv_val );
677 if ( rc == LDAP_SUCCESS )
678 rc = rwm_op_dn_massage( op, rs, "searchDN" );
679 #else /* ! ENABLE_REWRITE */
681 rc = rwm_op_dn_massage( op, rs, &rc );
682 #endif /* ! ENABLE_REWRITE */
683 if ( rc != LDAP_SUCCESS ) {
684 text = "searchDN massage error";
689 * Rewrite the dn if needed
692 #ifdef ENABLE_REWRITE
693 dc.conn = op->o_conn;
695 dc.ctx = "searchFilterAttrDN";
696 #else /* ! ENABLE_REWRITE */
699 #endif /* ! ENABLE_REWRITE */
701 rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
702 if ( rc != LDAP_SUCCESS ) {
703 text = "searchFilter/searchFilterAttrDN massage error";
707 f = str2filter_x( op, fstr.bv_val );
710 text = "massaged filter parse error";
714 if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
715 ch_free( op->ors_filterstr.bv_val );
718 if( op->ors_filter ) {
719 filter_free_x( op, op->ors_filter );
723 op->ors_filterstr = fstr;
725 rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
726 op->ors_attrs, &an, RWM_MAP );
727 if ( rc != LDAP_SUCCESS ) {
728 text = "attribute list mapping error";
732 cb = rwm_callback_get( op );
734 cb->sc_response = rwm_swap_attrs;
735 cb->sc_cleanup = NULL;
736 cb->sc_private = (void *)op->ors_attrs;
737 cb->sc_next = op->o_callback;
742 return SLAP_CB_CONTINUE;
750 filter_free_x( op, f );
753 if ( !BER_BVISNULL( &fstr ) ) {
754 ch_free( fstr.bv_val );
757 op->o_bd->bd_info = (BackendInfo *)on->on_info;
758 send_ldap_error( op, rs, rc, text );
765 rwm_extended( Operation *op, SlapReply *rs )
767 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
770 #ifdef ENABLE_REWRITE
771 rc = rwm_op_dn_massage( op, rs, "extendedDN" );
772 #else /* ! ENABLE_REWRITE */
774 rc = rwm_op_dn_massage( op, rs, &rc );
775 #endif /* ! ENABLE_REWRITE */
776 if ( rc != LDAP_SUCCESS ) {
777 op->o_bd->bd_info = (BackendInfo *)on->on_info;
778 send_ldap_error( op, rs, rc, "extendedDN massage error" );
782 /* TODO: rewrite/map extended data ? ... */
783 return SLAP_CB_CONTINUE;
787 rwm_matched( Operation *op, SlapReply *rs )
789 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
790 struct ldaprwmap *rwmap =
791 (struct ldaprwmap *)on->on_bi.bi_private;
793 struct berval dn, mdn;
797 if ( rs->sr_matched == NULL ) {
798 return SLAP_CB_CONTINUE;
802 #ifdef ENABLE_REWRITE
803 dc.conn = op->o_conn;
805 dc.ctx = "matchedDN";
806 #else /* ! ENABLE_REWRITE */
809 #endif /* ! ENABLE_REWRITE */
810 ber_str2bv( rs->sr_matched, 0, 0, &dn );
812 rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
813 if ( rc != LDAP_SUCCESS ) {
815 rs->sr_text = "Rewrite error";
819 if ( mdn.bv_val != dn.bv_val ) {
820 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
821 ch_free( (void *)rs->sr_matched );
824 rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
826 rs->sr_matched = mdn.bv_val;
829 return SLAP_CB_CONTINUE;
833 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
835 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
836 struct ldaprwmap *rwmap =
837 (struct ldaprwmap *)on->on_bi.bi_private;
845 * Rewrite the dn attrs, if needed
848 #ifdef ENABLE_REWRITE
849 dc.conn = op->o_conn;
851 #else /* ! ENABLE_REWRITE */
854 #endif /* ! ENABLE_REWRITE */
856 /* FIXME: the entries are in the remote mapping form;
857 * so we need to select those attributes we are willing
858 * to return, and remap them accordingly */
860 /* FIXME: in principle, one could map an attribute
861 * on top of another, which already exists.
862 * As such, in the end there might exist more than
863 * one instance of an attribute.
864 * We should at least check if this occurs, and issue
865 * an error (because multiple instances of attrs in
866 * response are not valid), or merge the values (what
867 * about duplicate values?) */
868 isupdate = be_shadow_update( op );
869 for ( ap = a_first; *ap; ) {
870 struct ldapmapping *mapping = NULL;
875 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
880 if ( op->ors_attrs != NULL &&
881 !SLAP_USERATTRS( rs->sr_attr_flags ) &&
882 !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
887 drop_missing = rwm_mapping( &rwmap->rwm_at,
888 &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
889 if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
894 if ( mapping != NULL ) {
895 (*ap)->a_desc = mapping->m_dst_ad;
899 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
900 if ( stripEntryDN ) {
901 /* will be generated by frontend */
905 } else if ( !isupdate
906 && !get_manageDIT( op )
907 && (*ap)->a_desc->ad_type->sat_no_user_mod
908 && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
913 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
917 /* empty? leave it in place because of attrsonly and vlv */
922 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
923 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
927 for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
928 struct berval mapped;
930 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
931 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
932 ch_free( bv[0].bv_val );
933 BER_BVZERO( &bv[0] );
934 if ( &(*ap)->a_vals[last] > &bv[0] ) {
935 bv[0] = (*ap)->a_vals[last];
936 BER_BVZERO( &(*ap)->a_vals[last] );
941 } else if ( mapped.bv_val != bv[0].bv_val ) {
943 * FIXME: after LBER_FREEing
944 * the value is replaced by
947 ber_bvreplace( &bv[0], &mapped );
952 * It is necessary to try to rewrite attributes with
953 * dn syntax because they might be used in ACLs as
954 * members of groups; since ACLs are applied to the
955 * rewritten stuff, no dn-based subject clause could
956 * be used at the ldap backend side (see
957 * http://www.OpenLDAP.org/faq/data/cache/452.html)
958 * The problem can be overcome by moving the dn-based
959 * ACLs to the target directory server, and letting
960 * everything pass thru the ldap backend. */
961 /* FIXME: handle distinguishedName-like syntaxes, like
962 * nameAndOptionalUID */
963 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
964 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
966 #ifdef ENABLE_REWRITE
967 dc.ctx = "searchAttrDN";
968 #endif /* ENABLE_REWRITE */
969 rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
970 if ( rc != LDAP_SUCCESS ) {
974 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
975 #ifdef ENABLE_REWRITE
976 dc.ctx = "searchAttrDN";
977 #endif /* ENABLE_REWRITE */
978 rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
979 if ( rc != LDAP_SUCCESS ) {
984 if ( mapping != NULL ) {
985 /* rewrite the attribute description */
986 assert( mapping->m_dst_ad != NULL );
987 (*ap)->a_desc = mapping->m_dst_ad;
1005 rwm_send_entry( Operation *op, SlapReply *rs )
1007 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1008 struct ldaprwmap *rwmap =
1009 (struct ldaprwmap *)on->on_bi.bi_private;
1013 struct berval dn = BER_BVNULL,
1018 assert( rs->sr_entry != NULL );
1021 * Rewrite the dn of the result, if needed
1024 #ifdef ENABLE_REWRITE
1025 dc.conn = op->o_conn;
1027 dc.ctx = "searchEntryDN";
1028 #else /* ! ENABLE_REWRITE */
1031 #endif /* ! ENABLE_REWRITE */
1034 flags = rs->sr_flags;
1035 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1036 /* FIXME: all we need to duplicate are:
1039 * - attributes that are requested
1040 * - no values if attrsonly is set
1045 rc = LDAP_NO_MEMORY;
1049 flags &= ~REP_ENTRY_MUSTRELEASE;
1050 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1054 * Note: this may fail if the target host(s) schema differs
1055 * from the one known to the meta, and a DN with unknown
1056 * attributes is returned.
1060 rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1061 if ( rc != LDAP_SUCCESS ) {
1066 if ( e->e_name.bv_val != dn.bv_val ) {
1067 ch_free( e->e_name.bv_val );
1068 ch_free( e->e_nname.bv_val );
1074 /* TODO: map entry attribute types, objectclasses
1075 * and dn-valued attribute values */
1077 /* FIXME: the entries are in the remote mapping form;
1078 * so we need to select those attributes we are willing
1079 * to return, and remap them accordingly */
1080 (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1082 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1083 be_entry_release_rw( op, rs->sr_entry, 0 );
1087 rs->sr_flags = flags;
1089 return SLAP_CB_CONTINUE;
1092 if ( e != NULL && e != rs->sr_entry ) {
1093 if ( e->e_name.bv_val == dn.bv_val ) {
1094 BER_BVZERO( &e->e_name );
1097 if ( e->e_nname.bv_val == ndn.bv_val ) {
1098 BER_BVZERO( &e->e_nname );
1104 if ( !BER_BVISNULL( &dn ) ) {
1105 ch_free( dn.bv_val );
1108 if ( !BER_BVISNULL( &ndn ) ) {
1109 ch_free( ndn.bv_val );
1116 rwm_operational( Operation *op, SlapReply *rs )
1118 /* FIXME: the entries are in the remote mapping form;
1119 * so we need to select those attributes we are willing
1120 * to return, and remap them accordingly */
1121 if ( rs->sr_operational_attrs ) {
1122 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1125 return SLAP_CB_CONTINUE;
1129 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1130 * rewritten for subsequent operations; fine for plain suffixmassage,
1131 * but destroys everything else */
1133 rwm_chk_referrals( Operation *op, SlapReply *rs )
1135 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1138 #ifdef ENABLE_REWRITE
1139 rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1140 #else /* ! ENABLE_REWRITE */
1142 rc = rwm_op_dn_massage( op, rs, &rc );
1143 #endif /* ! ENABLE_REWRITE */
1144 if ( rc != LDAP_SUCCESS ) {
1145 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1146 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1150 return SLAP_CB_CONTINUE;
1162 #ifdef ENABLE_REWRITE
1163 slap_overinst *on = (slap_overinst *) be->bd_info;
1164 struct ldaprwmap *rwmap =
1165 (struct ldaprwmap *)on->on_bi.bi_private;
1167 return rewrite_parse( rwmap->rwm_rw,
1168 fname, lineno, argc, argv );
1170 #else /* !ENABLE_REWRITE */
1171 fprintf( stderr, "%s: line %d: rewrite capabilities "
1172 "are not enabled\n", fname, lineno );
1173 #endif /* !ENABLE_REWRITE */
1179 rwm_suffixmassage_config(
1186 slap_overinst *on = (slap_overinst *) be->bd_info;
1187 struct ldaprwmap *rwmap =
1188 (struct ldaprwmap *)on->on_bi.bi_private;
1190 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1192 #ifdef ENABLE_REWRITE
1194 #endif /* ENABLE_REWRITE */
1199 * suffixmassage [<suffix>] <massaged suffix>
1201 * the [<suffix>] field must be defined as a valid suffix
1202 * for the current database;
1203 * the <massaged suffix> shouldn't have already been
1204 * defined as a valid suffix for the current server
1207 if ( be->be_suffix == NULL ) {
1208 fprintf( stderr, "%s: line %d: "
1209 " \"suffixMassage [<suffix>]"
1210 " <massaged suffix>\" without "
1211 "<suffix> part requires database "
1212 "suffix be defined first.\n",
1216 bvnc = be->be_suffix[ 0 ];
1219 } else if ( argc == 3 ) {
1220 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1224 fprintf( stderr, "%s: line %d: syntax is"
1225 " \"suffixMassage [<suffix>]"
1226 " <massaged suffix>\"\n",
1231 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1232 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1233 fname, lineno, bvnc.bv_val );
1237 ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1238 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1239 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1240 fname, lineno, brnc.bv_val );
1241 free( nvnc.bv_val );
1242 free( pvnc.bv_val );
1246 #ifdef ENABLE_REWRITE
1248 * The suffix massaging is emulated
1249 * by means of the rewrite capabilities
1251 rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1252 &pvnc, &nvnc, &prnc, &nrnc );
1253 free( nvnc.bv_val );
1254 free( pvnc.bv_val );
1255 free( nrnc.bv_val );
1256 free( prnc.bv_val );
1260 #else /* !ENABLE_REWRITE */
1261 ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
1262 ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
1264 ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
1265 ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
1266 #endif /* !ENABLE_REWRITE */
1279 slap_overinst *on = (slap_overinst *) be->bd_info;
1280 struct ldaprwmap *rwmap =
1281 (struct ldaprwmap *)on->on_bi.bi_private;
1283 /* objectclass/attribute mapping */
1284 return rwm_map_config( &rwmap->rwm_oc,
1286 fname, lineno, argc, argv );
1290 rwm_response( Operation *op, SlapReply *rs )
1292 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1293 struct ldaprwmap *rwmap =
1294 (struct ldaprwmap *)on->on_bi.bi_private;
1298 if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1299 return rwm_send_entry( op, rs );
1302 switch( op->o_tag ) {
1303 case LDAP_REQ_SEARCH:
1304 /* Note: the operation attrs are remapped */
1305 if ( rs->sr_type == REP_RESULT
1306 && op->ors_attrs != NULL
1307 && op->ors_attrs != rs->sr_attrs )
1309 ch_free( op->ors_attrs );
1310 op->ors_attrs = rs->sr_attrs;
1316 case LDAP_REQ_DELETE:
1317 case LDAP_REQ_MODRDN:
1318 case LDAP_REQ_MODIFY:
1319 case LDAP_REQ_COMPARE:
1320 case LDAP_REQ_EXTENDED:
1325 * Rewrite the dn of the referrals, if needed
1328 #ifdef ENABLE_REWRITE
1329 dc.conn = op->o_conn;
1331 dc.ctx = "referralDN";
1332 #else /* ! ENABLE_REWRITE */
1335 #endif /* ! ENABLE_REWRITE */
1336 rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1337 if ( rc != LDAP_SUCCESS ) {
1342 rc = rwm_matched( op, rs );
1346 rc = SLAP_CB_CONTINUE;
1361 slap_overinst *on = (slap_overinst *) be->bd_info;
1362 struct ldaprwmap *rwmap =
1363 (struct ldaprwmap *)on->on_bi.bi_private;
1368 if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1370 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1373 if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1374 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1376 } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1377 rc = rwm_m_config( be, fname, lineno, argc, argv );
1379 } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1380 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1382 } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1385 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1390 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1391 rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F|RWM_F_SUPPORT_T_F_DISCOVER);
1393 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1394 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1396 /* TODO: not implemented yet */
1397 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1399 "%s: line %d: \"discover\" not supported yet "
1400 "in \"t-f-support {no|yes|discover}\".\n",
1404 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1409 "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1410 fname, lineno, argv[ 1 ] );
1415 rc = SLAP_CONF_UNKNOWN;
1429 slap_overinst *on = (slap_overinst *) be->bd_info;
1430 struct ldapmapping *mapping = NULL;
1431 struct ldaprwmap *rwmap;
1432 #ifdef ENABLE_REWRITE
1434 #endif /* ENABLE_REWRITE */
1437 rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
1439 #ifdef ENABLE_REWRITE
1440 rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1441 if ( rwmap->rwm_rw == NULL ) {
1446 /* this rewriteContext by default must be null;
1447 * rules can be added if required */
1448 rargv[ 0 ] = "rewriteContext";
1449 rargv[ 1 ] = "searchFilter";
1451 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1453 rargv[ 0 ] = "rewriteContext";
1454 rargv[ 1 ] = "default";
1456 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1457 #endif /* ENABLE_REWRITE */
1459 if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1460 rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1467 on->on_bi.bi_private = (void *)rwmap;
1470 (void)rwm_db_destroy( be );
1480 slap_overinst *on = (slap_overinst *) be->bd_info;
1483 if ( on->on_bi.bi_private ) {
1484 struct ldaprwmap *rwmap =
1485 (struct ldaprwmap *)on->on_bi.bi_private;
1487 #ifdef ENABLE_REWRITE
1488 if ( rwmap->rwm_rw ) {
1489 rewrite_info_delete( &rwmap->rwm_rw );
1491 #else /* !ENABLE_REWRITE */
1492 if ( rwmap->rwm_suffix_massage ) {
1493 ber_bvarray_free( rwmap->rwm_suffix_massage );
1495 #endif /* !ENABLE_REWRITE */
1497 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1498 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1499 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1500 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1508 static slap_overinst rwm = { { NULL } };
1510 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1512 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1514 rwm_initialize( void )
1516 memset( &rwm, 0, sizeof( slap_overinst ) );
1518 rwm.on_bi.bi_type = "rwm";
1519 rwm.on_bi.bi_flags =
1520 SLAPO_BFLAG_SINGLE |
1523 rwm.on_bi.bi_db_init = rwm_db_init;
1524 rwm.on_bi.bi_db_config = rwm_db_config;
1525 rwm.on_bi.bi_db_destroy = rwm_db_destroy;
1527 rwm.on_bi.bi_op_bind = rwm_op_bind;
1528 rwm.on_bi.bi_op_search = rwm_op_search;
1529 rwm.on_bi.bi_op_compare = rwm_op_compare;
1530 rwm.on_bi.bi_op_modify = rwm_op_modify;
1531 rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
1532 rwm.on_bi.bi_op_add = rwm_op_add;
1533 rwm.on_bi.bi_op_delete = rwm_op_delete;
1534 rwm.on_bi.bi_op_unbind = rwm_op_unbind;
1535 rwm.on_bi.bi_extended = rwm_extended;
1537 rwm.on_bi.bi_operational = rwm_operational;
1538 rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
1540 #ifdef ENABLE_REWRITE
1541 rwm.on_bi.bi_connection_init = rwm_conn_init;
1542 rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
1543 #endif /* ENABLE_REWRITE */
1545 rwm.on_response = rwm_response;
1547 return overlay_register( &rwm );
1550 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1552 init_module( int argc, char *argv[] )
1554 return rwm_initialize();
1556 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1558 #endif /* SLAPD_OVER_RWM */