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

497
	p = val->bv_val;
498

499
500
501
	/* Ignore initial whitespace */
	while ( ldap_utf8_isspace( p ) ) {
		LDAP_UTF8_INCR( p );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
	}
503

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

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

	assert( normalized->bv_val );

	p = q = normalized->bv_val;
513
	s = NULL;
514

515
516
	while ( *p ) {
		int len;
517

518
519
520
521
522
		if ( ldap_utf8_isspace( p ) ) {
			len = LDAP_UTF8_COPY(q,p);
			s=q;
			p+=len;
			q+=len;
523

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

536
	assert( normalized->bv_val < p );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
537
	assert( q <= p );
538

539
	/* cannot start with a space */
540
	assert( !ldap_utf8_isspace(normalized->bv_val) );
541
542
543
544
545
546
547
548
549

	/*
	 * 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
550
	}
551

552
553
554
555
556
557
	/* cannot end with a space */
	assert( !ldap_utf8_isspace( LDAP_UTF8_PREV(q) ) );

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

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

560
	return LDAP_SUCCESS;
561
562
}

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

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

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

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

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

	return nsa;

err:
612
613
614
	free( nsa->sa_final.bv_val );
	bvarray_free( nsa->sa_any );
	free( nsa->sa_initial.bv_val );
615
616
617
618
	ch_free( nsa );
	return NULL;
}

619
/* Strip characters with the 8th bit set */
620
static char *
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
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;
}

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

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

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

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

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

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

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

	return LDAP_SUCCESS;
}

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

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

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

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

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

	return LDAP_SUCCESS;
}

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

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

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

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

862
	free( val );
863

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

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

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

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

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

	*matchp = strcmp( vapprox, avapprox );

	ch_free( vapprox );
	ch_free( avapprox );

	return LDAP_SUCCESS;
}

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

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

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

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

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

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

	*keysp = keys;
	return LDAP_SUCCESS;
}


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

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

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

	*keysp = keys;
	return LDAP_SUCCESS;
}
#endif


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

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

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

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

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

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

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

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

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

1062
1063
1064
		left.bv_val += sub->sa_initial.bv_len;
		left.bv_len -= sub->sa_initial.bv_len;
		inlen -= sub->sa_initial.bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1065
	}
1066

1067
	if( sub->sa_final.bv_val ) {
1068
1069
1070
1071
		if( inlen > left.bv_len ) {
			match = 1;
			goto done;
		}
1072