]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/map.c
don't lookup rootdn if the password is incorrect (ITS#4004)
[openldap] / servers / slapd / back-meta / map.c
1 /* map.c - ldap backend mapping routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by the Howard Chu for inclusion
18  * in OpenLDAP Software and subsequently enhanced by Pierangelo
19  * Masarati.
20  */
21 /* This is an altered version */
22 /*
23  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
24  * 
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:
28  * 
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.
31  * 
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.
35  * 
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.
39  * 
40  * 4. This notice may not be removed or altered.
41  *
42  *
43  *
44  * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
45  * 
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.
50  */
51
52 #include "portable.h"
53
54 #include <stdio.h>
55
56 #include <ac/string.h>
57 #include <ac/socket.h>
58
59 #include "slap.h"
60 #include "../back-ldap/back-ldap.h"
61 #include "back-meta.h"
62
63 #undef ldap_debug       /* silence a warning in ldap-int.h */
64 #include "../../../libraries/libldap/ldap-int.h"
65
66 int
67 mapping_cmp ( const void *c1, const void *c2 )
68 {
69         struct ldapmapping *map1 = (struct ldapmapping *)c1;
70         struct ldapmapping *map2 = (struct ldapmapping *)c2;
71         int rc = map1->src.bv_len - map2->src.bv_len;
72         if (rc) return rc;
73         return ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) );
74 }
75
76 int
77 mapping_dup ( void *c1, void *c2 )
78 {
79         struct ldapmapping *map1 = (struct ldapmapping *)c1;
80         struct ldapmapping *map2 = (struct ldapmapping *)c2;
81
82         return ( ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) == 0 ) ? -1 : 0 );
83 }
84
85 void
86 ldap_back_map_init ( struct ldapmap *lm, struct ldapmapping **m )
87 {
88         struct ldapmapping *mapping;
89
90         assert( m != NULL );
91
92         *m = NULL;
93         
94         mapping = (struct ldapmapping *)ch_calloc( 2, 
95                         sizeof( struct ldapmapping ) );
96         if ( mapping == NULL ) {
97                 return;
98         }
99
100         ber_str2bv( "objectclass", sizeof("objectclass")-1, 1, &mapping->src);
101         ber_dupbv( &mapping->dst, &mapping->src );
102         mapping[1].src = mapping->src;
103         mapping[1].dst = mapping->dst;
104
105         avl_insert( &lm->map, (caddr_t)mapping, 
106                         mapping_cmp, mapping_dup );
107         avl_insert( &lm->remap, (caddr_t)&mapping[1], 
108                         mapping_cmp, mapping_dup );
109         *m = mapping;
110 }
111
112 int
113 ldap_back_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **m,
114         int remap )
115 {
116         Avlnode *tree;
117         struct ldapmapping fmapping;
118
119         assert( m != NULL );
120
121         if ( remap == BACKLDAP_REMAP ) {
122                 tree = map->remap;
123         } else {
124                 tree = map->map;
125         }
126
127         fmapping.src = *s;
128         *m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, mapping_cmp );
129         if ( *m == NULL ) {
130                 return map->drop_missing;
131         }
132
133         return 0;
134 }
135
136 void
137 ldap_back_map ( struct ldapmap *map, struct berval *s, struct berval *bv,
138         int remap )
139 {
140         struct ldapmapping *mapping;
141
142         BER_BVZERO( bv );
143         ( void )ldap_back_mapping( map, s, &mapping, remap );
144         if ( mapping != NULL ) {
145                 if ( !BER_BVISNULL( &mapping->dst ) ) {
146                         *bv = mapping->dst;
147                 }
148                 return;
149         }
150
151         if ( !map->drop_missing ) {
152                 *bv = *s;
153         }
154 }
155
156 int
157 ldap_back_map_attrs(
158                 struct ldapmap *at_map,
159                 AttributeName *an,
160                 int remap,
161                 char ***mapped_attrs
162 )
163 {
164         int i, j;
165         char **na;
166         struct berval mapped;
167
168         if ( an == NULL ) {
169                 *mapped_attrs = NULL;
170                 return LDAP_SUCCESS;
171         }
172
173         for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
174                 /*  */ ;
175
176         na = (char **)ch_calloc( i + 1, sizeof(char *) );
177         if ( na == NULL ) {
178                 *mapped_attrs = NULL;
179                 return LDAP_NO_MEMORY;
180         }
181
182         for ( i = j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
183                 ldap_back_map( at_map, &an[i].an_name, &mapped, remap );
184                 if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
185                         na[j++] = mapped.bv_val;
186                 }
187         }
188         if ( j == 0 && i != 0 ) {
189                 na[j++] = LDAP_NO_ATTRS;
190         }
191         na[j] = NULL;
192
193         *mapped_attrs = na;
194         return LDAP_SUCCESS;
195 }
196
197 int
198 map_attr_value(
199                 dncookie                *dc,
200                 AttributeDescription    *ad,
201                 struct berval           *mapped_attr,
202                 struct berval           *value,
203                 struct berval           *mapped_value,
204                 int                     remap )
205 {
206         struct berval           vtmp;
207         int                     freeval = 0;
208
209         ldap_back_map( &dc->target->mt_rwmap.rwm_at, &ad->ad_cname, mapped_attr, remap );
210         if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
211                 /*
212                  * FIXME: are we sure we need to search oc_map if at_map fails?
213                  */
214                 ldap_back_map( &dc->target->mt_rwmap.rwm_oc, &ad->ad_cname, mapped_attr, remap );
215                 if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
216                         *mapped_attr = ad->ad_cname;
217                 }
218         }
219
220         if ( value == NULL ) {
221                 return 0;
222         }
223
224         if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
225         {
226                 dncookie fdc = *dc;
227
228 #ifdef ENABLE_REWRITE
229                 fdc.ctx = "searchFilterAttrDN";
230 #endif
231
232                 switch ( ldap_back_dn_massage( &fdc, value, &vtmp ) ) {
233                 case LDAP_SUCCESS:
234                         if ( vtmp.bv_val != value->bv_val ) {
235                                 freeval = 1;
236                         }
237                         break;
238                 
239                 case LDAP_UNWILLING_TO_PERFORM:
240                         return -1;
241
242                 case LDAP_OTHER:
243                         return -1;
244                 }
245
246         } else if ( ad == slap_schema.si_ad_objectClass || ad == slap_schema.si_ad_structuralObjectClass ) {
247                 ldap_back_map( &dc->target->mt_rwmap.rwm_oc, value, &vtmp, remap );
248                 if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
249                         vtmp = *value;
250                 }
251                 
252         } else {
253                 vtmp = *value;
254         }
255
256         filter_escape_value( &vtmp, mapped_value );
257
258         if ( freeval ) {
259                 ber_memfree( vtmp.bv_val );
260         }
261         
262         return 0;
263 }
264
265 static int
266 ldap_back_int_filter_map_rewrite(
267                 dncookie                *dc,
268                 Filter                  *f,
269                 struct berval           *fstr,
270                 int                     remap )
271 {
272         int             i;
273         Filter          *p;
274         struct berval   atmp;
275         struct berval   vtmp;
276         ber_len_t       len;
277
278         if ( f == NULL ) {
279                 ber_str2bv( "No filter!", STRLENOF( "No filter!" ), 1, fstr );
280                 return -1;
281         }
282
283         switch ( f->f_choice ) {
284         case LDAP_FILTER_EQUALITY:
285                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
286                                         &f->f_av_value, &vtmp, remap ) )
287                 {
288                         return -1;
289                 }
290
291                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
292                         + ( sizeof("(=)") - 1 );
293                 fstr->bv_val = malloc( fstr->bv_len + 1 );
294
295                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
296                         atmp.bv_val, vtmp.bv_val );
297
298                 ber_memfree( vtmp.bv_val );
299                 break;
300
301         case LDAP_FILTER_GE:
302                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
303                                         &f->f_av_value, &vtmp, remap ) )
304                 {
305                         return -1;
306                 }
307
308                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
309                         + ( sizeof("(>=)") - 1 );
310                 fstr->bv_val = malloc( fstr->bv_len + 1 );
311
312                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
313                         atmp.bv_val, vtmp.bv_val );
314
315                 ber_memfree( vtmp.bv_val );
316                 break;
317
318         case LDAP_FILTER_LE:
319                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
320                                         &f->f_av_value, &vtmp, remap ) )
321                 {
322                         return -1;
323                 }
324
325                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
326                         + ( sizeof("(<=)") - 1 );
327                 fstr->bv_val = malloc( fstr->bv_len + 1 );
328
329                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
330                         atmp.bv_val, vtmp.bv_val );
331
332                 ber_memfree( vtmp.bv_val );
333                 break;
334
335         case LDAP_FILTER_APPROX:
336                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
337                                         &f->f_av_value, &vtmp, remap ) )
338                 {
339                         return -1;
340                 }
341
342                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
343                         + ( sizeof("(~=)") - 1 );
344                 fstr->bv_val = malloc( fstr->bv_len + 1 );
345
346                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
347                         atmp.bv_val, vtmp.bv_val );
348
349                 ber_memfree( vtmp.bv_val );
350                 break;
351
352         case LDAP_FILTER_SUBSTRINGS:
353                 if ( map_attr_value( dc, f->f_sub_desc, &atmp,
354                                         NULL, NULL, remap ) )
355                 {
356                         return -1;
357                 }
358
359                 /* cannot be a DN ... */
360
361                 fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
362                 fstr->bv_val = malloc( fstr->bv_len + 128 ); /* FIXME: why 128 ? */
363
364                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
365                         atmp.bv_val );
366
367                 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
368                         len = fstr->bv_len;
369
370                         filter_escape_value( &f->f_sub_initial, &vtmp );
371
372                         fstr->bv_len += vtmp.bv_len;
373                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
374
375                         snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
376                                 /* "(attr=" */ "%s*)",
377                                 vtmp.bv_val );
378
379                         ber_memfree( vtmp.bv_val );
380                 }
381
382                 if ( f->f_sub_any != NULL ) {
383                         for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
384                                 len = fstr->bv_len;
385                                 filter_escape_value( &f->f_sub_any[i], &vtmp );
386
387                                 fstr->bv_len += vtmp.bv_len + 1;
388                                 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
389
390                                 snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
391                                         /* "(attr=[init]*[any*]" */ "%s*)",
392                                         vtmp.bv_val );
393                                 ber_memfree( vtmp.bv_val );
394                         }
395                 }
396
397                 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
398                         len = fstr->bv_len;
399
400                         filter_escape_value( &f->f_sub_final, &vtmp );
401
402                         fstr->bv_len += vtmp.bv_len;
403                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
404
405                         snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
406                                 /* "(attr=[init*][any*]" */ "%s)",
407                                 vtmp.bv_val );
408
409                         ber_memfree( vtmp.bv_val );
410                 }
411
412                 break;
413
414         case LDAP_FILTER_PRESENT:
415                 if ( map_attr_value( dc, f->f_desc, &atmp,
416                                         NULL, NULL, remap ) )
417                 {
418                         return -1;
419                 }
420
421                 fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
422                 fstr->bv_val = malloc( fstr->bv_len + 1 );
423
424                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
425                         atmp.bv_val );
426                 break;
427
428         case LDAP_FILTER_AND:
429         case LDAP_FILTER_OR:
430         case LDAP_FILTER_NOT:
431                 fstr->bv_len = STRLENOF( "(%)" );
432                 fstr->bv_val = malloc( fstr->bv_len + 128 );    /* FIXME: why 128? */
433
434                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
435                         f->f_choice == LDAP_FILTER_AND ? '&' :
436                         f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
437
438                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
439                         len = fstr->bv_len;
440
441                         if ( ldap_back_int_filter_map_rewrite( dc, p, &vtmp, remap ) )
442                         {
443                                 return -1;
444                         }
445                         
446                         fstr->bv_len += vtmp.bv_len;
447                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
448
449                         snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, 
450                                 /*"("*/ "%s)", vtmp.bv_val );
451
452                         ch_free( vtmp.bv_val );
453                 }
454
455                 break;
456
457         case LDAP_FILTER_EXT:
458                 if ( f->f_mr_desc ) {
459                         if ( map_attr_value( dc, f->f_mr_desc, &atmp,
460                                                 &f->f_mr_value, &vtmp, remap ) )
461                         {
462                                 return -1;
463                         }
464
465                 } else {
466                         BER_BVSTR( &atmp, "" );
467                         filter_escape_value( &f->f_mr_value, &vtmp );
468                 }
469
470                 /* FIXME: cleanup (less ?: operators...) */
471                 fstr->bv_len = atmp.bv_len +
472                         ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
473                         ( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
474                         vtmp.bv_len + ( STRLENOF( "(:=)" ) );
475                 fstr->bv_val = malloc( fstr->bv_len + 1 );
476
477                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
478                         atmp.bv_val,
479                         f->f_mr_dnattrs ? ":dn" : "",
480                         !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
481                         !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
482                         vtmp.bv_val );
483                 ber_memfree( vtmp.bv_val );
484                 break;
485
486         case SLAPD_FILTER_COMPUTED: {
487                 struct berval   bv;
488
489                 switch ( f->f_result ) {
490                 case LDAP_COMPARE_FALSE:
491                         if ( dc->target->mt_flags & LDAP_BACK_F_SUPPORT_T_F ) {
492                                 BER_BVSTR( &bv, "(|)" );
493                                 break;
494                         }
495                         /* fallthru */
496
497                 /* FIXME: treat UNDEFINED as FALSE */
498                 case SLAPD_COMPARE_UNDEFINED:
499                         /* better than nothing... */
500                         BER_BVSTR( &bv, "(!(objectClass=*))" );
501                         break;
502
503                 case LDAP_COMPARE_TRUE:
504                         if ( dc->target->mt_flags & LDAP_BACK_F_SUPPORT_T_F ) {
505                                 BER_BVSTR( &bv, "(&)" );
506                                 break;
507                         }
508
509                         /* better than nothing... */
510                         BER_BVSTR( &bv, "(objectClass=*)" );
511                         break;
512
513                 default:
514                         BER_BVSTR( &bv, "(?=error)" );
515                         break;
516                 }
517
518                 ber_dupbv( fstr, &bv );
519                 } break;
520
521         default:
522                 ber_str2bv( "(?=unknown)", STRLENOF( "(?=unknown)" ), 1, fstr );
523                 break;
524         }
525
526         return 0;
527 }
528
529 int
530 ldap_back_filter_map_rewrite(
531                 dncookie                *dc,
532                 Filter                  *f,
533                 struct berval           *fstr,
534                 int                     remap )
535 {
536         int             rc;
537         dncookie        fdc;
538         struct berval   ftmp;
539         static char     *dmy = "";
540
541         rc = ldap_back_int_filter_map_rewrite( dc, f, fstr, remap );
542
543 #ifdef ENABLE_REWRITE
544         if ( rc != LDAP_SUCCESS ) {
545                 return rc;
546         }
547
548         fdc = *dc;
549         ftmp = *fstr;
550
551         fdc.ctx = "searchFilter";
552         
553         switch ( rewrite_session( fdc.target->mt_rwmap.rwm_rw, fdc.ctx,
554                                 ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : dmy ),
555                                 fdc.conn, &fstr->bv_val ) )
556         {
557         case REWRITE_REGEXEC_OK:
558                 if ( !BER_BVISNULL( fstr ) ) {
559                         fstr->bv_len = strlen( fstr->bv_val );
560
561                 } else {
562                         *fstr = ftmp;
563                 }
564                 Debug( LDAP_DEBUG_ARGS,
565                         "[rw] %s: \"%s\" -> \"%s\"\n",
566                         fdc.ctx, BER_BVISNULL( &ftmp ) ? "" : ftmp.bv_val,
567                         BER_BVISNULL( fstr ) ? "" : fstr->bv_val );             
568                 rc = LDAP_SUCCESS;
569                 break;
570                 
571         case REWRITE_REGEXEC_UNWILLING:
572                 if ( fdc.rs ) {
573                         fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
574                         fdc.rs->sr_text = "Operation not allowed";
575                 }
576                 rc = LDAP_UNWILLING_TO_PERFORM;
577                 break;
578                 
579         case REWRITE_REGEXEC_ERR:
580                 if ( fdc.rs ) {
581                         fdc.rs->sr_err = LDAP_OTHER;
582                         fdc.rs->sr_text = "Rewrite error";
583                 }
584                 rc = LDAP_OTHER;
585                 break;
586         }
587
588         if ( fstr->bv_val == dmy ) {
589                 BER_BVZERO( fstr );
590         }
591 #endif /* ENABLE_REWRITE */
592
593         return rc;
594 }
595
596 int
597 ldap_back_referral_result_rewrite(
598         dncookie                *dc,
599         BerVarray               a_vals
600 )
601 {
602         int             i, last;
603
604         assert( dc != NULL );
605         assert( a_vals != NULL );
606
607         for ( last = 0; !BER_BVISNULL( &a_vals[ last ] ); last++ )
608                 ;
609         last--;
610
611         for ( i = 0; !BER_BVISNULL( &a_vals[ i ] ); i++ ) {
612                 struct berval   dn,
613                                 olddn = BER_BVNULL;
614                 int             rc;
615                 LDAPURLDesc     *ludp;
616
617                 rc = ldap_url_parse( a_vals[ i ].bv_val, &ludp );
618                 if ( rc != LDAP_URL_SUCCESS ) {
619                         /* leave attr untouched if massage failed */
620                         continue;
621                 }
622
623                 /* FIXME: URLs like "ldap:///dc=suffix" if passed
624                  * thru ldap_url_parse() and ldap_url_desc2str()
625                  * get rewritten as "ldap:///dc=suffix??base";
626                  * we don't want this to occur... */
627                 if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
628                         ludp->lud_scope = LDAP_SCOPE_DEFAULT;
629                 }
630
631                 ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
632                 
633                 rc = ldap_back_dn_massage( dc, &olddn, &dn );
634                 switch ( rc ) {
635                 case LDAP_UNWILLING_TO_PERFORM:
636                         /*
637                          * FIXME: need to check if it may be considered 
638                          * legal to trim values when adding/modifying;
639                          * it should be when searching (e.g. ACLs).
640                          */
641                         LBER_FREE( a_vals[ i ].bv_val );
642                         if ( last > i ) {
643                                 a_vals[ i ] = a_vals[ last ];
644                         }
645                         BER_BVZERO( &a_vals[ last ] );
646                         last--;
647                         i--;
648                         break;
649
650                 default:
651                         /* leave attr untouched if massage failed */
652                         if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val )
653                         {
654                                 char    *newurl;
655
656                                 ludp->lud_dn = dn.bv_val;
657                                 newurl = ldap_url_desc2str( ludp );
658                                 if ( newurl == NULL ) {
659                                         /* FIXME: leave attr untouched
660                                          * even if ldap_url_desc2str failed...
661                                          */
662                                         break;
663                                 }
664
665                                 LBER_FREE( a_vals[ i ].bv_val );
666                                 ber_str2bv( newurl, 0, 1, &a_vals[ i ] );
667                                 LDAP_FREE( newurl );
668                                 ludp->lud_dn = olddn.bv_val;
669                         }
670                         break;
671                 }
672
673                 ldap_free_urldesc( ludp );
674         }
675
676         return 0;
677 }
678
679 /*
680  * I don't like this much, but we need two different
681  * functions because different heap managers may be
682  * in use in back-ldap/meta to reduce the amount of
683  * calls to malloc routines, and some of the free()
684  * routines may be macros with args
685  */
686 int
687 ldap_dnattr_rewrite(
688         dncookie                *dc,
689         BerVarray               a_vals
690 )
691 {
692         struct berval   bv;
693         int             i, last;
694
695         assert( a_vals != NULL );
696
697         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
698                 ;
699         last--;
700
701         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
702                 switch ( ldap_back_dn_massage( dc, &a_vals[i], &bv ) ) {
703                 case LDAP_UNWILLING_TO_PERFORM:
704                         /*
705                          * FIXME: need to check if it may be considered 
706                          * legal to trim values when adding/modifying;
707                          * it should be when searching (e.g. ACLs).
708                          */
709                         ch_free( a_vals[i].bv_val );
710                         if ( last > i ) {
711                                 a_vals[i] = a_vals[last];
712                         }
713                         BER_BVZERO( &a_vals[last] );
714                         last--;
715                         break;
716
717                 default:
718                         /* leave attr untouched if massage failed */
719                         if ( !BER_BVISNULL( &bv ) && bv.bv_val != a_vals[i].bv_val ) {
720                                 ch_free( a_vals[i].bv_val );
721                                 a_vals[i] = bv;
722                         }
723                         break;
724                 }
725         }
726         
727         return 0;
728 }
729
730 int
731 ldap_dnattr_result_rewrite(
732         dncookie                *dc,
733         BerVarray               a_vals
734 )
735 {
736         struct berval   bv;
737         int             i, last;
738
739         assert( a_vals != NULL );
740
741         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
742                 ;
743         last--;
744
745         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
746                 switch ( ldap_back_dn_massage( dc, &a_vals[i], &bv ) ) {
747                 case LDAP_UNWILLING_TO_PERFORM:
748                         /*
749                          * FIXME: need to check if it may be considered 
750                          * legal to trim values when adding/modifying;
751                          * it should be when searching (e.g. ACLs).
752                          */
753                         LBER_FREE( a_vals[i].bv_val );
754                         if ( last > i ) {
755                                 a_vals[i] = a_vals[last];
756                         }
757                         BER_BVZERO( &a_vals[last] );
758                         last--;
759                         break;
760
761                 default:
762                         /* leave attr untouched if massage failed */
763                         if ( !BER_BVISNULL( &bv ) && a_vals[i].bv_val != bv.bv_val ) {
764                                 LBER_FREE( a_vals[i].bv_val );
765                                 a_vals[i] = bv;
766                         }
767                         break;
768                 }
769         }
770
771         return 0;
772 }
773