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