schema_init.c 104 KB
Newer Older
1
2
3
/* schema_init.c - init builtin schema */
/* $OpenLDAP$ */
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5
6
7
8
9
10
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */

#include "portable.h"

#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
#include <limits.h>
12
13

#include <ac/ctype.h>
14
#include <ac/errno.h>
15
16
17
18
19
#include <ac/string.h>
#include <ac/socket.h>

#include "slap.h"
#include "ldap_pvt.h"
20

21
22
#include "ldap_utf8.h"

23
24
25
26
27
28
#include "lutil_hash.h"
#define HASH_BYTES				LUTIL_HASH_BYTES
#define HASH_CONTEXT			lutil_HASH_CTX
#define HASH_Init(c)			lutil_HASHInit(c)
#define HASH_Update(c,buf,len)	lutil_HASHUpdate(c,buf,len)
#define HASH_Final(d,c)			lutil_HASHFinal(d,c)
29

30
/* recycled validatation routines */
31
#define berValidate						blobValidate
32
33

/* unimplemented pretters */
34
#define integerPretty					NULL
35
36

/* recycled matching routines */
37
#define bitStringMatch					octetStringMatch
38
39
40
#define numericStringMatch				caseIgnoreIA5Match
#define objectIdentifierMatch			caseIgnoreIA5Match
#define telephoneNumberMatch			caseIgnoreIA5Match
41
#define telephoneNumberSubstringsMatch	caseIgnoreIA5SubstringsMatch
42
43
#define generalizedTimeMatch			caseIgnoreIA5Match
#define generalizedTimeOrderingMatch	caseIgnoreIA5Match
44
#define uniqueMemberMatch				dnMatch
45

46
47
/* approx matching rules */
#define directoryStringApproxMatchOID	"1.3.6.1.4.1.4203.666.4.4"
Gary Williams's avatar
Gary Williams committed
48
49
50
#define directoryStringApproxMatch	approxMatch
#define directoryStringApproxIndexer	approxIndexer
#define directoryStringApproxFilter	approxFilter
51
#define IA5StringApproxMatchOID			"1.3.6.1.4.1.4203.666.4.5"
Gary Williams's avatar
Gary Williams committed
52
#define IA5StringApproxMatch			approxMatch
53
#define IA5StringApproxIndexer			approxIndexer
Gary Williams's avatar
Gary Williams committed
54
#define IA5StringApproxFilter			approxFilter
55

56
57
58
59
/* orderring matching rules */
#define caseIgnoreOrderingMatch			caseIgnoreMatch
#define caseExactOrderingMatch			caseExactMatch

60
/* unimplemented matching routines */
61
62
63
64
65
66
67
#define caseIgnoreListMatch				NULL
#define caseIgnoreListSubstringsMatch	NULL
#define protocolInformationMatch		NULL
#define integerFirstComponentMatch		NULL

#define OpenLDAPaciMatch				NULL
#define authPasswordMatch				NULL
68
69

/* recycled indexing/filtering routines */
70
71
#define dnIndexer				caseExactIgnoreIndexer
#define dnFilter				caseExactIgnoreFilter
72
73
#define bitStringFilter			octetStringFilter
#define bitStringIndexer		octetStringIndexer
74

75
76
77
78
79
#define telephoneNumberIndexer			caseIgnoreIA5Indexer
#define telephoneNumberFilter			caseIgnoreIA5Filter
#define telephoneNumberSubstringsIndexer	caseIgnoreIA5SubstringsIndexer
#define telephoneNumberSubstringsFilter		caseIgnoreIA5SubstringsFilter

80
81
82
83
/* must match OIDs below */
#define caseExactMatchOID			"2.5.13.5"
#define caseExactSubstringsMatchOID		"2.5.13.7"

84
85
86
87
static char *strcasechr( const char *str, int c )
{
	char *lower = strchr( str, TOLOWER(c) );
	char *upper = strchr( str, TOUPPER(c) );
88

89
90
91
92
93
94
95
96
	if( lower && upper ) {
		return lower < upper ? lower : upper;
	} else if ( lower ) {
		return lower;
	} else {
		return upper;
	}
}
97

98
99
100
static int
octetStringMatch(
	int *matchp,
101
	slap_mask_t flags,
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;

	if( match == 0 ) {
		match = memcmp( value->bv_val,
			((struct berval *) assertedValue)->bv_val,
			value->bv_len );
	}

	*matchp = match;
	return LDAP_SUCCESS;
}

/* Index generation function */
120
static int octetStringIndexer(
121
122
	slap_mask_t use,
	slap_mask_t flags,
123
124
125
126
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	struct berval **values,
127
	struct berval **keysp )
128
129
130
{
	int i;
	size_t slen, mlen;
131
	struct berval *keys;
132
	HASH_CONTEXT   HASHcontext;
Gary Williams's avatar
Gary Williams committed
133
	unsigned char	HASHdigest[HASH_BYTES];
134
	struct berval digest;
135
136
	digest.bv_val = HASHdigest;
	digest.bv_len = sizeof(HASHdigest);
137
138
139
140
141

	for( i=0; values[i] != NULL; i++ ) {
		/* just count them */
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
142
143
144
	/* we should have at least one value at this point */
	assert( i > 0 );

145
	keys = ch_malloc( sizeof( struct berval ) * (i+1) );
146

147
148
	slen = syntax->ssyn_oidlen;
	mlen = mr->smr_oidlen;
149
150

	for( i=0; values[i] != NULL; i++ ) {
151
		HASH_Init( &HASHcontext );
152
		if( prefix != NULL && prefix->bv_len > 0 ) {
153
			HASH_Update( &HASHcontext,
154
155
				prefix->bv_val, prefix->bv_len );
		}
156
		HASH_Update( &HASHcontext,
157
			syntax->ssyn_oid, slen );
158
		HASH_Update( &HASHcontext,
159
			mr->smr_oid, mlen );
160
		HASH_Update( &HASHcontext,
161
			values[i]->bv_val, values[i]->bv_len );
162
		HASH_Final( HASHdigest, &HASHcontext );
163

164
		ber_dupbv( &keys[i], &digest );
165
166
	}

167
	keys[i].bv_val = NULL;
168
169
170
171
172
173
174

	*keysp = keys;

	return LDAP_SUCCESS;
}

/* Index generation function */
175
static int octetStringFilter(
176
177
	slap_mask_t use,
	slap_mask_t flags,
178
179
180
181
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
182
	struct berval **keysp )
183
184
{
	size_t slen, mlen;
185
	struct berval *keys;
186
	HASH_CONTEXT   HASHcontext;
Gary Williams's avatar
Gary Williams committed
187
	unsigned char	HASHdigest[HASH_BYTES];
188
189
	struct berval *value = (struct berval *) assertValue;
	struct berval digest;
190
191
	digest.bv_val = HASHdigest;
	digest.bv_len = sizeof(HASHdigest);
192

193
194
	slen = syntax->ssyn_oidlen;
	mlen = mr->smr_oidlen;
195

196
	keys = ch_malloc( sizeof( struct berval ) * 2 );
197

198
	HASH_Init( &HASHcontext );
199
	if( prefix != NULL && prefix->bv_len > 0 ) {
200
		HASH_Update( &HASHcontext,
201
202
			prefix->bv_val, prefix->bv_len );
	}
203
	HASH_Update( &HASHcontext,
204
		syntax->ssyn_oid, slen );
205
	HASH_Update( &HASHcontext,
206
		mr->smr_oid, mlen );
207
	HASH_Update( &HASHcontext,
208
		value->bv_val, value->bv_len );
209
	HASH_Final( HASHdigest, &HASHcontext );
210

211
212
	ber_dupbv( keys, &digest );
	keys[1].bv_val = NULL;
213
214
215
216
217

	*keysp = keys;

	return LDAP_SUCCESS;
}
218

219
220
221
222
223
224
225
226
227
228
229
static int
nameUIDValidate(
	Syntax *syntax,
	struct berval *in )
{
	int rc;
	struct berval *dn;

	if( in->bv_len == 0 ) return LDAP_SUCCESS;

	dn = ber_bvdup( in );
230
	if( !dn ) return LDAP_OTHER;
231

232
233
234
	if( dn->bv_val[dn->bv_len-1] == 'B'
		&& dn->bv_val[dn->bv_len-2] == '\'' )
	{
235
236
237
		/* assume presence of optional UID */
		ber_len_t i;

238
		for(i=dn->bv_len-3; i>1; i--) {
239
240
241
242
			if( dn->bv_val[i] != '0' &&	dn->bv_val[i] != '1' ) {
				break;
			}
		}
Stig Venaas's avatar
Stig Venaas committed
243
		if( dn->bv_val[i] != '\'' ||
244
		    dn->bv_val[i-1] != '#' ) {
Stig Venaas's avatar
Stig Venaas committed
245
			ber_bvfree( dn );
246
247
248
			return LDAP_INVALID_SYNTAX;
		}

249
250
251
		/* trim the UID to allow use of dnValidate */
		dn->bv_val[i-1] = '\0';
		dn->bv_len = i-1;
252
253
	}

254
	rc = dnValidate( NULL, dn );
255
256
257
258
259
260
261
262
263

	ber_bvfree( dn );
	return rc;
}

static int
nameUIDNormalize(
	Syntax *syntax,
	struct berval *val,
264
	struct berval *normalized )
265
{
266
	struct berval out;
Howard Chu's avatar
Howard Chu committed
267
	int rc;
268

269
270
	ber_dupbv( &out, val );
	if( out.bv_len != 0 ) {
271
272
273
274
		ber_len_t dnlen;
		char *uid = NULL;
		ber_len_t uidlen = 0;

275
		if( out.bv_val[out.bv_len-1] == '\'' ) {
276
			/* assume presence of optional UID */
277
			uid = strrchr( out.bv_val, '#' );
278
279

			if( uid == NULL ) {
280
				free( out.bv_val );
281
282
283
				return LDAP_INVALID_SYNTAX;
			}

284
			uidlen = out.bv_len - (uid - out.bv_val);
285
286
			/* temporarily trim the UID */
			*uid = '\0';
287
			out.bv_len -= uidlen;
288
289
290
		}

#ifdef USE_DN_NORMALIZE
291
		rc = dnNormalize2( NULL, &out, normalized );
292
#else
293
		rc = dnPretty2( NULL, &out, normalized );
294
295
#endif

Howard Chu's avatar
Howard Chu committed
296
		if( rc != LDAP_SUCCESS ) {
297
			free( out.bv_val );
298
299
300
			return LDAP_INVALID_SYNTAX;
		}

301
		dnlen = normalized->bv_len;
302
303

		if( uidlen ) {
304
305
306
			struct berval b2;
			b2.bv_val = ch_malloc(dnlen + uidlen + 1);
			SAFEMEMCPY( b2.bv_val, normalized->bv_val, dnlen );
Howard Chu's avatar
Howard Chu committed
307

308
309
310
			/* restore the separator */
			*uid = '#';
			/* shift the UID */
311
312
313
314
			SAFEMEMCPY( normalized->bv_val+dnlen, uid, uidlen );
			b2.bv_len = dnlen + uidlen;
			normalized->bv_val[dnlen+uidlen] = '\0';
			free(normalized->bv_val);
Howard Chu's avatar
Howard Chu committed
315
			*normalized = b2;
316
		}
317
		free( out.bv_val );
318
319
320
321
322
	}

	return LDAP_SUCCESS;
}

323
324
325
326
327
328
329
330
331
static int
inValidate(
	Syntax *syntax,
	struct berval *in )
{
	/* any value allowed */
	return LDAP_OTHER;
}

332
static int
333
blobValidate(
334
335
336
337
	Syntax *syntax,
	struct berval *in )
{
	/* any value allowed */
338
	return LDAP_SUCCESS;
339
340
}

341
342
343
344
345
346
347
348
349
350
351
352
353
static int
bitStringValidate(
	Syntax *syntax,
	struct berval *in )
{
	ber_len_t i;

	/* very unforgiving validation, requires no normalization
	 * before simplistic matching
	 */
	if( in->bv_len < 3 ) {
		return LDAP_INVALID_SYNTAX;
	}
354

355
356
357
358
359
360
361
362
363
364
	/*
	 * rfc 2252 section 6.3 Bit String
	 * bitstring = "'" *binary-digit "'"
	 * binary-digit = "0" / "1"
	 * example: '0101111101'B
	 */
	
	if( in->bv_val[0] != '\'' ||
		in->bv_val[in->bv_len-2] != '\'' ||
		in->bv_val[in->bv_len-1] != 'B' )
365
366
367
368
	{
		return LDAP_INVALID_SYNTAX;
	}

369
	for( i=in->bv_len-3; i>0; i-- ) {
370
371
372
373
374
375
376
377
		if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
			return LDAP_INVALID_SYNTAX;
		}
	}

	return LDAP_SUCCESS;
}

378
379
380
381
static int
bitStringNormalize(
	Syntax *syntax,
	struct berval *val,
382
	struct berval *normalized )
383
384
{
	/*
385
	 * A normalized bitString is has no extaneous (leading) zero bits.
386
387
	 * That is, '00010'B is normalized to '10'B
	 * However, as a special case, '0'B requires no normalization.
388
	 */
389
390
391
392
393
394
395
396
397
398
	char *p;

	/* start at the first bit */
	p = &val->bv_val[1];

	/* Find the first non-zero bit */
	while ( *p == '0' ) p++;

	if( *p == '\'' ) {
		/* no non-zero bits */
399
		ber_str2bv( "\'0\'B", sizeof("\'0\'B") - 1, 1, normalized );
400
401
402
		goto done;
	}

403
	normalized->bv_val = ch_malloc( val->bv_len + 1 );
404

405
406
	normalized->bv_val[0] = '\'';
	normalized->bv_len = 1;
407
408

	for( ; *p != '\0'; p++ ) {
409
		normalized->bv_val[normalized->bv_len++] = *p;
410
411
	}

412
	normalized->bv_val[normalized->bv_len] = '\0';
413
414
415
416
417

done:
	return LDAP_SUCCESS;
}

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/*
 * Handling boolean syntax and matching is quite rigid.
 * A more flexible approach would be to allow a variety
 * of strings to be normalized and prettied into TRUE
 * and FALSE.
 */
static int
booleanValidate(
	Syntax *syntax,
	struct berval *in )
{
	/* very unforgiving validation, requires no normalization
	 * before simplistic matching
	 */

	if( in->bv_len == 4 ) {
		if( !memcmp( in->bv_val, "TRUE", 4 ) ) {
			return LDAP_SUCCESS;
		}
	} else if( in->bv_len == 5 ) {
		if( !memcmp( in->bv_val, "FALSE", 5 ) ) {
			return LDAP_SUCCESS;
		}
	}

	return LDAP_INVALID_SYNTAX;
}

static int
booleanMatch(
	int *matchp,
449
	slap_mask_t flags,
450
451
452
453
454
455
456
457
458
459
460
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	/* simplistic matching allowed by rigid validation */
	struct berval *asserted = (struct berval *) assertedValue;
	*matchp = value->bv_len != asserted->bv_len;
	return LDAP_SUCCESS;
}

461
462
463
464
465
466
467
468
469
static int
UTF8StringValidate(
	Syntax *syntax,
	struct berval *in )
{
	ber_len_t count;
	int len;
	unsigned char *u = in->bv_val;

470
471
	if( !in->bv_len ) return LDAP_INVALID_SYNTAX;

472
	for( count = in->bv_len; count > 0; count-=len, u+=len ) {
473
474
475
476
		/* get the length indicated by the first byte */
		len = LDAP_UTF8_CHARLEN( u );

		/* should not be zero */
477
		if( len == 0 ) return LDAP_INVALID_SYNTAX;
478
479
480

		/* make sure len corresponds with the offset
			to the next character */
481
		if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
482
483
	}

484
	if( count != 0 ) return LDAP_INVALID_SYNTAX;
485

486
	return LDAP_SUCCESS;
487
488
489
490
491
492
}

static int
UTF8StringNormalize(
	Syntax *syntax,
	struct berval *val,
493
	struct berval *normalized )
494
{
495
	char *p, *q, *s;
496
	int len = 0;
497

498
	p = val->bv_val;
499

500
	/* Ignore initial whitespace */
501
502
503
	/* All space is ASCII. All ASCII is 1 byte */
	while ( ASCII_SPACE( *p ) ) {
		p++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
504
	}
505

506
	if( *p == '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
507
508
		return LDAP_INVALID_SYNTAX;
	}
509

510
511
512
513
514
	ber_str2bv( p, val->bv_len - (p - val->bv_val), 1, normalized );

	assert( normalized->bv_val );

	p = q = normalized->bv_val;
515
	s = NULL;
516

517
	while ( *p ) {
518
519
520
521
522
		q += len;
		if ( ASCII_SPACE( *p ) ) {
			s = q - len;
			len = 1;
			*q = *p++;
523

524
			/* Ignore the extra whitespace */
525
526
			while ( ASCII_SPACE( *p ) ) {
				p++;
527
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
528
		} else {
529
530
531
			len = LDAP_UTF8_COPY(q,p);
			s=NULL;
			p+=len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
532
		}
533
534
	}

535
	assert( normalized->bv_val < p );
536
	assert( q+len <= p );
537

538
	/* cannot start with a space */
539
	assert( !ASCII_SPACE(normalized->bv_val[0]) );
540
541
542
543
544
545
546
547
548

	/*
	 * If the string ended in space, backup the pointer one
	 * position.  One is enough because the above loop collapsed
	 * all whitespace to a single space.
	 */

	if ( s != NULL ) {
		q = s;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
	}
550

551
	/* cannot end with a space */
552
553
554
	assert( !ASCII_SPACE( *q ) );

	q += len;
555
556
557
558

	/* null terminate */
	*q = '\0';

559
	normalized->bv_len = q - normalized->bv_val;
560

561
	return LDAP_SUCCESS;
562
563
}

564
/* Returns Unicode canonically normalized copy of a substring assertion
565
 * Skipping attribute description */
566
static SubstringsAssertion *
567
568
569
570
571
572
573
574
575
576
577
578
UTF8SubstringsassertionNormalize(
	SubstringsAssertion *sa,
	char casefold )
{
	SubstringsAssertion *nsa;
	int i;

	nsa = (SubstringsAssertion *)ch_calloc( 1, sizeof(SubstringsAssertion) );
	if( nsa == NULL ) {
		return NULL;
	}

579
580
581
582
	if( sa->sa_initial.bv_val != NULL ) {
		ber_str2bv( UTF8normalize( &sa->sa_initial, casefold ), 0,
			0, &nsa->sa_initial );
		if( nsa->sa_initial.bv_val == NULL ) {
583
584
585
586
587
			goto err;
		}
	}

	if( sa->sa_any != NULL ) {
588
		for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
589
590
			/* empty */
		}
591
592
593
594
595
		nsa->sa_any = (struct berval *)ch_malloc( (i + 1) * sizeof(struct berval) );
		for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
			ber_str2bv( UTF8normalize( &sa->sa_any[i], casefold ),
				0, 0, &nsa->sa_any[i] );
			if( nsa->sa_any[i].bv_val == NULL ) {
596
597
598
				goto err;
			}
		}
599
		nsa->sa_any[i].bv_val = NULL;
600
601
	}

602
603
604
605
	if( sa->sa_final.bv_val != NULL ) {
		ber_str2bv( UTF8normalize( &sa->sa_final, casefold ), 0,
			0, &nsa->sa_final );
		if( nsa->sa_final.bv_val == NULL ) {
606
607
608
609
610
611
612
			goto err;
		}
	}

	return nsa;

err:
Howard Chu's avatar
Howard Chu committed
613
614
615
	if ( nsa->sa_final.bv_val ) free( nsa->sa_final.bv_val );
	if ( nsa->sa_any )bvarray_free( nsa->sa_any );
	if ( nsa->sa_initial.bv_val ) free( nsa->sa_initial.bv_val );
616
617
618
619
	ch_free( nsa );
	return NULL;
}

620
/* Strip characters with the 8th bit set */
621
static char *
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
strip8bitChars(
	char *in )      
{
	char *p = in, *q;
  
	if( in == NULL ) {
		return NULL;
	}
	while( *p ) {
		if( *p & 0x80 ) {
			q = p;
			while( *++q & 0x80 ) {
				/* empty */
			}
			p = memmove(p, q, strlen(q) + 1);
		} else {
			p++;
		}
	}
	return in;
}

644
#ifndef SLAPD_APPROX_OLDSINGLESTRING
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662

#if defined(SLAPD_APPROX_INITIALS)
#define SLAPD_APPROX_DELIMITER "._ "
#define SLAPD_APPROX_WORDLEN 2
#else
#define SLAPD_APPROX_DELIMITER " "
#define SLAPD_APPROX_WORDLEN 1
#endif

static int
approxMatch(
	int *matchp,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
663
	char *val, *nval, *assertv, **values, **words, *c;
664
	int i, count, len, nextchunk=0, nextavail=0;
665
	size_t avlen;
666

667
	/* Yes, this is necessary */
668
	nval = UTF8normalize( value, UTF8_NOCASEFOLD );
669
	if( nval == NULL ) {
670
671
672
		*matchp = 1;
		return LDAP_SUCCESS;
	}
673
	strip8bitChars( nval );
674
675

	/* Yes, this is necessary */
676
	assertv = UTF8normalize( ((struct berval *)assertedValue),
677
678
				 UTF8_NOCASEFOLD );
	if( assertv == NULL ) {
679
		ch_free( nval );
680
681
682
683
684
		*matchp = 1;
		return LDAP_SUCCESS;
	}
	strip8bitChars( assertv );
	avlen = strlen( assertv );
685
686

	/* Isolate how many words there are */
687
	for( c=nval,count=1; *c; c++ ) {
688
689
690
691
692
693
694
695
696
		c = strpbrk( c, SLAPD_APPROX_DELIMITER );
		if ( c == NULL ) break;
		*c = '\0';
		count++;
	}

	/* Get a phonetic copy of each word */
	words = (char **)ch_malloc( count * sizeof(char *) );
	values = (char **)ch_malloc( count * sizeof(char *) );
697
	for( c=nval,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
698
699
700
701
		words[i] = c;
		values[i] = phonetic(c);
	}

702
	/* Work through the asserted value's words, to see if at least some
703
704
	   of the words are there, in the same order. */
	len = 0;
705
	while ( (size_t) nextchunk < avlen ) {
706
		len = strcspn( assertv + nextchunk, SLAPD_APPROX_DELIMITER);
707
708
709
710
		if( len == 0 ) {
			nextchunk++;
			continue;
		}
711
#if defined(SLAPD_APPROX_INITIALS)
712
		else if( len == 1 ) {
713
714
			/* Single letter words need to at least match one word's initial */
			for( i=nextavail; i<count; i++ )
715
716
				if( !strncasecmp( assertv+nextchunk, words[i], 1 )) {
					nextavail=i+1;
717
					break;
718
				}
719
720
		}
#endif
721
		else {
722
723
724
725
726
727
728
729
730
731
732
			/* Isolate the next word in the asserted value and phonetic it */
			assertv[nextchunk+len] = '\0';
			val = phonetic( assertv + nextchunk );

			/* See if this phonetic chunk is in the remaining words of *value */
			for( i=nextavail; i<count; i++ ){
				if( !strcmp( val, values[i] ) ){
					nextavail = i+1;
					break;
				}
			}
733
			ch_free( val );
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
		}

		/* This chunk in the asserted value was NOT within the *value. */
		if( i >= count ) {
			nextavail=-1;
			break;
		}

		/* Go on to the next word in the asserted value */
		nextchunk += len+1;
	}

	/* If some of the words were seen, call it a match */
	if( nextavail > 0 ) {
		*matchp = 0;
	}
	else {
		*matchp = 1;
	}

	/* Cleanup allocs */
755
	free( assertv );
756
757
758
759
760
	for( i=0; i<count; i++ ) {
		ch_free( values[i] );
	}
	ch_free( values );
	ch_free( words );
761
	ch_free( nval );
762
763
764
765

	return LDAP_SUCCESS;
}

766
static int 
767
768
769
770
771
772
773
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	struct berval **values,
774
	struct berval **keysp )
775
776
777
{
	char *val, *c;
	int i,j, len, wordcount, keycount=0;
778
	struct berval *newkeys, *keys=NULL;
779
780

	for( j=0; values[j] != NULL; j++ ) {
781
		/* Yes, this is necessary */
782
		val = UTF8normalize( values[j], UTF8_NOCASEFOLD );
783
784
		strip8bitChars( val );

785
		/* Isolate how many words there are. There will be a key for each */
Gary Williams's avatar
Gary Williams committed
786
		for( wordcount=0,c=val;	 *c;  c++) {
787
788
789
790
791
792
793
794
			len = strcspn(c, SLAPD_APPROX_DELIMITER);
			if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
			c+= len;
			if (*c == '\0') break;
			*c = '\0';
		}

		/* Allocate/increase storage to account for new keys */
795
796
797
		newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
			* sizeof(struct berval) );
		memcpy( newkeys, keys, keycount * sizeof(struct berval) );
798
799
800
801
		if( keys ) ch_free( keys );
		keys = newkeys;

		/* Get a phonetic copy of each word */
Gary Williams's avatar
Gary Williams committed
802
		for( c=val,i=0;	 i<wordcount;  c+=len+1	 ) {
803
804
			len = strlen( c );
			if( len < SLAPD_APPROX_WORDLEN ) continue;
805
			ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
806
807
808
809
			keycount++;
			i++;
		}

810
		free( val );
811
	}
812
	keys[keycount].bv_val = NULL;
813
814
815
816
817
	*keysp = keys;

	return LDAP_SUCCESS;
}

818
static int 
819
820
821
822
823
824
825
approxFilter(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
826
	struct berval **keysp )
827
828
829
{
	char *val, *c;
	int i, count, len;
830
	struct berval *keys;
831

832
	/* Yes, this is necessary */
833
	val = UTF8normalize( ((struct berval *)assertValue),
834
835
			     UTF8_NOCASEFOLD );
	if( val == NULL ) {
836
837
		keys = (struct berval *)ch_malloc( sizeof(struct berval) );
		keys[0].bv_val = NULL;
838
839
840
841
842
		*keysp = keys;
		return LDAP_SUCCESS;
	}
	strip8bitChars( val );

843
844
845
846
847
848
849
850
851
852
	/* Isolate how many words there are. There will be a key for each */
	for( count=0,c=val;  *c;  c++) {
		len = strcspn(c, SLAPD_APPROX_DELIMITER);
		if( len >= SLAPD_APPROX_WORDLEN ) count++;
		c+= len;
		if (*c == '\0') break;
		*c = '\0';
	}

	/* Allocate storage for new keys */
853
	keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
854
855

	/* Get a phonetic copy of each word */
Gary Williams's avatar
Gary Williams committed
856
	for( c=val,i=0;	 i<count; c+=len+1 ) {
857
858
		len = strlen(c);
		if( len < SLAPD_APPROX_WORDLEN ) continue;
859
		ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
860
861
862
		i++;
	}

863
	free( val );
864

865
	keys[count].bv_val = NULL;
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
	*keysp = keys;

	return LDAP_SUCCESS;
}


#else
/* No other form of Approximate Matching is defined */

static int
approxMatch(
	int *matchp,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	char *vapprox, *avapprox;
885
	char *s, *t;
886

887
	/* Yes, this is necessary */
888
	s = UTF8normalize( value, UTF8_NOCASEFOLD );
889
890
891
892
893
894
	if( s == NULL ) {
		*matchp = 1;
		return LDAP_SUCCESS;
	}

	/* Yes, this is necessary */
895
	t = UTF8normalize( ((struct berval *)assertedValue),
896
897
898
899
900
901
902
903
904
905
906
907
			   UTF8_NOCASEFOLD );
	if( t == NULL ) {
		free( s );
		*matchp = -1;
		return LDAP_SUCCESS;
	}

	vapprox = phonetic( strip8bitChars( s ) );
	avapprox = phonetic( strip8bitChars( t ) );

	free( s );
	free( t );
908
909
910
911
912
913
914
915
916

	*matchp = strcmp( vapprox, avapprox );

	ch_free( vapprox );
	ch_free( avapprox );

	return LDAP_SUCCESS;
}

917
static int 
918
919
920
921
922
923
924
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	struct berval **values,
925
	struct berval **keysp )
926
927
{
	int i;
928
	struct berval *keys;
929
	char *s;
930
931

	for( i=0; values[i] != NULL; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
932
		/* empty - just count them */
933
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
934
935

	/* we should have at least one value at this point */
936
937
	assert( i > 0 );

938
	keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
939
940
941

	/* Copy each value and run it through phonetic() */
	for( i=0; values[i] != NULL; i++ ) {
942
		/* Yes, this is necessary */
943
		s = UTF8normalize( values[i], UTF8_NOCASEFOLD );
944
945

		/* strip 8-bit chars and run through phonetic() */
946
		ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
947
		free( s );
948
	}
949
	keys[i].bv_val = NULL;
950
951
952
953
954
955

	*keysp = keys;
	return LDAP_SUCCESS;
}


956
static int 
957
958
959
960
961
962
963
approxFilter(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
964
	struct berval **keysp )
965
{
966
	struct berval *keys;
967
	char *s;
968

969
	keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
970

971
	/* Yes, this is necessary */
972
	s = UTF8normalize( ((struct berval *)assertValue),
973
974
975
976
977
978
979
980
981
			     UTF8_NOCASEFOLD );
	if( s == NULL ) {
		keys[0] = NULL;
	} else {
		/* strip 8-bit chars and run through phonetic() */
		keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
		free( s );
		keys[1] = NULL;
	}
982
983
984
985
986
987
988

	*keysp = keys;
	return LDAP_SUCCESS;
}
#endif


989
static int
990
caseExactMatch(
991
	int *matchp,
992
	slap_mask_t flags,
993
994
995
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
996
	void *assertedValue )
997
{
998
999
1000
	*matchp = UTF8normcmp( value->bv_val,
		((struct berval *) assertedValue)->bv_val,
		UTF8_NOCASEFOLD );
1001
	return LDAP_SUCCESS;
1002
1003
}

1004
static int
1005
caseExactIgnoreSubstringsMatch(
1006
	int *matchp,
1007
	slap_mask_t flags,
1008
1009
1010
1011
1012
1013
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	int match = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1014
	SubstringsAssertion *sub = NULL;
1015
	struct berval left;
1016
1017
	int i;
	ber_len_t inlen=0;
1018
1019
1020
1021
	char *nav, casefold;

	casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID )
		? UTF8_CASEFOLD : UTF8_NOCASEFOLD;
1022

1023
	nav = UTF8normalize( value, casefold );
1024
1025
1026
1027
1028
1029
	if( nav == NULL ) {
		match = 1;
		goto done;
	}
	left.bv_val = nav;
	left.bv_len = strlen( nav );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1030

1031
	sub = UTF8SubstringsassertionNormalize( assertedValue, casefold );
1032
1033
1034
1035
	if( sub == NULL ) {
		match = -1;
		goto done;
	}
1036

1037
	/* Add up asserted input length */
1038
1039
	if( sub->sa_initial.bv_val ) {
		inlen += sub->sa_initial.bv_len;
1040
1041
	}
	if( sub->sa_any ) {
1042
1043
		for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
			inlen += sub->sa_any[i].bv_len;
1044
1045
		}
	}
1046
1047
	if( sub->sa_final.bv_val ) {
		inlen += sub->sa_final.bv_len;
1048
1049
	}

1050
	if( sub->sa_initial.bv_val ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1051
1052
1053
1054
1055
		if( inlen > left.bv_len ) {
			match = 1;
			goto done;
		}

1056
1057
		match = strncmp( sub->sa_initial.bv_val, left.bv_val,
			sub->sa_initial.bv_len );
1058
1059
1060
1061
1062

		if( match != 0 ) {
			goto done;
		}

1063
1064
1065
		left.bv_val += sub->sa_initial.bv_len;
		left.bv_len -= sub->sa_initial.bv_len;
		inlen -= sub->sa_initial.bv_len;