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
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
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
126
127
	BVarray values,
	BVarray *keysp )
128
129
130
{
	int i;
	size_t slen, mlen;
131
	BVarray 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
	for( i=0; values[i].bv_val != NULL; i++ ) {
139
140
141
		/* 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].bv_val != 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
	BVarray *keysp )
183
184
{
	size_t slen, mlen;
185
	BVarray 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
static int
nameUIDValidate(
	Syntax *syntax,
	struct berval *in )
{
	int rc;
225
	struct berval dn;
226
227
228

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

229
230
	ber_dupbv( &dn, in );
	if( !dn.bv_val ) return LDAP_OTHER;
231

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

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

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

254
	rc = dnValidate( NULL, &dn );
255

256
	ber_memfree( &dn );
257
258
259
260
261
262
263
	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
			struct berval b2;
			b2.bv_val = ch_malloc(dnlen + uidlen + 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
306
			AC_MEMCPY( 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 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311
			AC_MEMCPY( normalized->bv_val+dnlen, uid, uidlen );
312
313
314
			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

	/*
	 * 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
548
		len = q - s;
549
		q = s;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
550
	}
551

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

	q += len;
556
557
558
559

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

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

562
	return LDAP_SUCCESS;
563
564
}

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

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

580
581
582
583
	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 ) {
584
585
586
587
588
			goto err;
		}
	}

	if( sa->sa_any != NULL ) {
589
		for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
590
591
			/* empty */
		}
592
593
594
595
596
		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 ) {
597
598
599
				goto err;
			}
		}
600
		nsa->sa_any[i].bv_val = NULL;
601
602
	}

603
604
605
606
	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 ) {
607
608
609
610
611
612
613
			goto err;
		}
	}

	return nsa;

err:
Howard Chu's avatar
Howard Chu committed
614
615
616
	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 );
617
618
619
620
	ch_free( nsa );
	return NULL;
}

621
/* Strip characters with the 8th bit set */
622
static char *
623
624
625
626
627
628
629
630
631
632
633
634
635
636
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
637
			p = AC_MEMCPY(p, q, strlen(q) + 1);
638
639
640
641
642
643
644
		} else {
			p++;
		}
	}
	return in;
}

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

#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 )
{
664
	char *val, *nval, *assertv, **values, **words, *c;
665
	int i, count, len, nextchunk=0, nextavail=0;
666
	size_t avlen;
667

668
	/* Yes, this is necessary */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
669
	nval = UTF8normalize( value, LDAP_UTF8_NOCASEFOLD );
670
	if( nval == NULL ) {
671
672
673
		*matchp = 1;
		return LDAP_SUCCESS;
	}
674
	strip8bitChars( nval );
675
676

	/* Yes, this is necessary */
677
	assertv = UTF8normalize( ((struct berval *)assertedValue),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
678
		LDAP_UTF8_NOCASEFOLD );
679
	if( assertv == NULL ) {
680
		ch_free( nval );
681
682
683
684
685
		*matchp = 1;
		return LDAP_SUCCESS;
	}
	strip8bitChars( assertv );
	avlen = strlen( assertv );
686
687

	/* Isolate how many words there are */
688
	for( c=nval,count=1; *c; c++ ) {
689
690
691
692
693
694
695
696
697
		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 *) );
698
	for( c=nval,i=0;  i<count;  i++,c+=strlen(c)+1 ) {
699
700
701
702
		words[i] = c;
		values[i] = phonetic(c);
	}

703
	/* Work through the asserted value's words, to see if at least some
704
705
	   of the words are there, in the same order. */
	len = 0;
706
	while ( (size_t) nextchunk < avlen ) {
707
		len = strcspn( assertv + nextchunk, SLAPD_APPROX_DELIMITER);
708
709
710
711
		if( len == 0 ) {
			nextchunk++;
			continue;
		}
712
#if defined(SLAPD_APPROX_INITIALS)
713
		else if( len == 1 ) {
714
715
			/* Single letter words need to at least match one word's initial */
			for( i=nextavail; i<count; i++ )
716
717
				if( !strncasecmp( assertv+nextchunk, words[i], 1 )) {
					nextavail=i+1;
718
					break;
719
				}
720
721
		}
#endif
722
		else {
723
724
725
726
727
728
729
730
731
732
733
			/* 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;
				}
			}
734
			ch_free( val );
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
		}

		/* 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 */
756
	free( assertv );
757
758
759
760
761
	for( i=0; i<count; i++ ) {
		ch_free( values[i] );
	}
	ch_free( values );
	ch_free( words );
762
	ch_free( nval );
763
764
765
766

	return LDAP_SUCCESS;
}

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

782
	for( j=0; values[j].bv_val != NULL; j++ ) {
783
		/* Yes, this is necessary */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
784
		val = UTF8normalize( &values[j], LDAP_UTF8_NOCASEFOLD );
785
786
		strip8bitChars( val );

787
		/* Isolate how many words there are. There will be a key for each */
Gary Williams's avatar
Gary Williams committed
788
		for( wordcount=0,c=val;	 *c;  c++) {
789
790
791
792
793
794
795
796
			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 */
797
798
		newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
			* sizeof(struct berval) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
		AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
800
801
802
803
		if( keys ) ch_free( keys );
		keys = newkeys;

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

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

	return LDAP_SUCCESS;
}

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

834
	/* Yes, this is necessary */
835
	val = UTF8normalize( ((struct berval *)assertValue),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
836
		LDAP_UTF8_NOCASEFOLD );
837
	if( val == NULL ) {
838
839
		keys = (struct berval *)ch_malloc( sizeof(struct berval) );
		keys[0].bv_val = NULL;
840
841
842
843
844
		*keysp = keys;
		return LDAP_SUCCESS;
	}
	strip8bitChars( val );

845
846
847
848
849
850
851
852
853
854
	/* 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 */
855
	keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
856
857

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

865
	free( val );
866

867
	keys[count].bv_val = NULL;
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
	*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;
887
	char *s, *t;
888

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

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

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

	free( s );
	free( t );
910
911
912
913
914
915
916
917
918

	*matchp = strcmp( vapprox, avapprox );

	ch_free( vapprox );
	ch_free( avapprox );

	return LDAP_SUCCESS;
}

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

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

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

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

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

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

	*keysp = keys;
	return LDAP_SUCCESS;
}


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

971
	keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
972

973
	/* Yes, this is necessary */
974
	s = UTF8normalize( ((struct berval *)assertValue),
975
976
977
978
979
980
981
982
983
			     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;
	}
984
985
986
987
988
989
990

	*keysp = keys;
	return LDAP_SUCCESS;
}
#endif


991
static int
992
caseExactMatch(
993
	int *matchp,
994
	slap_mask_t flags,
995
996
997
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
998
	void *assertedValue )
999
{
1000
1001
	*matchp = UTF8normcmp( value->bv_val,
		((struct berval *) assertedValue)->bv_val,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1002
		LDAP_UTF8_NOCASEFOLD );
1003
	return LDAP_SUCCESS;
1004
1005
}

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

	casefold = strcmp( mr->smr_oid, caseExactSubstringsMatchOID )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1024
		? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
1025

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

1034
	sub = UTF8SubstringsassertionNormalize( assertedValue, casefold );
1035
1036
1037
1038
	if( sub == NULL ) {
		match = -1;
		goto done;
	}
1039

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