1 /* rwmmap.c - rewrite/mapping routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1999-2004 The OpenLDAP Foundation.
6 * Portions Copyright 1999-2003 Howard Chu.
7 * Portions Copyright 2000-2003 Pierangelo Masarati.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by the Howard Chu for inclusion
20 * in OpenLDAP Software and subsequently enhanced by Pierangelo
30 #include <ac/string.h>
31 #include <ac/socket.h>
36 #undef ldap_debug /* silence a warning in ldap-int.h */
37 #include "../../../libraries/libldap/ldap-int.h"
40 rwm_mapping_cmp( const void *c1, const void *c2 )
42 struct ldapmapping *map1 = (struct ldapmapping *)c1;
43 struct ldapmapping *map2 = (struct ldapmapping *)c2;
44 int rc = map1->m_src.bv_len - map2->m_src.bv_len;
50 return strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val );
54 rwm_mapping_dup( void *c1, void *c2 )
56 struct ldapmapping *map1 = (struct ldapmapping *)c1;
57 struct ldapmapping *map2 = (struct ldapmapping *)c2;
58 int rc = map1->m_src.bv_len - map2->m_src.bv_len;
64 return ( ( strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val ) == 0 ) ? -1 : 0 );
68 rwm_map_init( struct ldapmap *lm, struct ldapmapping **m )
70 struct ldapmapping *mapping;
78 mapping = (struct ldapmapping *)ch_calloc( 2,
79 sizeof( struct ldapmapping ) );
80 if ( mapping == NULL ) {
81 return LDAP_NO_MEMORY;
84 /* FIXME: I don't think this is needed any more... */
85 rc = slap_str2ad( "objectClass", &mapping->m_src_ad, &text );
86 if ( rc != LDAP_SUCCESS ) {
90 mapping->m_dst_ad = mapping->m_src_ad;
91 ber_dupbv( &mapping->m_dst, &mapping->m_src_ad->ad_cname );
92 ber_dupbv( &mapping->m_dst, &mapping->m_src );
94 mapping[1].m_src = mapping->m_src;
95 mapping[1].m_dst = mapping->m_dst;
97 avl_insert( &lm->map, (caddr_t)mapping,
98 rwm_mapping_cmp, rwm_mapping_dup );
99 avl_insert( &lm->remap, (caddr_t)&mapping[1],
100 rwm_mapping_cmp, rwm_mapping_dup );
108 rwm_mapping( struct ldapmap *map, struct berval *s, struct ldapmapping **m, int remap )
111 struct ldapmapping fmapping;
115 if ( remap == RWM_REMAP ) {
123 *m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping,
127 return map->drop_missing;
134 rwm_map( struct ldapmap *map, struct berval *s, struct berval *bv, int remap )
136 struct ldapmapping *mapping;
139 rwm_mapping( map, s, &mapping, remap );
140 if ( mapping != NULL ) {
141 if ( !BER_BVISNULL( &mapping->m_dst ) ) {
142 *bv = mapping->m_dst;
147 if ( !map->drop_missing ) {
153 * Map attribute names in place
157 struct ldapmap *at_map,
158 struct ldapmap *oc_map,
170 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
172 *anp = ch_malloc( ( i + 1 )* sizeof( AttributeName ) );
173 if ( *anp == NULL ) {
174 return LDAP_NO_MEMORY;
177 for ( i = 0, j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
178 struct ldapmapping *m;
179 int at_drop_missing = 0,
182 if ( an[i].an_desc ) {
184 /* FIXME: better leave as is? */
188 at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
189 if ( at_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
200 if ( remap == RWM_MAP ) {
201 (*anp)[j].an_name = m->m_dst;
202 (*anp)[j].an_desc = m->m_dst_ad;
204 (*anp)[j].an_name = m->m_src;
205 (*anp)[j].an_desc = m->m_src_ad;
212 } else if ( an[i].an_oc ) {
214 /* FIXME: better leave as is? */
218 oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
220 if ( oc_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
231 if ( remap == RWM_MAP ) {
232 (*anp)[j].an_name = m->m_dst;
233 (*anp)[j].an_oc = m->m_dst_oc;
235 (*anp)[j].an_name = m->m_src;
236 (*anp)[j].an_oc = m->m_src_oc;
240 at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
242 if ( at_drop_missing || !m ) {
244 oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
246 /* if both at_map and oc_map required to drop missing,
248 if ( oc_drop_missing && at_drop_missing ) {
252 /* if no oc_map mapping was found and at_map required
253 * to drop missing, then do it; otherwise, at_map wins
254 * and an is considered an attr and is left unchanged */
256 if ( at_drop_missing ) {
264 if ( BER_BVISNULL( &m->m_dst ) ) {
269 if ( remap == RWM_MAP ) {
270 (*anp)[j].an_name = m->m_dst;
271 (*anp)[j].an_oc = m->m_dst_oc;
273 (*anp)[j].an_name = m->m_src;
274 (*anp)[j].an_oc = m->m_src_oc;
280 if ( !BER_BVISNULL( &m->m_dst ) ) {
282 if ( remap == RWM_MAP ) {
283 (*anp)[j].an_name = m->m_dst;
284 (*anp)[j].an_desc = m->m_dst_ad;
286 (*anp)[j].an_name = m->m_src;
287 (*anp)[j].an_desc = m->m_src_ad;
295 if ( j == 0 && i != 0 ) {
296 memset( &(*anp)[0], 0, sizeof( AttributeName ) );
297 BER_BVSTR( &(*anp)[0].an_name, LDAP_NO_ATTRS );
299 memset( &(*anp)[j], 0, sizeof( AttributeName ) );
306 struct ldapmap *at_map,
316 *mapped_attrs = NULL;
320 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
324 na = (char **)ch_calloc( i + 1, sizeof( char * ) );
326 *mapped_attrs = NULL;
327 return LDAP_NO_MEMORY;
330 for ( i = j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
331 struct ldapmapping *m;
333 if ( rwm_mapping( at_map, &an[i].an_name, &m, remap ) ) {
337 if ( !m || ( m && !BER_BVISNULL( &m->m_dst ) ) ) {
338 na[j++] = m->m_dst.bv_val;
341 if ( j == 0 && i != 0 ) {
342 na[j++] = LDAP_NO_ATTRS;
353 AttributeDescription *ad,
354 struct berval *mapped_attr,
355 struct berval *value,
356 struct berval *mapped_value,
362 rwm_map( &dc->rwmap->rwm_at, &ad->ad_cname, mapped_attr, remap );
363 if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
365 * FIXME: are we sure we need to search oc_map if at_map fails?
367 rwm_map( &dc->rwmap->rwm_oc, &ad->ad_cname, mapped_attr, remap );
368 if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) )
370 *mapped_attr = ad->ad_cname;
374 if ( value == NULL ) {
378 if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
383 #ifdef ENABLE_REWRITE
384 fdc.ctx = "searchFilterAttrDN";
387 rc = rwm_dn_massage( &fdc, value, &vtmp, NULL );
390 if ( vtmp.bv_val != value->bv_val ) {
395 case LDAP_UNWILLING_TO_PERFORM:
401 } else if ( ad == slap_schema.si_ad_objectClass
402 || ad == slap_schema.si_ad_structuralObjectClass )
404 rwm_map( &dc->rwmap->rwm_oc, value, &vtmp, remap );
405 if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
413 filter_escape_value( &vtmp, mapped_value );
416 ber_memfree( vtmp.bv_val );
423 rwm_int_filter_map_rewrite(
426 struct berval *fstr )
434 ber_bvfalse = BER_BVC( "(?=false)" ),
435 ber_bvtrue = BER_BVC( "(?=true)" ),
436 ber_bvundefined = BER_BVC( "(?=undefined)" ),
437 ber_bverror = BER_BVC( "(?=error)" ),
438 ber_bvunknown = BER_BVC( "(?=unknown)" ),
439 ber_bvnone = BER_BVC( "(?=none)" );
443 ber_dupbv( fstr, &ber_bvnone );
447 switch ( f->f_choice ) {
448 case LDAP_FILTER_EQUALITY:
449 if ( map_attr_value( dc, f->f_av_desc, &atmp,
450 &f->f_av_value, &vtmp, RWM_MAP ) )
455 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(=)" );
456 fstr->bv_val = malloc( fstr->bv_len + 1 );
458 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
459 atmp.bv_val, vtmp.bv_val );
461 ber_memfree( vtmp.bv_val );
465 if ( map_attr_value( dc, f->f_av_desc, &atmp,
466 &f->f_av_value, &vtmp, RWM_MAP ) )
471 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(>=)" );
472 fstr->bv_val = malloc( fstr->bv_len + 1 );
474 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
475 atmp.bv_val, vtmp.bv_val );
477 ber_memfree( vtmp.bv_val );
481 if ( map_attr_value( dc, f->f_av_desc, &atmp,
482 &f->f_av_value, &vtmp, RWM_MAP ) )
487 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(<=)" );
488 fstr->bv_val = malloc( fstr->bv_len + 1 );
490 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
491 atmp.bv_val, vtmp.bv_val );
493 ber_memfree( vtmp.bv_val );
496 case LDAP_FILTER_APPROX:
497 if ( map_attr_value( dc, f->f_av_desc, &atmp,
498 &f->f_av_value, &vtmp, RWM_MAP ) )
503 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(~=)" );
504 fstr->bv_val = malloc( fstr->bv_len + 1 );
506 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
507 atmp.bv_val, vtmp.bv_val );
509 ber_memfree( vtmp.bv_val );
512 case LDAP_FILTER_SUBSTRINGS:
513 if ( map_attr_value( dc, f->f_sub_desc, &atmp,
514 NULL, NULL, RWM_MAP ) )
519 /* cannot be a DN ... */
521 fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
522 fstr->bv_val = malloc( fstr->bv_len + 128 );
524 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
527 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
530 filter_escape_value( &f->f_sub_initial, &vtmp );
532 fstr->bv_len += vtmp.bv_len;
533 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
535 snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
536 /* "(attr=" */ "%s*)",
539 ber_memfree( vtmp.bv_val );
542 if ( f->f_sub_any != NULL ) {
543 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
545 filter_escape_value( &f->f_sub_any[i], &vtmp );
547 fstr->bv_len += vtmp.bv_len + 1;
548 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
550 snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
551 /* "(attr=[init]*[any*]" */ "%s*)",
553 ber_memfree( vtmp.bv_val );
557 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
560 filter_escape_value( &f->f_sub_final, &vtmp );
562 fstr->bv_len += vtmp.bv_len;
563 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
565 snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
566 /* "(attr=[init*][any*]" */ "%s)",
569 ber_memfree( vtmp.bv_val );
574 case LDAP_FILTER_PRESENT:
575 if ( map_attr_value( dc, f->f_desc, &atmp,
576 NULL, NULL, RWM_MAP ) )
581 fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
582 fstr->bv_val = malloc( fstr->bv_len + 1 );
584 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
588 case LDAP_FILTER_AND:
590 case LDAP_FILTER_NOT:
591 fstr->bv_len = STRLENOF( "(%)" );
592 fstr->bv_val = malloc( fstr->bv_len + 128 );
594 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
595 f->f_choice == LDAP_FILTER_AND ? '&' :
596 f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
598 for ( p = f->f_list; p != NULL; p = p->f_next ) {
601 if ( rwm_int_filter_map_rewrite( dc, p, &vtmp ) )
606 fstr->bv_len += vtmp.bv_len;
607 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
609 snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
610 /*"("*/ "%s)", vtmp.bv_val );
612 ch_free( vtmp.bv_val );
617 case LDAP_FILTER_EXT: {
618 if ( f->f_mr_desc ) {
619 if ( map_attr_value( dc, f->f_mr_desc, &atmp,
620 &f->f_mr_value, &vtmp, RWM_MAP ) )
626 BER_BVSTR( &atmp, "" );
627 filter_escape_value( &f->f_mr_value, &vtmp );
631 fstr->bv_len = atmp.bv_len +
632 ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
633 ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
634 vtmp.bv_len + STRLENOF( "(:=)" );
635 fstr->bv_val = malloc( fstr->bv_len + 1 );
637 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
639 f->f_mr_dnattrs ? ":dn" : "",
640 !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
641 !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
643 ber_memfree( vtmp.bv_val );
646 case SLAPD_FILTER_COMPUTED:
647 switch ( f->f_result ) {
648 case LDAP_COMPARE_FALSE:
652 case LDAP_COMPARE_TRUE:
656 case SLAPD_COMPARE_UNDEFINED:
657 tmp = ber_bvundefined;
665 ber_dupbv( fstr, &tmp );
669 ber_dupbv( fstr, &ber_bvunknown );
677 rwm_filter_map_rewrite(
680 struct berval *fstr )
686 rc = rwm_int_filter_map_rewrite( dc, f, fstr );
688 #ifdef ENABLE_REWRITE
689 if ( rc != LDAP_SUCCESS ) {
696 fdc.ctx = "searchFilter";
698 switch ( rewrite_session( fdc.rwmap->rwm_rw, fdc.ctx,
699 ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : "" ),
700 fdc.conn, &fstr->bv_val )) {
701 case REWRITE_REGEXEC_OK:
702 if ( !BER_BVISNULL( fstr ) ) {
703 fstr->bv_len = strlen( fstr->bv_val );
711 LDAP_LOG( BACK_LDAP, DETAIL1,
712 "[rw] %s: \"%s\" -> \"%s\"\n",
713 dc->ctx, ftmp.bv_val, fstr->bv_val );
714 #else /* !NEW_LOGGING */
715 Debug( LDAP_DEBUG_ARGS,
716 "[rw] %s: \"%s\" -> \"%s\"\n",
717 dc->ctx, ftmp.bv_val, fstr->bv_val );
718 #endif /* !NEW_LOGGING */
722 case REWRITE_REGEXEC_UNWILLING:
724 fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
725 fdc.rs->sr_text = "Operation not allowed";
727 rc = LDAP_UNWILLING_TO_PERFORM;
730 case REWRITE_REGEXEC_ERR:
732 fdc.rs->sr_err = LDAP_OTHER;
733 fdc.rs->sr_text = "Rewrite error";
739 #endif /* ENABLE_REWRITE */
744 * I don't like this much, but we need two different
745 * functions because different heap managers may be
746 * in use in back-ldap/meta to reduce the amount of
747 * calls to malloc routines, and some of the free()
748 * routines may be macros with args
756 BerVarray *pa_nvals )
758 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
759 struct ldaprwmap *rwmap =
760 (struct ldaprwmap *)on->on_bi.bi_private;
765 struct berval dn, ndn, *pndn = NULL;
770 * Rewrite the bind dn if needed
773 #ifdef ENABLE_REWRITE
774 dc.conn = op->o_conn;
776 dc.ctx = (char *)cookie;
778 dc.tofrom = ((int *)cookie)[0];
782 for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
783 if ( pa_nvals != NULL ) {
786 if ( *pa_nvals == NULL ) {
787 *pa_nvals = ch_malloc( last * sizeof(struct berval) );
788 memset( *pa_nvals, 0, last * sizeof(struct berval) );
793 for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
796 rc = rwm_dn_massage( &dc, &a_vals[i], &dn, pndn );
798 case LDAP_UNWILLING_TO_PERFORM:
800 * FIXME: need to check if it may be considered
801 * legal to trim values when adding/modifying;
802 * it should be when searching (e.g. ACLs).
804 ch_free( a_vals[i].bv_val );
806 a_vals[i] = a_vals[last];
808 (*pa_nvals)[i] = (*pa_nvals)[last];
811 BER_BVZERO( &a_vals[last] );
813 BER_BVZERO( &(*pa_nvals)[last] );
819 if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) {
820 ch_free( a_vals[i].bv_val );
823 if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
824 ch_free( (*pa_nvals)[i].bv_val );
826 (*pa_nvals)[i] = *pndn;
832 /* leave attr untouched if massage failed */
833 if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
834 dnNormalize( 0, NULL, NULL, &a_vals[i], &(*pa_nvals)[i], NULL );
844 rwm_dnattr_result_rewrite(
851 for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
854 for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
858 rc = rwm_dn_massage( dc, &a_vals[i], &dn, NULL );
860 case LDAP_UNWILLING_TO_PERFORM:
862 * FIXME: need to check if it may be considered
863 * legal to trim values when adding/modifying;
864 * it should be when searching (e.g. ACLs).
866 LBER_FREE( &a_vals[i].bv_val );
868 a_vals[i] = a_vals[last];
870 BER_BVZERO( &a_vals[last] );
875 /* leave attr untouched if massage failed */
876 if ( !BER_BVISNULL( &dn ) && a_vals[i].bv_val != dn.bv_val ) {
877 LBER_FREE( a_vals[i].bv_val );
888 rwm_mapping_free( void *v_mapping )
890 struct ldapmapping *mapping = v_mapping;
892 if ( !BER_BVISNULL( &mapping[0].m_src ) ) {
893 ch_free( mapping[0].m_src.bv_val );
896 if ( mapping[0].m_flags & RWMMAP_F_FREE_SRC ) {
897 if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
898 if ( mapping[0].m_src_oc ) {
899 ch_free( mapping[0].m_src_oc );
903 if ( mapping[0].m_src_ad ) {
904 ch_free( mapping[0].m_src_ad );
909 if ( !BER_BVISNULL( &mapping[0].m_dst ) ) {
910 ch_free( mapping[0].m_dst.bv_val );
913 if ( mapping[0].m_flags & RWMMAP_F_FREE_DST ) {
914 if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
915 if ( mapping[0].m_dst_oc ) {
916 ch_free( mapping[0].m_dst_oc );
920 if ( mapping[0].m_dst_ad ) {
921 ch_free( mapping[0].m_dst_ad );
930 #endif /* SLAPD_OVER_RWM */