attr.c 14.4 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* attr.c - routines for dealing with attributes */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2008 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
26

Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
31

#ifdef HAVE_FCNTL_H
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
#include <fcntl.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33
34
35
#endif

#include <ac/ctype.h>
36
#include <ac/errno.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
38
39
40
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
41
42
#include "slap.h"

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
 * Allocate in chunks, minimum of 1000 at a time.
 */
#define	CHUNK_SIZE	1000
typedef struct slap_list {
	struct slap_list *next;
} slap_list;
static slap_list *attr_chunks;
static Attribute *attr_list;
static ldap_pvt_thread_mutex_t attr_mutex;

int
attr_prealloc( int num )
{
	Attribute *a;
	slap_list *s;

	if (!num) return 0;

	s = ch_calloc( 1, sizeof(slap_list) + num * sizeof(Attribute));
	s->next = attr_chunks;
	attr_chunks = s;

	a = (Attribute *)(s+1);
	for ( ;num>1; num--) {
		a->a_next = a+1;
		a++;
	}
	a->a_next = attr_list;
	attr_list = (Attribute *)(s+1);

	return 0;
}

Howard Chu's avatar
Howard Chu committed
77
78
79
Attribute *
attr_alloc( AttributeDescription *ad )
{
80
	Attribute *a;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
81

82
83
84
85
86
	ldap_pvt_thread_mutex_lock( &attr_mutex );
	if ( !attr_list )
		attr_prealloc( CHUNK_SIZE );
	a = attr_list;
	attr_list = a->a_next;
Howard Chu's avatar
Howard Chu committed
87
	a->a_next = NULL;
88
89
90
	ldap_pvt_thread_mutex_unlock( &attr_mutex );
	
	a->a_desc = ad;
Howard Chu's avatar
Howard Chu committed
91
92
93
94

	return a;
}

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* Return a list of num attrs */
Attribute *
attrs_alloc( int num )
{
	Attribute *head = NULL;
	Attribute **a;

	ldap_pvt_thread_mutex_lock( &attr_mutex );
	for ( a = &attr_list; *a && num > 0; a = &(*a)->a_next ) {
		if ( !head )
			head = *a;
		num--;
	}
	attr_list = *a;
	if ( num > 0 ) {
		attr_prealloc( num > CHUNK_SIZE ? num : CHUNK_SIZE );
		*a = attr_list;
		for ( ; *a && num > 0; a = &(*a)->a_next ) {
			if ( !head )
				head = *a;
			num--;
		}
		attr_list = *a;
	}
	*a = NULL;
	ldap_pvt_thread_mutex_unlock( &attr_mutex );

	return head;
}


Kurt Zeilenga's avatar
Kurt Zeilenga committed
126
void
Howard Chu's avatar
Howard Chu committed
127
attr_clean( Attribute *a )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
128
{
129
130
131
132
133
134
135
	if ( a->a_nvals && a->a_nvals != a->a_vals &&
		!( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) {
		if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) {
			free( a->a_nvals );
		} else {
			ber_bvarray_free( a->a_nvals );
		}
Kurt Zeilenga's avatar
Cleanup    
Kurt Zeilenga committed
136
	}
137
138
139
140
	/* a_vals may be equal to slap_dummy_bv, a static empty berval;
	 * this is used as a placeholder for attributes that do not carry
	 * values, e.g. when proxying search entries with the "attrsonly"
	 * bit set. */
141
142
143
144
145
146
147
	if ( a->a_vals != &slap_dummy_bv &&
		!( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) {
		if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) {
			free( a->a_vals );
		} else {
			ber_bvarray_free( a->a_vals );
		}
148
	}
Howard Chu's avatar
Howard Chu committed
149
150
151
152
153
154
155
	a->a_desc = NULL;
	a->a_vals = NULL;
	a->a_nvals = NULL;
#ifdef LDAP_COMP_MATCH
	a->a_comp_data = NULL;
#endif
	a->a_flags = 0;
156
	a->a_numvals = 0;
Howard Chu's avatar
Howard Chu committed
157
158
159
160
161
162
}

void
attr_free( Attribute *a )
{
	attr_clean( a );
163
164
165
166
	ldap_pvt_thread_mutex_lock( &attr_mutex );
	a->a_next = attr_list;
	attr_list = a;
	ldap_pvt_thread_mutex_unlock( &attr_mutex );
167
168
}

169
#ifdef LDAP_COMP_MATCH
170
171
172
173
174
175
176
void
comp_tree_free( Attribute *a )
{
	Attribute *next;

	for( ; a != NULL ; a = next ) {
		next = a->a_next;
177
178
179
		if ( component_destructor && a->a_comp_data ) {
			if ( a->a_comp_data->cd_mem_op )
				component_destructor( a->a_comp_data->cd_mem_op );
180
181
			free ( a->a_comp_data );
		}
182
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
183
}
184
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
185

186
187
188
void
attrs_free( Attribute *a )
{
Howard Chu's avatar
Howard Chu committed
189
	if ( a ) {
190
191
192
		Attribute *b = (Attribute *)0xBAD, *tail, *next;

		/* save tail */
193
194
195
196
197
198
199
200
201
		tail = a;
		do {
			next = a->a_next;
			attr_clean( a );
			a->a_next = b;
			b = a;
			a = next;
		} while ( next );

Howard Chu's avatar
Howard Chu committed
202
		ldap_pvt_thread_mutex_lock( &attr_mutex );
203
204
		/* replace NULL with current attr list and let attr list
		 * start from last attribute returned to list */
205
206
		tail->a_next = attr_list;
		attr_list = b;
Howard Chu's avatar
Howard Chu committed
207
		ldap_pvt_thread_mutex_unlock( &attr_mutex );
208
209
210
	}
}

211
212
213
static void
attr_dup2( Attribute *tmp, Attribute *a )
{
214
	tmp->a_flags = a->a_flags & SLAP_ATTR_PERSISTENT_FLAGS;
215
	if ( a->a_vals != NULL ) {
216
		int	i;
217

218
219
220
		tmp->a_numvals = a->a_numvals;
		tmp->a_vals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) );
		for ( i = 0; i < tmp->a_numvals; i++ ) {
221
			ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] );
222
223
			if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break;
			/* FIXME: error? */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
224
		}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
225
		BER_BVZERO( &tmp->a_vals[i] );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
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
232
			int	j;

233
			tmp->a_nvals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) );
234
235
236
237
			for ( j = 0; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) {
				assert( j < i );
				ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] );
				if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break;
238
				/* FIXME: error? */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
239
			}
240
241
			assert( j == i );
			BER_BVZERO( &tmp->a_nvals[j] );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
243

		} else {
244
			tmp->a_nvals = tmp->a_vals;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
		}
246
	}
247
248
249
250
251
252
253
254
255
256
257
}

Attribute *
attr_dup( Attribute *a )
{
	Attribute *tmp;

	if ( a == NULL) return NULL;

	tmp = attr_alloc( a->a_desc );
	attr_dup2( tmp, a );
258
259
260
	return tmp;
}

261
262
Attribute *
attrs_dup( Attribute *a )
263
{
264
265
	int i;
	Attribute *tmp, *anew;
266
267
268

	if( a == NULL ) return NULL;

269
270
271
272
	/* count them */
	for( tmp=a,i=0; tmp; tmp=tmp->a_next ) {
		i++;
	}
273

274
275
276
	anew = attrs_alloc( i );

	for( tmp=anew; a; a=a->a_next ) {
277
		tmp->a_desc = a->a_desc;
278
279
		attr_dup2( tmp, a );
		tmp=tmp->a_next;
280
281
	}

282
	return anew;
283
284
}

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
int
attr_valfind(
	Attribute *a,
	unsigned flags,
	struct berval *val,
	unsigned *slot,
	void *ctx )
{
	struct berval nval = BER_BVNULL, *cval;
	MatchingRule *mr;
	const char *text;
	int match = -1, rc;
	unsigned i;

	if ( flags & SLAP_MR_ORDERING )
		mr = a->a_desc->ad_type->sat_ordering;
	else
		mr = a->a_desc->ad_type->sat_equality;

	if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) &&
		mr->smr_normalize )
	{
		rc = (mr->smr_normalize)(
			flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX),
			a->a_desc->ad_type->sat_syntax,
			mr, val, &nval, ctx );

		if( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}
		cval = &nval;
	} else {
		cval = val;
	}

	if ( a->a_flags & SLAP_ATTR_SORTED_VALS ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
321
		/* Binary search */
322
323
324
325
326
327
328
329
330
		unsigned base = 0, n = a->a_numvals;

		while ( 0 < n ) {
			unsigned pivot = n >> 1;
			i = base + pivot;
			rc = value_match( &match, a->a_desc, mr, flags,
				&a->a_nvals[i], cval, &text );
			if ( rc == LDAP_SUCCESS && match == 0 )
				break;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
331
			if ( match < 0 ) {
332
				base = i+1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
333
334
335
336
				n -= pivot+1;
			} else {
				n = pivot;
			}
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
		}
		if ( match < 0 )
			i++;
	} else {
	/* Linear search */
		for ( i = 0; i < a->a_numvals; i++ ) {
			const char *text;

			rc = ordered_value_match( &match, a->a_desc, mr, flags,
				&a->a_nvals[i], cval, &text );
			if ( rc == LDAP_SUCCESS && match == 0 )
				break;
		}
	}
	if ( slot )
		*slot = i;
	if ( match )
		rc = LDAP_NO_SUCH_ATTRIBUTE;
	if ( nval.bv_val )
		slap_sl_free( nval.bv_val, ctx );

	return rc;
}

int
attr_valadd(
	Attribute *a,
	BerVarray vals,
	BerVarray nvals,
	int nn )
{
	int		i;
	BerVarray	v2;

	v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_vals,
		    (a->a_numvals + nn + 1) * sizeof(struct berval) );
	if( v2 == NULL ) {
		Debug(LDAP_DEBUG_TRACE,
		  "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 );
		return LBER_ERROR_MEMORY;
	}
	a->a_vals = v2;
	if ( nvals ) {
		v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_nvals,
				(a->a_numvals + nn + 1) * sizeof(struct berval) );
		if( v2 == NULL ) {
			Debug(LDAP_DEBUG_TRACE,
			  "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 );
			return LBER_ERROR_MEMORY;
		}
		a->a_nvals = v2;
	} else {
		a->a_nvals = a->a_vals;
	}

	/* If sorted and old vals exist, must insert */
	if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && a->a_numvals ) {
		unsigned slot;
		int j, rc;
		v2 = nvals ? nvals : vals;
		for ( i = 0; i < nn; i++ ) {
			rc = attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
				SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
				&v2[i], &slot, NULL );
			if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) {
				/* should never happen */
				if ( rc == LDAP_SUCCESS )
					rc = LDAP_TYPE_OR_VALUE_EXISTS;
				return rc;
			}
			for ( j = a->a_numvals; j >= slot; j-- ) {
				a->a_vals[j+1] = a->a_vals[j];
				if ( nvals )
					a->a_nvals[j+1] = a->a_nvals[j];
			}
			ber_dupbv( &a->a_nvals[slot], &v2[i] );
			if ( nvals )
				ber_dupbv( &a->a_vals[slot], &vals[i] );
			a->a_numvals++;
		}
		BER_BVZERO( &a->a_vals[a->a_numvals] );
		if ( a->a_vals != a->a_nvals )
			BER_BVZERO( &a->a_nvals[a->a_numvals] );
	} else {
		v2 = &a->a_vals[a->a_numvals];
		for ( i = 0 ; i < nn; i++ ) {
			ber_dupbv( &v2[i], &vals[i] );
			if ( BER_BVISNULL( &v2[i] ) ) break;
		}
		BER_BVZERO( &v2[i] );

		if ( nvals ) {
			v2 = &a->a_nvals[a->a_numvals];
			for ( i = 0 ; i < nn; i++ ) {
				ber_dupbv( &v2[i], &nvals[i] );
				if ( BER_BVISNULL( &v2[i] ) ) break;
			}
			BER_BVZERO( &v2[i] );
		}
		a->a_numvals += i;
	}
	return 0;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
440
441
442
443

/*
 * attr_merge - merge the given type and value with the list of
 * attributes in attrs.
444
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
445
446
 * nvals must be NULL if the attribute has no normalizer.
 * In this case, a->a_nvals will be set equal to a->a_vals.
447
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
448
449
450
451
452
453
 * returns	0	everything went ok
 *		-1	trouble
 */

int
attr_merge(
454
	Entry		*e,
455
	AttributeDescription *desc,
456
	BerVarray	vals,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
457
458
	BerVarray	nvals )
{
459
	int i = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460

Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
462
463
	Attribute	**a;

	for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
Howard Chu's avatar
Howard Chu committed
464
		if (  (*a)->a_desc == desc ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
465
466
467
468
469
			break;
		}
	}

	if ( *a == NULL ) {
Howard Chu's avatar
Howard Chu committed
470
		*a = attr_alloc( desc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
471
472
473
474
475
476
	} else {
		/*
		 * FIXME: if the attribute already exists, the presence
		 * of nvals and the value of (*a)->a_nvals must be consistent
		 */
		assert( ( nvals == NULL && (*a)->a_nvals == (*a)->a_vals )
477
478
479
				|| ( nvals != NULL && (
					( (*a)->a_vals == NULL && (*a)->a_nvals == NULL )
					|| ( (*a)->a_nvals != (*a)->a_vals ) ) ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
480
481
	}

482
483
	if ( vals != NULL ) {
		for ( ; !BER_BVISNULL( &vals[i] ); i++ ) ;
484
	}
485
	return attr_valadd( *a, vals, nvals, i );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
486
487
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
488
489
490
491
492
/*
 * if a normalization function is defined for the equality matchingRule
 * of desc, the value is normalized and stored in nval; otherwise nval 
 * is NULL
 */
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
int
attr_normalize(
	AttributeDescription	*desc,
	BerVarray		vals,
	BerVarray		*nvalsp,
	void	 		*memctx )
{
	int		rc = LDAP_SUCCESS;
	BerVarray	nvals = NULL;

	*nvalsp = NULL;

	if ( desc->ad_type->sat_equality &&
		desc->ad_type->sat_equality->smr_normalize )
	{
		int	i;
		
		for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ );

		nvals = slap_sl_calloc( sizeof(struct berval), i + 1, memctx );
		for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) {
			rc = desc->ad_type->sat_equality->smr_normalize(
					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
					desc->ad_type->sat_syntax,
					desc->ad_type->sat_equality,
					&vals[i], &nvals[i], memctx );

			if ( rc != LDAP_SUCCESS ) {
				BER_BVZERO( &nvals[i + 1] );
				break;
			}
		}
		BER_BVZERO( &nvals[i] );
		*nvalsp = nvals;
	}

	if ( rc != LDAP_SUCCESS && nvals != NULL ) {
		ber_bvarray_free_x( nvals, memctx );
	}

	return rc;
}

536
537
int
attr_merge_normalize(
538
539
540
541
	Entry			*e,
	AttributeDescription	*desc,
	BerVarray		vals,
	void	 		*memctx )
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
542
{
543
544
545
	BerVarray	nvals = NULL;
	int		rc;

546
547
548
	rc = attr_normalize( desc, vals, &nvals, memctx );
	if ( rc == LDAP_SUCCESS ) {
		rc = attr_merge( e, desc, vals, nvals );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
549
550
551
		if ( nvals != NULL ) {
			ber_bvarray_free_x( nvals, memctx );
		}
552
	}
553

554
555
556
	return rc;
}

557
558
559
560
int
attr_merge_one(
	Entry		*e,
	AttributeDescription *desc,
561
	struct berval	*val,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
562
563
	struct berval	*nval )
{
564
565
566
	Attribute	**a;

	for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) {
Howard Chu's avatar
Howard Chu committed
567
		if ( (*a)->a_desc == desc ) {
568
569
570
571
572
			break;
		}
	}

	if ( *a == NULL ) {
Howard Chu's avatar
Howard Chu committed
573
		*a = attr_alloc( desc );
574
575
	}

576
	return attr_valadd( *a, val, nval, 1 );
577
578
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
579
580
581
582
583
/*
 * if a normalization function is defined for the equality matchingRule
 * of desc, the value is normalized and stored in nval; otherwise nval 
 * is NULL
 */
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
int
attr_normalize_one(
	AttributeDescription *desc,
	struct berval	*val,
	struct berval	*nval,
	void		*memctx )
{
	int		rc = LDAP_SUCCESS;

	BER_BVZERO( nval );

	if ( desc->ad_type->sat_equality &&
		desc->ad_type->sat_equality->smr_normalize )
	{
		rc = desc->ad_type->sat_equality->smr_normalize(
				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
				desc->ad_type->sat_syntax,
				desc->ad_type->sat_equality,
				val, nval, memctx );

		if ( rc != LDAP_SUCCESS ) {
			return rc;
		}
	}

	return rc;
}

612
613
614
615
int
attr_merge_normalize_one(
	Entry		*e,
	AttributeDescription *desc,
Howard Chu's avatar
Howard Chu committed
616
	struct berval	*val,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
617
618
	void		*memctx )
{
619
	struct berval	nval = BER_BVNULL;
620
	struct berval	*nvalp = NULL;
621
622
	int		rc;

623
624
625
626
627
	rc = attr_normalize_one( desc, val, &nval, memctx );
	if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &nval ) ) {
		nvalp = &nval;
	}

628
629
	rc = attr_merge_one( e, desc, val, nvalp );
	if ( nvalp != NULL ) {
630
		slap_sl_free( nval.bv_val, memctx );
631
	}
632
633
634
	return rc;
}

635
636
637
638
639
640
641
642
/*
 * attrs_find - find attribute(s) by AttributeDescription
 * returns next attribute which is subtype of provided description.
 */

Attribute *
attrs_find(
    Attribute	*a,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
643
	AttributeDescription *desc )
644
645
{
	for ( ; a != NULL; a = a->a_next ) {
646
		if ( is_ad_subtype( a->a_desc, desc ) ) {
647
648
649
650
651
652
653
			return( a );
		}
	}

	return( NULL );
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
654
/*
655
 * attr_find - find attribute by type
Kurt Zeilenga's avatar
Kurt Zeilenga committed
656
657
658
659
660
 */

Attribute *
attr_find(
    Attribute	*a,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
661
	AttributeDescription *desc )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
662
663
{
	for ( ; a != NULL; a = a->a_next ) {
Howard Chu's avatar
Howard Chu committed
664
		if ( a->a_desc == desc ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
			return( a );
		}
	}

	return( NULL );
}

/*
 * attr_delete - delete the attribute type in list pointed to by attrs
 * return	0	deleted ok
 * 		1	not found in list a
 * 		-1	something bad happened
 */

int
attr_delete(
    Attribute	**attrs,
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
682
	AttributeDescription *desc )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
683
684
685
686
{
	Attribute	**a;

	for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
Howard Chu's avatar
Howard Chu committed
687
		if ( (*a)->a_desc == desc ) {
688
689
690
			Attribute	*save = *a;
			*a = (*a)->a_next;
			attr_free( save );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
691

692
			return LDAP_SUCCESS;
693
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
694
695
	}

696
	return LDAP_NO_SUCH_ATTRIBUTE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
697
698
}

699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
int
attr_init( void )
{
	ldap_pvt_thread_mutex_init( &attr_mutex );
	return 0;
}

int
attr_destroy( void )
{
	slap_list *a;

	for ( a=attr_chunks; a; a=attr_chunks ) {
		attr_chunks = a->next;
		free( a );
	}
	ldap_pvt_thread_mutex_destroy( &attr_mutex );
	return 0;
}