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"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
20
#include "lber_pvt.h"
21

22
23
#include "ldap_utf8.h"

24
25
26
27
28
29
#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)
30

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

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

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

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

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

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

#define OpenLDAPaciMatch				NULL
#define authPasswordMatch				NULL
69
70

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

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

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

85
static char *bvcasechr( struct berval *bv, int c, ber_len_t *len )
86
{
87
88
89
	ber_len_t i;
	int lower = TOLOWER( c );
	int upper = TOUPPER( c );
90
91

	if( c == 0 ) return NULL;
92
93
94
95
96
97
	
	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];
		}
98
	}
99
100

	return NULL;
101
}
102

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

143
	for( i=0; values[i].bv_val != NULL; i++ ) {
144
145
146
		/* just count them */
	}

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

150
	keys = ch_malloc( sizeof( struct berval ) * (i+1) );
151

152
153
	slen = syntax->ssyn_oidlen;
	mlen = mr->smr_oidlen;
154

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

169
		ber_dupbv( &keys[i], &digest );
170
171
	}

172
	keys[i].bv_val = NULL;
173
174
175
176
177
178
179

	*keysp = keys;

	return LDAP_SUCCESS;
}

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

198
199
	slen = syntax->ssyn_oidlen;
	mlen = mr->smr_oidlen;
200

201
	keys = ch_malloc( sizeof( struct berval ) * 2 );
202

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

216
217
	ber_dupbv( keys, &digest );
	keys[1].bv_val = NULL;
218
219
220
221
222

	*keysp = keys;

	return LDAP_SUCCESS;
}
223

224
225
226
227
228
229
static int
nameUIDValidate(
	Syntax *syntax,
	struct berval *in )
{
	int rc;
230
	struct berval dn;
231
232
233

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

234
235
	ber_dupbv( &dn, in );
	if( !dn.bv_val ) return LDAP_OTHER;
236

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

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

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

259
	rc = dnValidate( NULL, &dn );
260

261
	ber_memfree( &dn );
262
263
264
265
266
267
268
	return rc;
}

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

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

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

			if( uid == NULL ) {
285
				free( out.bv_val );
286
287
288
				return LDAP_INVALID_SYNTAX;
			}

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

#ifdef USE_DN_NORMALIZE
296
		rc = dnNormalize2( NULL, &out, normalized );
297
#else
298
		rc = dnPretty2( NULL, &out, normalized );
299
300
#endif

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

306
		dnlen = normalized->bv_len;
307
308

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

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

	return LDAP_SUCCESS;
}

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

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

346
347
348
349
350
351
352
353
354
355
356
357
358
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;
	}
359

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

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

	return LDAP_SUCCESS;
}

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

408
	normalized->bv_val = ch_malloc( val->bv_len + 1 );
409

410
411
	normalized->bv_val[0] = '\'';
	normalized->bv_len = 1;
412
413

	for( ; *p != '\0'; p++ ) {
414
		normalized->bv_val[normalized->bv_len++] = *p;
415
416
	}

417
	normalized->bv_val[normalized->bv_len] = '\0';
418
419
420
421
422

done:
	return LDAP_SUCCESS;
}

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

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

475
476
	if( !in->bv_len ) return LDAP_INVALID_SYNTAX;

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

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

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

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

517
	return LDAP_SUCCESS;
518
519
520
521
522
523
}

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

529
	p = val->bv_val;
530

531
	/* Ignore initial whitespace */
532
	/* All space is ASCII. All ASCII is 1 byte */
533
	for ( ; p < val->bv_val + val->bv_len && ASCII_SPACE( p[ 0 ] ); p++ );
534

535
536
	ber_mem2bv( p, val->bv_len - (p - val->bv_val), 1, normalized );
	e = normalized->bv_val + val->bv_len - (p - val->bv_val);
537
538
539
540

	assert( normalized->bv_val );

	p = q = normalized->bv_val;
541
	s = NULL;
542

543
	while ( p < e ) {
544
545
546
547
548
		q += len;
		if ( ASCII_SPACE( *p ) ) {
			s = q - len;
			len = 1;
			*q = *p++;
549

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

561
	assert( normalized->bv_val < p );
562
	assert( q+len <= p );
563

564
	/* cannot start with a space */
565
	assert( !ASCII_SPACE(normalized->bv_val[0]) );
566
567
568
569
570
571
572
573

	/*
	 * 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
574
		len = q - s;
575
		q = s;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
576
	}
577

578
	/* cannot end with a space */
579
580
581
	assert( !ASCII_SPACE( *q ) );

	q += len;
582
583
584
585

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

586
	normalized->bv_len = q - normalized->bv_val;
587

588
	return LDAP_SUCCESS;
589
590
}

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

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

606
	if( sa->sa_initial.bv_val != NULL ) {
607
		UTF8bvnormalize( &sa->sa_initial, &nsa->sa_initial, casefold );
608
		if( nsa->sa_initial.bv_val == NULL ) {
609
610
611
612
613
			goto err;
		}
	}

	if( sa->sa_any != NULL ) {
614
		for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
615
616
			/* empty */
		}
617
618
		nsa->sa_any = (struct berval *)ch_malloc( (i + 1) * sizeof(struct berval) );
		for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
619
620
			UTF8bvnormalize( &sa->sa_any[i], &nsa->sa_any[i], 
					casefold );
621
			if( nsa->sa_any[i].bv_val == NULL ) {
622
623
624
				goto err;
			}
		}
625
		nsa->sa_any[i].bv_val = NULL;
626
627
	}

628
	if( sa->sa_final.bv_val != NULL ) {
629
		UTF8bvnormalize( &sa->sa_final, &nsa->sa_final, casefold );
630
		if( nsa->sa_final.bv_val == NULL ) {
631
632
633
634
635
636
637
			goto err;
		}
	}

	return nsa;

err:
Howard Chu's avatar
Howard Chu committed
638
	if ( nsa->sa_final.bv_val ) free( nsa->sa_final.bv_val );
639
	if ( nsa->sa_any )ber_bvarray_free( nsa->sa_any );
Howard Chu's avatar
Howard Chu committed
640
	if ( nsa->sa_initial.bv_val ) free( nsa->sa_initial.bv_val );
641
642
643
644
	ch_free( nsa );
	return NULL;
}

645
/* Strip characters with the 8th bit set */
646
static char *
647
648
649
650
651
652
653
654
655
656
657
658
659
660
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
661
			p = AC_MEMCPY(p, q, strlen(q) + 1);
662
663
664
665
666
667
668
		} else {
			p++;
		}
	}
	return in;
}

669
#ifndef SLAPD_APPROX_OLDSINGLESTRING
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687

#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 )
{
688
	char *val, *nval, *assertv, **values, **words, *c;
689
	int i, count, len, nextchunk=0, nextavail=0;
690
	size_t avlen;
691

692
	/* Yes, this is necessary */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
693
	nval = UTF8normalize( value, LDAP_UTF8_NOCASEFOLD );
694
	if( nval == NULL ) {
695
696
697
		*matchp = 1;
		return LDAP_SUCCESS;
	}
698
	strip8bitChars( nval );
699
700

	/* Yes, this is necessary */
701
	assertv = UTF8normalize( ((struct berval *)assertedValue),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
		LDAP_UTF8_NOCASEFOLD );
703
	if( assertv == NULL ) {
704
		ch_free( nval );
705
706
707
708
709
		*matchp = 1;
		return LDAP_SUCCESS;
	}
	strip8bitChars( assertv );
	avlen = strlen( assertv );
710
711

	/* Isolate how many words there are */
712
	for( c=nval,count=1; *c; c++ ) {
713
714
715
716
717
718
719
720
721
		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 *) );
722
	for( c=nval,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
723
724
725
726
		words[i] = c;
		values[i] = phonetic(c);
	}

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

		/* 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 */
780
	free( assertv );
781
782
783
784
785
	for( i=0; i<count; i++ ) {
		ch_free( values[i] );
	}
	ch_free( values );
	ch_free( words );
786
	ch_free( nval );
787
788
789
790

	return LDAP_SUCCESS;
}

791
static int 
792
793
794
795
796
797
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
798
799
	BerVarray values,
	BerVarray *keysp )
800
801
802
{
	char *val, *c;
	int i,j, len, wordcount, keycount=0;
803
	struct berval *newkeys;
804
	BerVarray keys=NULL;
805

806
	for( j=0; values[j].bv_val != NULL; j++ ) {
807
		/* Yes, this is necessary */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
808
		val = UTF8normalize( &values[j], LDAP_UTF8_NOCASEFOLD );
809
810
		strip8bitChars( val );

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

		/* Get a phonetic copy of each word */
Gary Williams's avatar
Gary Williams committed
828
		for( c=val,i=0;	 i<wordcount;  c+=len+1	 ) {
829
830
			len = strlen( c );
			if( len < SLAPD_APPROX_WORDLEN ) continue;
831
			ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
832
833
834
835
			keycount++;
			i++;
		}

836
		free( val );
837
	}
838
	keys[keycount].bv_val = NULL;
839
840
841
842
843
	*keysp = keys;

	return LDAP_SUCCESS;
}

844
static int 
845
846
847
848
849
850
851
approxFilter(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
852
	BerVarray *keysp )
853
854
855
{
	char *val, *c;
	int i, count, len;
856
	BerVarray keys;
857

858
	/* Yes, this is necessary */
859
	val = UTF8normalize( ((struct berval *)assertValue),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
860
		LDAP_UTF8_NOCASEFOLD );
861
	if( val == NULL ) {
862
863
		keys = (struct berval *)ch_malloc( sizeof(struct berval) );
		keys[0].bv_val = NULL;
864
865
866
867
868
		*keysp = keys;
		return LDAP_SUCCESS;
	}
	strip8bitChars( val );

869
870
871
872
873
874
875
876
877
878
	/* 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 */
879
	keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
880
881

	/* Get a phonetic copy of each word */
Gary Williams's avatar
Gary Williams committed
882
	for( c=val,i=0;	 i<count; c+=len+1 ) {
883
884
		len = strlen(c);
		if( len < SLAPD_APPROX_WORDLEN ) continue;
885
		ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
886
887
888
		i++;
	}

889
	free( val );
890

891
	keys[count].bv_val = NULL;
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
	*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;
911
	char *s, *t;
912

913
	/* Yes, this is necessary */
914
	s = UTF8normalize( value, UTF8_NOCASEFOLD );
915
916
917
918
919
920
	if( s == NULL ) {
		*matchp = 1;
		return LDAP_SUCCESS;
	}

	/* Yes, this is necessary */
921
	t = UTF8normalize( ((struct berval *)assertedValue),
922
923
924
925
926
927
928
929
930
931
932
933
			   UTF8_NOCASEFOLD );
	if( t == NULL ) {
		free( s );
		*matchp = -1;
		return LDAP_SUCCESS;
	}

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

	free( s );
	free( t );
934
935
936
937
938
939
940
941
942

	*matchp = strcmp( vapprox, avapprox );

	ch_free( vapprox );
	ch_free( avapprox );

	return LDAP_SUCCESS;
}

943
static int 
944
945
946
947
948
949
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
950
951
	BerVarray values,
	BerVarray *keysp )
952
953
{
	int i;
954
	BerVarray *keys;
955
	char *s;
956

957
	for( i=0; values[i].bv_val != NULL; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
958
		/* empty - just count them */
959
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
960
961

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

964
	keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
965
966

	/* Copy each value and run it through phonetic() */
967
	for( i=0; values[i].bv_val != NULL; i++ ) {
968
		/* Yes, this is necessary */
969
		s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
970
971

		/* strip 8-bit chars and run through phonetic() */
972
		ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
973
		free( s );
974
	}
975
	keys[i].bv_val = NULL;
976
977
978
979
980
981

	*keysp = keys;
	return LDAP_SUCCESS;
}


982
static int 
983
984
985
986
987
988
989
approxFilter(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	void * assertValue,
990
	BerVarray *keysp )
991
{
992
	BerVarray keys;
993
	char *s;
994

995
	keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
996

997
	/* Yes, this is necessary */
998
	s = UTF8normalize( ((struct berval *)assertValue),
999
1000
1001
1002
1003
1004
1005
1006
1007
			     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;
	}
1008
1009
1010
1011
1012
1013
1014

	*keysp = keys;
	return LDAP_SUCCESS;
}
#endif


1015
static int
1016
caseExactMatch(
Kurt Zeilenga's avatar