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

#include "portable.h"

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

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

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

21
22
#include "ldap_utf8.h"

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

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

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

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

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

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

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

#define OpenLDAPaciMatch				NULL
#define authPasswordMatch				NULL
68
69

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

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

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

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

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

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

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

	*matchp = match;
	return LDAP_SUCCESS;
}

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

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

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

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

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

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

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

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

	*keysp = keys;

	return LDAP_SUCCESS;
}

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

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

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

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

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

	*keysp = keys;

	return LDAP_SUCCESS;
}
218

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

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

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

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

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

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

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

	ber_bvfree( dn );
	return rc;
}

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

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

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

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

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

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

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

301
		dnlen = normalized->bv_len;
302
303

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

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

	return LDAP_SUCCESS;
}

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

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

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

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

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

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

	return LDAP_SUCCESS;
}

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

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

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

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

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

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

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

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

done:
	return LDAP_SUCCESS;
}

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

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

	return LDAP_INVALID_SYNTAX;
}

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

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

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

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

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

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

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

486
	return LDAP_SUCCESS;
487
488
489
490
491
492
}

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

498
	p = val->bv_val;
499

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

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

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

	assert( normalized->bv_val );

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

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

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

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

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

	/*
	 * 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
570
571
572
573
574
575
576
577
578
579
UTF8SubstringsassertionNormalize(
	SubstringsAssertion *sa,
	char casefold )
{
	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
637
638
639
640
641
642
643
644
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;
}

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 */
669
	nval = UTF8normalize( value, 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),
678
679
				 UTF8_NOCASEFOLD );
	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
774
approxIndexer(
	slap_mask_t use,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *prefix,
	struct berval **values,
775
	struct berval **keysp )
776
777
778
{
	char *val, *c;
	int i,j, len, wordcount, keycount=0;
779
	struct berval *newkeys, *keys=NULL;
780
781

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

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

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

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

	return LDAP_SUCCESS;
}

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

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

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

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

864
	free( val );
865

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

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

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

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

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

	*matchp = strcmp( vapprox, avapprox );

	ch_free( vapprox );
	ch_free( avapprox );

	return LDAP_SUCCESS;
}

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

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

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

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

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

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

	*keysp = keys;
	return LDAP_SUCCESS;
}


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

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

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

	*keysp = keys;
	return LDAP_SUCCESS;
}
#endif


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

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

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

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

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

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

1051
	if( sub->sa_initial.bv_val ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1052
1053
1054
1055