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