]> git.sur5r.net Git - openldap/blob - servers/slapd/attr.c
36878d2398d43f960fbde55fbbd21a255c1185bd
[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-2006 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         
83         ldap_pvt_thread_mutex_lock( &attr_mutex );
84         if ( !attr_list )
85                 attr_prealloc( CHUNK_SIZE );
86         a = attr_list;
87         attr_list = a->a_next;
88         a->a_next = NULL;
89         ldap_pvt_thread_mutex_unlock( &attr_mutex );
90         
91         a->a_desc = ad;
92
93         return a;
94 }
95
96 /* Return a list of num attrs */
97 Attribute *
98 attrs_alloc( int num )
99 {
100         Attribute *head = NULL;
101         Attribute **a;
102
103         ldap_pvt_thread_mutex_lock( &attr_mutex );
104         for ( a = &attr_list; *a && num > 0; a = &(*a)->a_next ) {
105                 if ( !head )
106                         head = *a;
107                 num--;
108         }
109         attr_list = *a;
110         if ( num > 0 ) {
111                 attr_prealloc( num > CHUNK_SIZE ? num : CHUNK_SIZE );
112                 *a = attr_list;
113                 for ( ; *a && num > 0; a = &(*a)->a_next ) {
114                         if ( !head )
115                                 head = *a;
116                         num--;
117                 }
118                 attr_list = *a;
119         }
120         *a = NULL;
121         ldap_pvt_thread_mutex_unlock( &attr_mutex );
122
123         return head;
124 }
125
126
127 void
128 attr_free( Attribute *a )
129 {
130         if ( a->a_nvals && a->a_nvals != a->a_vals &&
131                 !( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) {
132                 if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) {
133                         free( a->a_nvals );
134                 } else {
135                         ber_bvarray_free( a->a_nvals );
136                 }
137         }
138         /* a_vals may be equal to slap_dummy_bv, a static empty berval;
139          * this is used as a placeholder for attributes that do not carry
140          * values, e.g. when proxying search entries with the "attrsonly"
141          * bit set. */
142         if ( a->a_vals != &slap_dummy_bv &&
143                 !( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) {
144                 if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) {
145                         free( a->a_vals );
146                 } else {
147                         ber_bvarray_free( a->a_vals );
148                 }
149         }
150         memset( a, 0, sizeof( Attribute ));
151         ldap_pvt_thread_mutex_lock( &attr_mutex );
152         a->a_next = attr_list;
153         attr_list = a;
154         ldap_pvt_thread_mutex_unlock( &attr_mutex );
155 }
156
157 #ifdef LDAP_COMP_MATCH
158 void
159 comp_tree_free( Attribute *a )
160 {
161         Attribute *next;
162
163         for( ; a != NULL ; a = next ) {
164                 next = a->a_next;
165                 if ( component_destructor && a->a_comp_data ) {
166                         if ( a->a_comp_data->cd_mem_op )
167                                 component_destructor( a->a_comp_data->cd_mem_op );
168                         free ( a->a_comp_data );
169                 }
170         }
171 }
172 #endif
173
174 void
175 attrs_free( Attribute *a )
176 {
177         Attribute *next;
178
179         for( ; a != NULL ; a = next ) {
180                 next = a->a_next;
181                 attr_free( a );
182         }
183 }
184
185 Attribute *
186 attr_dup( Attribute *a )
187 {
188         Attribute *tmp;
189
190         if ( a == NULL) return NULL;
191
192         tmp = attr_alloc( a->a_desc );
193
194         if ( a->a_vals != NULL ) {
195                 int     i;
196
197                 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
198                         /* EMPTY */ ;
199                 }
200
201                 tmp->a_vals = ch_malloc( (i + 1) * sizeof(struct berval) );
202                 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
203                         ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] );
204                         if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break;
205                         /* FIXME: error? */
206                 }
207                 BER_BVZERO( &tmp->a_vals[i] );
208
209                 /* a_nvals must be non null; it may be equal to a_vals */
210                 assert( a->a_nvals != NULL );
211
212                 if ( a->a_nvals != a->a_vals ) {
213                         int     j;
214
215                         tmp->a_nvals = ch_malloc( (i + 1) * sizeof(struct berval) );
216                         for ( j = 0; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) {
217                                 assert( j < i );
218                                 ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] );
219                                 if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break;
220                                 /* FIXME: error? */
221                         }
222                         assert( j == i );
223                         BER_BVZERO( &tmp->a_nvals[j] );
224
225                 } else {
226                         tmp->a_nvals = tmp->a_vals;
227                 }
228
229         } else {
230                 tmp->a_vals = NULL;
231                 tmp->a_nvals = NULL;
232         }
233         return tmp;
234 }
235
236 Attribute *
237 attrs_dup( Attribute *a )
238 {
239         Attribute *tmp, **next;
240
241         if( a == NULL ) return NULL;
242
243         tmp = NULL;
244         next = &tmp;
245
246         for( ; a != NULL ; a = a->a_next ) {
247                 *next = attr_dup( a );
248                 next = &((*next)->a_next);
249         }
250         *next = NULL;
251
252         return tmp;
253 }
254
255
256 /*
257  * attr_merge - merge the given type and value with the list of
258  * attributes in attrs.
259  *
260  * nvals must be NULL if the attribute has no normalizer.
261  * In this case, a->a_nvals will be set equal to a->a_vals.
262  *
263  * returns      0       everything went ok
264  *              -1      trouble
265  */
266
267 int
268 attr_merge(
269         Entry           *e,
270         AttributeDescription *desc,
271         BerVarray       vals,
272         BerVarray       nvals )
273 {
274         int rc;
275
276         Attribute       **a;
277
278         for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
279                 if (  (*a)->a_desc == desc ) {
280                         break;
281                 }
282         }
283
284         if ( *a == NULL ) {
285                 *a = attr_alloc( desc );
286         } else {
287                 /*
288                  * FIXME: if the attribute already exists, the presence
289                  * of nvals and the value of (*a)->a_nvals must be consistent
290                  */
291                 assert( ( nvals == NULL && (*a)->a_nvals == (*a)->a_vals )
292                                 || ( nvals != NULL && (
293                                         ( (*a)->a_vals == NULL && (*a)->a_nvals == NULL )
294                                         || ( (*a)->a_nvals != (*a)->a_vals ) ) ) );
295         }
296
297         rc = value_add( &(*a)->a_vals, vals );
298
299         if ( rc == LDAP_SUCCESS ) {
300                 if ( nvals ) {
301                         rc = value_add( &(*a)->a_nvals, nvals );
302                         /* FIXME: what if rc != LDAP_SUCCESS ? */
303                 } else {
304                         (*a)->a_nvals = (*a)->a_vals;
305                 }
306         }
307
308         return rc;
309 }
310
311 int
312 attr_merge_normalize(
313         Entry           *e,
314         AttributeDescription *desc,
315         BerVarray       vals,
316         void     *memctx )
317 {
318         BerVarray       nvals = NULL;
319         int             rc;
320
321         if ( desc->ad_type->sat_equality &&
322                 desc->ad_type->sat_equality->smr_normalize )
323         {
324                 int     i;
325                 
326                 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ );
327
328                 nvals = slap_sl_calloc( sizeof(struct berval), i + 1, memctx );
329                 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) {
330                         rc = (*desc->ad_type->sat_equality->smr_normalize)(
331                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
332                                         desc->ad_type->sat_syntax,
333                                         desc->ad_type->sat_equality,
334                                         &vals[i], &nvals[i], memctx );
335
336                         if ( rc != LDAP_SUCCESS ) {
337                                 BER_BVZERO( &nvals[i + 1] );
338                                 goto error_return;
339                         }
340                 }
341                 BER_BVZERO( &nvals[i] );
342         }
343
344         rc = attr_merge( e, desc, vals, nvals );
345
346 error_return:;
347         if ( nvals != NULL ) {
348                 ber_bvarray_free_x( nvals, memctx );
349         }
350         return rc;
351 }
352
353 int
354 attr_merge_one(
355         Entry           *e,
356         AttributeDescription *desc,
357         struct berval   *val,
358         struct berval   *nval )
359 {
360         int rc;
361         Attribute       **a;
362
363         for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
364                 if ( (*a)->a_desc == desc ) {
365                         break;
366                 }
367         }
368
369         if ( *a == NULL ) {
370                 *a = attr_alloc( desc );
371         }
372
373         rc = value_add_one( &(*a)->a_vals, val );
374
375         if ( rc == LDAP_SUCCESS ) {
376                 if ( nval ) {
377                         rc = value_add_one( &(*a)->a_nvals, nval );
378                         /* FIXME: what if rc != LDAP_SUCCESS ? */
379                 } else {
380                         (*a)->a_nvals = (*a)->a_vals;
381                 }
382         }
383         return rc;
384 }
385
386 int
387 attr_merge_normalize_one(
388         Entry           *e,
389         AttributeDescription *desc,
390         struct berval   *val,
391         void            *memctx )
392 {
393         struct berval   nval;
394         struct berval   *nvalp = NULL;
395         int             rc;
396
397         if ( desc->ad_type->sat_equality &&
398                 desc->ad_type->sat_equality->smr_normalize )
399         {
400                 rc = (*desc->ad_type->sat_equality->smr_normalize)(
401                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
402                                 desc->ad_type->sat_syntax,
403                                 desc->ad_type->sat_equality,
404                                 val, &nval, memctx );
405
406                 if ( rc != LDAP_SUCCESS ) {
407                         return rc;
408                 }
409                 nvalp = &nval;
410         }
411
412         rc = attr_merge_one( e, desc, val, nvalp );
413         if ( nvalp != NULL ) {
414                 slap_sl_free( nval.bv_val, memctx );
415         }
416         return rc;
417 }
418
419 /*
420  * attrs_find - find attribute(s) by AttributeDescription
421  * returns next attribute which is subtype of provided description.
422  */
423
424 Attribute *
425 attrs_find(
426     Attribute   *a,
427         AttributeDescription *desc )
428 {
429         for ( ; a != NULL; a = a->a_next ) {
430                 if ( is_ad_subtype( a->a_desc, desc ) ) {
431                         return( a );
432                 }
433         }
434
435         return( NULL );
436 }
437
438 /*
439  * attr_find - find attribute by type
440  */
441
442 Attribute *
443 attr_find(
444     Attribute   *a,
445         AttributeDescription *desc )
446 {
447         for ( ; a != NULL; a = a->a_next ) {
448                 if ( a->a_desc == desc ) {
449                         return( a );
450                 }
451         }
452
453         return( NULL );
454 }
455
456 /*
457  * attr_delete - delete the attribute type in list pointed to by attrs
458  * return       0       deleted ok
459  *              1       not found in list a
460  *              -1      something bad happened
461  */
462
463 int
464 attr_delete(
465     Attribute   **attrs,
466         AttributeDescription *desc )
467 {
468         Attribute       **a;
469
470         for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
471                 if ( (*a)->a_desc == desc ) {
472                         Attribute       *save = *a;
473                         *a = (*a)->a_next;
474                         attr_free( save );
475
476                         return LDAP_SUCCESS;
477                 }
478         }
479
480         return LDAP_NO_SUCH_ATTRIBUTE;
481 }
482
483 int
484 attr_init( void )
485 {
486         ldap_pvt_thread_mutex_init( &attr_mutex );
487         return 0;
488 }
489
490 int
491 attr_destroy( void )
492 {
493         slap_list *a;
494
495         for ( a=attr_chunks; a; a=attr_chunks ) {
496                 attr_chunks = a->next;
497                 free( a );
498         }
499         ldap_pvt_thread_mutex_destroy( &attr_mutex );
500         return 0;
501 }