1 /* map.c - ldap backend mapping routines */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/map.c,v 1.15.2.7 2008/02/11 23:26:47 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by the Howard Chu for inclusion
18 * in OpenLDAP Software and subsequently enhanced by Pierangelo
21 /* This is an altered version */
23 * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
25 * Permission is granted to anyone to use this software for any purpose
26 * on any computer system, and to alter it and redistribute it, subject
27 * to the following restrictions:
29 * 1. The author is not responsible for the consequences of use of this
30 * software, no matter how awful, even if they arise from flaws in it.
32 * 2. The origin of this software must not be misrepresented, either by
33 * explicit claim or by omission. Since few users ever read sources,
34 * credits should appear in the documentation.
36 * 3. Altered versions must be plainly marked as such, and must not be
37 * misrepresented as being the original software. Since few users
38 * ever read sources, credits should appear in the documentation.
40 * 4. This notice may not be removed or altered.
44 * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
46 * This software is being modified by Pierangelo Masarati.
47 * The previously reported conditions apply to the modified code as well.
48 * Changes in the original code are highlighted where required.
49 * Credits for the original code go to the author, Howard Chu.
56 #include <ac/string.h>
57 #include <ac/socket.h>
61 #include "../back-ldap/back-ldap.h"
62 #include "back-meta.h"
64 #undef ldap_debug /* silence a warning in ldap-int.h */
65 #include "../../../libraries/libldap/ldap-int.h"
68 mapping_cmp ( const void *c1
, const void *c2
)
70 struct ldapmapping
*map1
= (struct ldapmapping
*)c1
;
71 struct ldapmapping
*map2
= (struct ldapmapping
*)c2
;
72 int rc
= map1
->src
.bv_len
- map2
->src
.bv_len
;
74 return ( strcasecmp( map1
->src
.bv_val
, map2
->src
.bv_val
) );
78 mapping_dup ( void *c1
, void *c2
)
80 struct ldapmapping
*map1
= (struct ldapmapping
*)c1
;
81 struct ldapmapping
*map2
= (struct ldapmapping
*)c2
;
83 return ( ( strcasecmp( map1
->src
.bv_val
, map2
->src
.bv_val
) == 0 ) ? -1 : 0 );
87 ldap_back_map_init ( struct ldapmap
*lm
, struct ldapmapping
**m
)
89 struct ldapmapping
*mapping
;
95 mapping
= (struct ldapmapping
*)ch_calloc( 2,
96 sizeof( struct ldapmapping
) );
97 if ( mapping
== NULL
) {
101 ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping
[0].src
);
102 ber_dupbv( &mapping
[0].dst
, &mapping
[0].src
);
103 mapping
[1].src
= mapping
[0].src
;
104 mapping
[1].dst
= mapping
[0].dst
;
106 avl_insert( &lm
->map
, (caddr_t
)&mapping
[0],
107 mapping_cmp
, mapping_dup
);
108 avl_insert( &lm
->remap
, (caddr_t
)&mapping
[1],
109 mapping_cmp
, mapping_dup
);
114 ldap_back_mapping ( struct ldapmap
*map
, struct berval
*s
, struct ldapmapping
**m
,
118 struct ldapmapping fmapping
;
122 if ( remap
== BACKLDAP_REMAP
) {
130 *m
= (struct ldapmapping
*)avl_find( tree
, (caddr_t
)&fmapping
, mapping_cmp
);
132 return map
->drop_missing
;
139 ldap_back_map ( struct ldapmap
*map
, struct berval
*s
, struct berval
*bv
,
142 struct ldapmapping
*mapping
;
144 /* map->map may be NULL when mapping is configured,
145 * but map->remap can't */
146 if ( map
->remap
== NULL
) {
152 ( void )ldap_back_mapping( map
, s
, &mapping
, remap
);
153 if ( mapping
!= NULL
) {
154 if ( !BER_BVISNULL( &mapping
->dst
) ) {
160 if ( !map
->drop_missing
) {
167 struct ldapmap
*at_map
,
175 struct berval mapped
;
178 *mapped_attrs
= NULL
;
182 for ( i
= 0; !BER_BVISNULL( &an
[i
].an_name
); i
++ )
185 na
= (char **)ch_calloc( i
+ 1, sizeof(char *) );
187 *mapped_attrs
= NULL
;
188 return LDAP_NO_MEMORY
;
191 for ( i
= j
= 0; !BER_BVISNULL( &an
[i
].an_name
); i
++ ) {
192 ldap_back_map( at_map
, &an
[i
].an_name
, &mapped
, remap
);
193 if ( !BER_BVISNULL( &mapped
) && !BER_BVISEMPTY( &mapped
) ) {
194 na
[j
++] = mapped
.bv_val
;
197 if ( j
== 0 && i
!= 0 ) {
198 na
[j
++] = LDAP_NO_ATTRS
;
209 AttributeDescription
*ad
,
210 struct berval
*mapped_attr
,
211 struct berval
*value
,
212 struct berval
*mapped_value
,
218 ldap_back_map( &dc
->target
->mt_rwmap
.rwm_at
, &ad
->ad_cname
, mapped_attr
, remap
);
219 if ( BER_BVISNULL( mapped_attr
) || BER_BVISEMPTY( mapped_attr
) ) {
222 * FIXME: are we sure we need to search oc_map if at_map fails?
224 ldap_back_map( &dc
->target
->mt_rwmap
.rwm_oc
, &ad
->ad_cname
, mapped_attr
, remap
);
225 if ( BER_BVISNULL( mapped_attr
) || BER_BVISEMPTY( mapped_attr
) ) {
226 *mapped_attr
= ad
->ad_cname
;
229 if ( dc
->target
->mt_rwmap
.rwm_at
.drop_missing
) {
233 *mapped_attr
= ad
->ad_cname
;
236 if ( value
== NULL
) {
240 if ( ad
->ad_type
->sat_syntax
== slap_schema
.si_syn_distinguishedName
)
244 #ifdef ENABLE_REWRITE
245 fdc
.ctx
= "searchFilterAttrDN";
248 switch ( ldap_back_dn_massage( &fdc
, value
, &vtmp
) ) {
250 if ( vtmp
.bv_val
!= value
->bv_val
) {
255 case LDAP_UNWILLING_TO_PERFORM
:
262 } else if ( ad
->ad_type
->sat_equality
->smr_usage
& SLAP_MR_MUTATION_NORMALIZER
) {
263 if ( ad
->ad_type
->sat_equality
->smr_normalize(
264 (SLAP_MR_DENORMALIZE
|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
),
265 NULL
, NULL
, value
, &vtmp
, NULL
) )
271 } else if ( ad
== slap_schema
.si_ad_objectClass
|| ad
== slap_schema
.si_ad_structuralObjectClass
) {
272 ldap_back_map( &dc
->target
->mt_rwmap
.rwm_oc
, value
, &vtmp
, remap
);
273 if ( BER_BVISNULL( &vtmp
) || BER_BVISEMPTY( &vtmp
) ) {
281 filter_escape_value( &vtmp
, mapped_value
);
284 ber_memfree( vtmp
.bv_val
);
291 ldap_back_int_filter_map_rewrite(
303 /* better than nothing... */
304 ber_bvfalse
= BER_BVC( "(!(objectClass=*))" ),
305 ber_bvtf_false
= BER_BVC( "(|)" ),
306 /* better than nothing... */
307 ber_bvtrue
= BER_BVC( "(objectClass=*)" ),
308 ber_bvtf_true
= BER_BVC( "(&)" ),
310 /* no longer needed; preserved for completeness */
311 ber_bvundefined
= BER_BVC( "(?=undefined)" ),
313 ber_bverror
= BER_BVC( "(?=error)" ),
314 ber_bvunknown
= BER_BVC( "(?=unknown)" ),
315 ber_bvnone
= BER_BVC( "(?=none)" );
318 assert( fstr
!= NULL
);
322 ber_dupbv( fstr
, &ber_bvnone
);
326 switch ( f
->f_choice
) {
327 case LDAP_FILTER_EQUALITY
:
328 if ( map_attr_value( dc
, f
->f_av_desc
, &atmp
,
329 &f
->f_av_value
, &vtmp
, remap
) )
334 fstr
->bv_len
= atmp
.bv_len
+ vtmp
.bv_len
335 + ( sizeof("(=)") - 1 );
336 fstr
->bv_val
= malloc( fstr
->bv_len
+ 1 );
338 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s=%s)",
339 atmp
.bv_val
, vtmp
.bv_len
? vtmp
.bv_val
: "" );
341 ber_memfree( vtmp
.bv_val
);
345 if ( map_attr_value( dc
, f
->f_av_desc
, &atmp
,
346 &f
->f_av_value
, &vtmp
, remap
) )
351 fstr
->bv_len
= atmp
.bv_len
+ vtmp
.bv_len
352 + ( sizeof("(>=)") - 1 );
353 fstr
->bv_val
= malloc( fstr
->bv_len
+ 1 );
355 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s>=%s)",
356 atmp
.bv_val
, vtmp
.bv_len
? vtmp
.bv_val
: "" );
358 ber_memfree( vtmp
.bv_val
);
362 if ( map_attr_value( dc
, f
->f_av_desc
, &atmp
,
363 &f
->f_av_value
, &vtmp
, remap
) )
368 fstr
->bv_len
= atmp
.bv_len
+ vtmp
.bv_len
369 + ( sizeof("(<=)") - 1 );
370 fstr
->bv_val
= malloc( fstr
->bv_len
+ 1 );
372 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s<=%s)",
373 atmp
.bv_val
, vtmp
.bv_len
? vtmp
.bv_val
: "" );
375 ber_memfree( vtmp
.bv_val
);
378 case LDAP_FILTER_APPROX
:
379 if ( map_attr_value( dc
, f
->f_av_desc
, &atmp
,
380 &f
->f_av_value
, &vtmp
, remap
) )
385 fstr
->bv_len
= atmp
.bv_len
+ vtmp
.bv_len
386 + ( sizeof("(~=)") - 1 );
387 fstr
->bv_val
= malloc( fstr
->bv_len
+ 1 );
389 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s~=%s)",
390 atmp
.bv_val
, vtmp
.bv_len
? vtmp
.bv_val
: "" );
392 ber_memfree( vtmp
.bv_val
);
395 case LDAP_FILTER_SUBSTRINGS
:
396 if ( map_attr_value( dc
, f
->f_sub_desc
, &atmp
,
397 NULL
, NULL
, remap
) )
402 /* cannot be a DN ... */
404 fstr
->bv_len
= atmp
.bv_len
+ ( STRLENOF( "(=*)" ) );
405 fstr
->bv_val
= malloc( fstr
->bv_len
+ 128 ); /* FIXME: why 128 ? */
407 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s=*)",
410 if ( !BER_BVISNULL( &f
->f_sub_initial
) ) {
413 filter_escape_value( &f
->f_sub_initial
, &vtmp
);
415 fstr
->bv_len
+= vtmp
.bv_len
;
416 fstr
->bv_val
= ch_realloc( fstr
->bv_val
, fstr
->bv_len
+ 1 );
418 snprintf( &fstr
->bv_val
[len
- 2], vtmp
.bv_len
+ 3,
419 /* "(attr=" */ "%s*)",
420 vtmp
.bv_len
? vtmp
.bv_val
: "" );
422 ber_memfree( vtmp
.bv_val
);
425 if ( f
->f_sub_any
!= NULL
) {
426 for ( i
= 0; !BER_BVISNULL( &f
->f_sub_any
[i
] ); i
++ ) {
428 filter_escape_value( &f
->f_sub_any
[i
], &vtmp
);
430 fstr
->bv_len
+= vtmp
.bv_len
+ 1;
431 fstr
->bv_val
= ch_realloc( fstr
->bv_val
, fstr
->bv_len
+ 1 );
433 snprintf( &fstr
->bv_val
[len
- 1], vtmp
.bv_len
+ 3,
434 /* "(attr=[init]*[any*]" */ "%s*)",
435 vtmp
.bv_len
? vtmp
.bv_val
: "" );
436 ber_memfree( vtmp
.bv_val
);
440 if ( !BER_BVISNULL( &f
->f_sub_final
) ) {
443 filter_escape_value( &f
->f_sub_final
, &vtmp
);
445 fstr
->bv_len
+= vtmp
.bv_len
;
446 fstr
->bv_val
= ch_realloc( fstr
->bv_val
, fstr
->bv_len
+ 1 );
448 snprintf( &fstr
->bv_val
[len
- 1], vtmp
.bv_len
+ 3,
449 /* "(attr=[init*][any*]" */ "%s)",
450 vtmp
.bv_len
? vtmp
.bv_val
: "" );
452 ber_memfree( vtmp
.bv_val
);
457 case LDAP_FILTER_PRESENT
:
458 if ( map_attr_value( dc
, f
->f_desc
, &atmp
,
459 NULL
, NULL
, remap
) )
464 fstr
->bv_len
= atmp
.bv_len
+ ( STRLENOF( "(=*)" ) );
465 fstr
->bv_val
= malloc( fstr
->bv_len
+ 1 );
467 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s=*)",
471 case LDAP_FILTER_AND
:
473 case LDAP_FILTER_NOT
:
474 fstr
->bv_len
= STRLENOF( "(%)" );
475 fstr
->bv_val
= malloc( fstr
->bv_len
+ 128 ); /* FIXME: why 128? */
477 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%c)",
478 f
->f_choice
== LDAP_FILTER_AND
? '&' :
479 f
->f_choice
== LDAP_FILTER_OR
? '|' : '!' );
481 for ( p
= f
->f_list
; p
!= NULL
; p
= p
->f_next
) {
486 rc
= ldap_back_int_filter_map_rewrite( dc
, p
, &vtmp
, remap
);
487 if ( rc
!= LDAP_SUCCESS
) {
491 fstr
->bv_len
+= vtmp
.bv_len
;
492 fstr
->bv_val
= ch_realloc( fstr
->bv_val
, fstr
->bv_len
+ 1 );
494 snprintf( &fstr
->bv_val
[len
-1], vtmp
.bv_len
+ 2,
495 /*"("*/ "%s)", vtmp
.bv_len
? vtmp
.bv_val
: "" );
497 ch_free( vtmp
.bv_val
);
502 case LDAP_FILTER_EXT
:
503 if ( f
->f_mr_desc
) {
504 if ( map_attr_value( dc
, f
->f_mr_desc
, &atmp
,
505 &f
->f_mr_value
, &vtmp
, remap
) )
511 BER_BVSTR( &atmp
, "" );
512 filter_escape_value( &f
->f_mr_value
, &vtmp
);
515 /* FIXME: cleanup (less ?: operators...) */
516 fstr
->bv_len
= atmp
.bv_len
+
517 ( f
->f_mr_dnattrs
? STRLENOF( ":dn" ) : 0 ) +
518 ( !BER_BVISEMPTY( &f
->f_mr_rule_text
) ? f
->f_mr_rule_text
.bv_len
+ 1 : 0 ) +
519 vtmp
.bv_len
+ ( STRLENOF( "(:=)" ) );
520 fstr
->bv_val
= malloc( fstr
->bv_len
+ 1 );
522 snprintf( fstr
->bv_val
, fstr
->bv_len
+ 1, "(%s%s%s%s:=%s)",
524 f
->f_mr_dnattrs
? ":dn" : "",
525 !BER_BVISEMPTY( &f
->f_mr_rule_text
) ? ":" : "",
526 !BER_BVISEMPTY( &f
->f_mr_rule_text
) ? f
->f_mr_rule_text
.bv_val
: "",
527 vtmp
.bv_len
? vtmp
.bv_val
: "" );
528 ber_memfree( vtmp
.bv_val
);
531 case SLAPD_FILTER_COMPUTED
:
532 switch ( f
->f_result
) {
533 case LDAP_COMPARE_FALSE
:
534 /* FIXME: treat UNDEFINED as FALSE */
535 case SLAPD_COMPARE_UNDEFINED
:
537 if ( META_BACK_TGT_T_F( dc
->target
) ) {
538 tmp
= &ber_bvtf_false
;
544 case LDAP_COMPARE_TRUE
:
545 if ( META_BACK_TGT_T_F( dc
->target
) ) {
546 tmp
= &ber_bvtf_true
;
558 ber_dupbv( fstr
, tmp
);
562 ber_dupbv( fstr
, &ber_bvunknown
);
570 ldap_back_filter_map_rewrite(
579 static char *dmy
= "";
581 rc
= ldap_back_int_filter_map_rewrite( dc
, f
, fstr
, remap
);
583 #ifdef ENABLE_REWRITE
584 if ( rc
!= LDAP_SUCCESS
) {
591 fdc
.ctx
= "searchFilter";
593 switch ( rewrite_session( fdc
.target
->mt_rwmap
.rwm_rw
, fdc
.ctx
,
594 ( !BER_BVISEMPTY( &ftmp
) ? ftmp
.bv_val
: dmy
),
595 fdc
.conn
, &fstr
->bv_val
) )
597 case REWRITE_REGEXEC_OK
:
598 if ( !BER_BVISNULL( fstr
) ) {
599 fstr
->bv_len
= strlen( fstr
->bv_val
);
604 Debug( LDAP_DEBUG_ARGS
,
605 "[rw] %s: \"%s\" -> \"%s\"\n",
606 fdc
.ctx
, BER_BVISNULL( &ftmp
) ? "" : ftmp
.bv_val
,
607 BER_BVISNULL( fstr
) ? "" : fstr
->bv_val
);
611 case REWRITE_REGEXEC_UNWILLING
:
613 fdc
.rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
614 fdc
.rs
->sr_text
= "Operation not allowed";
616 rc
= LDAP_UNWILLING_TO_PERFORM
;
619 case REWRITE_REGEXEC_ERR
:
621 fdc
.rs
->sr_err
= LDAP_OTHER
;
622 fdc
.rs
->sr_text
= "Rewrite error";
628 if ( fstr
->bv_val
== dmy
) {
631 #endif /* ENABLE_REWRITE */
637 ldap_back_referral_result_rewrite(
644 assert( dc
!= NULL
);
645 assert( a_vals
!= NULL
);
647 for ( last
= 0; !BER_BVISNULL( &a_vals
[ last
] ); last
++ )
651 for ( i
= 0; !BER_BVISNULL( &a_vals
[ i
] ); i
++ ) {
657 rc
= ldap_url_parse( a_vals
[ i
].bv_val
, &ludp
);
658 if ( rc
!= LDAP_URL_SUCCESS
) {
659 /* leave attr untouched if massage failed */
663 /* FIXME: URLs like "ldap:///dc=suffix" if passed
664 * thru ldap_url_parse() and ldap_url_desc2str()
665 * get rewritten as "ldap:///dc=suffix??base";
666 * we don't want this to occur... */
667 if ( ludp
->lud_scope
== LDAP_SCOPE_BASE
) {
668 ludp
->lud_scope
= LDAP_SCOPE_DEFAULT
;
671 ber_str2bv( ludp
->lud_dn
, 0, 0, &olddn
);
673 rc
= ldap_back_dn_massage( dc
, &olddn
, &dn
);
675 case LDAP_UNWILLING_TO_PERFORM
:
677 * FIXME: need to check if it may be considered
678 * legal to trim values when adding/modifying;
679 * it should be when searching (e.g. ACLs).
681 LBER_FREE( a_vals
[ i
].bv_val
);
683 a_vals
[ i
] = a_vals
[ last
];
685 BER_BVZERO( &a_vals
[ last
] );
691 /* leave attr untouched if massage failed */
692 if ( !BER_BVISNULL( &dn
) && olddn
.bv_val
!= dn
.bv_val
)
696 ludp
->lud_dn
= dn
.bv_val
;
697 newurl
= ldap_url_desc2str( ludp
);
699 if ( newurl
== NULL
) {
700 /* FIXME: leave attr untouched
701 * even if ldap_url_desc2str failed...
706 LBER_FREE( a_vals
[ i
].bv_val
);
707 ber_str2bv( newurl
, 0, 1, &a_vals
[ i
] );
709 ludp
->lud_dn
= olddn
.bv_val
;
714 ldap_free_urldesc( ludp
);
721 * I don't like this much, but we need two different
722 * functions because different heap managers may be
723 * in use in back-ldap/meta to reduce the amount of
724 * calls to malloc routines, and some of the free()
725 * routines may be macros with args
736 assert( a_vals
!= NULL
);
738 for ( last
= 0; !BER_BVISNULL( &a_vals
[last
] ); last
++ )
742 for ( i
= 0; !BER_BVISNULL( &a_vals
[i
] ); i
++ ) {
743 switch ( ldap_back_dn_massage( dc
, &a_vals
[i
], &bv
) ) {
744 case LDAP_UNWILLING_TO_PERFORM
:
746 * FIXME: need to check if it may be considered
747 * legal to trim values when adding/modifying;
748 * it should be when searching (e.g. ACLs).
750 ch_free( a_vals
[i
].bv_val
);
752 a_vals
[i
] = a_vals
[last
];
754 BER_BVZERO( &a_vals
[last
] );
759 /* leave attr untouched if massage failed */
760 if ( !BER_BVISNULL( &bv
) && bv
.bv_val
!= a_vals
[i
].bv_val
) {
761 ch_free( a_vals
[i
].bv_val
);
772 ldap_dnattr_result_rewrite(
780 assert( a_vals
!= NULL
);
782 for ( last
= 0; !BER_BVISNULL( &a_vals
[last
] ); last
++ )
786 for ( i
= 0; !BER_BVISNULL( &a_vals
[i
] ); i
++ ) {
787 switch ( ldap_back_dn_massage( dc
, &a_vals
[i
], &bv
) ) {
788 case LDAP_UNWILLING_TO_PERFORM
:
790 * FIXME: need to check if it may be considered
791 * legal to trim values when adding/modifying;
792 * it should be when searching (e.g. ACLs).
794 LBER_FREE( a_vals
[i
].bv_val
);
796 a_vals
[i
] = a_vals
[last
];
798 BER_BVZERO( &a_vals
[last
] );
803 /* leave attr untouched if massage failed */
804 if ( !BER_BVISNULL( &bv
) && a_vals
[i
].bv_val
!= bv
.bv_val
) {
805 LBER_FREE( a_vals
[i
].bv_val
);