]> git.sur5r.net Git - openldap/blob - servers/slapd/attr.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / servers / slapd / attr.c
1 /* attr.c - routines for dealing with attributes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2013 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 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 #include <ac/ctype.h>
36 #include <ac/errno.h>
37 #include <ac/socket.h>
38 #include <ac/string.h>
39 #include <ac/time.h>
40
41 #include "slap.h"
42
43 /*
44  * Allocate in chunks, minimum of 1000 at a time.
45  */
46 #define CHUNK_SIZE      1000
47 typedef struct slap_list {
48         struct slap_list *next;
49 } slap_list;
50 static slap_list *attr_chunks;
51 static Attribute *attr_list;
52 static ldap_pvt_thread_mutex_t attr_mutex;
53
54 int
55 attr_prealloc( int num )
56 {
57         Attribute *a;
58         slap_list *s;
59
60         if (!num) return 0;
61
62         s = ch_calloc( 1, sizeof(slap_list) + num * sizeof(Attribute));
63         s->next = attr_chunks;
64         attr_chunks = s;
65
66         a = (Attribute *)(s+1);
67         for ( ;num>1; num--) {
68                 a->a_next = a+1;
69                 a++;
70         }
71         a->a_next = attr_list;
72         attr_list = (Attribute *)(s+1);
73
74         return 0;
75 }
76
77 Attribute *
78 attr_alloc( AttributeDescription *ad )
79 {
80         Attribute *a;
81
82         ldap_pvt_thread_mutex_lock( &attr_mutex );
83         if ( !attr_list )
84                 attr_prealloc( CHUNK_SIZE );
85         a = attr_list;
86         attr_list = a->a_next;
87         a->a_next = NULL;
88         ldap_pvt_thread_mutex_unlock( &attr_mutex );
89         
90         a->a_desc = ad;
91         if ( ad && ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL ))
92                 a->a_flags |= SLAP_ATTR_SORTED_VALS;
93
94         return a;
95 }
96
97 /* Return a list of num attrs */
98 Attribute *
99 attrs_alloc( int num )
100 {
101         Attribute *head = NULL;
102         Attribute **a;
103
104         ldap_pvt_thread_mutex_lock( &attr_mutex );
105         for ( a = &attr_list; *a && num > 0; a = &(*a)->a_next ) {
106                 if ( !head )
107                         head = *a;
108                 num--;
109         }
110         attr_list = *a;
111         if ( num > 0 ) {
112                 attr_prealloc( num > CHUNK_SIZE ? num : CHUNK_SIZE );
113                 *a = attr_list;
114                 for ( ; *a && num > 0; a = &(*a)->a_next ) {
115                         if ( !head )
116                                 head = *a;
117                         num--;
118                 }
119                 attr_list = *a;
120         }
121         *a = NULL;
122         ldap_pvt_thread_mutex_unlock( &attr_mutex );
123
124         return head;
125 }
126
127
128 void
129 attr_clean( Attribute *a )
130 {
131         if ( a->a_nvals && a->a_nvals != a->a_vals &&
132                 !( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) {
133                 if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) {
134                         free( a->a_nvals );
135                 } else {
136                         ber_bvarray_free( a->a_nvals );
137                 }
138         }
139         /* a_vals may be equal to slap_dummy_bv, a static empty berval;
140          * this is used as a placeholder for attributes that do not carry
141          * values, e.g. when proxying search entries with the "attrsonly"
142          * bit set. */
143         if ( a->a_vals != &slap_dummy_bv &&
144                 !( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) {
145                 if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) {
146                         free( a->a_vals );
147                 } else {
148                         ber_bvarray_free( a->a_vals );
149                 }
150         }
151         a->a_desc = NULL;
152         a->a_vals = NULL;
153         a->a_nvals = NULL;
154 #ifdef LDAP_COMP_MATCH
155         a->a_comp_data = NULL;
156 #endif
157         a->a_flags = 0;
158         a->a_numvals = 0;
159 }
160
161 void
162 attr_free( Attribute *a )
163 {
164         attr_clean( a );
165         ldap_pvt_thread_mutex_lock( &attr_mutex );
166         a->a_next = attr_list;
167         attr_list = a;
168         ldap_pvt_thread_mutex_unlock( &attr_mutex );
169 }
170
171 #ifdef LDAP_COMP_MATCH
172 void
173 comp_tree_free( Attribute *a )
174 {
175         Attribute *next;
176
177         for( ; a != NULL ; a = next ) {
178                 next = a->a_next;
179                 if ( component_destructor && a->a_comp_data ) {
180                         if ( a->a_comp_data->cd_mem_op )
181                                 component_destructor( a->a_comp_data->cd_mem_op );
182                         free ( a->a_comp_data );
183                 }
184         }
185 }
186 #endif
187
188 void
189 attrs_free( Attribute *a )
190 {
191         if ( a ) {
192                 Attribute *b = (Attribute *)0xBAD, *tail, *next;
193
194                 /* save tail */
195                 tail = a;
196                 do {
197                         next = a->a_next;
198                         attr_clean( a );
199                         a->a_next = b;
200                         b = a;
201                         a = next;
202                 } while ( next );
203
204                 ldap_pvt_thread_mutex_lock( &attr_mutex );
205                 /* replace NULL with current attr list and let attr list
206                  * start from last attribute returned to list */
207                 tail->a_next = attr_list;
208                 attr_list = b;
209                 ldap_pvt_thread_mutex_unlock( &attr_mutex );
210         }
211 }
212
213 static void
214 attr_dup2( Attribute *tmp, Attribute *a )
215 {
216         tmp->a_flags = a->a_flags & SLAP_ATTR_PERSISTENT_FLAGS;
217         if ( a->a_vals != NULL ) {
218                 unsigned        i, j;
219
220                 tmp->a_numvals = a->a_numvals;
221                 tmp->a_vals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) );
222                 for ( i = 0; i < tmp->a_numvals; i++ ) {
223                         ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] );
224                         if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break;
225                         /* FIXME: error? */
226                 }
227                 BER_BVZERO( &tmp->a_vals[i] );
228
229                 /* a_nvals must be non null; it may be equal to a_vals */
230                 assert( a->a_nvals != NULL );
231
232                 if ( a->a_nvals != a->a_vals ) {
233
234                         tmp->a_nvals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) );
235                         j = 0;
236                         if ( i ) {
237                                 for ( ; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) {
238                                         assert( j < i );
239                                         ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] );
240                                         if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break;
241                                         /* FIXME: error? */
242                                 }
243                                 assert( j == i );
244                         }
245                         BER_BVZERO( &tmp->a_nvals[j] );
246
247                 } else {
248                         tmp->a_nvals = tmp->a_vals;
249                 }
250         }
251 }
252
253 Attribute *
254 attr_dup( Attribute *a )
255 {
256         Attribute *tmp;
257
258         if ( a == NULL) return NULL;
259
260         tmp = attr_alloc( a->a_desc );
261         attr_dup2( tmp, a );
262         return tmp;
263 }
264
265 Attribute *
266 attrs_dup( Attribute *a )
267 {
268         int i;
269         Attribute *tmp, *anew;
270
271         if( a == NULL ) return NULL;
272
273         /* count them */
274         for( tmp=a,i=0; tmp; tmp=tmp->a_next ) {
275                 i++;
276         }
277
278         anew = attrs_alloc( i );
279
280         for( tmp=anew; a; a=a->a_next ) {
281                 tmp->a_desc = a->a_desc;
282                 attr_dup2( tmp, a );
283                 tmp=tmp->a_next;
284         }
285
286         return anew;
287 }
288
289 int
290 attr_valfind(
291         Attribute *a,
292         unsigned flags,
293         struct berval *val,
294         unsigned *slot,
295         void *ctx )
296 {
297         struct berval nval = BER_BVNULL, *cval;
298         MatchingRule *mr;
299         const char *text;
300         int match = -1, rc;
301         unsigned i, n;
302
303         if ( flags & SLAP_MR_ORDERING )
304                 mr = a->a_desc->ad_type->sat_ordering;
305         else
306                 mr = a->a_desc->ad_type->sat_equality;
307
308         if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) &&
309                 mr->smr_normalize )
310         {
311                 rc = (mr->smr_normalize)(
312                         flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX),
313                         a->a_desc->ad_type->sat_syntax,
314                         mr, val, &nval, ctx );
315
316                 if( rc != LDAP_SUCCESS ) {
317                         return LDAP_INVALID_SYNTAX;
318                 }
319                 cval = &nval;
320         } else {
321                 cval = val;
322         }
323
324         n = a->a_numvals;
325         if ( (a->a_flags & SLAP_ATTR_SORTED_VALS) && n ) {
326                 /* Binary search */
327                 unsigned base = 0;
328
329                 do {
330                         unsigned pivot = n >> 1;
331                         i = base + pivot;
332                         rc = value_match( &match, a->a_desc, mr, flags,
333                                 &a->a_nvals[i], cval, &text );
334                         if ( rc == LDAP_SUCCESS && match == 0 )
335                                 break;
336                         if ( match < 0 ) {
337                                 base = i+1;
338                                 n -= pivot+1;
339                         } else {
340                                 n = pivot;
341                         }
342                 } while ( n );
343                 if ( match < 0 )
344                         i++;
345         } else {
346         /* Linear search */
347                 for ( i = 0; i < n; i++ ) {
348                         const char *text;
349
350                         rc = ordered_value_match( &match, a->a_desc, mr, flags,
351                                 &a->a_nvals[i], cval, &text );
352                         if ( rc == LDAP_SUCCESS && match == 0 )
353                                 break;
354                 }
355         }
356         if ( match )
357                 rc = LDAP_NO_SUCH_ATTRIBUTE;
358         if ( slot )
359                 *slot = i;
360         if ( nval.bv_val )
361                 slap_sl_free( nval.bv_val, ctx );
362
363         return rc;
364 }
365
366 int
367 attr_valadd(
368         Attribute *a,
369         BerVarray vals,
370         BerVarray nvals,
371         int nn )
372 {
373         int             i;
374         BerVarray       v2;
375
376         v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_vals,
377                     (a->a_numvals + nn + 1) * sizeof(struct berval) );
378         if( v2 == NULL ) {
379                 Debug(LDAP_DEBUG_TRACE,
380                   "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 );
381                 return LBER_ERROR_MEMORY;
382         }
383         a->a_vals = v2;
384         if ( nvals ) {
385                 v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_nvals,
386                                 (a->a_numvals + nn + 1) * sizeof(struct berval) );
387                 if( v2 == NULL ) {
388                         Debug(LDAP_DEBUG_TRACE,
389                           "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 );
390                         return LBER_ERROR_MEMORY;
391                 }
392                 a->a_nvals = v2;
393         } else {
394                 a->a_nvals = a->a_vals;
395         }
396
397         /* If sorted and old vals exist, must insert */
398         if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && a->a_numvals ) {
399                 unsigned slot;
400                 int j, rc;
401                 v2 = nvals ? nvals : vals;
402                 for ( i = 0; i < nn; i++ ) {
403                         rc = attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
404                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
405                                 &v2[i], &slot, NULL );
406                         if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) {
407                                 /* should never happen */
408                                 if ( rc == LDAP_SUCCESS )
409                                         rc = LDAP_TYPE_OR_VALUE_EXISTS;
410                                 return rc;
411                         }
412                         for ( j = a->a_numvals; j >= (int)slot; j-- ) {
413                                 a->a_vals[j+1] = a->a_vals[j];
414                                 if ( nvals )
415                                         a->a_nvals[j+1] = a->a_nvals[j];
416                         }
417                         ber_dupbv( &a->a_nvals[slot], &v2[i] );
418                         if ( nvals )
419                                 ber_dupbv( &a->a_vals[slot], &vals[i] );
420                         a->a_numvals++;
421                 }
422                 BER_BVZERO( &a->a_vals[a->a_numvals] );
423                 if ( a->a_vals != a->a_nvals )
424                         BER_BVZERO( &a->a_nvals[a->a_numvals] );
425         } else {
426                 v2 = &a->a_vals[a->a_numvals];
427                 for ( i = 0 ; i < nn; i++ ) {
428                         ber_dupbv( &v2[i], &vals[i] );
429                         if ( BER_BVISNULL( &v2[i] ) ) break;
430                 }
431                 BER_BVZERO( &v2[i] );
432
433                 if ( nvals ) {
434                         v2 = &a->a_nvals[a->a_numvals];
435                         for ( i = 0 ; i < nn; i++ ) {
436                                 ber_dupbv( &v2[i], &nvals[i] );
437                                 if ( BER_BVISNULL( &v2[i] ) ) break;
438                         }
439                         BER_BVZERO( &v2[i] );
440                 }
441                 a->a_numvals += i;
442         }
443         return 0;
444 }
445
446 /*
447  * attr_merge - merge the given type and value with the list of
448  * attributes in attrs.
449  *
450  * nvals must be NULL if the attribute has no normalizer.
451  * In this case, a->a_nvals will be set equal to a->a_vals.
452  *
453  * returns      0       everything went ok
454  *              -1      trouble
455  */
456
457 int
458 attr_merge(
459         Entry           *e,
460         AttributeDescription *desc,
461         BerVarray       vals,
462         BerVarray       nvals )
463 {
464         int i = 0;
465
466         Attribute       **a;
467
468         for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
469                 if (  (*a)->a_desc == desc ) {
470                         break;
471                 }
472         }
473
474         if ( *a == NULL ) {
475                 *a = attr_alloc( desc );
476         } else {
477                 /*
478                  * FIXME: if the attribute already exists, the presence
479                  * of nvals and the value of (*a)->a_nvals must be consistent
480                  */
481                 assert( ( nvals == NULL && (*a)->a_nvals == (*a)->a_vals )
482                                 || ( nvals != NULL && (
483                                         ( (*a)->a_vals == NULL && (*a)->a_nvals == NULL )
484                                         || ( (*a)->a_nvals != (*a)->a_vals ) ) ) );
485         }
486
487         if ( vals != NULL ) {
488                 for ( ; !BER_BVISNULL( &vals[i] ); i++ ) ;
489         }
490         return attr_valadd( *a, vals, nvals, i );
491 }
492
493 /*
494  * if a normalization function is defined for the equality matchingRule
495  * of desc, the value is normalized and stored in nval; otherwise nval 
496  * is NULL
497  */
498 int
499 attr_normalize(
500         AttributeDescription    *desc,
501         BerVarray               vals,
502         BerVarray               *nvalsp,
503         void                    *memctx )
504 {
505         int             rc = LDAP_SUCCESS;
506         BerVarray       nvals = NULL;
507
508         *nvalsp = NULL;
509
510         if ( desc->ad_type->sat_equality &&
511                 desc->ad_type->sat_equality->smr_normalize )
512         {
513                 int     i;
514                 
515                 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ );
516
517                 nvals = slap_sl_calloc( sizeof(struct berval), i + 1, memctx );
518                 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) {
519                         rc = desc->ad_type->sat_equality->smr_normalize(
520                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
521                                         desc->ad_type->sat_syntax,
522                                         desc->ad_type->sat_equality,
523                                         &vals[i], &nvals[i], memctx );
524
525                         if ( rc != LDAP_SUCCESS ) {
526                                 BER_BVZERO( &nvals[i + 1] );
527                                 break;
528                         }
529                 }
530                 BER_BVZERO( &nvals[i] );
531                 *nvalsp = nvals;
532         }
533
534         if ( rc != LDAP_SUCCESS && nvals != NULL ) {
535                 ber_bvarray_free_x( nvals, memctx );
536         }
537
538         return rc;
539 }
540
541 int
542 attr_merge_normalize(
543         Entry                   *e,
544         AttributeDescription    *desc,
545         BerVarray               vals,
546         void                    *memctx )
547 {
548         BerVarray       nvals = NULL;
549         int             rc;
550
551         rc = attr_normalize( desc, vals, &nvals, memctx );
552         if ( rc == LDAP_SUCCESS ) {
553                 rc = attr_merge( e, desc, vals, nvals );
554                 if ( nvals != NULL ) {
555                         ber_bvarray_free_x( nvals, memctx );
556                 }
557         }
558
559         return rc;
560 }
561
562 int
563 attr_merge_one(
564         Entry           *e,
565         AttributeDescription *desc,
566         struct berval   *val,
567         struct berval   *nval )
568 {
569         Attribute       **a;
570
571         for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
572                 if ( (*a)->a_desc == desc ) {
573                         break;
574                 }
575         }
576
577         if ( *a == NULL ) {
578                 *a = attr_alloc( desc );
579         }
580
581         return attr_valadd( *a, val, nval, 1 );
582 }
583
584 /*
585  * if a normalization function is defined for the equality matchingRule
586  * of desc, the value is normalized and stored in nval; otherwise nval 
587  * is NULL
588  */
589 int
590 attr_normalize_one(
591         AttributeDescription *desc,
592         struct berval   *val,
593         struct berval   *nval,
594         void            *memctx )
595 {
596         int             rc = LDAP_SUCCESS;
597
598         BER_BVZERO( nval );
599
600         if ( desc->ad_type->sat_equality &&
601                 desc->ad_type->sat_equality->smr_normalize )
602         {
603                 rc = desc->ad_type->sat_equality->smr_normalize(
604                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
605                                 desc->ad_type->sat_syntax,
606                                 desc->ad_type->sat_equality,
607                                 val, nval, memctx );
608
609                 if ( rc != LDAP_SUCCESS ) {
610                         return rc;
611                 }
612         }
613
614         return rc;
615 }
616
617 int
618 attr_merge_normalize_one(
619         Entry           *e,
620         AttributeDescription *desc,
621         struct berval   *val,
622         void            *memctx )
623 {
624         struct berval   nval = BER_BVNULL;
625         struct berval   *nvalp = NULL;
626         int             rc;
627
628         rc = attr_normalize_one( desc, val, &nval, memctx );
629         if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &nval ) ) {
630                 nvalp = &nval;
631         }
632
633         rc = attr_merge_one( e, desc, val, nvalp );
634         if ( nvalp != NULL ) {
635                 slap_sl_free( nval.bv_val, memctx );
636         }
637         return rc;
638 }
639
640 /*
641  * attrs_find - find attribute(s) by AttributeDescription
642  * returns next attribute which is subtype of provided description.
643  */
644
645 Attribute *
646 attrs_find(
647     Attribute   *a,
648         AttributeDescription *desc )
649 {
650         for ( ; a != NULL; a = a->a_next ) {
651                 if ( is_ad_subtype( a->a_desc, desc ) ) {
652                         return( a );
653                 }
654         }
655
656         return( NULL );
657 }
658
659 /*
660  * attr_find - find attribute by type
661  */
662
663 Attribute *
664 attr_find(
665     Attribute   *a,
666         AttributeDescription *desc )
667 {
668         for ( ; a != NULL; a = a->a_next ) {
669                 if ( a->a_desc == desc ) {
670                         return( a );
671                 }
672         }
673
674         return( NULL );
675 }
676
677 /*
678  * attr_delete - delete the attribute type in list pointed to by attrs
679  * return       0       deleted ok
680  *              1       not found in list a
681  *              -1      something bad happened
682  */
683
684 int
685 attr_delete(
686     Attribute   **attrs,
687         AttributeDescription *desc )
688 {
689         Attribute       **a;
690
691         for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
692                 if ( (*a)->a_desc == desc ) {
693                         Attribute       *save = *a;
694                         *a = (*a)->a_next;
695                         attr_free( save );
696
697                         return LDAP_SUCCESS;
698                 }
699         }
700
701         return LDAP_NO_SUCH_ATTRIBUTE;
702 }
703
704 int
705 attr_init( void )
706 {
707         ldap_pvt_thread_mutex_init( &attr_mutex );
708         return 0;
709 }
710
711 int
712 attr_destroy( void )
713 {
714         slap_list *a;
715
716         for ( a=attr_chunks; a; a=attr_chunks ) {
717                 attr_chunks = a->next;
718                 free( a );
719         }
720         ldap_pvt_thread_mutex_destroy( &attr_mutex );
721         return 0;
722 }