value.c 18.2 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* value.c - routines for dealing with values */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1998-2019 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
 * 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>.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
17
18
19
20
21
22
23
24
25
 * 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
26
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
31
32
33
34
35
36

#include <ac/ctype.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
#include <sys/stat.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38

Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
40
#include "slap.h"

41
42
int
value_add( 
43
44
    BerVarray	*vals,
    BerVarray	addvals )
45
{
46
47
	int		n, nn = 0;
	BerVarray	v2;
48

49
50
51
52
	if ( addvals != NULL ) {
		for ( ; !BER_BVISNULL( &addvals[nn] ); nn++ )
			;	/* NULL */
	}
53
54

	if ( *vals == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
55
		*vals = (BerVarray) SLAP_MALLOC( (nn + 1)
56
		    * sizeof(struct berval) );
Julius Enarusai's avatar
   
Julius Enarusai committed
57
58
59
60
61
		if( *vals == NULL ) {
			Debug(LDAP_DEBUG_TRACE,
		      "value_add: SLAP_MALLOC failed.\n", 0, 0, 0 );
			return LBER_ERROR_MEMORY;
		}
62
		n = 0;
63

64
	} else {
65
		for ( n = 0; !BER_BVISNULL( &(*vals)[n] ); n++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
66
67
			;	/* Empty */
		}
Julius Enarusai's avatar
   
Julius Enarusai committed
68
		*vals = (BerVarray) SLAP_REALLOC( (char *) *vals,
69
		    (n + nn + 1) * sizeof(struct berval) );
Julius Enarusai's avatar
   
Julius Enarusai committed
70
71
72
73
74
		if( *vals == NULL ) {
			Debug(LDAP_DEBUG_TRACE,
		      "value_add: SLAP_MALLOC failed.\n", 0, 0, 0 );
			return LBER_ERROR_MEMORY;
		}
75
76
	}

77
	v2 = &(*vals)[n];
Howard Chu's avatar
Cleanup    
Howard Chu committed
78
	for ( n = 0 ; n < nn; v2++, addvals++ ) {
79
80
		ber_dupbv( v2, addvals );
		if ( BER_BVISNULL( v2 ) ) break;
81
	}
82
	BER_BVZERO( v2 );
83

84
85
86
87
88
	return LDAP_SUCCESS;
}

int
value_add_one( 
89
90
    BerVarray		*vals,
    struct berval	*addval )
91
{
92
93
	int		n;
	BerVarray	v2;
94
95

	if ( *vals == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
96
97
98
99
100
101
		*vals = (BerVarray) SLAP_MALLOC( 2 * sizeof(struct berval) );
		if( *vals == NULL ) {
			Debug(LDAP_DEBUG_TRACE,
		      "value_add_one: SLAP_MALLOC failed.\n", 0, 0, 0 );
			return LBER_ERROR_MEMORY;
		}
102
		n = 0;
103

104
	} else {
105
		for ( n = 0; !BER_BVISNULL( &(*vals)[n] ); n++ ) {
106
107
			;	/* Empty */
		}
Julius Enarusai's avatar
   
Julius Enarusai committed
108
		*vals = (BerVarray) SLAP_REALLOC( (char *) *vals,
109
		    (n + 2) * sizeof(struct berval) );
Julius Enarusai's avatar
   
Julius Enarusai committed
110
111
112
113
114
		if( *vals == NULL ) {
			Debug(LDAP_DEBUG_TRACE,
		      "value_add_one: SLAP_MALLOC failed.\n", 0, 0, 0 );
			return LBER_ERROR_MEMORY;
		}
115
116
	}

117
	v2 = &(*vals)[n];
118
119
120
	ber_dupbv(v2, addval);

	v2++;
121
	BER_BVZERO( v2 );
122

123
	return LDAP_SUCCESS;
124
125
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
126
127
128
129
130
131
int asserted_value_validate_normalize( 
	AttributeDescription *ad,
	MatchingRule *mr,
	unsigned usage,
	struct berval *in,
	struct berval *out,
Howard Chu's avatar
Howard Chu committed
132
133
	const char ** text,
	void *ctx )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
134
135
{
	int rc;
136
137
	struct berval pval;
	pval.bv_val = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
138
139
140
141
142
143
144
145
146
147
148
149
150
151

	/* we expect the value to be in the assertion syntax */
	assert( !SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );

	if( mr == NULL ) {
		*text = "inappropriate matching request";
		return LDAP_INAPPROPRIATE_MATCHING;
	}

	if( !mr->smr_match ) {
		*text = "requested matching rule not supported";
		return LDAP_INAPPROPRIATE_MATCHING;
	}

152
153
154
155
	if( mr->smr_syntax->ssyn_pretty ) {
		rc = (mr->smr_syntax->ssyn_pretty)( mr->smr_syntax, in, &pval, ctx );
		in = &pval;

156
	} else if ( mr->smr_syntax->ssyn_validate ) {
157
		rc = (mr->smr_syntax->ssyn_validate)( mr->smr_syntax, in );
158
159
160
161

	} else {
		*text = "inappropriate matching request";
		return LDAP_INAPPROPRIATE_MATCHING;
162
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
163
164
165
166
167
168
169

	if( rc != LDAP_SUCCESS ) {
		*text = "value does not conform to assertion syntax";
		return LDAP_INVALID_SYNTAX;
	}

	if( mr->smr_normalize ) {
170
171
		rc = (mr->smr_normalize)(
			usage|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
			ad ? ad->ad_type->sat_syntax : NULL,
Howard Chu's avatar
Howard Chu committed
173
			mr, in, out, ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
174

175
176
		if( pval.bv_val ) ber_memfree_x( pval.bv_val, ctx );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
177
178
179
180
181
		if( rc != LDAP_SUCCESS ) {
			*text = "unable to normalize value for matching";
			return LDAP_INVALID_SYNTAX;
		}

182
183
184
	} else if ( pval.bv_val != NULL ) {
		*out = pval;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
185
	} else {
Howard Chu's avatar
Howard Chu committed
186
		ber_dupbv_x( out, in, ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
187
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
188
189

	return LDAP_SUCCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
190
191
}

192
193
int
value_match(
194
	int *match,
195
196
	AttributeDescription *ad,
	MatchingRule *mr,
197
	unsigned flags,
198
199
	struct berval *v1, /* stored value */
	void *v2, /* assertion */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
200
	const char ** text )
201
{
202
	int rc;
203

204
205
206
	assert( mr != NULL );

	if( !mr->smr_match ) {
207
208
209
		return LDAP_INAPPROPRIATE_MATCHING;
	}

210
	rc = (mr->smr_match)( match, flags,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
211
		ad->ad_type->sat_syntax, mr, v1, v2 );
212
213
	
	return rc;
214
}
215

216
int value_find_ex(
217
	AttributeDescription *ad,
218
	unsigned flags,
219
	BerVarray vals,
Howard Chu's avatar
Howard Chu committed
220
221
	struct berval *val,
	void *ctx )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
222
223
{
	int	i;
224
	int rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
225
	struct berval nval = BER_BVNULL;
226
227
	MatchingRule *mr = ad->ad_type->sat_equality;

228
	if( mr == NULL || !mr->smr_match ) {
229
230
		return LDAP_INAPPROPRIATE_MATCHING;
	}
231

232
	assert( SLAP_IS_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH( flags ) != 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
234
235
236
237

	if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) &&
		mr->smr_normalize )
	{
		rc = (mr->smr_normalize)(
238
			flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX),
Howard Chu's avatar
Cleanup    
Howard Chu committed
239
			ad->ad_type->sat_syntax,
Howard Chu's avatar
Howard Chu committed
240
			mr, val, &nval, ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
241
242
243
244
245

		if( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
246

247
	for ( i = 0; vals[i].bv_val != NULL; i++ ) {
248
		int match;
249
		const char *text;
250

251
		rc = value_match( &match, ad, mr, flags,
252
			&vals[i], nval.bv_val == NULL ? val : &nval, &text );
253

254
		if( rc == LDAP_SUCCESS && match == 0 ) {
255
			slap_sl_free( nval.bv_val, ctx );
Howard Chu's avatar
Howard Chu committed
256
			return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
258
259
		}
	}

260
	slap_sl_free( nval.bv_val, ctx );
Howard Chu's avatar
Howard Chu committed
261
	return LDAP_NO_SUCH_ATTRIBUTE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
262
}
Howard Chu's avatar
Howard Chu committed
263
264
265

/* assign new indexes to an attribute's ordered values */
void
266
ordered_value_renumber( Attribute *a )
Howard Chu's avatar
Howard Chu committed
267
268
269
{
	char *ptr, ibuf[64];	/* many digits */
	struct berval ibv, tmp, vtmp;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
270
	unsigned i;
Howard Chu's avatar
Howard Chu committed
271
272
273

	ibv.bv_val = ibuf;

274
	for (i=0; i<a->a_numvals; i++) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
275
		ibv.bv_len = sprintf(ibv.bv_val, "{%u}", i);
Howard Chu's avatar
Howard Chu committed
276
277
		vtmp = a->a_vals[i];
		if ( vtmp.bv_val[0] == '{' ) {
278
			ptr = ber_bvchr(&vtmp, '}');
279
			assert( ptr != NULL );
280
			++ptr;
Howard Chu's avatar
Howard Chu committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
			vtmp.bv_len -= ptr - vtmp.bv_val;
			vtmp.bv_val = ptr;
		}
		tmp.bv_len = ibv.bv_len + vtmp.bv_len;
		tmp.bv_val = ch_malloc( tmp.bv_len + 1 );
		strcpy( tmp.bv_val, ibv.bv_val );
		AC_MEMCPY( tmp.bv_val + ibv.bv_len, vtmp.bv_val, vtmp.bv_len );
		tmp.bv_val[tmp.bv_len] = '\0';
		ch_free( a->a_vals[i].bv_val );
		a->a_vals[i] = tmp;

		if ( a->a_nvals && a->a_nvals != a->a_vals ) {
			vtmp = a->a_nvals[i];
			if ( vtmp.bv_val[0] == '{' ) {
295
				ptr = ber_bvchr(&vtmp, '}');
296
				assert( ptr != NULL );
297
				++ptr;
Howard Chu's avatar
Howard Chu committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
				vtmp.bv_len -= ptr - vtmp.bv_val;
				vtmp.bv_val = ptr;
			}
			tmp.bv_len = ibv.bv_len + vtmp.bv_len;
			tmp.bv_val = ch_malloc( tmp.bv_len + 1 );
			strcpy( tmp.bv_val, ibv.bv_val );
			AC_MEMCPY( tmp.bv_val + ibv.bv_len, vtmp.bv_val, vtmp.bv_len );
			tmp.bv_val[tmp.bv_len] = '\0';
			ch_free( a->a_nvals[i].bv_val );
			a->a_nvals[i] = tmp;
		}
	}
}

/* Sort the values in an X-ORDERED VALUES attribute.
 * If the values have no index, index them in their given order.
 * If the values have indexes, sort them.
 * If some are indexed and some are not, return Error.
 */
int
ordered_value_sort( Attribute *a, int do_renumber )
{
	int i, vals;
	int index = 0, noindex = 0, renumber = 0, gotnvals = 0;
	struct berval tmp;

	if ( a->a_nvals && a->a_nvals != a->a_vals )
		gotnvals = 1;

	/* count attrs, look for index */
	for (i=0; a->a_vals[i].bv_val; i++) {
		if ( a->a_vals[i].bv_val[0] == '{' ) {
			char *ptr;
			index = 1;
332
			ptr = ber_bvchr( &a->a_vals[i], '}' );
333
			if ( !ptr )
Howard Chu's avatar
Howard Chu committed
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
				return LDAP_INVALID_SYNTAX;
			if ( noindex )
				return LDAP_INVALID_SYNTAX;
		} else {
			noindex = 1;
			if ( index )
				return LDAP_INVALID_SYNTAX;
		}
	}
	vals = i;

	/* If values have indexes, sort the values */
	if ( index ) {
		int *indexes, j, idx;
		struct berval ntmp;

#if 0
		/* Strip index from normalized values */
		if ( !a->a_nvals || a->a_vals == a->a_nvals ) {
			a->a_nvals = ch_malloc( (vals+1)*sizeof(struct berval));
			BER_BVZERO(a->a_nvals+vals);
			for ( i=0; i<vals; i++ ) {
356
				char *ptr = ber_bvchr(&a->a_vals[i], '}') + 1;
Howard Chu's avatar
Howard Chu committed
357
358
359
360
361
362
363
				a->a_nvals[i].bv_len = a->a_vals[i].bv_len -
					(ptr - a->a_vals[i].bv_val);
				a->a_nvals[i].bv_val = ch_malloc( a->a_nvals[i].bv_len + 1);
				strcpy(a->a_nvals[i].bv_val, ptr );
			}
		} else {
			for ( i=0; i<vals; i++ ) {
364
				char *ptr = ber_bvchr(&a->a_nvals[i], '}') + 1;
Howard Chu's avatar
Howard Chu committed
365
366
367
368
369
370
371
				a->a_nvals[i].bv_len -= ptr - a->a_nvals[i].bv_val;
				strcpy(a->a_nvals[i].bv_val, ptr);
			}
		}
#endif
				
		indexes = ch_malloc( vals * sizeof(int) );
372
373
374
375
376
377
378
379
		for ( i=0; i<vals; i++) {
			char *ptr;
			indexes[i] = strtol(a->a_vals[i].bv_val+1, &ptr, 0);
			if ( *ptr != '}' ) {
				ch_free( indexes );
				return LDAP_INVALID_SYNTAX;
			}
		}
Howard Chu's avatar
Howard Chu committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401

		/* Insertion sort */
		for ( i=1; i<vals; i++ ) {
			idx = indexes[i];
			tmp = a->a_vals[i];
			if ( gotnvals ) ntmp = a->a_nvals[i];
			j = i;
			while ((j > 0) && (indexes[j-1] > idx)) {
				indexes[j] = indexes[j-1];
				a->a_vals[j] = a->a_vals[j-1];
				if ( gotnvals ) a->a_nvals[j] = a->a_nvals[j-1];
				j--;
			}
			indexes[j] = idx;
			a->a_vals[j] = tmp;
			if ( gotnvals ) a->a_nvals[j] = ntmp;
		}

		/* If range is not contiguous, must renumber */
		if ( indexes[0] != 0 || indexes[vals-1] != vals-1 ) {
			renumber = 1;
		}
Howard Chu's avatar
Howard Chu committed
402
		ch_free( indexes );
Howard Chu's avatar
Howard Chu committed
403
404
405
406
407
	} else {
		renumber = 1;
	}

	if ( do_renumber && renumber )
408
		ordered_value_renumber( a );
Howard Chu's avatar
Howard Chu committed
409
410
411
412

	return 0;
}

413
414
415
/*
 * wrapper for validate function
 * uses the validate function of the syntax after removing
Howard Chu's avatar
Howard Chu committed
416
 * the index, if allowed and present
417
418
419
420
 */
int
ordered_value_validate(
	AttributeDescription *ad,
Howard Chu's avatar
Howard Chu committed
421
422
	struct berval *in,
	int mop )
423
424
425
426
427
428
429
430
431
432
{
	struct berval	bv = *in;

	assert( ad->ad_type->sat_syntax != NULL );
	assert( ad->ad_type->sat_syntax->ssyn_validate != NULL );

	if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {

		/* Skip past the assertion index */
		if ( bv.bv_val[0] == '{' ) {
433
			char		*ptr;
434

435
			ptr = ber_bvchr( &bv, '}' );
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
			if ( ptr != NULL ) {
				struct berval	ns;

				ns.bv_val = bv.bv_val + 1;
				ns.bv_len = ptr - ns.bv_val;

				if ( numericStringValidate( NULL, &ns ) == LDAP_SUCCESS ) {
					ptr++;
					bv.bv_len -= ptr - bv.bv_val;
					bv.bv_val = ptr;
					in = &bv;
					/* If deleting by index, just succeed */
					if ( mop == LDAP_MOD_DELETE && BER_BVISEMPTY( &bv ) ) {
						return LDAP_SUCCESS;
					}
				}
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
			}
		}
	}

	return ad->ad_type->sat_syntax->ssyn_validate( ad->ad_type->sat_syntax, in );
}

/*
 * wrapper for pretty function
 * uses the pretty function of the syntax after removing
 * the index, if allowed and present; in case, it's prepended
 * to the pretty value
 */
int
ordered_value_pretty(
	AttributeDescription *ad,
	struct berval *val,
	struct berval *out,
	void *ctx )
{
472
	struct berval	bv,
473
474
475
476
477
478
479
480
			idx = BER_BVNULL;
	int		rc;

	assert( ad->ad_type->sat_syntax != NULL );
	assert( ad->ad_type->sat_syntax->ssyn_pretty != NULL );
	assert( val != NULL );
	assert( out != NULL );

481
482
	bv = *val;

483
484
485
486
487
488
	if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {

		/* Skip past the assertion index */
		if ( bv.bv_val[0] == '{' ) {
			char	*ptr;

489
			ptr = ber_bvchr( &bv, '}' );
490
491
492
493
494
			if ( ptr != NULL ) {
				struct berval	ns;

				ns.bv_val = bv.bv_val + 1;
				ns.bv_len = ptr - ns.bv_val;
495

496
497
				if ( numericStringValidate( NULL, &ns ) == LDAP_SUCCESS ) {
					ptr++;
498

499
500
					idx = bv;
					idx.bv_len = ptr - bv.bv_val;
501

502
503
504
505
506
507
					bv.bv_len -= idx.bv_len;
					bv.bv_val = ptr;

					val = &bv;
				}
			}
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
536
537
538
539
540
541
542
		}
	}

	rc = ad->ad_type->sat_syntax->ssyn_pretty( ad->ad_type->sat_syntax, val, out, ctx );

	if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &idx ) ) {
		bv = *out;

		out->bv_len = idx.bv_len + bv.bv_len;
		out->bv_val = ber_memalloc_x( out->bv_len + 1, ctx );
		
		AC_MEMCPY( out->bv_val, idx.bv_val, idx.bv_len );
		AC_MEMCPY( &out->bv_val[ idx.bv_len ], bv.bv_val, bv.bv_len + 1 );

		ber_memfree_x( bv.bv_val, ctx );
	}

	return rc;
}

/*
 * wrapper for normalize function
 * uses the normalize function of the attribute description equality rule
 * after removing the index, if allowed and present; in case, it's
 * prepended to the value
 */
int
ordered_value_normalize(
	slap_mask_t usage,
	AttributeDescription *ad,
	MatchingRule *mr,
	struct berval *val,
	struct berval *normalized,
	void *ctx )
{
543
	struct berval	bv,
544
545
546
547
548
549
550
551
			idx = BER_BVNULL;
	int		rc;

	assert( ad->ad_type->sat_equality != NULL );
	assert( ad->ad_type->sat_equality->smr_normalize != NULL );
	assert( val != NULL );
	assert( normalized != NULL );

552
553
	bv = *val;

554
555
556
	if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {

		/* Skip past the assertion index */
557
		if ( bv.bv_val[ 0 ] == '{' ) {
558
559
			char	*ptr;

560
			ptr = ber_bvchr( &bv, '}' );
561
562
563
564
565
			if ( ptr != NULL ) {
				struct berval	ns;

				ns.bv_val = bv.bv_val + 1;
				ns.bv_len = ptr - ns.bv_val;
566

567
568
				if ( numericStringValidate( NULL, &ns ) == LDAP_SUCCESS ) {
					ptr++;
569

570
571
					idx = bv;
					idx.bv_len = ptr - bv.bv_val;
572

573
574
575
576
577
578
579
580
581
582
					bv.bv_len -= idx.bv_len;
					bv.bv_val = ptr;

					/* validator will already prevent this for Adds */
					if ( BER_BVISEMPTY( &bv )) {
						ber_dupbv_x( normalized, &idx, ctx );
						return LDAP_SUCCESS;
					}
					val = &bv;
				}
Howard Chu's avatar
Howard Chu committed
583
			}
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
		}
	}

	rc = ad->ad_type->sat_equality->smr_normalize( usage,
		ad->ad_type->sat_syntax, mr, val, normalized, ctx );

	if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &idx ) ) {
		bv = *normalized;

		normalized->bv_len = idx.bv_len + bv.bv_len;
		normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
		
		AC_MEMCPY( normalized->bv_val, idx.bv_val, idx.bv_len );
		AC_MEMCPY( &normalized->bv_val[ idx.bv_len ], bv.bv_val, bv.bv_len + 1 );

		ber_memfree_x( bv.bv_val, ctx );
	}

	return rc;
}

Howard Chu's avatar
Howard Chu committed
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
/* A wrapper for value match, handles Equality matches for attributes
 * with ordered values.
 */
int
ordered_value_match(
	int *match,
	AttributeDescription *ad,
	MatchingRule *mr,
	unsigned flags,
	struct berval *v1, /* stored value */
	struct berval *v2, /* assertion */
	const char ** text )
{
	struct berval bv1, bv2;

	/* X-ORDERED VALUES equality matching:
	 * If (SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX) that means we are
	 * comparing two attribute values. In this case, we want to ignore
	 * the ordering index of both values, we just want to know if their
	 * main values are equal.
	 *
	 * If (SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX) then we are comparing
	 * an assertion against an attribute value.
	 *    If the assertion has no index, the index of the value is ignored. 
	 *    If the assertion has only an index, the remainder of the value is
	 *      ignored.
	 *    If the assertion has index and value, both are compared.
	 */
	if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {
		char *ptr;
635
		struct berval ns1 = BER_BVNULL, ns2 = BER_BVNULL;
Howard Chu's avatar
Howard Chu committed
636
637
638
639
640
641

		bv1 = *v1;
		bv2 = *v2;

		/* Skip past the assertion index */
		if ( bv2.bv_val[0] == '{' ) {
642
			ptr = ber_bvchr( &bv2, '}' );
643
644
645
646
647
648
649
650
651
652
			if ( ptr != NULL ) {
				ns2.bv_val = bv2.bv_val + 1;
				ns2.bv_len = ptr - ns2.bv_val;

				if ( numericStringValidate( NULL, &ns2 ) == LDAP_SUCCESS ) {
					ptr++;
					bv2.bv_len -= ptr - bv2.bv_val;
					bv2.bv_val = ptr;
					v2 = &bv2;
				}
653
			}
Howard Chu's avatar
Howard Chu committed
654
655
		}

656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
		/* Skip past the attribute index */
		if ( bv1.bv_val[0] == '{' ) {
			ptr = ber_bvchr( &bv1, '}' );
			if ( ptr != NULL ) {
				ns1.bv_val = bv1.bv_val + 1;
				ns1.bv_len = ptr - ns1.bv_val;

				if ( numericStringValidate( NULL, &ns1 ) == LDAP_SUCCESS ) {
					ptr++;
					bv1.bv_len -= ptr - bv1.bv_val;
					bv1.bv_val = ptr;
					v1 = &bv1;
				}
			}
		}
Howard Chu's avatar
Howard Chu committed
671

672
673
674
675
		if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( flags )) {
			if ( !BER_BVISNULL( &ns2 ) && !BER_BVISNULL( &ns1 ) ) {
				/* compare index values first */
				(void)octetStringOrderingMatch( match, 0, NULL, NULL, &ns1, &ns2 );
Howard Chu's avatar
Howard Chu committed
676
677
678
679

				/* If not equal, or we're only comparing the index,
				 * return result now.
				 */
680
				if ( *match != 0 || BER_BVISEMPTY( &bv2 ) ) {
Howard Chu's avatar
Howard Chu committed
681
682
683
684
					return LDAP_SUCCESS;
				}
			}
		}
685

Howard Chu's avatar
Howard Chu committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
	}

	if ( !mr || !mr->smr_match ) {
		*match = ber_bvcmp( v1, v2 );
		return LDAP_SUCCESS;
	}

	return value_match( match, ad, mr, flags, v1, v2, text );
}

int
ordered_value_add(
	Entry *e,
	AttributeDescription *ad,
	Attribute *a,
	BerVarray vals,
	BerVarray nvals
)
{
	int i, j, k, anum, vnum;
	BerVarray new, nnew = NULL;

	/* count new vals */
	for (i=0; !BER_BVISNULL( vals+i ); i++) ;
	vnum = i;

	if ( a ) {
		ordered_value_sort( a, 0 );
	} else {
		Attribute **ap;
		for ( ap=&e->e_attrs; *ap; ap = &(*ap)->a_next ) ;
717
		a = attr_alloc( ad );
Howard Chu's avatar
Howard Chu committed
718
719
		*ap = a;
	}
720
	anum = a->a_numvals;
Howard Chu's avatar
Howard Chu committed
721
722

	new = ch_malloc( (anum+vnum+1) * sizeof(struct berval));
Pierangelo Masarati's avatar
Pierangelo Masarati committed
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737

	/* sanity check: if normalized modifications come in, either
	 * no values are present or normalized existing values differ
	 * from non-normalized; if no normalized modifications come in,
	 * either no values are present or normalized existing values
	 * don't differ from non-normalized */
	if ( nvals != NULL ) {
		assert( nvals != vals );
		assert( a->a_nvals == NULL || a->a_nvals != a->a_vals );

	} else {
		assert( a->a_nvals == NULL || a->a_nvals == a->a_vals );
	}

	if ( ( a->a_nvals && a->a_nvals != a->a_vals ) || nvals != NULL ) {
Howard Chu's avatar
Howard Chu committed
738
739
740
741
742
743
		nnew = ch_malloc( (anum+vnum+1) * sizeof(struct berval));
		/* Shouldn't happen... */
		if ( !nvals ) nvals = vals;
	}
	if ( anum ) {
		AC_MEMCPY( new, a->a_vals, anum * sizeof(struct berval));
744
		if ( nnew && a->a_nvals )
Howard Chu's avatar
Howard Chu committed
745
746
747
748
			AC_MEMCPY( nnew, a->a_nvals, anum * sizeof(struct berval));
	}

	for (i=0; i<vnum; i++) {
749
750
		char	*next;

Howard Chu's avatar
Howard Chu committed
751
752
		k = -1;
		if ( vals[i].bv_val[0] == '{' ) {
753
			/* FIXME: strtol() could go past end... */
754
			k = strtol( vals[i].bv_val + 1, &next, 0 );
755
756
			if ( next == vals[i].bv_val + 1 ||
				next[ 0 ] != '}' ||
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
757
				(ber_len_t) (next - vals[i].bv_val) > vals[i].bv_len )
758
			{
Howard Chu's avatar
Cleanup    
Howard Chu committed
759
760
				ch_free( nnew );
				ch_free( new );
761
762
				return -1;
			}
Howard Chu's avatar
Howard Chu committed
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
			if ( k > anum ) k = -1;
		}
		/* No index, or index is greater than current number of
		 * values, just tack onto the end
		 */
		if ( k < 0 ) {
			ber_dupbv( new+anum, vals+i );
			if ( nnew ) ber_dupbv( nnew+anum, nvals+i );

		/* Indexed, push everything else down one and insert */
		} else {
			for (j=anum; j>k; j--) {
				new[j] = new[j-1];
				if ( nnew ) nnew[j] = nnew[j-1];
			}
			ber_dupbv( new+k, vals+i );
			if ( nnew ) ber_dupbv( nnew+k, nvals+i );
		}
		anum++;
	}
	BER_BVZERO( new+anum );
	ch_free( a->a_vals );
	a->a_vals = new;
	if ( nnew ) {
		BER_BVZERO( nnew+anum );
		ch_free( a->a_nvals );
		a->a_nvals = nnew;
	} else {
		a->a_nvals = a->a_vals;
	}

794
795
	a->a_numvals = anum;
	ordered_value_renumber( a );
Howard Chu's avatar
Howard Chu committed
796
797
798

	return 0;
}