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-2002 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
static char *bvcasechr( struct berval *bv, int c, ber_len_t *len )
85
{
86
87
88
89
90
91
92
93
94
	ber_len_t i;
	int lower = TOLOWER( c );
	int upper = TOUPPER( c );
	
	for( i=0; i < bv->bv_len; i++ ) {
		if( upper == bv->bv_val[i] || lower == bv->bv_val[i] ) {
			*len = i;
			return &bv->bv_val[i];
		}
95
	}
96
97

	return NULL;
98
}
99

100
101
102
static int
octetStringMatch(
	int *matchp,
103
	slap_mask_t flags,
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
	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 */
122
static int octetStringIndexer(
123
124
	slap_mask_t use,
	slap_mask_t flags,
125
126
127
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
128
129
	BerVarray values,
	BerVarray *keysp )
130
131
132
{
	int i;
	size_t slen, mlen;
133
	BerVarray keys;
134
	HASH_CONTEXT   HASHcontext;
Gary Williams's avatar
Gary Williams committed
135
	unsigned char	HASHdigest[HASH_BYTES];
136
	struct berval digest;
137
138
	digest.bv_val = HASHdigest;
	digest.bv_len = sizeof(HASHdigest);
139

140
	for( i=0; values[i].bv_val != NULL; i++ ) {
141
142
143
		/* just count them */
	}

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

147
	keys = ch_malloc( sizeof( struct berval ) * (i+1) );
148

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

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

166
		ber_dupbv( &keys[i], &digest );
167
168
	}

169
	keys[i].bv_val = NULL;
170
171
172
173
174
175
176

	*keysp = keys;

	return LDAP_SUCCESS;
}

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

195
196
	slen = syntax->ssyn_oidlen;
	mlen = mr->smr_oidlen;
197

198
	keys = ch_malloc( sizeof( struct berval ) * 2 );
199

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

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

	*keysp = keys;

	return LDAP_SUCCESS;
}
220

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

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

231
232
	ber_dupbv( &dn, in );
	if( !dn.bv_val ) return LDAP_OTHER;
233

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

240
241
		for(i=dn.bv_len-3; i>1; i--) {
			if( dn.bv_val[i] != '0' &&	dn.bv_val[i] != '1' ) {
242
243
244
				break;
			}
		}
245
246
247
		if( dn.bv_val[i] != '\'' ||
		    dn.bv_val[i-1] != '#' ) {
			ber_memfree( dn.bv_val );
248
249
250
			return LDAP_INVALID_SYNTAX;
		}

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

256
	rc = dnValidate( NULL, &dn );
257

258
	ber_memfree( &dn );
259
260
261
262
263
264
265
	return rc;
}

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

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

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

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

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

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

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

303
		dnlen = normalized->bv_len;
304
305

		if( uidlen ) {
306
307
			struct berval b2;
			b2.bv_val = ch_malloc(dnlen + uidlen + 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
308
			AC_MEMCPY( b2.bv_val, normalized->bv_val, dnlen );
Howard Chu's avatar
Howard Chu committed
309

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

	return LDAP_SUCCESS;
}

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

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

343
344
345
346
347
348
349
350
351
352
353
354
355
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;
	}
356

357
358
359
360
361
362
363
364
365
366
	/*
	 * 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' )
367
368
369
370
	{
		return LDAP_INVALID_SYNTAX;
	}

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

	return LDAP_SUCCESS;
}

380
381
382
383
static int
bitStringNormalize(
	Syntax *syntax,
	struct berval *val,
384
	struct berval *normalized )
385
386
{
	/*
387
	 * A normalized bitString is has no extaneous (leading) zero bits.
388
389
	 * That is, '00010'B is normalized to '10'B
	 * However, as a special case, '0'B requires no normalization.
390
	 */
391
392
393
394
395
396
397
398
399
400
	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 */
401
		ber_str2bv( "\'0\'B", sizeof("\'0\'B") - 1, 1, normalized );
402
403
404
		goto done;
	}

405
	normalized->bv_val = ch_malloc( val->bv_len + 1 );
406

407
408
	normalized->bv_val[0] = '\'';
	normalized->bv_len = 1;
409
410

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

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

done:
	return LDAP_SUCCESS;
}

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
449
450
/*
 * 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,
451
	slap_mask_t flags,
452
453
454
455
456
457
458
459
460
461
462
	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;
}

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

472
473
	if( !in->bv_len ) return LDAP_INVALID_SYNTAX;

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
478
479
480
		/* very basic checks */
		switch( len ) {
			case 6:
481
				if( (u[5] & 0xC0) != 0x80 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
483
484
					return LDAP_INVALID_SYNTAX;
				}
			case 5:
485
				if( (u[4] & 0xC0) != 0x80 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
486
487
488
					return LDAP_INVALID_SYNTAX;
				}
			case 4:
489
				if( (u[3] & 0xC0) != 0x80 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
490
491
492
					return LDAP_INVALID_SYNTAX;
				}
			case 3:
493
				if( (u[2] & 0xC0 )!= 0x80 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
495
496
					return LDAP_INVALID_SYNTAX;
				}
			case 2:
497
				if( (u[1] & 0xC0) != 0x80 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498
499
500
501
502
503
504
505
506
507
					return LDAP_INVALID_SYNTAX;
				}
			case 1:
				if( u[0] >= 0xFE ) {
					return LDAP_INVALID_SYNTAX;
				}
				break;
			default:
				return LDAP_INVALID_SYNTAX;
		}
508
509
510

		/* make sure len corresponds with the offset
			to the next character */
511
		if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
512
513
	}

514
	if( count != 0 ) return LDAP_INVALID_SYNTAX;
515

516
	return LDAP_SUCCESS;
517
518
519
520
521
522
}

static int
UTF8StringNormalize(
	Syntax *syntax,
	struct berval *val,
523
	struct berval *normalized )
524
{
525
	char *p, *q, *s;
526
	int len = 0;
527

528
	p = val->bv_val;
529

530
	/* Ignore initial whitespace */
531
532
533
	/* All space is ASCII. All ASCII is 1 byte */
	while ( ASCII_SPACE( *p ) ) {
		p++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
	}
535

536
	if( *p == '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
537
538
		return LDAP_INVALID_SYNTAX;
	}
539

540
541
542
543
544
	ber_str2bv( p, val->bv_len - (p - val->bv_val), 1, normalized );

	assert( normalized->bv_val );

	p = q = normalized->bv_val;
545
	s = NULL;
546

547
	while ( *p ) {
548
549
550
551
552
		q += len;
		if ( ASCII_SPACE( *p ) ) {
			s = q - len;
			len = 1;
			*q = *p++;
553

554
			/* Ignore the extra whitespace */
555
556
			while ( ASCII_SPACE( *p ) ) {
				p++;
557
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
558
		} else {
559
560
561
			len = LDAP_UTF8_COPY(q,p);
			s=NULL;
			p+=len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
562
		}
563
564
	}

565
	assert( normalized->bv_val < p );
566
	assert( q+len <= p );
567

568
	/* cannot start with a space */
569
	assert( !ASCII_SPACE(normalized->bv_val[0]) );
570
571
572
573
574
575
576
577

	/*
	 * 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 ) {
Howard Chu's avatar
Howard Chu committed
578
		len = q - s;
579
		q = s;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
580
	}
581

582
	/* cannot end with a space */
583
584
585
	assert( !ASCII_SPACE( *q ) );

	q += len;
586
587
588
589

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

590
	normalized->bv_len = q - normalized->bv_val;
591

592
	return LDAP_SUCCESS;
593
594
}

595
/* Returns Unicode canonically normalized copy of a substring assertion
596
 * Skipping attribute description */
597
static SubstringsAssertion *
598
599
UTF8SubstringsassertionNormalize(
	SubstringsAssertion *sa,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
600
	unsigned casefold )
601
602
603
604
605
606
607
608
609
{
	SubstringsAssertion *nsa;
	int i;

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

610
611
612
613
	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 ) {
614
615
616
617
618
			goto err;
		}
	}

	if( sa->sa_any != NULL ) {
619
		for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
620
621
			/* empty */
		}
622
623
624
625
626
		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 ) {
627
628
629
				goto err;
			}
		}
630
		nsa->sa_any[i].bv_val = NULL;
631
632
	}

633
634
635
636
	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 ) {
637
638
639
640
641
642
643
			goto err;
		}
	}

	return nsa;

err:
Howard Chu's avatar
Howard Chu committed
644
	if ( nsa->sa_final.bv_val ) free( nsa->sa_final.bv_val );
645
	if ( nsa->sa_any )ber_bvarray_free( nsa->sa_any );
Howard Chu's avatar
Howard Chu committed
646
	if ( nsa->sa_initial.bv_val ) free( nsa->sa_initial.bv_val );
647
648
649
650
	ch_free( nsa );
	return NULL;
}

651
/* Strip characters with the 8th bit set */
652
static char *
653
654
655
656
657
658
659
660
661
662
663
664
665
666
strip8bitChars(
	char *in )      
{
	char *p = in, *q;
  
	if( in == NULL ) {
		return NULL;
	}
	while( *p ) {
		if( *p & 0x80 ) {
			q = p;
			while( *++q & 0x80 ) {
				/* empty */
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
			p = AC_MEMCPY(p, q, strlen(q) + 1);
668
669
670
671
672
673
674
		} else {
			p++;
		}
	}
	return in;
}

675
#ifndef SLAPD_APPROX_OLDSINGLESTRING
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693

#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 )
{
694
	char *val, *nval, *assertv, **values, **words, *c;
695
	int i, count, len, nextchunk=0, nextavail=0;
696
	size_t avlen;
697

698
	/* Yes, this is necessary */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
699
	nval = UTF8normalize( value, LDAP_UTF8_NOCASEFOLD );
700
	if( nval == NULL ) {
701
702
703
		*matchp = 1;
		return LDAP_SUCCESS;
	}
704
	strip8bitChars( nval );
705
706

	/* Yes, this is necessary */
707
	assertv = UTF8normalize( ((struct berval *)assertedValue),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
708
		LDAP_UTF8_NOCASEFOLD );
709
	if( assertv == NULL ) {
710
		ch_free( nval );
711
712
713
714
715
		*matchp = 1;
		return LDAP_SUCCESS;
	}
	strip8bitChars( assertv );
	avlen = strlen( assertv );
716
717

	/* Isolate how many words there are */
718
	for( c=nval,count=1; *c; c++ ) {
719
720
721
722
723
724
725
726
727
		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 *) );
728
	for( c=nval,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
729
730
731
732
		words[i] = c;
		values[i] = phonetic(c);
	}

733
	/* Work through the asserted value's words, to see if at least some
734
735
	   of the words are there, in the same order. */
	len = 0;
736
	while ( (size_t) nextchunk < avlen ) {
737
		len = strcspn( assertv + nextchunk, SLAPD_APPROX_DELIMITER);
738
739
740
741
		if( len == 0 ) {
			nextchunk++;
			continue;
		}
742
#if defined(SLAPD_APPROX_INITIALS)
743
		else if( len == 1 ) {
744
745
			/* Single letter words need to at least match one word's initial */
			for( i=nextavail; i<count; i++ )
746
747
				if( !strncasecmp( assertv+nextchunk, words[i], 1 )) {
					nextavail=i+1;
748
					break;
749
				}
750
751
		}
#endif
752
		else {
753
754
755
756
757
758
759
760
761
762
763
			/* 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;
				}
			}
764
			ch_free( val );
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
		}

		/* 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 */
786
	free( assertv );
787
788
789
790
791
	for( i=0; i<count; i++ ) {
		ch_free( values[i] );
	}
	ch_free( values );
	ch_free( words );
792
	ch_free( nval );
793
794
795
796

	return LDAP_SUCCESS;
}

797
static int 
798
799
800
801
802
803
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
804
805
	BerVarray values,
	BerVarray *keysp )
806
807
808
{
	char *val, *c;
	int i,j, len, wordcount, keycount=0;
809
	struct berval *newkeys;
810
	BerVarray keys=NULL;
811

812
	for( j=0; values[j].bv_val != NULL; j++ ) {
813
		/* Yes, this is necessary */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
814
		val = UTF8normalize( &values[j], LDAP_UTF8_NOCASEFOLD );
815
816
		strip8bitChars( val );

817
		/* Isolate how many words there are. There will be a key for each */
Gary Williams's avatar
Gary Williams committed
818
		for( wordcount=0,c=val;	 *c;  c++) {
819
820
821
822
823
824
825
826
			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 */
827
828
		newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
			* sizeof(struct berval) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
829
		AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
830
831
832
833
		if( keys ) ch_free( keys );
		keys = newkeys;

		/* Get a phonetic copy of each word */
Gary Williams's avatar
Gary Williams committed
834
		for( c=val,i=0;	 i<wordcount;  c+=len+1	 ) {
835
836
			len = strlen( c );
			if( len < SLAPD_APPROX_WORDLEN ) continue;
837
			ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
838
839
840
841
			keycount++;
			i++;
		}

842
		free( val );
843
	}
844
	keys[keycount].bv_val = NULL;
845
846
847
848
849
	*keysp = keys;

	return LDAP_SUCCESS;
}

850
static int 
851
852
853
854
855
856
857
approxFilter(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
858
	BerVarray *keysp )
859
860
861
{
	char *val, *c;
	int i, count, len;
862
	BerVarray keys;
863

864
	/* Yes, this is necessary */
865
	val = UTF8normalize( ((struct berval *)assertValue),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
866
		LDAP_UTF8_NOCASEFOLD );
867
	if( val == NULL ) {
868
869
		keys = (struct berval *)ch_malloc( sizeof(struct berval) );
		keys[0].bv_val = NULL;
870
871
872
873
874
		*keysp = keys;
		return LDAP_SUCCESS;
	}
	strip8bitChars( val );

875
876
877
878
879
880
881
882
883
884
	/* 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 */
885
	keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
886
887

	/* Get a phonetic copy of each word */
Gary Williams's avatar
Gary Williams committed
888
	for( c=val,i=0;	 i<count; c+=len+1 ) {
889
890
		len = strlen(c);
		if( len < SLAPD_APPROX_WORDLEN ) continue;
891
		ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
892
893
894
		i++;
	}

895
	free( val );
896

897
	keys[count].bv_val = NULL;
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
	*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;
917
	char *s, *t;
918

919
	/* Yes, this is necessary */
920
	s = UTF8normalize( value, UTF8_NOCASEFOLD );
921
922
923
924
925
926
	if( s == NULL ) {
		*matchp = 1;
		return LDAP_SUCCESS;
	}

	/* Yes, this is necessary */
927
	t = UTF8normalize( ((struct berval *)assertedValue),
928
929
930
931
932
933
934
935
936
937
938
939
			   UTF8_NOCASEFOLD );
	if( t == NULL ) {
		free( s );
		*matchp = -1;
		return LDAP_SUCCESS;
	}

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

	free( s );
	free( t );
940
941
942
943
944
945
946
947
948

	*matchp = strcmp( vapprox, avapprox );

	ch_free( vapprox );
	ch_free( avapprox );

	return LDAP_SUCCESS;
}

949
static int 
950
951
952
953
954
955
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
956
957
	BerVarray values,
	BerVarray *keysp )
958
959
{
	int i;
960
	BerVarray *keys;
961
	char *s;
962

963
	for( i=0; values[i].bv_val != NULL; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
964
		/* empty - just count them */
965
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
966
967

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

970
	keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
971
972

	/* Copy each value and run it through phonetic() */
973
	for( i=0; values[i].bv_val != NULL; i++ ) {
974
		/* Yes, this is necessary */
975
		s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
976
977

		/* strip 8-bit chars and run through phonetic() */
978
		ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
979
		free( s );
980
	}
981
	keys[i].bv_val = NULL;
982
983
984
985
986
987

	*keysp = keys;
	return LDAP_SUCCESS;
}


988
static int 
989
990
991
992
993
994
995
approxFilter(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
996
	BerVarray *keysp )
997
{
998
	BerVarray keys;
999
	char *s;
1000

1001
	keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
1002

1003
	/* Yes, this is necessary */
1004
	s = UTF8normalize( ((struct berval *)assertValue),
1005
1006
1007
1008
1009
1010
1011
1012
1013
			     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;
	}
1014
1015
1016
1017
1018
1019
1020

	*keysp = keys;
	return LDAP_SUCCESS;
}
#endif


1021
static int
1022
caseExactMatch(
1023
	int *matchp,
1024
	slap_mask_t flags,
1025
1026
1027
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
1028
	void *assertedValue )
1029
{
1030
1031
	*matchp = UTF8normcmp( value->bv_val,
		((struct berval *) assertedValue)->bv_val,