]> git.sur5r.net Git - openldap/blob - servers/slapd/attr.c
ITS#4667 fix assert in connection_next() for PENDING connections
[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         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_free( 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         memset( a, 0, sizeof( Attribute ));
150         ldap_pvt_thread_mutex_lock( &attr_mutex );
151         a->a_next = attr_list;
152         attr_list = a;
153         ldap_pvt_thread_mutex_unlock( &attr_mutex );
154 }
155
156 #ifdef LDAP_COMP_MATCH
157 void
158 comp_tree_free( Attribute *a )
159 {
160         Attribute *next;
161
162         for( ; a != NULL ; a = next ) {
163                 next = a->a_next;
164                 if ( component_destructor && a->a_comp_data ) {
165                         if ( a->a_comp_data->cd_mem_op )
166                                 component_destructor( a->a_comp_data->cd_mem_op );
167                         free ( a->a_comp_data );
168                 }
169         }
170 }
171 #endif
172
173 void
174 attrs_free( Attribute *a )
175 {
176         Attribute *next;
177
178         for( ; a != NULL ; a = next ) {
179                 next = a->a_next;
180                 attr_free( a );
181         }
182 }
183
184 Attribute *
185 attr_dup( Attribute *a )
186 {
187         Attribute *tmp;
188
189         if ( a == NULL) return NULL;
190
191         tmp = attr_alloc( a->a_desc );
192
193         if ( a->a_vals != NULL ) {
194                 int     i;
195
196                 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
197                         /* EMPTY */ ;
198                 }
199
200                 tmp->a_vals = ch_malloc( (i + 1) * sizeof(struct berval) );
201                 for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
202                         ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] );
203                         if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break;
204                         /* FIXME: error? */
205                 }
206                 BER_BVZERO( &tmp->a_vals[i] );
207
208                 /* a_nvals must be non null; it may be equal to a_vals */
209                 assert( a->a_nvals != NULL );
210
211                 if ( a->a_nvals != a->a_vals ) {
212                         int     j;
213
214                         tmp->a_nvals = ch_malloc( (i + 1) * sizeof(struct berval) );
215                         for ( j = 0; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) {
216                                 assert( j < i );
217                                 ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] );
218                                 if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break;
219                                 /* FIXME: error? */
220                         }
221                         assert( j == i );
222                         BER_BVZERO( &tmp->a_nvals[j] );
223
224                 } else {
225                         tmp->a_nvals = tmp->a_vals;
226                 }
227
228         } else {
229                 tmp->a_vals = NULL;
230                 tmp->a_nvals = NULL;
231         }
232         return tmp;
233 }
234
235 Attribute *
236 attrs_dup( Attribute *a )
237 {
238         Attribute *tmp, **next;
239
240         if( a == NULL ) return NULL;
241
242         tmp = NULL;
243         next = &tmp;
244
245         for( ; a != NULL ; a = a->a_next ) {
246                 *next = attr_dup( a );
247                 next = &((*next)->a_next);
248         }
249         *next = NULL;
250
251         return tmp;
252 }
253
254
255 /*
256  * attr_merge - merge the given type and value with the list of
257  * attributes in attrs.
258  *
259  * nvals must be NULL if the attribute has no normalizer.
260  * In this case, a->a_nvals will be set equal to a->a_vals.
261  *
262  * returns      0       everything went ok
263  *              -1      trouble
264  */
265
266 int
267 attr_merge(
268         Entry           *e,
269         AttributeDescription *desc,
270         BerVarray       vals,
271         BerVarray       nvals )
272 {
273         int rc;
274
275         Attribute       **a;
276
277         for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
278                 if (  (*a)->a_desc == desc ) {
279                         break;
280                 }
281         }
282
283         if ( *a == NULL ) {
284                 *a = attr_alloc( desc );
285         } else {
286                 /*
287                  * FIXME: if the attribute already exists, the presence
288                  * of nvals and the value of (*a)->a_nvals must be consistent
289                  */
290                 assert( ( nvals == NULL && (*a)->a_nvals == (*a)->a_vals )
291                                 || ( nvals != NULL && (
292                                         ( (*a)->a_vals == NULL && (*a)->a_nvals == NULL )
293                                         || ( (*a)->a_nvals != (*a)->a_vals ) ) ) );
294         }
295
296         rc = value_add( &(*a)->a_vals, vals );
297
298         if ( rc == LDAP_SUCCESS ) {
299                 if ( nvals ) {
300                         rc = value_add( &(*a)->a_nvals, nvals );
301                         /* FIXME: what if rc != LDAP_SUCCESS ? */
302                 } else {
303                         (*a)->a_nvals = (*a)->a_vals;
304                 }
305         }
306
307         return rc;
308 }
309
310 /*
311  * if a normalization function is defined for the equality matchingRule
312  * of desc, the value is normalized and stored in nval; otherwise nval 
313  * is NULL
314  */
315 int
316 attr_normalize(
317         AttributeDescription    *desc,
318         BerVarray               vals,
319         BerVarray               *nvalsp,
320         void                    *memctx )
321 {
322         int             rc = LDAP_SUCCESS;
323         BerVarray       nvals = NULL;
324
325         *nvalsp = NULL;
326
327         if ( desc->ad_type->sat_equality &&
328                 desc->ad_type->sat_equality->smr_normalize )
329         {
330                 int     i;
331                 
332                 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ );
333
334                 nvals = slap_sl_calloc( sizeof(struct berval), i + 1, memctx );
335                 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) {
336                         rc = desc->ad_type->sat_equality->smr_normalize(
337                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
338                                         desc->ad_type->sat_syntax,
339                                         desc->ad_type->sat_equality,
340                                         &vals[i], &nvals[i], memctx );
341
342                         if ( rc != LDAP_SUCCESS ) {
343                                 BER_BVZERO( &nvals[i + 1] );
344                                 break;
345                         }
346                 }
347                 BER_BVZERO( &nvals[i] );
348                 *nvalsp = nvals;
349         }
350
351 error_return:;
352         if ( rc != LDAP_SUCCESS && nvals != NULL ) {
353                 ber_bvarray_free_x( nvals, memctx );
354         }
355
356         return rc;
357 }
358
359 int
360 attr_merge_normalize(
361         Entry                   *e,
362         AttributeDescription    *desc,
363         BerVarray               vals,
364         void                    *memctx )
365 {
366         BerVarray       nvals = NULL;
367         int             rc;
368
369         rc = attr_normalize( desc, vals, &nvals, memctx );
370         if ( rc == LDAP_SUCCESS ) {
371                 rc = attr_merge( e, desc, vals, nvals );
372                 if ( nvals != NULL ) {
373                         ber_bvarray_free_x( nvals, memctx );
374                 }
375         }
376
377         return rc;
378 }
379
380 int
381 attr_merge_one(
382         Entry           *e,
383         AttributeDescription *desc,
384         struct berval   *val,
385         struct berval   *nval )
386 {
387         int rc;
388         Attribute       **a;
389
390         for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
391                 if ( (*a)->a_desc == desc ) {
392                         break;
393                 }
394         }
395
396         if ( *a == NULL ) {
397                 *a = attr_alloc( desc );
398         }
399
400         rc = value_add_one( &(*a)->a_vals, val );
401
402         if ( rc == LDAP_SUCCESS ) {
403                 if ( nval ) {
404                         rc = value_add_one( &(*a)->a_nvals, nval );
405                         /* FIXME: what if rc != LDAP_SUCCESS ? */
406                 } else {
407                         (*a)->a_nvals = (*a)->a_vals;
408                 }
409         }
410         return rc;
411 }
412
413 /*
414  * if a normalization function is defined for the equality matchingRule
415  * of desc, the value is normalized and stored in nval; otherwise nval 
416  * is NULL
417  */
418 int
419 attr_normalize_one(
420         AttributeDescription *desc,
421         struct berval   *val,
422         struct berval   *nval,
423         void            *memctx )
424 {
425         int             rc = LDAP_SUCCESS;
426
427         BER_BVZERO( nval );
428
429         if ( desc->ad_type->sat_equality &&
430                 desc->ad_type->sat_equality->smr_normalize )
431         {
432                 rc = desc->ad_type->sat_equality->smr_normalize(
433                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
434                                 desc->ad_type->sat_syntax,
435                                 desc->ad_type->sat_equality,
436                                 val, nval, memctx );
437
438                 if ( rc != LDAP_SUCCESS ) {
439                         return rc;
440                 }
441         }
442
443         return rc;
444 }
445
446 int
447 attr_merge_normalize_one(
448         Entry           *e,
449         AttributeDescription *desc,
450         struct berval   *val,
451         void            *memctx )
452 {
453         struct berval   nval = BER_BVNULL;
454         struct berval   *nvalp = NULL;
455         int             rc;
456
457         rc = attr_normalize_one( desc, val, &nval, memctx );
458         if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &nval ) ) {
459                 nvalp = &nval;
460         }
461
462         rc = attr_merge_one( e, desc, val, nvalp );
463         if ( nvalp != NULL ) {
464                 slap_sl_free( nval.bv_val, memctx );
465         }
466         return rc;
467 }
468
469 /*
470  * attrs_find - find attribute(s) by AttributeDescription
471  * returns next attribute which is subtype of provided description.
472  */
473
474 Attribute *
475 attrs_find(
476     Attribute   *a,
477         AttributeDescription *desc )
478 {
479         for ( ; a != NULL; a = a->a_next ) {
480                 if ( is_ad_subtype( a->a_desc, desc ) ) {
481                         return( a );
482                 }
483         }
484
485         return( NULL );
486 }
487
488 /*
489  * attr_find - find attribute by type
490  */
491
492 Attribute *
493 attr_find(
494     Attribute   *a,
495         AttributeDescription *desc )
496 {
497         for ( ; a != NULL; a = a->a_next ) {
498                 if ( a->a_desc == desc ) {
499                         return( a );
500                 }
501         }
502
503         return( NULL );
504 }
505
506 /*
507  * attr_delete - delete the attribute type in list pointed to by attrs
508  * return       0       deleted ok
509  *              1       not found in list a
510  *              -1      something bad happened
511  */
512
513 int
514 attr_delete(
515     Attribute   **attrs,
516         AttributeDescription *desc )
517 {
518         Attribute       **a;
519
520         for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
521                 if ( (*a)->a_desc == desc ) {
522                         Attribute       *save = *a;
523                         *a = (*a)->a_next;
524                         attr_free( save );
525
526                         return LDAP_SUCCESS;
527                 }
528         }
529
530         return LDAP_NO_SUCH_ATTRIBUTE;
531 }
532
533 int
534 attr_init( void )
535 {
536         ldap_pvt_thread_mutex_init( &attr_mutex );
537         return 0;
538 }
539
540 int
541 attr_destroy( void )
542 {
543         slap_list *a;
544
545         for ( a=attr_chunks; a; a=attr_chunks ) {
546                 attr_chunks = a->next;
547                 free( a );
548         }
549         ldap_pvt_thread_mutex_destroy( &attr_mutex );
550         return 0;
551 }