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_relax( 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_relax( 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_exop_passwd( Operation *op, SlapReply *rs )
767 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
770 struct berval id = BER_BVNULL,
774 if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
778 if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
779 rs->sr_err = LDAP_OTHER;
783 rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
784 &pwold, &pwnew, &rs->sr_text );
785 if ( rs->sr_err != LDAP_SUCCESS ) {
789 if ( !BER_BVISNULL( &id ) ) {
790 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
791 &op->o_req_ndn, op->o_tmpmemctx );
792 if ( rs->sr_err != LDAP_SUCCESS ) {
793 rs->sr_text = "Invalid DN";
798 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
799 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
802 #ifdef ENABLE_REWRITE
803 rc = rwm_op_dn_massage( op, rs, "extendedDN" );
804 #else /* ! ENABLE_REWRITE */
806 rc = rwm_op_dn_massage( op, rs, &rc );
807 #endif /* ! ENABLE_REWRITE */
808 if ( rc != LDAP_SUCCESS ) {
809 op->o_bd->bd_info = (BackendInfo *)on->on_info;
810 send_ldap_error( op, rs, rc, "extendedDN massage error" );
814 /* TODO: re-encode the request */
816 return SLAP_CB_CONTINUE;
821 BI_op_extended *extended;
823 { BER_BVC(LDAP_EXOP_MODIFY_PASSWD), rwm_exop_passwd },
828 rwm_extended( Operation *op, SlapReply *rs )
830 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
835 for ( i = 0; exop_table[i].extended != NULL; i++ ) {
836 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
838 rc = exop_table[i].extended( op, rs );
843 case SLAP_CB_CONTINUE:
848 send_ldap_result( op, rs );
855 #ifdef ENABLE_REWRITE
856 rc = rwm_op_dn_massage( op, rs, "extendedDN" );
857 #else /* ! ENABLE_REWRITE */
859 rc = rwm_op_dn_massage( op, rs, &rc );
860 #endif /* ! ENABLE_REWRITE */
861 if ( rc != LDAP_SUCCESS ) {
862 op->o_bd->bd_info = (BackendInfo *)on->on_info;
863 send_ldap_error( op, rs, rc, "extendedDN massage error" );
867 /* TODO: rewrite/map extended data ? ... */
868 return SLAP_CB_CONTINUE;
872 rwm_matched( Operation *op, SlapReply *rs )
874 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
875 struct ldaprwmap *rwmap =
876 (struct ldaprwmap *)on->on_bi.bi_private;
878 struct berval dn, mdn;
882 if ( rs->sr_matched == NULL ) {
883 return SLAP_CB_CONTINUE;
887 #ifdef ENABLE_REWRITE
888 dc.conn = op->o_conn;
890 dc.ctx = "matchedDN";
891 #else /* ! ENABLE_REWRITE */
894 #endif /* ! ENABLE_REWRITE */
895 ber_str2bv( rs->sr_matched, 0, 0, &dn );
897 rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
898 if ( rc != LDAP_SUCCESS ) {
900 rs->sr_text = "Rewrite error";
904 if ( mdn.bv_val != dn.bv_val ) {
905 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
906 ch_free( (void *)rs->sr_matched );
909 rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
911 rs->sr_matched = mdn.bv_val;
914 return SLAP_CB_CONTINUE;
918 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
920 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
921 struct ldaprwmap *rwmap =
922 (struct ldaprwmap *)on->on_bi.bi_private;
930 * Rewrite the dn attrs, if needed
933 #ifdef ENABLE_REWRITE
934 dc.conn = op->o_conn;
936 #else /* ! ENABLE_REWRITE */
939 #endif /* ! ENABLE_REWRITE */
941 /* FIXME: the entries are in the remote mapping form;
942 * so we need to select those attributes we are willing
943 * to return, and remap them accordingly */
945 /* FIXME: in principle, one could map an attribute
946 * on top of another, which already exists.
947 * As such, in the end there might exist more than
948 * one instance of an attribute.
949 * We should at least check if this occurs, and issue
950 * an error (because multiple instances of attrs in
951 * response are not valid), or merge the values (what
952 * about duplicate values?) */
953 isupdate = be_shadow_update( op );
954 for ( ap = a_first; *ap; ) {
955 struct ldapmapping *mapping = NULL;
960 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
965 if ( op->ors_attrs != NULL &&
966 !SLAP_USERATTRS( rs->sr_attr_flags ) &&
967 !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
972 drop_missing = rwm_mapping( &rwmap->rwm_at,
973 &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
974 if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
979 if ( mapping != NULL ) {
980 (*ap)->a_desc = mapping->m_dst_ad;
984 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
985 if ( stripEntryDN ) {
986 /* will be generated by frontend */
990 } else if ( !isupdate
992 && (*ap)->a_desc->ad_type->sat_no_user_mod
993 && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
998 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
1002 /* empty? leave it in place because of attrsonly and vlv */
1007 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1008 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1012 for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1013 struct berval mapped;
1015 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1016 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1017 ch_free( bv[0].bv_val );
1018 BER_BVZERO( &bv[0] );
1019 if ( &(*ap)->a_vals[last] > &bv[0] ) {
1020 bv[0] = (*ap)->a_vals[last];
1021 BER_BVZERO( &(*ap)->a_vals[last] );
1026 } else if ( mapped.bv_val != bv[0].bv_val ) {
1028 * FIXME: after LBER_FREEing
1029 * the value is replaced by
1030 * ch_alloc'ed memory
1032 ber_bvreplace( &bv[0], &mapped );
1037 * It is necessary to try to rewrite attributes with
1038 * dn syntax because they might be used in ACLs as
1039 * members of groups; since ACLs are applied to the
1040 * rewritten stuff, no dn-based subject clause could
1041 * be used at the ldap backend side (see
1042 * http://www.OpenLDAP.org/faq/data/cache/452.html)
1043 * The problem can be overcome by moving the dn-based
1044 * ACLs to the target directory server, and letting
1045 * everything pass thru the ldap backend. */
1046 /* FIXME: handle distinguishedName-like syntaxes, like
1047 * nameAndOptionalUID */
1048 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1049 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1051 #ifdef ENABLE_REWRITE
1052 dc.ctx = "searchAttrDN";
1053 #endif /* ENABLE_REWRITE */
1054 rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
1055 if ( rc != LDAP_SUCCESS ) {
1059 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1060 #ifdef ENABLE_REWRITE
1061 dc.ctx = "searchAttrDN";
1062 #endif /* ENABLE_REWRITE */
1063 rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1064 if ( rc != LDAP_SUCCESS ) {
1069 if ( mapping != NULL ) {
1070 /* rewrite the attribute description */
1071 assert( mapping->m_dst_ad != NULL );
1072 (*ap)->a_desc = mapping->m_dst_ad;
1076 ap = &(*ap)->a_next;
1081 *ap = (*ap)->a_next;
1090 rwm_send_entry( Operation *op, SlapReply *rs )
1092 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1093 struct ldaprwmap *rwmap =
1094 (struct ldaprwmap *)on->on_bi.bi_private;
1098 struct berval dn = BER_BVNULL,
1103 assert( rs->sr_entry != NULL );
1106 * Rewrite the dn of the result, if needed
1109 #ifdef ENABLE_REWRITE
1110 dc.conn = op->o_conn;
1112 dc.ctx = "searchEntryDN";
1113 #else /* ! ENABLE_REWRITE */
1116 #endif /* ! ENABLE_REWRITE */
1119 flags = rs->sr_flags;
1120 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1121 /* FIXME: all we need to duplicate are:
1124 * - attributes that are requested
1125 * - no values if attrsonly is set
1130 rc = LDAP_NO_MEMORY;
1134 flags &= ~REP_ENTRY_MUSTRELEASE;
1135 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1139 * Note: this may fail if the target host(s) schema differs
1140 * from the one known to the meta, and a DN with unknown
1141 * attributes is returned.
1145 rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1146 if ( rc != LDAP_SUCCESS ) {
1151 if ( e->e_name.bv_val != dn.bv_val ) {
1152 ch_free( e->e_name.bv_val );
1153 ch_free( e->e_nname.bv_val );
1159 /* TODO: map entry attribute types, objectclasses
1160 * and dn-valued attribute values */
1162 /* FIXME: the entries are in the remote mapping form;
1163 * so we need to select those attributes we are willing
1164 * to return, and remap them accordingly */
1165 (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1167 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1168 be_entry_release_rw( op, rs->sr_entry, 0 );
1172 rs->sr_flags = flags;
1174 return SLAP_CB_CONTINUE;
1177 if ( e != NULL && e != rs->sr_entry ) {
1178 if ( e->e_name.bv_val == dn.bv_val ) {
1179 BER_BVZERO( &e->e_name );
1182 if ( e->e_nname.bv_val == ndn.bv_val ) {
1183 BER_BVZERO( &e->e_nname );
1189 if ( !BER_BVISNULL( &dn ) ) {
1190 ch_free( dn.bv_val );
1193 if ( !BER_BVISNULL( &ndn ) ) {
1194 ch_free( ndn.bv_val );
1201 rwm_operational( Operation *op, SlapReply *rs )
1203 /* FIXME: the entries are in the remote mapping form;
1204 * so we need to select those attributes we are willing
1205 * to return, and remap them accordingly */
1206 if ( rs->sr_operational_attrs ) {
1207 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1210 return SLAP_CB_CONTINUE;
1214 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1215 * rewritten for subsequent operations; fine for plain suffixmassage,
1216 * but destroys everything else */
1218 rwm_chk_referrals( Operation *op, SlapReply *rs )
1220 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1223 #ifdef ENABLE_REWRITE
1224 rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1225 #else /* ! ENABLE_REWRITE */
1227 rc = rwm_op_dn_massage( op, rs, &rc );
1228 #endif /* ! ENABLE_REWRITE */
1229 if ( rc != LDAP_SUCCESS ) {
1230 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1231 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1235 return SLAP_CB_CONTINUE;
1247 #ifdef ENABLE_REWRITE
1248 slap_overinst *on = (slap_overinst *) be->bd_info;
1249 struct ldaprwmap *rwmap =
1250 (struct ldaprwmap *)on->on_bi.bi_private;
1252 return rewrite_parse( rwmap->rwm_rw,
1253 fname, lineno, argc, argv );
1255 #else /* !ENABLE_REWRITE */
1256 fprintf( stderr, "%s: line %d: rewrite capabilities "
1257 "are not enabled\n", fname, lineno );
1258 #endif /* !ENABLE_REWRITE */
1264 rwm_suffixmassage_config(
1271 slap_overinst *on = (slap_overinst *) be->bd_info;
1272 struct ldaprwmap *rwmap =
1273 (struct ldaprwmap *)on->on_bi.bi_private;
1275 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1277 #ifdef ENABLE_REWRITE
1279 #endif /* ENABLE_REWRITE */
1284 * suffixmassage [<suffix>] <massaged suffix>
1286 * the [<suffix>] field must be defined as a valid suffix
1287 * for the current database;
1288 * the <massaged suffix> shouldn't have already been
1289 * defined as a valid suffix for the current server
1292 if ( be->be_suffix == NULL ) {
1293 fprintf( stderr, "%s: line %d: "
1294 " \"suffixMassage [<suffix>]"
1295 " <massaged suffix>\" without "
1296 "<suffix> part requires database "
1297 "suffix be defined first.\n",
1301 bvnc = be->be_suffix[ 0 ];
1304 } else if ( argc == 3 ) {
1305 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1309 fprintf( stderr, "%s: line %d: syntax is"
1310 " \"suffixMassage [<suffix>]"
1311 " <massaged suffix>\"\n",
1316 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1317 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1318 fname, lineno, bvnc.bv_val );
1322 ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1323 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1324 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1325 fname, lineno, brnc.bv_val );
1326 free( nvnc.bv_val );
1327 free( pvnc.bv_val );
1331 #ifdef ENABLE_REWRITE
1333 * The suffix massaging is emulated
1334 * by means of the rewrite capabilities
1336 rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1337 &pvnc, &nvnc, &prnc, &nrnc );
1338 free( nvnc.bv_val );
1339 free( pvnc.bv_val );
1340 free( nrnc.bv_val );
1341 free( prnc.bv_val );
1345 #else /* !ENABLE_REWRITE */
1346 ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
1347 ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
1349 ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
1350 ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
1351 #endif /* !ENABLE_REWRITE */
1364 slap_overinst *on = (slap_overinst *) be->bd_info;
1365 struct ldaprwmap *rwmap =
1366 (struct ldaprwmap *)on->on_bi.bi_private;
1368 /* objectclass/attribute mapping */
1369 return rwm_map_config( &rwmap->rwm_oc,
1371 fname, lineno, argc, argv );
1375 rwm_response( Operation *op, SlapReply *rs )
1377 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1378 struct ldaprwmap *rwmap =
1379 (struct ldaprwmap *)on->on_bi.bi_private;
1383 if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1384 return rwm_send_entry( op, rs );
1387 switch( op->o_tag ) {
1388 case LDAP_REQ_SEARCH:
1389 /* Note: the operation attrs are remapped */
1390 if ( rs->sr_type == REP_RESULT
1391 && op->ors_attrs != NULL
1392 && op->ors_attrs != rs->sr_attrs )
1394 ch_free( op->ors_attrs );
1395 op->ors_attrs = rs->sr_attrs;
1401 case LDAP_REQ_DELETE:
1402 case LDAP_REQ_MODRDN:
1403 case LDAP_REQ_MODIFY:
1404 case LDAP_REQ_COMPARE:
1405 case LDAP_REQ_EXTENDED:
1410 * Rewrite the dn of the referrals, if needed
1413 #ifdef ENABLE_REWRITE
1414 dc.conn = op->o_conn;
1416 dc.ctx = "referralDN";
1417 #else /* ! ENABLE_REWRITE */
1420 #endif /* ! ENABLE_REWRITE */
1421 rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1422 if ( rc != LDAP_SUCCESS ) {
1427 rc = rwm_matched( op, rs );
1431 rc = SLAP_CB_CONTINUE;
1446 slap_overinst *on = (slap_overinst *) be->bd_info;
1447 struct ldaprwmap *rwmap =
1448 (struct ldaprwmap *)on->on_bi.bi_private;
1453 if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1455 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1458 if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1459 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1461 } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1462 rc = rwm_m_config( be, fname, lineno, argc, argv );
1464 } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1465 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1467 } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1470 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1475 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1476 rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F|RWM_F_SUPPORT_T_F_DISCOVER);
1478 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1479 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1481 /* TODO: not implemented yet */
1482 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1484 "%s: line %d: \"discover\" not supported yet "
1485 "in \"t-f-support {no|yes|discover}\".\n",
1489 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1494 "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1495 fname, lineno, argv[ 1 ] );
1500 rc = SLAP_CONF_UNKNOWN;
1514 slap_overinst *on = (slap_overinst *) be->bd_info;
1515 struct ldapmapping *mapping = NULL;
1516 struct ldaprwmap *rwmap;
1517 #ifdef ENABLE_REWRITE
1519 #endif /* ENABLE_REWRITE */
1522 rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
1524 #ifdef ENABLE_REWRITE
1525 rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1526 if ( rwmap->rwm_rw == NULL ) {
1531 /* this rewriteContext by default must be null;
1532 * rules can be added if required */
1533 rargv[ 0 ] = "rewriteContext";
1534 rargv[ 1 ] = "searchFilter";
1536 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1538 rargv[ 0 ] = "rewriteContext";
1539 rargv[ 1 ] = "default";
1541 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1542 #endif /* ENABLE_REWRITE */
1544 if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1545 rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1552 on->on_bi.bi_private = (void *)rwmap;
1555 (void)rwm_db_destroy( be );
1565 slap_overinst *on = (slap_overinst *) be->bd_info;
1568 if ( on->on_bi.bi_private ) {
1569 struct ldaprwmap *rwmap =
1570 (struct ldaprwmap *)on->on_bi.bi_private;
1572 #ifdef ENABLE_REWRITE
1573 if ( rwmap->rwm_rw ) {
1574 rewrite_info_delete( &rwmap->rwm_rw );
1576 #else /* !ENABLE_REWRITE */
1577 if ( rwmap->rwm_suffix_massage ) {
1578 ber_bvarray_free( rwmap->rwm_suffix_massage );
1580 #endif /* !ENABLE_REWRITE */
1582 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1583 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1584 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1585 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1593 static slap_overinst rwm = { { NULL } };
1595 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1597 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1599 rwm_initialize( void )
1601 memset( &rwm, 0, sizeof( slap_overinst ) );
1603 rwm.on_bi.bi_type = "rwm";
1604 rwm.on_bi.bi_flags =
1605 SLAPO_BFLAG_SINGLE |
1608 rwm.on_bi.bi_db_init = rwm_db_init;
1609 rwm.on_bi.bi_db_config = rwm_db_config;
1610 rwm.on_bi.bi_db_destroy = rwm_db_destroy;
1612 rwm.on_bi.bi_op_bind = rwm_op_bind;
1613 rwm.on_bi.bi_op_search = rwm_op_search;
1614 rwm.on_bi.bi_op_compare = rwm_op_compare;
1615 rwm.on_bi.bi_op_modify = rwm_op_modify;
1616 rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
1617 rwm.on_bi.bi_op_add = rwm_op_add;
1618 rwm.on_bi.bi_op_delete = rwm_op_delete;
1619 rwm.on_bi.bi_op_unbind = rwm_op_unbind;
1620 rwm.on_bi.bi_extended = rwm_extended;
1622 rwm.on_bi.bi_operational = rwm_operational;
1623 rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
1625 #ifdef ENABLE_REWRITE
1626 rwm.on_bi.bi_connection_init = rwm_conn_init;
1627 rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
1628 #endif /* ENABLE_REWRITE */
1630 rwm.on_response = rwm_response;
1632 return overlay_register( &rwm );
1635 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1637 init_module( int argc, char *argv[] )
1639 return rwm_initialize();
1641 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1643 #endif /* SLAPD_OVER_RWM */