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