1 /* rwm.c - rewrite/remap operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2008 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>
31 typedef struct rwm_op_state {
37 AttributeName *mapped_attrs;
42 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
44 typedef struct rwm_op_cb {
50 rwm_op_cleanup( Operation *op, SlapReply *rs )
52 slap_callback *cb = op->o_callback;
53 rwm_op_state *ros = cb->sc_private;
55 if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
56 op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
58 op->o_req_dn = ros->ro_dn;
59 op->o_req_ndn = ros->ro_ndn;
61 if ( !BER_BVISNULL( &ros->r_dn )
62 && ros->r_dn.bv_val != ros->r_ndn.bv_val
63 && ros->r_dn.bv_val != ros->ro_dn.bv_val )
65 ch_free( ros->r_dn.bv_val );
66 BER_BVZERO( &ros->r_dn );
69 if ( !BER_BVISNULL( &ros->r_ndn )
70 && ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
72 ch_free( ros->r_ndn.bv_val );
73 BER_BVZERO( &ros->r_ndn );
76 switch( ros->r_tag ) {
77 case LDAP_REQ_COMPARE:
78 if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
79 op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
80 op->orc_ava = ros->orc_ava;
83 slap_mods_free( op->orm_modlist, 1 );
84 op->orm_modlist = ros->orm_modlist;
87 if ( op->orr_newSup != ros->orr_newSup ) {
88 ch_free( op->orr_newSup->bv_val );
89 ch_free( op->orr_nnewSup->bv_val );
90 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
91 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
92 op->orr_newSup = ros->orr_newSup;
93 op->orr_nnewSup = ros->orr_nnewSup;
97 ch_free( ros->mapped_attrs );
98 filter_free_x( op, op->ors_filter );
99 ch_free( op->ors_filterstr.bv_val );
100 op->ors_attrs = ros->ors_attrs;
101 op->ors_filter = ros->ors_filter;
102 op->ors_filterstr = ros->ors_filterstr;
104 case LDAP_REQ_EXTENDED:
105 if ( op->ore_reqdata != ros->ore_reqdata ) {
106 ber_bvfree( op->ore_reqdata );
107 op->ore_reqdata = ros->ore_reqdata;
111 if ( rs->sr_err == LDAP_SUCCESS ) {
113 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
114 /* too late, c_mutex released */
115 fprintf( stderr, "*** DN: \"%s\" => \"%s\"\n",
116 op->o_conn->c_ndn.bv_val,
117 op->o_req_ndn.bv_val );
118 ber_bvreplace( &op->o_conn->c_ndn,
120 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
126 op->o_callback = op->o_callback->sc_next;
127 op->o_tmpfree( cb, op->o_tmpmemctx );
130 return SLAP_CB_CONTINUE;
134 rwm_callback_get( Operation *op, SlapReply *rs )
136 rwm_op_cb *roc = NULL;
138 roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
139 roc->cb.sc_cleanup = rwm_op_cleanup;
140 roc->cb.sc_response = NULL;
141 roc->cb.sc_next = op->o_callback;
142 roc->cb.sc_private = &roc->ros;
143 roc->ros.r_tag = op->o_tag;
144 roc->ros.ro_dn = op->o_req_dn;
145 roc->ros.ro_ndn = op->o_req_ndn;
146 roc->ros.o_request = op->o_request;
147 BER_BVZERO( &roc->ros.r_dn );
148 BER_BVZERO( &roc->ros.r_ndn );
155 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
158 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
159 struct ldaprwmap *rwmap =
160 (struct ldaprwmap *)on->on_bi.bi_private;
162 struct berval dn = BER_BVNULL,
168 * Rewrite the dn if needed
171 dc.conn = op->o_conn;
173 dc.ctx = (char *)cookie;
175 /* NOTE: in those cases where only the ndn is available,
176 * and the caller sets op->o_req_dn = op->o_req_ndn,
177 * only rewrite the op->o_req_ndn and use it as
178 * op->o_req_dn as well */
180 if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
182 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
184 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
187 if ( rc != LDAP_SUCCESS ) {
191 if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
192 || ndn.bv_val == op->o_req_ndn.bv_val )
197 if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
210 rwm_op_add( Operation *op, SlapReply *rs )
212 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
213 struct ldaprwmap *rwmap =
214 (struct ldaprwmap *)on->on_bi.bi_private;
218 Attribute **ap = NULL;
219 char *olddn = op->o_req_dn.bv_val;
222 rwm_op_cb *roc = rwm_callback_get( op, rs );
224 rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
225 if ( rc != LDAP_SUCCESS ) {
226 op->o_bd->bd_info = (BackendInfo *)on->on_info;
227 send_ldap_error( op, rs, rc, "addDN massage error" );
231 if ( olddn != op->o_req_dn.bv_val ) {
232 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
233 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
236 /* Count number of attributes in entry */
237 isupdate = be_shadow_update( op );
238 for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
241 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
242 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
246 last = (*ap)->a_numvals - 1;
247 for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
248 struct ldapmapping *mapping = NULL;
250 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
252 if ( mapping == NULL ) {
253 if ( rwmap->rwm_at.drop_missing ) {
254 /* FIXME: we allow to remove objectClasses as well;
255 * if the resulting entry is inconsistent, that's
256 * the relayed database's business...
258 ch_free( (*ap)->a_vals[ j ].bv_val );
260 (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
262 BER_BVZERO( &(*ap)->a_vals[ last ] );
269 ch_free( (*ap)->a_vals[ j ].bv_val );
270 ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
274 } else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
279 struct ldapmapping *mapping = NULL;
281 ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
283 if ( mapping == NULL ) {
284 if ( rwmap->rwm_at.drop_missing ) {
289 if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
290 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
293 * FIXME: rewrite could fail; in this case
294 * the operation should give up, right?
296 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
298 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
303 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
304 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
306 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
307 if ( rc != LDAP_SUCCESS ) {
312 if ( mapping != NULL ) {
313 assert( mapping->m_dst_ad != NULL );
314 (*ap)->a_desc = mapping->m_dst_ad;
323 /* FIXME: leaking attribute/values? */
330 op->o_callback = &roc->cb;
332 return SLAP_CB_CONTINUE;
336 rwm_conn_init( BackendDB *be, Connection *conn )
338 slap_overinst *on = (slap_overinst *) be->bd_info;
339 struct ldaprwmap *rwmap =
340 (struct ldaprwmap *)on->on_bi.bi_private;
342 ( void )rewrite_session_init( rwmap->rwm_rw, conn );
344 return SLAP_CB_CONTINUE;
348 rwm_conn_destroy( BackendDB *be, Connection *conn )
350 slap_overinst *on = (slap_overinst *) be->bd_info;
351 struct ldaprwmap *rwmap =
352 (struct ldaprwmap *)on->on_bi.bi_private;
354 ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
356 return SLAP_CB_CONTINUE;
360 rwm_op_bind( Operation *op, SlapReply *rs )
362 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
365 rwm_op_cb *roc = rwm_callback_get( op, rs );
367 rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
368 if ( rc != LDAP_SUCCESS ) {
369 op->o_bd->bd_info = (BackendInfo *)on->on_info;
370 send_ldap_error( op, rs, rc, "bindDN massage error" );
374 overlay_callback_after_backover( op, &roc->cb, 1 );
376 return SLAP_CB_CONTINUE;
380 rwm_op_unbind( Operation *op, SlapReply *rs )
382 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
383 struct ldaprwmap *rwmap =
384 (struct ldaprwmap *)on->on_bi.bi_private;
386 rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
388 return SLAP_CB_CONTINUE;
392 rwm_op_compare( Operation *op, SlapReply *rs )
394 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
395 struct ldaprwmap *rwmap =
396 (struct ldaprwmap *)on->on_bi.bi_private;
399 struct berval mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
401 rwm_op_cb *roc = rwm_callback_get( op, rs );
403 rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
404 if ( rc != LDAP_SUCCESS ) {
405 op->o_bd->bd_info = (BackendInfo *)on->on_info;
406 send_ldap_error( op, rs, rc, "compareDN massage error" );
410 /* if the attribute is an objectClass, try to remap its value */
411 if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
412 || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
414 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
415 &mapped_vals[0], RWM_MAP );
416 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
418 op->o_bd->bd_info = (BackendInfo *)on->on_info;
419 send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
422 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
423 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
428 struct ldapmapping *mapping = NULL;
429 AttributeDescription *ad = op->orc_ava->aa_desc;
431 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
433 if ( mapping == NULL ) {
434 if ( rwmap->rwm_at.drop_missing ) {
435 op->o_bd->bd_info = (BackendInfo *)on->on_info;
436 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
441 assert( mapping->m_dst_ad != NULL );
442 ad = mapping->m_dst_ad;
445 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
446 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
448 struct berval *mapped_valsp[2];
450 mapped_valsp[0] = &mapped_vals[0];
451 mapped_valsp[1] = &mapped_vals[1];
453 mapped_vals[0] = op->orc_ava->aa_value;
455 rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
457 if ( rc != LDAP_SUCCESS ) {
458 op->o_bd->bd_info = (BackendInfo *)on->on_info;
459 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
463 if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
464 /* NOTE: if we get here, rwm_dnattr_rewrite()
465 * already freed the old value, so now
467 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
469 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
472 op->orc_ava->aa_desc = ad;
475 op->o_callback = &roc->cb;
477 return SLAP_CB_CONTINUE;
481 rwm_op_delete( Operation *op, SlapReply *rs )
483 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
486 rwm_op_cb *roc = rwm_callback_get( op, rs );
488 rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
489 if ( rc != LDAP_SUCCESS ) {
490 op->o_bd->bd_info = (BackendInfo *)on->on_info;
491 send_ldap_error( op, rs, rc, "deleteDN massage error" );
495 op->o_callback = &roc->cb;
497 return SLAP_CB_CONTINUE;
501 rwm_op_modify( Operation *op, SlapReply *rs )
503 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
504 struct ldaprwmap *rwmap =
505 (struct ldaprwmap *)on->on_bi.bi_private;
511 rwm_op_cb *roc = rwm_callback_get( op, rs );
513 rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
514 if ( rc != LDAP_SUCCESS ) {
515 op->o_bd->bd_info = (BackendInfo *)on->on_info;
516 send_ldap_error( op, rs, rc, "modifyDN massage error" );
520 isupdate = be_shadow_update( op );
521 for ( mlp = &op->orm_modlist; *mlp; ) {
523 Modifications *ml = *mlp;
524 struct ldapmapping *mapping = NULL;
526 /* ml points to a temporary mod until needs duplication */
527 if ( ml->sml_desc == slap_schema.si_ad_objectClass
528 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
532 } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
534 ml = ch_malloc( sizeof( Modifications ) );
536 if ( (*mlp)->sml_values ) {
537 ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
538 if ( (*mlp)->sml_nvalues ) {
539 ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
548 drop_missing = rwm_mapping( &rwmap->rwm_at,
549 &ml->sml_desc->ad_cname,
551 if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
557 /* duplicate the modlist */
558 ml = ch_malloc( sizeof( Modifications ));
562 if ( ml->sml_values != NULL ) {
566 for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
569 bva = ch_malloc( (num+1) * sizeof( struct berval ));
570 for (i=0; i<num; i++)
571 ber_dupbv( &bva[i], &ml->sml_values[i] );
572 BER_BVZERO( &bva[i] );
573 ml->sml_values = bva;
575 if ( ml->sml_nvalues ) {
576 bva = ch_malloc( (num+1) * sizeof( struct berval ));
577 for (i=0; i<num; i++)
578 ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
579 BER_BVZERO( &bva[i] );
580 ml->sml_nvalues = bva;
588 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
589 struct ldapmapping *oc_mapping = NULL;
591 ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
592 &oc_mapping, RWM_MAP );
593 if ( oc_mapping == NULL ) {
594 if ( rwmap->rwm_at.drop_missing ) {
595 /* FIXME: we allow to remove objectClasses as well;
596 * if the resulting entry is inconsistent, that's
597 * the relayed database's business...
600 ch_free( ml->sml_values[ j ].bv_val );
601 ml->sml_values[ j ] = ml->sml_values[ last ];
603 BER_BVZERO( &ml->sml_values[ last ] );
609 ch_free( ml->sml_values[ j ].bv_val );
610 ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
615 if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
616 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
618 rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
620 ml->sml_nvalues ? &ml->sml_nvalues : NULL );
622 } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
623 rc = rwm_referral_rewrite( op, rs,
626 ml->sml_nvalues ? &ml->sml_nvalues : NULL );
627 if ( rc != LDAP_SUCCESS ) {
632 if ( rc != LDAP_SUCCESS ) {
639 if ( mapping != NULL ) {
640 /* use new attribute description */
641 assert( mapping->m_dst_ad != NULL );
642 ml->sml_desc = mapping->m_dst_ad;
650 *mlp = (*mlp)->sml_next;
651 slap_mod_free( &ml->sml_mod, 0 );
655 op->o_callback = &roc->cb;
657 return SLAP_CB_CONTINUE;
661 rwm_op_modrdn( Operation *op, SlapReply *rs )
663 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
664 struct ldaprwmap *rwmap =
665 (struct ldaprwmap *)on->on_bi.bi_private;
669 rwm_op_cb *roc = rwm_callback_get( op, rs );
671 if ( op->orr_newSup ) {
673 struct berval nnewSup = BER_BVNULL;
674 struct berval newSup = BER_BVNULL;
677 * Rewrite the new superior, if defined and required
680 dc.conn = op->o_conn;
682 dc.ctx = "newSuperiorDN";
683 newSup = *op->orr_newSup;
684 nnewSup = *op->orr_nnewSup;
685 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
686 if ( rc != LDAP_SUCCESS ) {
687 op->o_bd->bd_info = (BackendInfo *)on->on_info;
688 send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
692 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
693 op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
695 op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
697 *op->orr_newSup = newSup;
698 *op->orr_nnewSup = nnewSup;
703 * Rewrite the dn, if needed
705 rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
706 if ( rc != LDAP_SUCCESS ) {
707 op->o_bd->bd_info = (BackendInfo *)on->on_info;
708 send_ldap_error( op, rs, rc, "renameDN massage error" );
709 if ( op->orr_newSup != roc->ros.orr_newSup ) {
710 ch_free( op->orr_newSup->bv_val );
711 ch_free( op->orr_nnewSup->bv_val );
712 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
713 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
714 op->orr_newSup = roc->ros.orr_newSup;
715 op->orr_nnewSup = roc->ros.orr_nnewSup;
720 /* TODO: rewrite newRDN, attribute types,
721 * values of DN-valued attributes ... */
723 op->o_callback = &roc->cb;
725 return SLAP_CB_CONTINUE;
730 rwm_swap_attrs( Operation *op, SlapReply *rs )
732 slap_callback *cb = op->o_callback;
733 rwm_op_state *ros = cb->sc_private;
735 rs->sr_attrs = ros->ors_attrs;
737 /* other overlays might have touched op->ors_attrs,
738 * so we restore the original version here, otherwise
739 * attribute-mapping might fail */
740 op->ors_attrs = ros->mapped_attrs;
742 return SLAP_CB_CONTINUE;
746 rwm_op_search( Operation *op, SlapReply *rs )
748 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
749 struct ldaprwmap *rwmap =
750 (struct ldaprwmap *)on->on_bi.bi_private;
755 struct berval fstr = BER_BVNULL;
758 AttributeName *an = NULL;
762 rwm_op_cb *roc = rwm_callback_get( op, rs );
764 rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
765 "searchFilter", op->ors_filterstr.bv_val );
766 if ( rc == LDAP_SUCCESS )
767 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
768 if ( rc != LDAP_SUCCESS ) {
769 text = "searchDN massage error";
774 * Rewrite the dn if needed
777 dc.conn = op->o_conn;
779 dc.ctx = "searchFilterAttrDN";
781 rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
782 if ( rc != LDAP_SUCCESS ) {
783 text = "searchFilter/searchFilterAttrDN massage error";
787 f = str2filter_x( op, fstr.bv_val );
790 text = "massaged filter parse error";
795 op->ors_filterstr = fstr;
797 rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
798 op->ors_attrs, &an, RWM_MAP );
799 if ( rc != LDAP_SUCCESS ) {
800 text = "attribute list mapping error";
805 /* store the mapped Attributes for later usage, in
806 * the case that other overlays change op->ors_attrs */
807 roc->ros.mapped_attrs = an;
808 roc->cb.sc_response = rwm_swap_attrs;
810 op->o_callback = &roc->cb;
812 return SLAP_CB_CONTINUE;
820 filter_free_x( op, f );
823 if ( !BER_BVISNULL( &fstr ) ) {
824 ch_free( fstr.bv_val );
827 op->oq_search = roc->ros.oq_search;
829 op->o_bd->bd_info = (BackendInfo *)on->on_info;
830 send_ldap_error( op, rs, rc, text );
837 rwm_exop_passwd( Operation *op, SlapReply *rs )
839 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
843 struct berval id = BER_BVNULL,
846 BerElement *ber = NULL;
848 if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
852 if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
853 rs->sr_err = LDAP_OTHER;
857 rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
858 &pwold, &pwnew, &rs->sr_text );
859 if ( rs->sr_err != LDAP_SUCCESS ) {
863 if ( !BER_BVISNULL( &id ) ) {
864 char idNul = id.bv_val[id.bv_len];
865 id.bv_val[id.bv_len] = '\0';
866 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
867 &op->o_req_ndn, op->o_tmpmemctx );
868 id.bv_val[id.bv_len] = idNul;
869 if ( rs->sr_err != LDAP_SUCCESS ) {
870 rs->sr_text = "Invalid DN";
875 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
876 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
879 roc = rwm_callback_get( op, rs );
881 rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
882 if ( rc != LDAP_SUCCESS ) {
883 op->o_bd->bd_info = (BackendInfo *)on->on_info;
884 send_ldap_error( op, rs, rc, "extendedDN massage error" );
888 ber = ber_alloc_t( LBER_USE_DER );
890 rs->sr_err = LDAP_OTHER;
891 rs->sr_text = "No memory";
894 ber_printf( ber, "{" );
895 if ( !BER_BVISNULL( &id )) {
896 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
899 if ( !BER_BVISNULL( &pwold )) {
900 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
902 if ( !BER_BVISNULL( &pwnew )) {
903 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
905 ber_printf( ber, "N}" );
906 ber_flatten( ber, &op->ore_reqdata );
909 op->o_callback = &roc->cb;
911 return SLAP_CB_CONTINUE;
916 BI_op_extended *extended;
918 { BER_BVC(LDAP_EXOP_MODIFY_PASSWD), rwm_exop_passwd },
923 rwm_extended( Operation *op, SlapReply *rs )
925 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
931 for ( i = 0; exop_table[i].extended != NULL; i++ ) {
932 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
934 rc = exop_table[i].extended( op, rs );
939 case SLAP_CB_CONTINUE:
944 send_ldap_result( op, rs );
951 roc = rwm_callback_get( op, rs );
953 rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
954 if ( rc != LDAP_SUCCESS ) {
955 op->o_bd->bd_info = (BackendInfo *)on->on_info;
956 send_ldap_error( op, rs, rc, "extendedDN massage error" );
960 /* TODO: rewrite/map extended data ? ... */
961 op->o_callback = &roc->cb;
963 return SLAP_CB_CONTINUE;
967 rwm_matched( Operation *op, SlapReply *rs )
969 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
970 struct ldaprwmap *rwmap =
971 (struct ldaprwmap *)on->on_bi.bi_private;
973 struct berval dn, mdn;
977 if ( rs->sr_matched == NULL ) {
978 return SLAP_CB_CONTINUE;
982 dc.conn = op->o_conn;
984 dc.ctx = "matchedDN";
985 ber_str2bv( rs->sr_matched, 0, 0, &dn );
987 rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
988 if ( rc != LDAP_SUCCESS ) {
990 rs->sr_text = "Rewrite error";
994 if ( mdn.bv_val != dn.bv_val ) {
995 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
996 ch_free( (void *)rs->sr_matched );
999 rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1001 rs->sr_matched = mdn.bv_val;
1004 return SLAP_CB_CONTINUE;
1008 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1010 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1011 struct ldaprwmap *rwmap =
1012 (struct ldaprwmap *)on->on_bi.bi_private;
1018 int check_duplicate_attrs = 0;
1021 * Rewrite the dn attrs, if needed
1024 dc.conn = op->o_conn;
1027 /* FIXME: the entries are in the remote mapping form;
1028 * so we need to select those attributes we are willing
1029 * to return, and remap them accordingly */
1031 /* FIXME: in principle, one could map an attribute
1032 * on top of another, which already exists.
1033 * As such, in the end there might exist more than
1034 * one instance of an attribute.
1035 * We should at least check if this occurs, and issue
1036 * an error (because multiple instances of attrs in
1037 * response are not valid), or merge the values (what
1038 * about duplicate values?) */
1039 isupdate = be_shadow_update( op );
1040 for ( ap = a_first; *ap; ) {
1041 struct ldapmapping *mapping = NULL;
1046 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
1051 if ( op->ors_attrs != NULL &&
1052 !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1053 !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1058 drop_missing = rwm_mapping( &rwmap->rwm_at,
1059 &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1060 if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1064 if ( mapping != NULL ) {
1065 assert( mapping->m_dst_ad != NULL );
1067 /* try to normalize mapped Attributes if the original
1068 * AttributeType was not normalized */
1069 if ( (!(*ap)->a_desc->ad_type->sat_equality ||
1070 !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
1071 mapping->m_dst_ad->ad_type->sat_equality &&
1072 mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
1074 if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
1078 last = (*ap)->a_numvals;
1081 (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
1083 for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
1086 * check that each value is valid per syntax
1087 * and pretty if appropriate
1089 rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
1090 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1091 mapping->m_dst_ad->ad_type->sat_syntax,
1092 mapping->m_dst_ad->ad_type->sat_equality,
1093 &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
1096 if ( rc != LDAP_SUCCESS ) {
1097 BER_BVZERO( &(*ap)->a_nvals[i] );
1100 BER_BVZERO( &(*ap)->a_nvals[i] );
1104 assert( (*ap)->a_nvals == (*ap)->a_vals );
1105 (*ap)->a_nvals = NULL;
1106 ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
1110 /* rewrite the attribute description */
1111 (*ap)->a_desc = mapping->m_dst_ad;
1113 /* will need to check for duplicate attrs */
1114 check_duplicate_attrs++;
1118 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1119 if ( stripEntryDN ) {
1120 /* will be generated by frontend */
1124 } else if ( !isupdate
1126 && (*ap)->a_desc->ad_type->sat_no_user_mod
1127 && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1132 if ( last == -1 ) { /* not yet counted */
1133 last = (*ap)->a_numvals;
1137 /* empty? leave it in place because of attrsonly and vlv */
1142 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1143 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1147 for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1148 struct berval mapped;
1150 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1151 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1153 ch_free( bv[0].bv_val );
1154 BER_BVZERO( &bv[0] );
1155 if ( &(*ap)->a_vals[last] > &bv[0] ) {
1156 bv[0] = (*ap)->a_vals[last];
1157 BER_BVZERO( &(*ap)->a_vals[last] );
1162 } else if ( mapped.bv_val != bv[0].bv_val ) {
1165 for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
1166 if ( &(*ap)->a_vals[ i ] == bv ) {
1170 if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
1175 if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
1180 * FIXME: after LBER_FREEing
1181 * the value is replaced by
1182 * ch_alloc'ed memory
1184 ber_bvreplace( &bv[0], &mapped );
1186 /* FIXME: will need to check
1187 * if the structuralObjectClass
1193 * It is necessary to try to rewrite attributes with
1194 * dn syntax because they might be used in ACLs as
1195 * members of groups; since ACLs are applied to the
1196 * rewritten stuff, no dn-based subject clause could
1197 * be used at the ldap backend side (see
1198 * http://www.OpenLDAP.org/faq/data/cache/452.html)
1199 * The problem can be overcome by moving the dn-based
1200 * ACLs to the target directory server, and letting
1201 * everything pass thru the ldap backend. */
1202 /* FIXME: handle distinguishedName-like syntaxes, like
1203 * nameAndOptionalUID */
1204 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1205 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1207 dc.ctx = "searchAttrDN";
1208 rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
1209 if ( rc != LDAP_SUCCESS ) {
1213 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1214 dc.ctx = "searchAttrDN";
1215 rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1216 if ( rc != LDAP_SUCCESS ) {
1223 ap = &(*ap)->a_next;
1228 *ap = (*ap)->a_next;
1233 /* only check if some mapping occurred */
1234 if ( check_duplicate_attrs ) {
1235 for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
1238 for ( tap = &(*ap)->a_next; *tap != NULL; ) {
1239 if ( (*tap)->a_desc == (*ap)->a_desc ) {
1241 Modification mod = { 0 };
1242 const char *text = NULL;
1243 char textbuf[ SLAP_TEXT_BUFLEN ];
1244 Attribute *next = (*tap)->a_next;
1246 BER_BVSTR( &e.e_name, "" );
1247 BER_BVSTR( &e.e_nname, "" );
1249 mod.sm_op = LDAP_MOD_ADD;
1250 mod.sm_desc = (*ap)->a_desc;
1251 mod.sm_type = mod.sm_desc->ad_cname;
1252 mod.sm_numvals = (*tap)->a_numvals;
1253 mod.sm_values = (*tap)->a_vals;
1254 if ( (*tap)->a_nvals != (*tap)->a_vals ) {
1255 mod.sm_nvalues = (*tap)->a_nvals;
1258 (void)modify_add_values( &e, &mod,
1260 &text, textbuf, sizeof( textbuf ) );
1262 /* should not insert new attrs! */
1263 assert( e.e_attrs == *ap );
1269 tap = &(*tap)->a_next;
1279 rwm_send_entry( Operation *op, SlapReply *rs )
1281 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1282 struct ldaprwmap *rwmap =
1283 (struct ldaprwmap *)on->on_bi.bi_private;
1287 struct berval dn = BER_BVNULL,
1292 assert( rs->sr_entry != NULL );
1295 * Rewrite the dn of the result, if needed
1298 dc.conn = op->o_conn;
1300 dc.ctx = "searchEntryDN";
1303 flags = rs->sr_flags;
1304 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1305 /* FIXME: all we need to duplicate are:
1308 * - attributes that are requested
1309 * - no values if attrsonly is set
1314 rc = LDAP_NO_MEMORY;
1318 flags &= ~REP_ENTRY_MUSTRELEASE;
1319 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1323 * Note: this may fail if the target host(s) schema differs
1324 * from the one known to the meta, and a DN with unknown
1325 * attributes is returned.
1329 rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1330 if ( rc != LDAP_SUCCESS ) {
1335 if ( e->e_name.bv_val != dn.bv_val ) {
1336 ch_free( e->e_name.bv_val );
1337 ch_free( e->e_nname.bv_val );
1343 /* TODO: map entry attribute types, objectclasses
1344 * and dn-valued attribute values */
1346 /* FIXME: the entries are in the remote mapping form;
1347 * so we need to select those attributes we are willing
1348 * to return, and remap them accordingly */
1349 (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1351 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1352 be_entry_release_rw( op, rs->sr_entry, 0 );
1356 rs->sr_flags = flags;
1358 return SLAP_CB_CONTINUE;
1361 if ( e != NULL && e != rs->sr_entry ) {
1362 if ( e->e_name.bv_val == dn.bv_val ) {
1363 BER_BVZERO( &e->e_name );
1366 if ( e->e_nname.bv_val == ndn.bv_val ) {
1367 BER_BVZERO( &e->e_nname );
1373 if ( !BER_BVISNULL( &dn ) ) {
1374 ch_free( dn.bv_val );
1377 if ( !BER_BVISNULL( &ndn ) ) {
1378 ch_free( ndn.bv_val );
1385 rwm_operational( Operation *op, SlapReply *rs )
1387 /* FIXME: the entries are in the remote mapping form;
1388 * so we need to select those attributes we are willing
1389 * to return, and remap them accordingly */
1390 if ( rs->sr_operational_attrs ) {
1391 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1394 return SLAP_CB_CONTINUE;
1398 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1399 * rewritten for subsequent operations; fine for plain suffixmassage,
1400 * but destroys everything else */
1402 rwm_chk_referrals( Operation *op, SlapReply *rs )
1404 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1407 rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1408 if ( rc != LDAP_SUCCESS ) {
1409 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1410 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1414 return SLAP_CB_CONTINUE;
1426 slap_overinst *on = (slap_overinst *) be->bd_info;
1427 struct ldaprwmap *rwmap =
1428 (struct ldaprwmap *)on->on_bi.bi_private;
1430 return rewrite_parse( rwmap->rwm_rw,
1431 fname, lineno, argc, argv );
1437 rwm_suffixmassage_config(
1444 slap_overinst *on = (slap_overinst *) be->bd_info;
1445 struct ldaprwmap *rwmap =
1446 (struct ldaprwmap *)on->on_bi.bi_private;
1448 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1455 * suffixmassage [<suffix>] <massaged suffix>
1457 * the [<suffix>] field must be defined as a valid suffix
1458 * for the current database;
1459 * the <massaged suffix> shouldn't have already been
1460 * defined as a valid suffix for the current server
1463 if ( be->be_suffix == NULL ) {
1464 fprintf( stderr, "%s: line %d: "
1465 " \"suffixMassage [<suffix>]"
1466 " <massaged suffix>\" without "
1467 "<suffix> part requires database "
1468 "suffix be defined first.\n",
1472 bvnc = be->be_suffix[ 0 ];
1475 } else if ( argc == 3 ) {
1476 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1480 fprintf( stderr, "%s: line %d: syntax is"
1481 " \"suffixMassage [<suffix>]"
1482 " <massaged suffix>\"\n",
1487 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1488 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1489 fname, lineno, bvnc.bv_val );
1493 ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1494 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1495 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1496 fname, lineno, brnc.bv_val );
1497 free( nvnc.bv_val );
1498 free( pvnc.bv_val );
1503 * The suffix massaging is emulated
1504 * by means of the rewrite capabilities
1506 rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1507 &pvnc, &nvnc, &prnc, &nrnc );
1508 free( nvnc.bv_val );
1509 free( pvnc.bv_val );
1510 free( nrnc.bv_val );
1511 free( prnc.bv_val );
1524 slap_overinst *on = (slap_overinst *) be->bd_info;
1525 struct ldaprwmap *rwmap =
1526 (struct ldaprwmap *)on->on_bi.bi_private;
1528 /* objectclass/attribute mapping */
1529 return rwm_map_config( &rwmap->rwm_oc,
1531 fname, lineno, argc, argv );
1535 rwm_response( Operation *op, SlapReply *rs )
1537 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1538 struct ldaprwmap *rwmap =
1539 (struct ldaprwmap *)on->on_bi.bi_private;
1543 if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1544 return rwm_send_entry( op, rs );
1547 switch( op->o_tag ) {
1548 case LDAP_REQ_SEARCH:
1551 case LDAP_REQ_DELETE:
1552 case LDAP_REQ_MODRDN:
1553 case LDAP_REQ_MODIFY:
1554 case LDAP_REQ_COMPARE:
1555 case LDAP_REQ_EXTENDED:
1560 * Rewrite the dn of the referrals, if needed
1563 dc.conn = op->o_conn;
1565 dc.ctx = "referralDN";
1566 rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1567 if ( rc != LDAP_SUCCESS ) {
1572 rc = rwm_matched( op, rs );
1576 rc = SLAP_CB_CONTINUE;
1591 slap_overinst *on = (slap_overinst *) be->bd_info;
1592 struct ldaprwmap *rwmap =
1593 (struct ldaprwmap *)on->on_bi.bi_private;
1598 if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1600 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1603 if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1604 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1606 } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1607 rc = rwm_m_config( be, fname, lineno, argc, argv );
1609 } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1610 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1612 } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1615 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1620 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1621 rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
1623 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1624 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1626 /* TODO: not implemented yet */
1627 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1629 "%s: line %d: \"discover\" not supported yet "
1630 "in \"t-f-support {no|yes|discover}\".\n",
1634 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1639 "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1640 fname, lineno, argv[ 1 ] );
1644 } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) == 0 ) {
1647 "%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
1652 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1653 rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
1655 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1656 rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
1660 rc = SLAP_CONF_UNKNOWN;
1671 * dynamic configuration...
1677 RWM_CF_SUFFIXMASSAGE,
1682 RWM_CF_NORMALIZE_MAPPED,
1687 static slap_verbmasks t_f_mode[] = {
1688 { BER_BVC( "yes" ), RWM_F_SUPPORT_T_F },
1689 { BER_BVC( "discover" ), RWM_F_SUPPORT_T_F_DISCOVER },
1690 { BER_BVC( "no" ), RWM_F_NONE },
1694 static ConfigDriver rwm_cf_gen;
1696 static ConfigTable rwmcfg[] = {
1697 { "rwm-rewrite", "rewrite",
1698 2, 0, STRLENOF("rwm-rewrite"),
1699 ARG_MAGIC|ARG_QUOTE|RWM_CF_REWRITE, rwm_cf_gen,
1700 "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
1701 "DESC 'Rewrites strings' "
1702 "EQUALITY caseIgnoreMatch "
1703 "SYNTAX OMsDirectoryString "
1704 "X-ORDERED 'VALUES' )",
1707 { "rwm-suffixmassage", "[virtual]> <real",
1708 2, 3, 0, ARG_MAGIC|RWM_CF_SUFFIXMASSAGE, rwm_cf_gen,
1711 { "rwm-t-f-support", "true|false|discover",
1712 2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
1713 "( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
1714 "DESC 'Absolute filters support' "
1715 "SYNTAX OMsDirectoryString "
1719 { "rwm-map", "{objectClass|attribute}",
1720 2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
1721 "( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
1722 "DESC 'maps attributes/objectClasses' "
1723 "SYNTAX OMsDirectoryString "
1724 "X-ORDERED 'VALUES' )",
1727 { "rwm-normalize-mapped-attrs", "true|false",
1728 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
1729 "( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
1730 "DESC 'Normalize mapped attributes/objectClasses' "
1731 "SYNTAX OMsBoolean "
1735 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1738 static ConfigOCs rwmocs[] = {
1739 { "( OLcfgOvOc:16.1 "
1740 "NAME 'olcRwmConfig' "
1741 "DESC 'Rewrite/remap configuration' "
1742 "SUP olcOverlayConfig "
1745 "olcRwmTFSupport $ "
1747 "olcRwmNormalizeMapped "
1749 Cft_Overlay, rwmcfg, NULL, NULL },
1754 slap_rewrite_unparse( BerVarray in, BerVarray *out )
1757 BerVarray bva = NULL;
1758 char ibuf[32], *ptr;
1761 assert( in != NULL );
1763 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
1772 bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
1773 BER_BVZERO( &bva[ 0 ] );
1775 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
1776 idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
1777 if ( idx.bv_len >= sizeof( ibuf ) ) {
1778 ber_bvarray_free( bva );
1782 bva[i].bv_len = idx.bv_len + in[i].bv_len;
1783 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
1784 ptr = lutil_strcopy( bva[i].bv_val, ibuf );
1785 ptr = lutil_strcopy( ptr, in[i].bv_val );
1787 BER_BVZERO( &bva[ i + 1 ] );
1794 rwm_cf_gen( ConfigArgs *c )
1796 slap_overinst *on = (slap_overinst *)c->bi;
1797 struct ldaprwmap *rwmap =
1798 (struct ldaprwmap *)on->on_bi.bi_private;
1807 if ( c->op == SLAP_CONFIG_EMIT ) {
1808 struct berval bv = BER_BVNULL;
1810 switch ( c->type ) {
1811 case RWM_CF_REWRITE:
1812 if ( rwmap->rwm_bva_rewrite == NULL ) {
1816 slap_rewrite_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
1817 if ( !c->rvalue_vals ) {
1823 case RWM_CF_T_F_SUPPORT:
1824 enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
1825 if ( BER_BVISNULL( &bv ) ) {
1826 /* there's something wrong... */
1831 value_add_one( &c->rvalue_vals, &bv );
1836 if ( rwmap->rwm_bva_map == NULL ) {
1840 value_add( &c->rvalue_vals, rwmap->rwm_bva_map );
1844 case RWM_CF_NORMALIZE_MAPPED:
1845 c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
1855 } else if ( c->op == LDAP_MOD_DELETE ) {
1856 switch ( c->type ) {
1857 case RWM_CF_REWRITE:
1858 if ( c->valx >= 0 ) {
1859 /* single modification is not allowed */
1862 } else if ( rwmap->rwm_rw != NULL ) {
1863 rewrite_info_delete( &rwmap->rwm_rw );
1864 assert( rwmap->rwm_rw == NULL );
1866 ber_bvarray_free( rwmap->rwm_bva_rewrite );
1867 rwmap->rwm_bva_rewrite = NULL;
1871 case RWM_CF_T_F_SUPPORT:
1872 rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
1876 if ( c->valx >= 0 ) {
1877 /* single modification is not allowed */
1881 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1882 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1883 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1884 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1886 rwmap->rwm_oc.remap = NULL;
1887 rwmap->rwm_oc.map = NULL;
1888 rwmap->rwm_at.remap = NULL;
1889 rwmap->rwm_at.map = NULL;
1891 ber_bvarray_free( rwmap->rwm_bva_map );
1892 rwmap->rwm_bva_map = NULL;
1896 case RWM_CF_NORMALIZE_MAPPED:
1897 rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
1906 switch ( c->type ) {
1907 case RWM_CF_REWRITE:
1908 argv0 = c->argv[ 0 ];
1909 c->argv[ 0 ] += STRLENOF( "rwm-" );
1910 rc = rwm_rw_config( &db, c->fname, c->lineno, c->argc, c->argv );
1911 c->argv[ 0 ] = argv0;
1919 line = ldap_charray2str( c->argv, "\" \"" );
1920 if ( line != NULL ) {
1921 int len = strlen( c->argv[ 0 ] );
1923 ber_str2bv( line, 0, 0, &bv );
1924 AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
1925 bv.bv_len - ( len + 1 ) );
1926 bv.bv_val[ bv.bv_len - 1 ] = '"';
1927 ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
1932 case RWM_CF_SUFFIXMASSAGE:
1933 argv0 = c->argv[ 0 ];
1934 c->argv[ 0 ] += STRLENOF( "rwm-" );
1935 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno, c->argc, c->argv );
1936 c->argv[ 0 ] = argv0;
1944 /* FIXME: not optimal; in fact, this keeps track
1945 * of the fact that a set of rules was added
1946 * using the rwm-suffixmassage shortcut, but the
1947 * rules are not clarified */
1949 line = ldap_charray2str( c->argv, "\" \"" );
1950 if ( line != NULL ) {
1951 int len = strlen( c->argv[ 0 ] );
1953 ber_str2bv( line, 0, 0, &bv );
1954 AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
1955 bv.bv_len - ( len + 1 ) );
1956 bv.bv_val[ bv.bv_len - 1 ] = '"';
1957 ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
1962 case RWM_CF_T_F_SUPPORT:
1963 rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
1964 if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
1968 rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
1969 rwmap->rwm_flags |= t_f_mode[ rc ].mask;
1974 argv0 = c->argv[ 0 ];
1975 c->argv[ 0 ] += STRLENOF( "rwm-" );
1976 rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
1977 c->argv[ 0 ] = argv0;
1985 line = ldap_charray2str( &c->argv[ 1 ], " " );
1986 if ( line != NULL ) {
1987 ber_str2bv( line, 0, 0, &bv );
1988 ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
1993 case RWM_CF_NORMALIZE_MAPPED:
1994 if ( c->value_int ) {
1995 rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
1997 rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2014 slap_overinst *on = (slap_overinst *) be->bd_info;
2015 struct ldaprwmap *rwmap;
2019 rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
2021 rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
2022 if ( rwmap->rwm_rw == NULL ) {
2027 /* this rewriteContext by default must be null;
2028 * rules can be added if required */
2029 rargv[ 0 ] = "rewriteContext";
2030 rargv[ 1 ] = "searchFilter";
2032 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
2034 rargv[ 0 ] = "rewriteContext";
2035 rargv[ 1 ] = "default";
2037 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
2040 on->on_bi.bi_private = (void *)rwmap;
2043 (void)rwm_db_destroy( be, NULL );
2054 slap_overinst *on = (slap_overinst *) be->bd_info;
2057 if ( on->on_bi.bi_private ) {
2058 struct ldaprwmap *rwmap =
2059 (struct ldaprwmap *)on->on_bi.bi_private;
2061 if ( rwmap->rwm_rw ) {
2062 rewrite_info_delete( &rwmap->rwm_rw );
2063 ber_bvarray_free( rwmap->rwm_bva_rewrite );
2066 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2067 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2068 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2069 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2070 ber_bvarray_free( rwmap->rwm_bva_map );
2078 static slap_overinst rwm = { { NULL } };
2080 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2082 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2084 rwm_initialize( void )
2088 /* Make sure we don't exceed the bits reserved for userland */
2089 config_check_userland( RWM_CF_LAST );
2091 memset( &rwm, 0, sizeof( slap_overinst ) );
2093 rwm.on_bi.bi_type = "rwm";
2094 rwm.on_bi.bi_flags =
2095 SLAPO_BFLAG_SINGLE |
2098 rwm.on_bi.bi_db_init = rwm_db_init;
2099 rwm.on_bi.bi_db_config = rwm_db_config;
2100 rwm.on_bi.bi_db_destroy = rwm_db_destroy;
2102 rwm.on_bi.bi_op_bind = rwm_op_bind;
2103 rwm.on_bi.bi_op_search = rwm_op_search;
2104 rwm.on_bi.bi_op_compare = rwm_op_compare;
2105 rwm.on_bi.bi_op_modify = rwm_op_modify;
2106 rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
2107 rwm.on_bi.bi_op_add = rwm_op_add;
2108 rwm.on_bi.bi_op_delete = rwm_op_delete;
2109 rwm.on_bi.bi_op_unbind = rwm_op_unbind;
2110 rwm.on_bi.bi_extended = rwm_extended;
2112 rwm.on_bi.bi_operational = rwm_operational;
2113 rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
2115 rwm.on_bi.bi_connection_init = rwm_conn_init;
2116 rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
2118 rwm.on_response = rwm_response;
2120 rwm.on_bi.bi_cf_ocs = rwmocs;
2122 rc = config_register_schema( rwmcfg, rwmocs );
2127 return overlay_register( &rwm );
2130 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2132 init_module( int argc, char *argv[] )
2134 return rwm_initialize();
2136 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2138 #endif /* SLAPD_OVER_RWM */