]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
f75c3b6f75ec0590c1d703214e35ebb32fee3f84
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <limits.h>
12
13 #include <ac/ctype.h>
14 #include <ac/errno.h>
15 #include <ac/string.h>
16 #include <ac/socket.h>
17
18 #include "slap.h"
19 #include "ldap_pvt.h"
20 #include "lber_pvt.h"
21
22 #include "ldap_utf8.h"
23
24 #include "lutil_hash.h"
25 #define HASH_BYTES                              LUTIL_HASH_BYTES
26 #define HASH_CONTEXT                    lutil_HASH_CTX
27 #define HASH_Init(c)                    lutil_HASHInit(c)
28 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
29 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
30
31 #define SLAP_NVALUES 1
32
33 /* not yet implemented */
34 #define uniqueMemberMatch NULL
35
36 #define OpenLDAPaciMatch                        NULL
37
38 /* approx matching rules */
39 #ifdef SLAP_NVALUES
40 #define directoryStringApproxMatchOID   NULL
41 #define IA5StringApproxMatchOID                 NULL
42 #else
43 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
44 #define directoryStringApproxMatch      approxMatch
45 #define directoryStringApproxIndexer    approxIndexer
46 #define directoryStringApproxFilter     approxFilter
47 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
48 #define IA5StringApproxMatch                    approxMatch
49 #define IA5StringApproxIndexer                  approxIndexer
50 #define IA5StringApproxFilter                   approxFilter
51 #endif
52
53 static int
54 inValidate(
55         Syntax *syntax,
56         struct berval *in )
57 {
58         /* no value allowed */
59         return LDAP_INVALID_SYNTAX;
60 }
61
62 static int
63 blobValidate(
64         Syntax *syntax,
65         struct berval *in )
66 {
67         /* any value allowed */
68         return LDAP_SUCCESS;
69 }
70
71 #define berValidate blobValidate
72
73 static int
74 octetStringMatch(
75         int *matchp,
76         slap_mask_t flags,
77         Syntax *syntax,
78         MatchingRule *mr,
79         struct berval *value,
80         void *assertedValue )
81 {
82         struct berval *asserted = (struct berval *) assertedValue;
83         int match = value->bv_len - asserted->bv_len;
84
85         if( match == 0 ) {
86                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
87         }
88
89         *matchp = match;
90         return LDAP_SUCCESS;
91 }
92
93 static int
94 octetStringOrderingMatch(
95         int *matchp,
96         slap_mask_t flags,
97         Syntax *syntax,
98         MatchingRule *mr,
99         struct berval *value,
100         void *assertedValue )
101 {
102         struct berval *asserted = (struct berval *) assertedValue;
103         ber_len_t v_len  = value->bv_len;
104         ber_len_t av_len = asserted->bv_len;
105
106         int match = memcmp( value->bv_val, asserted->bv_val,
107                 (v_len < av_len ? v_len : av_len) );
108
109         if( match == 0 ) match = v_len - av_len;
110
111         *matchp = match;
112         return LDAP_SUCCESS;
113 }
114
115 /* Index generation function */
116 int octetStringIndexer(
117         slap_mask_t use,
118         slap_mask_t flags,
119         Syntax *syntax,
120         MatchingRule *mr,
121         struct berval *prefix,
122         BerVarray values,
123         BerVarray *keysp,
124         void *ctx )
125 {
126         int i;
127         size_t slen, mlen;
128         BerVarray keys;
129         HASH_CONTEXT HASHcontext;
130         unsigned char HASHdigest[HASH_BYTES];
131         struct berval digest;
132         digest.bv_val = HASHdigest;
133         digest.bv_len = sizeof(HASHdigest);
134
135         for( i=0; values[i].bv_val != NULL; i++ ) {
136                 /* just count them */
137         }
138
139         /* we should have at least one value at this point */
140         assert( i > 0 );
141
142         keys = sl_malloc( sizeof( struct berval ) * (i+1), ctx );
143
144         slen = syntax->ssyn_oidlen;
145         mlen = mr->smr_oidlen;
146
147         for( i=0; values[i].bv_val != NULL; i++ ) {
148                 HASH_Init( &HASHcontext );
149                 if( prefix != NULL && prefix->bv_len > 0 ) {
150                         HASH_Update( &HASHcontext,
151                                 prefix->bv_val, prefix->bv_len );
152                 }
153                 HASH_Update( &HASHcontext,
154                         syntax->ssyn_oid, slen );
155                 HASH_Update( &HASHcontext,
156                         mr->smr_oid, mlen );
157                 HASH_Update( &HASHcontext,
158                         values[i].bv_val, values[i].bv_len );
159                 HASH_Final( HASHdigest, &HASHcontext );
160
161                 ber_dupbv_x( &keys[i], &digest, ctx );
162         }
163
164         keys[i].bv_val = NULL;
165         keys[i].bv_len = 0;
166
167         *keysp = keys;
168
169         return LDAP_SUCCESS;
170 }
171
172 /* Index generation function */
173 int octetStringFilter(
174         slap_mask_t use,
175         slap_mask_t flags,
176         Syntax *syntax,
177         MatchingRule *mr,
178         struct berval *prefix,
179         void * assertedValue,
180         BerVarray *keysp,
181         void *ctx )
182 {
183         size_t slen, mlen;
184         BerVarray keys;
185         HASH_CONTEXT HASHcontext;
186         unsigned char HASHdigest[HASH_BYTES];
187         struct berval *value = (struct berval *) assertedValue;
188         struct berval digest;
189         digest.bv_val = HASHdigest;
190         digest.bv_len = sizeof(HASHdigest);
191
192         slen = syntax->ssyn_oidlen;
193         mlen = mr->smr_oidlen;
194
195         keys = sl_malloc( sizeof( struct berval ) * 2, ctx );
196
197         HASH_Init( &HASHcontext );
198         if( prefix != NULL && prefix->bv_len > 0 ) {
199                 HASH_Update( &HASHcontext,
200                         prefix->bv_val, prefix->bv_len );
201         }
202         HASH_Update( &HASHcontext,
203                 syntax->ssyn_oid, slen );
204         HASH_Update( &HASHcontext,
205                 mr->smr_oid, mlen );
206         HASH_Update( &HASHcontext,
207                 value->bv_val, value->bv_len );
208         HASH_Final( HASHdigest, &HASHcontext );
209
210         ber_dupbv_x( keys, &digest, ctx );
211         keys[1].bv_val = NULL;
212         keys[1].bv_len = 0;
213
214         *keysp = keys;
215
216         return LDAP_SUCCESS;
217 }
218
219 static int
220 octetStringSubstringsMatch(
221         int *matchp,
222         slap_mask_t flags,
223         Syntax *syntax,
224         MatchingRule *mr,
225         struct berval *value,
226         void *assertedValue )
227 {
228         int match = 0;
229         SubstringsAssertion *sub = assertedValue;
230         struct berval left = *value;
231         int i;
232         ber_len_t inlen = 0;
233
234         /* Add up asserted input length */
235         if( sub->sa_initial.bv_val ) {
236                 inlen += sub->sa_initial.bv_len;
237         }
238         if( sub->sa_any ) {
239                 for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
240                         inlen += sub->sa_any[i].bv_len;
241                 }
242         }
243         if( sub->sa_final.bv_val ) {
244                 inlen += sub->sa_final.bv_len;
245         }
246
247         if( sub->sa_initial.bv_val ) {
248                 if( inlen > left.bv_len ) {
249                         match = 1;
250                         goto done;
251                 }
252
253                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
254                         sub->sa_initial.bv_len );
255
256                 if( match != 0 ) {
257                         goto done;
258                 }
259
260                 left.bv_val += sub->sa_initial.bv_len;
261                 left.bv_len -= sub->sa_initial.bv_len;
262                 inlen -= sub->sa_initial.bv_len;
263         }
264
265         if( sub->sa_final.bv_val ) {
266                 if( inlen > left.bv_len ) {
267                         match = 1;
268                         goto done;
269                 }
270
271                 match = memcmp( sub->sa_final.bv_val,
272                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
273                         sub->sa_final.bv_len );
274
275                 if( match != 0 ) {
276                         goto done;
277                 }
278
279                 left.bv_len -= sub->sa_final.bv_len;
280                 inlen -= sub->sa_final.bv_len;
281         }
282
283         if( sub->sa_any ) {
284                 for(i=0; sub->sa_any[i].bv_val; i++) {
285                         ber_len_t idx;
286                         char *p;
287
288 retry:
289                         if( inlen > left.bv_len ) {
290                                 /* not enough length */
291                                 match = 1;
292                                 goto done;
293                         }
294
295                         if( sub->sa_any[i].bv_len == 0 ) {
296                                 continue;
297                         }
298
299                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
300
301                         if( p == NULL ) {
302                                 match = 1;
303                                 goto done;
304                         }
305
306                         idx = p - left.bv_val;
307
308                         if( idx >= left.bv_len ) {
309                                 /* this shouldn't happen */
310                                 return LDAP_OTHER;
311                         }
312
313                         left.bv_val = p;
314                         left.bv_len -= idx;
315
316                         if( sub->sa_any[i].bv_len > left.bv_len ) {
317                                 /* not enough left */
318                                 match = 1;
319                                 goto done;
320                         }
321
322                         match = memcmp( left.bv_val,
323                                 sub->sa_any[i].bv_val,
324                                 sub->sa_any[i].bv_len );
325
326                         if( match != 0 ) {
327                                 left.bv_val++;
328                                 left.bv_len--;
329                                 goto retry;
330                         }
331
332                         left.bv_val += sub->sa_any[i].bv_len;
333                         left.bv_len -= sub->sa_any[i].bv_len;
334                         inlen -= sub->sa_any[i].bv_len;
335                 }
336         }
337
338 done:
339         *matchp = match;
340         return LDAP_SUCCESS;
341 }
342
343 /* Substrings Index generation function */
344 static int
345 octetStringSubstringsIndexer(
346         slap_mask_t use,
347         slap_mask_t flags,
348         Syntax *syntax,
349         MatchingRule *mr,
350         struct berval *prefix,
351         BerVarray values,
352         BerVarray *keysp,
353         void *ctx )
354 {
355         ber_len_t i, j, nkeys;
356         size_t slen, mlen;
357         BerVarray keys;
358
359         HASH_CONTEXT HASHcontext;
360         unsigned char HASHdigest[HASH_BYTES];
361         struct berval digest;
362         digest.bv_val = HASHdigest;
363         digest.bv_len = sizeof(HASHdigest);
364
365         nkeys=0;
366
367         for( i=0; values[i].bv_val != NULL; i++ ) {
368                 /* count number of indices to generate */
369                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
370                         continue;
371                 }
372
373                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
374                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
375                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
376                                         (SLAP_INDEX_SUBSTR_MINLEN - 1);
377                         } else {
378                                 nkeys += values[i].bv_len - (SLAP_INDEX_SUBSTR_MINLEN - 1);
379                         }
380                 }
381
382                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
383                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
384                                 nkeys += values[i].bv_len - (SLAP_INDEX_SUBSTR_MAXLEN - 1);
385                         }
386                 }
387
388                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
389                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
390                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
391                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
392                         } else {
393                                 nkeys += values[i].bv_len - (SLAP_INDEX_SUBSTR_MINLEN - 1);
394                         }
395                 }
396         }
397
398         if( nkeys == 0 ) {
399                 /* no keys to generate */
400                 *keysp = NULL;
401                 return LDAP_SUCCESS;
402         }
403
404         keys = sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
405
406         slen = syntax->ssyn_oidlen;
407         mlen = mr->smr_oidlen;
408
409         nkeys=0;
410         for( i=0; values[i].bv_val != NULL; i++ ) {
411                 ber_len_t j,max;
412
413                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
414
415                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
416                         ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
417                 {
418                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
419                         max = values[i].bv_len - (SLAP_INDEX_SUBSTR_MAXLEN - 1);
420
421                         for( j=0; j<max; j++ ) {
422                                 HASH_Init( &HASHcontext );
423                                 if( prefix != NULL && prefix->bv_len > 0 ) {
424                                         HASH_Update( &HASHcontext,
425                                                 prefix->bv_val, prefix->bv_len );
426                                 }
427
428                                 HASH_Update( &HASHcontext,
429                                         &pre, sizeof( pre ) );
430                                 HASH_Update( &HASHcontext,
431                                         syntax->ssyn_oid, slen );
432                                 HASH_Update( &HASHcontext,
433                                         mr->smr_oid, mlen );
434                                 HASH_Update( &HASHcontext,
435                                         &values[i].bv_val[j],
436                                         SLAP_INDEX_SUBSTR_MAXLEN );
437                                 HASH_Final( HASHdigest, &HASHcontext );
438
439                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
440                         }
441                 }
442
443                 max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len
444                         ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len;
445
446                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
447                         char pre;
448
449                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
450                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
451                                 HASH_Init( &HASHcontext );
452                                 if( prefix != NULL && prefix->bv_len > 0 ) {
453                                         HASH_Update( &HASHcontext,
454                                                 prefix->bv_val, prefix->bv_len );
455                                 }
456                                 HASH_Update( &HASHcontext,
457                                         &pre, sizeof( pre ) );
458                                 HASH_Update( &HASHcontext,
459                                         syntax->ssyn_oid, slen );
460                                 HASH_Update( &HASHcontext,
461                                         mr->smr_oid, mlen );
462                                 HASH_Update( &HASHcontext,
463                                         values[i].bv_val, j );
464                                 HASH_Final( HASHdigest, &HASHcontext );
465
466                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
467                         }
468
469                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
470                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
471                                 HASH_Init( &HASHcontext );
472                                 if( prefix != NULL && prefix->bv_len > 0 ) {
473                                         HASH_Update( &HASHcontext,
474                                                 prefix->bv_val, prefix->bv_len );
475                                 }
476                                 HASH_Update( &HASHcontext,
477                                         &pre, sizeof( pre ) );
478                                 HASH_Update( &HASHcontext,
479                                         syntax->ssyn_oid, slen );
480                                 HASH_Update( &HASHcontext,
481                                         mr->smr_oid, mlen );
482                                 HASH_Update( &HASHcontext,
483                                         &values[i].bv_val[values[i].bv_len-j], j );
484                                 HASH_Final( HASHdigest, &HASHcontext );
485
486                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
487                         }
488
489                 }
490
491         }
492
493         if( nkeys > 0 ) {
494                 keys[nkeys].bv_val = NULL;
495                 *keysp = keys;
496         } else {
497                 ch_free( keys );
498                 *keysp = NULL;
499         }
500
501         return LDAP_SUCCESS;
502 }
503
504 static int
505 octetStringSubstringsFilter (
506         slap_mask_t use,
507         slap_mask_t flags,
508         Syntax *syntax,
509         MatchingRule *mr,
510         struct berval *prefix,
511         void * assertedValue,
512         BerVarray *keysp,
513         void *ctx)
514 {
515         SubstringsAssertion *sa;
516         char pre;
517         ber_len_t nkeys = 0;
518         size_t slen, mlen, klen;
519         BerVarray keys;
520         HASH_CONTEXT HASHcontext;
521         unsigned char HASHdigest[HASH_BYTES];
522         struct berval *value;
523         struct berval digest;
524
525         sa = (SubstringsAssertion *) assertedValue;
526
527         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL
528                 && sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
529         {
530                 nkeys++;
531         }
532
533         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
534                 ber_len_t i;
535                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
536                         if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
537                                 /* don't bother accounting for stepping */
538                                 nkeys += sa->sa_any[i].bv_len -
539                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
540                         }
541                 }
542         }
543
544         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
545                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
546         {
547                 nkeys++;
548         }
549
550         if( nkeys == 0 ) {
551                 *keysp = NULL;
552                 return LDAP_SUCCESS;
553         }
554
555         digest.bv_val = HASHdigest;
556         digest.bv_len = sizeof(HASHdigest);
557
558         slen = syntax->ssyn_oidlen;
559         mlen = mr->smr_oidlen;
560
561         keys = sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
562         nkeys = 0;
563
564         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
565                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
566         {
567                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
568                 value = &sa->sa_initial;
569
570                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
571                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
572
573                 HASH_Init( &HASHcontext );
574                 if( prefix != NULL && prefix->bv_len > 0 ) {
575                         HASH_Update( &HASHcontext,
576                                 prefix->bv_val, prefix->bv_len );
577                 }
578                 HASH_Update( &HASHcontext,
579                         &pre, sizeof( pre ) );
580                 HASH_Update( &HASHcontext,
581                         syntax->ssyn_oid, slen );
582                 HASH_Update( &HASHcontext,
583                         mr->smr_oid, mlen );
584                 HASH_Update( &HASHcontext,
585                         value->bv_val, klen );
586                 HASH_Final( HASHdigest, &HASHcontext );
587
588                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
589         }
590
591         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
592                 ber_len_t i, j;
593                 pre = SLAP_INDEX_SUBSTR_PREFIX;
594                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
595
596                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
597                         if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
598                                 continue;
599                         }
600
601                         value = &sa->sa_any[i];
602
603                         for(j=0;
604                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
605                                 j += SLAP_INDEX_SUBSTR_STEP )
606                         {
607                                 HASH_Init( &HASHcontext );
608                                 if( prefix != NULL && prefix->bv_len > 0 ) {
609                                         HASH_Update( &HASHcontext,
610                                                 prefix->bv_val, prefix->bv_len );
611                                 }
612                                 HASH_Update( &HASHcontext,
613                                         &pre, sizeof( pre ) );
614                                 HASH_Update( &HASHcontext,
615                                         syntax->ssyn_oid, slen );
616                                 HASH_Update( &HASHcontext,
617                                         mr->smr_oid, mlen );
618                                 HASH_Update( &HASHcontext,
619                                         &value->bv_val[j], klen ); 
620                                 HASH_Final( HASHdigest, &HASHcontext );
621
622                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
623                         }
624                 }
625         }
626
627         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
628                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
629         {
630                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
631                 value = &sa->sa_final;
632
633                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
634                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
635
636                 HASH_Init( &HASHcontext );
637                 if( prefix != NULL && prefix->bv_len > 0 ) {
638                         HASH_Update( &HASHcontext,
639                                 prefix->bv_val, prefix->bv_len );
640                 }
641                 HASH_Update( &HASHcontext,
642                         &pre, sizeof( pre ) );
643                 HASH_Update( &HASHcontext,
644                         syntax->ssyn_oid, slen );
645                 HASH_Update( &HASHcontext,
646                         mr->smr_oid, mlen );
647                 HASH_Update( &HASHcontext,
648                         &value->bv_val[value->bv_len-klen], klen );
649                 HASH_Final( HASHdigest, &HASHcontext );
650
651                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
652         }
653
654         if( nkeys > 0 ) {
655                 keys[nkeys].bv_val = NULL;
656                 *keysp = keys;
657         } else {
658                 ch_free( keys );
659                 *keysp = NULL;
660         }
661
662         return LDAP_SUCCESS;
663 }
664
665 static int
666 bitStringValidate(
667         Syntax *syntax,
668         struct berval *in )
669 {
670         ber_len_t i;
671
672         /* very unforgiving validation, requires no normalization
673          * before simplistic matching
674          */
675         if( in->bv_len < 3 ) {
676                 return LDAP_INVALID_SYNTAX;
677         }
678
679         /*
680          * RFC 2252 section 6.3 Bit String
681          *      bitstring = "'" *binary-digit "'B"
682          *      binary-digit = "0" / "1"
683          * example: '0101111101'B
684          */
685         
686         if( in->bv_val[0] != '\'' ||
687                 in->bv_val[in->bv_len-2] != '\'' ||
688                 in->bv_val[in->bv_len-1] != 'B' )
689         {
690                 return LDAP_INVALID_SYNTAX;
691         }
692
693         for( i=in->bv_len-3; i>0; i-- ) {
694                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
695                         return LDAP_INVALID_SYNTAX;
696                 }
697         }
698
699         return LDAP_SUCCESS;
700 }
701
702 static int
703 nameUIDValidate(
704         Syntax *syntax,
705         struct berval *in )
706 {
707         int rc;
708         struct berval dn;
709
710         if( in->bv_len == 0 ) return LDAP_SUCCESS;
711
712         ber_dupbv( &dn, in );
713         if( !dn.bv_val ) return LDAP_OTHER;
714
715         if( dn.bv_val[dn.bv_len-1] == 'B'
716                 && dn.bv_val[dn.bv_len-2] == '\'' )
717         {
718                 /* assume presence of optional UID */
719                 ber_len_t i;
720
721                 for(i=dn.bv_len-3; i>1; i--) {
722                         if( dn.bv_val[i] != '0' && dn.bv_val[i] != '1' ) {
723                                 break;
724                         }
725                 }
726                 if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) {
727                         ber_memfree( dn.bv_val );
728                         return LDAP_INVALID_SYNTAX;
729                 }
730
731                 /* trim the UID to allow use of dnValidate */
732                 dn.bv_val[i-1] = '\0';
733                 dn.bv_len = i-1;
734         }
735
736         rc = dnValidate( NULL, &dn );
737
738         ber_memfree( dn.bv_val );
739         return rc;
740 }
741
742 static int
743 uniqueMemberNormalize(
744         slap_mask_t usage,
745         Syntax *syntax,
746         MatchingRule *mr,
747         struct berval *val,
748         struct berval *normalized,
749         void *ctx )
750 {
751         struct berval out;
752         int rc;
753
754         ber_dupbv( &out, val );
755         if( out.bv_len != 0 ) {
756                 struct berval uid = { 0, NULL };
757
758                 if( out.bv_val[out.bv_len-1] == 'B'
759                         && out.bv_val[out.bv_len-2] == '\'' )
760                 {
761                         /* assume presence of optional UID */
762                         uid.bv_val = strrchr( out.bv_val, '#' );
763
764                         if( uid.bv_val == NULL ) {
765                                 free( out.bv_val );
766                                 return LDAP_INVALID_SYNTAX;
767                         }
768
769                         uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val);
770                         out.bv_len -= uid.bv_len--;
771
772                         /* temporarily trim the UID */
773                         *(uid.bv_val++) = '\0';
774                 }
775
776                 rc = dnNormalize2( NULL, &out, normalized, ctx );
777
778                 if( rc != LDAP_SUCCESS ) {
779                         free( out.bv_val );
780                         return LDAP_INVALID_SYNTAX;
781                 }
782
783                 if( uid.bv_len ) {
784                         normalized->bv_val = ch_realloc( normalized->bv_val,
785                                 normalized->bv_len + uid.bv_len + sizeof("#") );
786
787                         /* insert the separator */
788                         normalized->bv_val[normalized->bv_len++] = '#';
789
790                         /* append the UID */
791                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
792                                 uid.bv_val, uid.bv_len );
793                         normalized->bv_len += uid.bv_len;
794
795                         /* terminate */
796                         normalized->bv_val[normalized->bv_len] = '\0';
797                 }
798
799                 free( out.bv_val );
800         }
801
802         return LDAP_SUCCESS;
803 }
804
805 /*
806  * Handling boolean syntax and matching is quite rigid.
807  * A more flexible approach would be to allow a variety
808  * of strings to be normalized and prettied into TRUE
809  * and FALSE.
810  */
811 static int
812 booleanValidate(
813         Syntax *syntax,
814         struct berval *in )
815 {
816         /* very unforgiving validation, requires no normalization
817          * before simplistic matching
818          */
819
820         if( in->bv_len == 4 ) {
821                 if( bvmatch( in, &slap_true_bv ) ) {
822                         return LDAP_SUCCESS;
823                 }
824         } else if( in->bv_len == 5 ) {
825                 if( bvmatch( in, &slap_false_bv ) ) {
826                         return LDAP_SUCCESS;
827                 }
828         }
829
830         return LDAP_INVALID_SYNTAX;
831 }
832
833 static int
834 booleanMatch(
835         int *matchp,
836         slap_mask_t flags,
837         Syntax *syntax,
838         MatchingRule *mr,
839         struct berval *value,
840         void *assertedValue )
841 {
842         /* simplistic matching allowed by rigid validation */
843         struct berval *asserted = (struct berval *) assertedValue;
844         *matchp = value->bv_len != asserted->bv_len;
845         return LDAP_SUCCESS;
846 }
847
848 /*-------------------------------------------------------------------
849 LDAP/X.500 string syntax / matching rules have a few oddities.  This
850 comment attempts to detail how slapd(8) treats them.
851
852 Summary:
853   StringSyntax          X.500   LDAP    Matching/Comments
854   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
855   PrintableString       subset  subset  i/e + ignore insignificant spaces
856   PrintableString       subset  subset  i/e + ignore insignificant spaces
857   NumericString         subset  subset  ignore all spaces
858   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
859   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
860
861   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
862
863   See draft-ietf-ldapbis-strpro for details (once published).
864
865
866 Directory String -
867   In X.500(93), a directory string can be either a PrintableString,
868   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
869   In later versions, more CHOICEs were added.  In all cases the string
870   must be non-empty.
871
872   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
873   A directory string cannot be zero length.
874
875   For matching, there are both case ignore and exact rules.  Both
876   also require that "insignificant" spaces be ignored.
877         spaces before the first non-space are ignored;
878         spaces after the last non-space are ignored;
879         spaces after a space are ignored.
880   Note: by these rules (and as clarified in X.520), a string of only
881   spaces is to be treated as if held one space, not empty (which
882   would be a syntax error).
883
884 NumericString
885   In ASN.1, numeric string is just a string of digits and spaces
886   and could be empty.  However, in X.500, all attribute values of
887   numeric string carry a non-empty constraint.  For example:
888
889         internationalISDNNumber ATTRIBUTE ::= {
890                 WITH SYNTAX InternationalISDNNumber
891                 EQUALITY MATCHING RULE numericStringMatch
892                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
893                 ID id-at-internationalISDNNumber }
894         InternationalISDNNumber ::=
895             NumericString (SIZE(1..ub-international-isdn-number))
896
897   Unforunately, some assertion values are don't carry the same
898   constraint (but its unclear how such an assertion could ever
899   be true). In LDAP, there is one syntax (numericString) not two
900   (numericString with constraint, numericString without constraint).
901   This should be treated as numericString with non-empty constraint.
902   Note that while someone may have no ISDN number, there are no ISDN
903   numbers which are zero length.
904
905   In matching, spaces are ignored.
906
907 PrintableString
908   In ASN.1, Printable string is just a string of printable characters
909   and can be empty.  In X.500, semantics much like NumericString (see
910   serialNumber for a like example) excepting uses insignificant space
911   handling instead of ignore all spaces.  
912
913 IA5String
914   Basically same as PrintableString.  There are no examples in X.500,
915   but same logic applies.  So we require them to be non-empty as
916   well.
917
918 -------------------------------------------------------------------*/
919
920 static int
921 UTF8StringValidate(
922         Syntax *syntax,
923         struct berval *in )
924 {
925         ber_len_t count;
926         int len;
927         unsigned char *u = in->bv_val;
928
929         if( in->bv_len == 0 && syntax == slap_schema.si_syn_directoryString ) {
930                 /* directory strings cannot be empty */
931                 return LDAP_INVALID_SYNTAX;
932         }
933
934         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
935                 /* get the length indicated by the first byte */
936                 len = LDAP_UTF8_CHARLEN2( u, len );
937
938                 /* very basic checks */
939                 switch( len ) {
940                         case 6:
941                                 if( (u[5] & 0xC0) != 0x80 ) {
942                                         return LDAP_INVALID_SYNTAX;
943                                 }
944                         case 5:
945                                 if( (u[4] & 0xC0) != 0x80 ) {
946                                         return LDAP_INVALID_SYNTAX;
947                                 }
948                         case 4:
949                                 if( (u[3] & 0xC0) != 0x80 ) {
950                                         return LDAP_INVALID_SYNTAX;
951                                 }
952                         case 3:
953                                 if( (u[2] & 0xC0 )!= 0x80 ) {
954                                         return LDAP_INVALID_SYNTAX;
955                                 }
956                         case 2:
957                                 if( (u[1] & 0xC0) != 0x80 ) {
958                                         return LDAP_INVALID_SYNTAX;
959                                 }
960                         case 1:
961                                 /* CHARLEN already validated it */
962                                 break;
963                         default:
964                                 return LDAP_INVALID_SYNTAX;
965                 }
966
967                 /* make sure len corresponds with the offset
968                         to the next character */
969                 if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
970         }
971
972         if( count != 0 ) {
973                 return LDAP_INVALID_SYNTAX;
974         }
975
976         return LDAP_SUCCESS;
977 }
978
979 static int
980 UTF8StringNormalize(
981         slap_mask_t use,
982         Syntax *syntax,
983         MatchingRule *mr,
984         struct berval *val,
985         struct berval *normalized,
986         void *ctx )
987 {
988         struct berval tmp, nvalue;
989         int flags;
990         int i, wasspace;
991
992         if( val->bv_val == NULL ) {
993                 /* assume we're dealing with a syntax (e.g., UTF8String)
994                  * which allows empty strings
995                  */
996                 normalized->bv_len = 0;
997                 normalized->bv_val = NULL;
998                 return LDAP_SUCCESS;
999         }
1000
1001         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1002                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1003         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1004                 ? LDAP_UTF8_APPROX : 0;
1005
1006         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1007         if( val == NULL ) {
1008                 return LDAP_OTHER;
1009         }
1010         
1011         /* collapse spaces (in place) */
1012         nvalue.bv_len = 0;
1013         nvalue.bv_val = tmp.bv_val;
1014
1015         wasspace=1; /* trim leading spaces */
1016         for( i=0; i<tmp.bv_len; i++) {
1017                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1018                         if( wasspace++ == 0 ) {
1019                                 /* trim repeated spaces */
1020                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1021                         }
1022                 } else {
1023                         wasspace = 0;
1024                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1025                 }
1026         }
1027
1028         if( nvalue.bv_len ) {
1029                 if( wasspace ) {
1030                         /* last character was a space, trim it */
1031                         --nvalue.bv_len;
1032                 }
1033                 nvalue.bv_val[nvalue.bv_len] = '\0';
1034
1035         } else {
1036                 /* string of all spaces is treated as one space */
1037                 nvalue.bv_val[0] = ' ';
1038                 nvalue.bv_val[1] = '\0';
1039                 nvalue.bv_len = 1;
1040         }
1041
1042         *normalized = nvalue;
1043         return LDAP_SUCCESS;
1044 }
1045
1046 #ifndef SLAP_NVALUES
1047
1048 #ifndef SLAPD_APPROX_OLDSINGLESTRING
1049 #if defined(SLAPD_APPROX_INITIALS)
1050 #define SLAPD_APPROX_DELIMITER "._ "
1051 #define SLAPD_APPROX_WORDLEN 2
1052 #else
1053 #define SLAPD_APPROX_DELIMITER " "
1054 #define SLAPD_APPROX_WORDLEN 1
1055 #endif
1056
1057 static int
1058 approxMatch(
1059         int *matchp,
1060         slap_mask_t flags,
1061         Syntax *syntax,
1062         MatchingRule *mr,
1063         struct berval *value,
1064         void *assertedValue )
1065 {
1066         struct berval *nval, *assertv;
1067         char *val, **values, **words, *c;
1068         int i, count, len, nextchunk=0, nextavail=0;
1069
1070         /* Yes, this is necessary */
1071         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX );
1072         if( nval == NULL ) {
1073                 *matchp = 1;
1074                 return LDAP_SUCCESS;
1075         }
1076
1077         /* Yes, this is necessary */
1078         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1079                 NULL, LDAP_UTF8_APPROX );
1080         if( assertv == NULL ) {
1081                 ber_bvfree( nval );
1082                 *matchp = 1;
1083                 return LDAP_SUCCESS;
1084         }
1085
1086         /* Isolate how many words there are */
1087         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1088                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1089                 if ( c == NULL ) break;
1090                 *c = '\0';
1091                 count++;
1092         }
1093
1094         /* Get a phonetic copy of each word */
1095         words = (char **)ch_malloc( count * sizeof(char *) );
1096         values = (char **)ch_malloc( count * sizeof(char *) );
1097         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1098                 words[i] = c;
1099                 values[i] = phonetic(c);
1100         }
1101
1102         /* Work through the asserted value's words, to see if at least some
1103            of the words are there, in the same order. */
1104         len = 0;
1105         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1106                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1107                 if( len == 0 ) {
1108                         nextchunk++;
1109                         continue;
1110                 }
1111 #if defined(SLAPD_APPROX_INITIALS)
1112                 else if( len == 1 ) {
1113                         /* Single letter words need to at least match one word's initial */
1114                         for( i=nextavail; i<count; i++ )
1115                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1116                                         nextavail=i+1;
1117                                         break;
1118                                 }
1119                 }
1120 #endif
1121                 else {
1122                         /* Isolate the next word in the asserted value and phonetic it */
1123                         assertv->bv_val[nextchunk+len] = '\0';
1124                         val = phonetic( assertv->bv_val + nextchunk );
1125
1126                         /* See if this phonetic chunk is in the remaining words of *value */
1127                         for( i=nextavail; i<count; i++ ){
1128                                 if( !strcmp( val, values[i] ) ){
1129                                         nextavail = i+1;
1130                                         break;
1131                                 }
1132                         }
1133                         ch_free( val );
1134                 }
1135
1136                 /* This chunk in the asserted value was NOT within the *value. */
1137                 if( i >= count ) {
1138                         nextavail=-1;
1139                         break;
1140                 }
1141
1142                 /* Go on to the next word in the asserted value */
1143                 nextchunk += len+1;
1144         }
1145
1146         /* If some of the words were seen, call it a match */
1147         if( nextavail > 0 ) {
1148                 *matchp = 0;
1149         }
1150         else {
1151                 *matchp = 1;
1152         }
1153
1154         /* Cleanup allocs */
1155         ber_bvfree( assertv );
1156         for( i=0; i<count; i++ ) {
1157                 ch_free( values[i] );
1158         }
1159         ch_free( values );
1160         ch_free( words );
1161         ber_bvfree( nval );
1162
1163         return LDAP_SUCCESS;
1164 }
1165
1166 static int 
1167 approxIndexer(
1168         slap_mask_t use,
1169         slap_mask_t flags,
1170         Syntax *syntax,
1171         MatchingRule *mr,
1172         struct berval *prefix,
1173         BerVarray values,
1174         BerVarray *keysp )
1175 {
1176         char *c;
1177         int i,j, len, wordcount, keycount=0;
1178         struct berval *newkeys;
1179         BerVarray keys=NULL;
1180
1181         for( j=0; values[j].bv_val != NULL; j++ ) {
1182                 struct berval val = { 0, NULL };
1183                 /* Yes, this is necessary */
1184                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX );
1185                 assert( val.bv_val != NULL );
1186
1187                 /* Isolate how many words there are. There will be a key for each */
1188                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1189                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1190                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1191                         c+= len;
1192                         if (*c == '\0') break;
1193                         *c = '\0';
1194                 }
1195
1196                 /* Allocate/increase storage to account for new keys */
1197                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1198                         * sizeof(struct berval) );
1199                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1200                 if( keys ) ch_free( keys );
1201                 keys = newkeys;
1202
1203                 /* Get a phonetic copy of each word */
1204                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1205                         len = strlen( c );
1206                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1207                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1208                         keycount++;
1209                         i++;
1210                 }
1211
1212                 ber_memfree( val.bv_val );
1213         }
1214         keys[keycount].bv_val = NULL;
1215         *keysp = keys;
1216
1217         return LDAP_SUCCESS;
1218 }
1219
1220 static int 
1221 approxFilter(
1222         slap_mask_t use,
1223         slap_mask_t flags,
1224         Syntax *syntax,
1225         MatchingRule *mr,
1226         struct berval *prefix,
1227         void * assertedValue,
1228         BerVarray *keysp )
1229 {
1230         char *c;
1231         int i, count, len;
1232         struct berval *val;
1233         BerVarray keys;
1234
1235         /* Yes, this is necessary */
1236         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1237                 NULL, LDAP_UTF8_APPROX );
1238         if( val == NULL || val->bv_val == NULL ) {
1239                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1240                 keys[0].bv_val = NULL;
1241                 *keysp = keys;
1242                 ber_bvfree( val );
1243                 return LDAP_SUCCESS;
1244         }
1245
1246         /* Isolate how many words there are. There will be a key for each */
1247         for( count = 0,c = val->bv_val; *c; c++) {
1248                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1249                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1250                 c+= len;
1251                 if (*c == '\0') break;
1252                 *c = '\0';
1253         }
1254
1255         /* Allocate storage for new keys */
1256         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1257
1258         /* Get a phonetic copy of each word */
1259         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1260                 len = strlen(c);
1261                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1262                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1263                 i++;
1264         }
1265
1266         ber_bvfree( val );
1267
1268         keys[count].bv_val = NULL;
1269         *keysp = keys;
1270
1271         return LDAP_SUCCESS;
1272 }
1273
1274 #else
1275 /* No other form of Approximate Matching is defined */
1276
1277 static int
1278 approxMatch(
1279         int *matchp,
1280         slap_mask_t flags,
1281         Syntax *syntax,
1282         MatchingRule *mr,
1283         struct berval *value,
1284         void *assertedValue )
1285 {
1286         char *vapprox, *avapprox;
1287         char *s, *t;
1288
1289         /* Yes, this is necessary */
1290         s = UTF8normalize( value, UTF8_NOCASEFOLD );
1291         if( s == NULL ) {
1292                 *matchp = 1;
1293                 return LDAP_SUCCESS;
1294         }
1295
1296         /* Yes, this is necessary */
1297         t = UTF8normalize( ((struct berval *)assertedValue),
1298                            UTF8_NOCASEFOLD );
1299         if( t == NULL ) {
1300                 free( s );
1301                 *matchp = -1;
1302                 return LDAP_SUCCESS;
1303         }
1304
1305         vapprox = phonetic( strip8bitChars( s ) );
1306         avapprox = phonetic( strip8bitChars( t ) );
1307
1308         free( s );
1309         free( t );
1310
1311         *matchp = strcmp( vapprox, avapprox );
1312
1313         ch_free( vapprox );
1314         ch_free( avapprox );
1315
1316         return LDAP_SUCCESS;
1317 }
1318
1319 static int 
1320 approxIndexer(
1321         slap_mask_t use,
1322         slap_mask_t flags,
1323         Syntax *syntax,
1324         MatchingRule *mr,
1325         struct berval *prefix,
1326         BerVarray values,
1327         BerVarray *keysp )
1328 {
1329         int i;
1330         BerVarray *keys;
1331         char *s;
1332
1333         for( i=0; values[i].bv_val != NULL; i++ ) {
1334                 /* empty - just count them */
1335         }
1336
1337         /* we should have at least one value at this point */
1338         assert( i > 0 );
1339
1340         keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
1341
1342         /* Copy each value and run it through phonetic() */
1343         for( i=0; values[i].bv_val != NULL; i++ ) {
1344                 /* Yes, this is necessary */
1345                 s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
1346
1347                 /* strip 8-bit chars and run through phonetic() */
1348                 ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
1349                 free( s );
1350         }
1351         keys[i].bv_val = NULL;
1352
1353         *keysp = keys;
1354         return LDAP_SUCCESS;
1355 }
1356
1357 static int 
1358 approxFilter(
1359         slap_mask_t use,
1360         slap_mask_t flags,
1361         Syntax *syntax,
1362         MatchingRule *mr,
1363         struct berval *prefix,
1364         void * assertedValue,
1365         BerVarray *keysp )
1366 {
1367         BerVarray keys;
1368         char *s;
1369
1370         keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
1371
1372         /* Yes, this is necessary */
1373         s = UTF8normalize( ((struct berval *)assertedValue),
1374                              UTF8_NOCASEFOLD );
1375         if( s == NULL ) {
1376                 keys[0] = NULL;
1377         } else {
1378                 /* strip 8-bit chars and run through phonetic() */
1379                 keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
1380                 free( s );
1381                 keys[1] = NULL;
1382         }
1383
1384         *keysp = keys;
1385         return LDAP_SUCCESS;
1386 }
1387 #endif
1388 #endif /* !SLAP_NVALUES */
1389
1390 /* Remove all spaces and '-' characters */
1391 static int
1392 telephoneNumberNormalize(
1393         slap_mask_t usage,
1394         Syntax *syntax,
1395         MatchingRule *mr,
1396         struct berval *val,
1397         struct berval *normalized,
1398         void *ctx )
1399 {
1400         char *p, *q;
1401
1402         /* validator should have refused an empty string */
1403         assert( val->bv_len );
1404
1405         q = normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1406
1407         for( p = val->bv_val; *p; p++ ) {
1408                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1409                         *q++ = *p;
1410                 }
1411         }
1412         *q = '\0';
1413
1414         normalized->bv_len = q - normalized->bv_val;
1415
1416         if( normalized->bv_len == 0 ) {
1417                 sl_free( normalized->bv_val, ctx );
1418                 return LDAP_INVALID_SYNTAX;
1419         }
1420
1421         return LDAP_SUCCESS;
1422 }
1423
1424 static int
1425 numericoidValidate(
1426         Syntax *syntax,
1427         struct berval *in )
1428 {
1429         struct berval val = *in;
1430
1431         if( val.bv_len == 0 ) {
1432                 /* disallow empty strings */
1433                 return LDAP_INVALID_SYNTAX;
1434         }
1435
1436         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1437                 if ( val.bv_len == 1 ) {
1438                         return LDAP_SUCCESS;
1439                 }
1440
1441                 if ( val.bv_val[0] == '0' ) {
1442                         break;
1443                 }
1444
1445                 val.bv_val++;
1446                 val.bv_len--;
1447
1448                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1449                         val.bv_val++;
1450                         val.bv_len--;
1451
1452                         if ( val.bv_len == 0 ) {
1453                                 return LDAP_SUCCESS;
1454                         }
1455                 }
1456
1457                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1458                         break;
1459                 }
1460
1461                 val.bv_val++;
1462                 val.bv_len--;
1463         }
1464
1465         return LDAP_INVALID_SYNTAX;
1466 }
1467
1468 static int
1469 integerValidate(
1470         Syntax *syntax,
1471         struct berval *in )
1472 {
1473         ber_len_t i;
1474         struct berval val = *in;
1475
1476         if( val.bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1477
1478         if ( val.bv_val[0] == '-' ) {
1479                 val.bv_len--;
1480                 val.bv_val++;
1481
1482                 if( val.bv_len == 0 ) { /* bare "-" */
1483                         return LDAP_INVALID_SYNTAX;
1484                 }
1485
1486                 if( val.bv_val[0] == '0' ) { /* "-0" */
1487                         return LDAP_INVALID_SYNTAX;
1488                 }
1489
1490         } else if ( val.bv_val[0] == '0' ) {
1491                 if( val.bv_len > 1 ) { /* "0<more>" */
1492                         return LDAP_INVALID_SYNTAX;
1493                 }
1494
1495                 return LDAP_SUCCESS;
1496         }
1497
1498         for( i=0; i < val.bv_len; i++ ) {
1499                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1500                         return LDAP_INVALID_SYNTAX;
1501                 }
1502         }
1503
1504         return LDAP_SUCCESS;
1505 }
1506
1507 static int
1508 integerMatch(
1509         int *matchp,
1510         slap_mask_t flags,
1511         Syntax *syntax,
1512         MatchingRule *mr,
1513         struct berval *value,
1514         void *assertedValue )
1515 {
1516         struct berval *asserted = (struct berval *) assertedValue;
1517         int vsign = 1, asign = 1;       /* default sign = '+' */
1518         struct berval v, a;
1519         int match;
1520
1521         v = *value;
1522         if( v.bv_val[0] == '-' ) {
1523                 vsign = -1;
1524                 v.bv_val++;
1525                 v.bv_len--;
1526         }
1527
1528         if( v.bv_len == 0 ) vsign = 0;
1529
1530         a = *asserted;
1531         if( a.bv_val[0] == '-' ) {
1532                 asign = -1;
1533                 a.bv_val++;
1534                 a.bv_len--;
1535         }
1536
1537         if( a.bv_len == 0 ) vsign = 0;
1538
1539         match = vsign - asign;
1540         if( match == 0 ) {
1541                 match = ( v.bv_len != a.bv_len
1542                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1543                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1544                 if( vsign < 0 ) match = -match;
1545         }
1546
1547         *matchp = match;
1548         return LDAP_SUCCESS;
1549 }
1550         
1551 static int
1552 countryStringValidate(
1553         Syntax *syntax,
1554         struct berval *val )
1555 {
1556         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1557
1558         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1559                 return LDAP_INVALID_SYNTAX;
1560         }
1561         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1562                 return LDAP_INVALID_SYNTAX;
1563         }
1564
1565         return LDAP_SUCCESS;
1566 }
1567
1568 static int
1569 printableStringValidate(
1570         Syntax *syntax,
1571         struct berval *val )
1572 {
1573         ber_len_t i;
1574
1575         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1576
1577         for(i=0; i < val->bv_len; i++) {
1578                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1579                         return LDAP_INVALID_SYNTAX;
1580                 }
1581         }
1582
1583         return LDAP_SUCCESS;
1584 }
1585
1586 static int
1587 printablesStringValidate(
1588         Syntax *syntax,
1589         struct berval *val )
1590 {
1591         ber_len_t i, len;
1592
1593         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1594
1595         for(i=0,len=0; i < val->bv_len; i++) {
1596                 int c = val->bv_val[i];
1597
1598                 if( c == '$' ) {
1599                         if( len == 0 ) {
1600                                 return LDAP_INVALID_SYNTAX;
1601                         }
1602                         len = 0;
1603
1604                 } else if ( SLAP_PRINTABLE(c) ) {
1605                         len++;
1606                 } else {
1607                         return LDAP_INVALID_SYNTAX;
1608                 }
1609         }
1610
1611         if( len == 0 ) {
1612                 return LDAP_INVALID_SYNTAX;
1613         }
1614
1615         return LDAP_SUCCESS;
1616 }
1617
1618 static int
1619 IA5StringValidate(
1620         Syntax *syntax,
1621         struct berval *val )
1622 {
1623         ber_len_t i;
1624
1625         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1626
1627         for(i=0; i < val->bv_len; i++) {
1628                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1629                         return LDAP_INVALID_SYNTAX;
1630                 }
1631         }
1632
1633         return LDAP_SUCCESS;
1634 }
1635
1636 static int
1637 IA5StringNormalize(
1638         slap_mask_t use,
1639         Syntax *syntax,
1640         MatchingRule *mr,
1641         struct berval *val,
1642         struct berval *normalized,
1643         void *ctx )
1644 {
1645         char *p, *q;
1646         int casefold = SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
1647
1648         assert( val->bv_len );
1649
1650         p = val->bv_val;
1651
1652         /* Ignore initial whitespace */
1653         while ( ASCII_SPACE( *p ) ) p++;
1654
1655         normalized->bv_val = ber_strdup_x( p, ctx );
1656         p = q = normalized->bv_val;
1657
1658         while ( *p ) {
1659                 if ( ASCII_SPACE( *p ) ) {
1660                         *q++ = *p++;
1661
1662                         /* Ignore the extra whitespace */
1663                         while ( ASCII_SPACE( *p ) ) {
1664                                 p++;
1665                         }
1666
1667                 } else if ( casefold ) {
1668                         /* Most IA5 rules require casefolding */
1669                         *q++ = TOLOWER(*p++);
1670
1671                 } else {
1672                         *q++ = *p++;
1673                 }
1674         }
1675
1676         assert( normalized->bv_val <= p );
1677         assert( q <= p );
1678
1679         /*
1680          * If the string ended in space, backup the pointer one
1681          * position.  One is enough because the above loop collapsed
1682          * all whitespace to a single space.
1683          */
1684         if ( ASCII_SPACE( q[-1] ) ) --q;
1685
1686         /* null terminate */
1687         *q = '\0';
1688
1689         normalized->bv_len = q - normalized->bv_val;
1690         if( normalized->bv_len == 0 ) {
1691                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1692                 normalized->bv_val[0] = ' ';
1693                 normalized->bv_val[1] = '\0';
1694                 normalized->bv_len = 1;
1695         }
1696
1697         return LDAP_SUCCESS;
1698 }
1699
1700 static int
1701 numericStringValidate(
1702         Syntax *syntax,
1703         struct berval *in )
1704 {
1705         ber_len_t i;
1706
1707         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1708
1709         for(i=0; i < in->bv_len; i++) {
1710                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
1711                         return LDAP_INVALID_SYNTAX;
1712                 }
1713         }
1714
1715         return LDAP_SUCCESS;
1716 }
1717
1718 static int
1719 numericStringNormalize(
1720         slap_mask_t usage,
1721         Syntax *syntax,
1722         MatchingRule *mr,
1723         struct berval *val,
1724         struct berval *normalized,
1725         void *ctx )
1726 {
1727         /* removal all spaces */
1728         char *p, *q;
1729
1730         assert( val->bv_len );
1731
1732         normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1733
1734         p = val->bv_val;
1735         q = normalized->bv_val;
1736
1737         while ( *p ) {
1738                 if ( ASCII_SPACE( *p ) ) {
1739                         /* Ignore whitespace */
1740                         p++;
1741                 } else {
1742                         *q++ = *p++;
1743                 }
1744         }
1745
1746         /* we should have copied no more then is in val */
1747         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
1748
1749         /* null terminate */
1750         *q = '\0';
1751
1752         normalized->bv_len = q - normalized->bv_val;
1753
1754         if( normalized->bv_len == 0 ) {
1755                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1756                 normalized->bv_val[0] = ' ';
1757                 normalized->bv_val[1] = '\0';
1758                 normalized->bv_len = 1;
1759         }
1760
1761         return LDAP_SUCCESS;
1762 }
1763
1764 static int
1765 integerBitAndMatch(
1766         int *matchp,
1767         slap_mask_t flags,
1768         Syntax *syntax,
1769         MatchingRule *mr,
1770         struct berval *value,
1771         void *assertedValue )
1772 {
1773         long lValue, lAssertedValue;
1774
1775         /* safe to assume integers are NUL terminated? */
1776         lValue = strtol(value->bv_val, NULL, 10);
1777         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1778                 return LDAP_CONSTRAINT_VIOLATION;
1779         }
1780
1781         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1782         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1783                 && errno == ERANGE )
1784         {
1785                 return LDAP_CONSTRAINT_VIOLATION;
1786         }
1787
1788         *matchp = (lValue & lAssertedValue) ? 0 : 1;
1789         return LDAP_SUCCESS;
1790 }
1791
1792 static int
1793 integerBitOrMatch(
1794         int *matchp,
1795         slap_mask_t flags,
1796         Syntax *syntax,
1797         MatchingRule *mr,
1798         struct berval *value,
1799         void *assertedValue )
1800 {
1801         long lValue, lAssertedValue;
1802
1803         /* safe to assume integers are NUL terminated? */
1804         lValue = strtol(value->bv_val, NULL, 10);
1805         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1806                 return LDAP_CONSTRAINT_VIOLATION;
1807         }
1808
1809         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1810         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1811                 && errno == ERANGE )
1812         {
1813                 return LDAP_CONSTRAINT_VIOLATION;
1814         }
1815
1816         *matchp = (lValue | lAssertedValue) ? 0 : -1;
1817         return LDAP_SUCCESS;
1818 }
1819
1820 #ifndef SLAP_NVALUES
1821 #ifdef HAVE_TLS
1822 #include <openssl/x509.h>
1823 #include <openssl/err.h>
1824
1825 /*
1826  * Next function returns a string representation of a ASN1_INTEGER.
1827  * It works for unlimited lengths.
1828  */
1829
1830 static struct berval *
1831 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
1832 {
1833         char buf[256];
1834         char *p;
1835         static char digit[] = "0123456789";
1836   
1837         /* We work backwards, make it fill from the end of buf */
1838         p = buf + sizeof(buf) - 1;
1839         *p = '\0';
1840
1841         if ( a == NULL || a->length == 0 ) {
1842                 *--p = '0';
1843         } else {
1844                 int i;
1845                 int n = a->length;
1846                 int base = 0;
1847                 unsigned int *copy;
1848
1849                 /* We want to preserve the original */
1850                 copy = ch_malloc(n*sizeof(unsigned int));
1851                 for (i = 0; i<n; i++) {
1852                         copy[i] = a->data[i];
1853                 }
1854
1855                 /* 
1856                  * base indicates the index of the most significant
1857                  * byte that might be nonzero.  When it goes off the
1858                  * end, we now there is nothing left to do.
1859                  */
1860                 while (base < n) {
1861                         unsigned int carry;
1862
1863                         carry = 0;
1864                         for (i = base; i<n; i++ ) {
1865                                 copy[i] += carry*256;
1866                                 carry = copy[i] % 10;
1867                                 copy[i] /= 10;
1868                         }
1869                         if (p <= buf+1) {
1870                                 /*
1871                                  * Way too large, we need to leave
1872                                  * room for sign if negative
1873                                  */
1874                                 free(copy);
1875                                 return NULL;
1876                         }
1877                         *--p = digit[carry];
1878
1879                         if (copy[base] == 0) base++;
1880                 }
1881                 free(copy);
1882         }
1883
1884         if ( a->type == V_ASN1_NEG_INTEGER ) {
1885                 *--p = '-';
1886         }
1887
1888         return ber_str2bv( p, 0, 1, bv );
1889 }
1890
1891 /*
1892  * Given a certificate in DER format, extract the corresponding
1893  * assertion value for certificateExactMatch
1894  */
1895 static int
1896 certificateExactConvert(
1897         struct berval * in,
1898         struct berval * out )
1899 {
1900         X509 *xcert;
1901         unsigned char *p = in->bv_val;
1902         struct berval serial;
1903         struct berval issuer_dn;
1904
1905         xcert = d2i_X509(NULL, &p, in->bv_len);
1906         if ( !xcert ) {
1907 #ifdef NEW_LOGGING
1908                 LDAP_LOG( CONFIG, ENTRY, 
1909                         "certificateExactConvert: error parsing cert: %s\n",
1910                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
1911 #else
1912                 Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
1913                        "error parsing cert: %s\n",
1914                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
1915 #endif
1916                 return LDAP_INVALID_SYNTAX;
1917         }
1918
1919         if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
1920                 X509_free(xcert);
1921                 return LDAP_INVALID_SYNTAX;
1922         }
1923         if ( dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn )
1924                 != LDAP_SUCCESS )
1925         {
1926                 X509_free(xcert);
1927                 ber_memfree(serial.bv_val);
1928                 return LDAP_INVALID_SYNTAX;
1929         }
1930
1931         X509_free(xcert);
1932
1933         out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
1934         out->bv_val = ch_malloc(out->bv_len);
1935         p = out->bv_val;
1936         AC_MEMCPY(p, serial.bv_val, serial.bv_len);
1937         p += serial.bv_len;
1938         AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
1939         p += 3;
1940         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
1941         p += issuer_dn.bv_len;
1942         *p++ = '\0';
1943
1944 #ifdef NEW_LOGGING
1945         LDAP_LOG( CONFIG, ARGS, 
1946                 "certificateExactConvert: \n    %s\n", out->bv_val, 0, 0 );
1947 #else
1948         Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
1949                 "\n\t\"%s\"\n",
1950                 out->bv_val, NULL, NULL );
1951 #endif
1952
1953         ber_memfree(serial.bv_val);
1954         ber_memfree(issuer_dn.bv_val);
1955
1956         return LDAP_SUCCESS;
1957 }
1958
1959 static int
1960 serial_and_issuer_parse(
1961         struct berval *assertion,
1962         struct berval *serial,
1963         struct berval *issuer_dn )
1964 {
1965         char *begin;
1966         char *end;
1967         char *p;
1968         struct berval bv;
1969
1970         begin = assertion->bv_val;
1971         end = assertion->bv_val+assertion->bv_len-1;
1972         for (p=begin; p<=end && *p != '$'; p++) /* empty */ ;
1973         if ( p > end ) return LDAP_INVALID_SYNTAX;
1974
1975         /* p now points at the $ sign, now use
1976          * begin and end to delimit the serial number
1977          */
1978         while (ASCII_SPACE(*begin)) begin++;
1979         end = p-1;
1980         while (ASCII_SPACE(*end)) end--;
1981
1982         if( end <= begin ) return LDAP_INVALID_SYNTAX;
1983
1984         bv.bv_len = end-begin+1;
1985         bv.bv_val = begin;
1986         ber_dupbv(serial, &bv);
1987
1988         /* now extract the issuer, remember p was at the dollar sign */
1989         begin = p+1;
1990         end = assertion->bv_val+assertion->bv_len-1;
1991         while (ASCII_SPACE(*begin)) begin++;
1992         /* should we trim spaces at the end too? is it safe always? no, no */
1993
1994         if( end <= begin ) return LDAP_INVALID_SYNTAX;
1995
1996         if ( issuer_dn ) {
1997                 bv.bv_len = end-begin+1;
1998                 bv.bv_val = begin;
1999
2000                 dnNormalize2( NULL, &bv, issuer_dn );
2001         }
2002
2003         return LDAP_SUCCESS;
2004 }
2005
2006 static int
2007 certificateExactMatch(
2008         int *matchp,
2009         slap_mask_t flags,
2010         Syntax *syntax,
2011         MatchingRule *mr,
2012         struct berval *value,
2013         void *assertedValue )
2014 {
2015         X509 *xcert;
2016         unsigned char *p = value->bv_val;
2017         struct berval serial;
2018         struct berval issuer_dn;
2019         struct berval asserted_serial;
2020         struct berval asserted_issuer_dn;
2021         int ret;
2022
2023         xcert = d2i_X509(NULL, &p, value->bv_len);
2024         if ( !xcert ) {
2025 #ifdef NEW_LOGGING
2026                 LDAP_LOG( CONFIG, ENTRY, 
2027                         "certificateExactMatch: error parsing cert: %s\n",
2028                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
2029 #else
2030                 Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
2031                        "error parsing cert: %s\n",
2032                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
2033 #endif
2034                 return LDAP_INVALID_SYNTAX;
2035         }
2036
2037         asn1_integer2str(xcert->cert_info->serialNumber, &serial);
2038         dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn);
2039
2040         X509_free(xcert);
2041
2042         serial_and_issuer_parse(assertedValue,
2043                 &asserted_serial, &asserted_issuer_dn);
2044
2045         ret = integerMatch(
2046                 matchp,
2047                 flags,
2048                 slap_schema.si_syn_integer,
2049                 slap_schema.si_mr_integerMatch,
2050                 &serial,
2051                 &asserted_serial);
2052         if ( ret == LDAP_SUCCESS ) {
2053                 if ( *matchp == 0 ) {
2054                         /* We need to normalize everything for dnMatch */
2055                         ret = dnMatch(
2056                                 matchp,
2057                                 flags,
2058                                 slap_schema.si_syn_distinguishedName,
2059                                 slap_schema.si_mr_distinguishedNameMatch,
2060                                 &issuer_dn,
2061                                 &asserted_issuer_dn);
2062                 }
2063         }
2064
2065 #ifdef NEW_LOGGING
2066         LDAP_LOG( CONFIG, ARGS, "certificateExactMatch "
2067                 "%d\n\t\"%s $ %s\"\n",
2068                 *matchp, serial.bv_val, issuer_dn.bv_val );
2069         LDAP_LOG( CONFIG, ARGS, "\t\"%s $ %s\"\n",
2070                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
2071                 0 );
2072 #else
2073         Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
2074                 "%d\n\t\"%s $ %s\"\n",
2075                 *matchp, serial.bv_val, issuer_dn.bv_val );
2076         Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
2077                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
2078                 NULL );
2079 #endif
2080
2081         ber_memfree(serial.bv_val);
2082         ber_memfree(issuer_dn.bv_val);
2083         ber_memfree(asserted_serial.bv_val);
2084         ber_memfree(asserted_issuer_dn.bv_val);
2085
2086         return ret;
2087 }
2088
2089 /* 
2090  * Index generation function
2091  * We just index the serials, in most scenarios the issuer DN is one of
2092  * a very small set of values.
2093  */
2094 static int certificateExactIndexer(
2095         slap_mask_t use,
2096         slap_mask_t flags,
2097         Syntax *syntax,
2098         MatchingRule *mr,
2099         struct berval *prefix,
2100         BerVarray values,
2101         BerVarray *keysp )
2102 {
2103         int i;
2104         BerVarray keys;
2105         X509 *xcert;
2106         unsigned char *p;
2107         struct berval serial;
2108
2109         /* we should have at least one value at this point */
2110         assert( values != NULL && values[0].bv_val != NULL );
2111
2112         for( i=0; values[i].bv_val != NULL; i++ ) {
2113                 /* empty -- just count them */
2114         }
2115
2116         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
2117
2118         for( i=0; values[i].bv_val != NULL; i++ ) {
2119                 p = values[i].bv_val;
2120                 xcert = d2i_X509(NULL, &p, values[i].bv_len);
2121                 if ( !xcert ) {
2122 #ifdef NEW_LOGGING
2123                         LDAP_LOG( CONFIG, ENTRY, 
2124                                 "certificateExactIndexer: error parsing cert: %s\n",
2125                                 ERR_error_string(ERR_get_error(),NULL), 0, 0);
2126 #else
2127                         Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
2128                                "error parsing cert: %s\n",
2129                                ERR_error_string(ERR_get_error(),NULL),
2130                                NULL, NULL );
2131 #endif
2132                         /* Do we leak keys on error? */
2133                         return LDAP_INVALID_SYNTAX;
2134                 }
2135
2136                 asn1_integer2str(xcert->cert_info->serialNumber, &serial);
2137                 X509_free(xcert);
2138                 xintegerNormalize( slap_schema.si_syn_integer,
2139                         &serial, &keys[i] );
2140                 ber_memfree(serial.bv_val);
2141 #ifdef NEW_LOGGING
2142                 LDAP_LOG( CONFIG, ENTRY, 
2143                         "certificateExactIndexer: returning: %s\n", keys[i].bv_val, 0, 0);
2144 #else
2145                 Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
2146                        "returning: %s\n",
2147                        keys[i].bv_val,
2148                        NULL, NULL );
2149 #endif
2150         }
2151
2152         keys[i].bv_val = NULL;
2153         *keysp = keys;
2154         return LDAP_SUCCESS;
2155 }
2156
2157 /* Index generation function */
2158 /* We think this is always called with a value in matching rule syntax */
2159 static int certificateExactFilter(
2160         slap_mask_t use,
2161         slap_mask_t flags,
2162         Syntax *syntax,
2163         MatchingRule *mr,
2164         struct berval *prefix,
2165         void * assertedValue,
2166         BerVarray *keysp )
2167 {
2168         BerVarray keys;
2169         struct berval asserted_serial;
2170         int ret;
2171
2172         ret = serial_and_issuer_parse( assertedValue, &asserted_serial, NULL );
2173         if( ret != LDAP_SUCCESS ) return ret;
2174
2175         keys = ch_malloc( sizeof( struct berval ) * 2 );
2176         xintegerNormalize( syntax, &asserted_serial, &keys[0] );
2177         keys[1].bv_val = NULL;
2178         *keysp = keys;
2179
2180         ber_memfree(asserted_serial.bv_val);
2181         return LDAP_SUCCESS;
2182 }
2183 #endif
2184 #endif
2185
2186 static int
2187 check_time_syntax (struct berval *val,
2188         int start,
2189         int *parts)
2190 {
2191         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
2192         static int mdays[2][12] = {
2193                 /* non-leap years */
2194                 { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
2195                 /* leap years */
2196                 { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
2197         };
2198         char *p, *e;
2199         int part, c, tzoffset, leapyear = 0 ;
2200
2201         if( val->bv_len == 0 ) {
2202                 return LDAP_INVALID_SYNTAX;
2203         }
2204
2205         p = (char *)val->bv_val;
2206         e = p + val->bv_len;
2207
2208         /* Ignore initial whitespace */
2209         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
2210                 p++;
2211         }
2212
2213         if (e - p < 13 - (2 * start)) {
2214                 return LDAP_INVALID_SYNTAX;
2215         }
2216
2217         for (part = 0; part < 9; part++) {
2218                 parts[part] = 0;
2219         }
2220
2221         for (part = start; part < 7; part++) {
2222                 c = *p;
2223                 if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
2224                         part++;
2225                         break;
2226                 }
2227                 p++;
2228                 c -= '0';
2229                 if (p == e) {
2230                         return LDAP_INVALID_SYNTAX;
2231                 }
2232                 if (c < 0 || c > 9) {
2233                         return LDAP_INVALID_SYNTAX;
2234                 }
2235                 parts[part] = c;
2236
2237                 c = *p++ - '0';
2238                 if (p == e) {
2239                         return LDAP_INVALID_SYNTAX;
2240                 }
2241                 if (c < 0 || c > 9) {
2242                         return LDAP_INVALID_SYNTAX;
2243                 }
2244                 parts[part] *= 10;
2245                 parts[part] += c;
2246
2247                 if (part == 2 || part == 3) {
2248                         parts[part]--;
2249                 }
2250                 if (parts[part] < 0) {
2251                         return LDAP_INVALID_SYNTAX;
2252                 }
2253                 if (parts[part] > ceiling[part]) {
2254                         return LDAP_INVALID_SYNTAX;
2255                 }
2256         }
2257
2258         /* leapyear check for the Gregorian calendar (year>1581) */
2259         if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
2260                 ((parts[0] % 4 == 0) && (parts[1] == 0)))
2261         {
2262                 leapyear = 1;
2263         }
2264
2265         if (parts[3] > mdays[leapyear][parts[2]]) {
2266                 return LDAP_INVALID_SYNTAX;
2267         }
2268         
2269         c = *p++;
2270         if (c == 'Z') {
2271                 tzoffset = 0; /* UTC */
2272         } else if (c != '+' && c != '-') {
2273                 return LDAP_INVALID_SYNTAX;
2274         } else {
2275                 if (c == '-') {
2276                         tzoffset = -1;
2277                 } else /* c == '+' */ {
2278                         tzoffset = 1;
2279                 }
2280
2281                 if (p > e - 4) {
2282                         return LDAP_INVALID_SYNTAX;
2283                 }
2284
2285                 for (part = 7; part < 9; part++) {
2286                         c = *p++ - '0';
2287                         if (c < 0 || c > 9) {
2288                                 return LDAP_INVALID_SYNTAX;
2289                         }
2290                         parts[part] = c;
2291
2292                         c = *p++ - '0';
2293                         if (c < 0 || c > 9) {
2294                                 return LDAP_INVALID_SYNTAX;
2295                         }
2296                         parts[part] *= 10;
2297                         parts[part] += c;
2298                         if (parts[part] < 0 || parts[part] > ceiling[part]) {
2299                                 return LDAP_INVALID_SYNTAX;
2300                         }
2301                 }
2302         }
2303
2304         /* Ignore trailing whitespace */
2305         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
2306                 p++;
2307         }
2308         if (p != e) {
2309                 return LDAP_INVALID_SYNTAX;
2310         }
2311
2312         switch ( tzoffset ) {
2313         case -1: /* negativ offset to UTC, ie west of Greenwich  */
2314                 parts[4] += parts[7];
2315                 parts[5] += parts[8];
2316                 for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
2317                         if (part != 3) {
2318                                 c = ceiling[part];
2319                         } else {
2320                                 c = mdays[leapyear][parts[2]];
2321                         }
2322                         if (parts[part] > c) {
2323                                 parts[part] -= c + 1;
2324                                 parts[part - 1]++;
2325                         }
2326                 }
2327                 break;
2328         case 1: /* positive offset to UTC, ie east of Greenwich */
2329                 parts[4] -= parts[7];
2330                 parts[5] -= parts[8];
2331                 for (part = 6; --part > 0; ) {
2332                         if (part != 3) {
2333                                 c = ceiling[part];
2334                         } else {
2335                                 /* first arg to % needs to be non negativ */
2336                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2337                         }
2338                         if (parts[part] < 0) {
2339                                 parts[part] += c + 1;
2340                                 parts[part - 1]--;
2341                         }
2342                 }
2343                 break;
2344         case 0: /* already UTC */
2345                 break;
2346         }
2347
2348         return LDAP_SUCCESS;
2349 }
2350
2351 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2352 static int
2353 xutcTimeNormalize(
2354         Syntax *syntax,
2355         struct berval *val,
2356         struct berval *normalized )
2357 {
2358         int parts[9], rc;
2359
2360         rc = check_time_syntax(val, 1, parts);
2361         if (rc != LDAP_SUCCESS) {
2362                 return rc;
2363         }
2364
2365         normalized->bv_val = ch_malloc( 14 );
2366         if ( normalized->bv_val == NULL ) {
2367                 return LBER_ERROR_MEMORY;
2368         }
2369
2370         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2371                 parts[1], parts[2] + 1, parts[3] + 1,
2372                 parts[4], parts[5], parts[6] );
2373         normalized->bv_len = 13;
2374
2375         return LDAP_SUCCESS;
2376 }
2377
2378 static int
2379 utcTimeValidate(
2380         Syntax *syntax,
2381         struct berval *in )
2382 {
2383         int parts[9];
2384         return check_time_syntax(in, 1, parts);
2385 }
2386 #endif
2387
2388 static int
2389 generalizedTimeValidate(
2390         Syntax *syntax,
2391         struct berval *in )
2392 {
2393         int parts[9];
2394         return check_time_syntax(in, 0, parts);
2395 }
2396
2397 static int
2398 generalizedTimeNormalize(
2399         slap_mask_t usage,
2400         Syntax *syntax,
2401         MatchingRule *mr,
2402         struct berval *val,
2403         struct berval *normalized,
2404         void *ctx )
2405 {
2406         int parts[9], rc;
2407
2408         rc = check_time_syntax(val, 0, parts);
2409         if (rc != LDAP_SUCCESS) {
2410                 return rc;
2411         }
2412
2413         normalized->bv_val = sl_malloc( 16, ctx );
2414         if ( normalized->bv_val == NULL ) {
2415                 return LBER_ERROR_MEMORY;
2416         }
2417
2418         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ",
2419                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2420                 parts[4], parts[5], parts[6] );
2421         normalized->bv_len = 15;
2422
2423         return LDAP_SUCCESS;
2424 }
2425
2426 static int
2427 nisNetgroupTripleValidate(
2428         Syntax *syntax,
2429         struct berval *val )
2430 {
2431         char *p, *e;
2432         int commas = 0;
2433
2434         if ( val->bv_len == 0 ) {
2435                 return LDAP_INVALID_SYNTAX;
2436         }
2437
2438         p = (char *)val->bv_val;
2439         e = p + val->bv_len;
2440
2441         if ( *p != '(' /*')'*/ ) {
2442                 return LDAP_INVALID_SYNTAX;
2443         }
2444
2445         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
2446                 if ( *p == ',' ) {
2447                         commas++;
2448                         if ( commas > 2 ) {
2449                                 return LDAP_INVALID_SYNTAX;
2450                         }
2451
2452                 } else if ( !AD_CHAR( *p ) ) {
2453                         return LDAP_INVALID_SYNTAX;
2454                 }
2455         }
2456
2457         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
2458                 return LDAP_INVALID_SYNTAX;
2459         }
2460
2461         p++;
2462
2463         if (p != e) {
2464                 return LDAP_INVALID_SYNTAX;
2465         }
2466
2467         return LDAP_SUCCESS;
2468 }
2469
2470 static int
2471 bootParameterValidate(
2472         Syntax *syntax,
2473         struct berval *val )
2474 {
2475         char *p, *e;
2476
2477         if ( val->bv_len == 0 ) {
2478                 return LDAP_INVALID_SYNTAX;
2479         }
2480
2481         p = (char *)val->bv_val;
2482         e = p + val->bv_len;
2483
2484         /* key */
2485         for (; ( p < e ) && ( *p != '=' ); p++ ) {
2486                 if ( !AD_CHAR( *p ) ) {
2487                         return LDAP_INVALID_SYNTAX;
2488                 }
2489         }
2490
2491         if ( *p != '=' ) {
2492                 return LDAP_INVALID_SYNTAX;
2493         }
2494
2495         /* server */
2496         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
2497                 if ( !AD_CHAR( *p ) ) {
2498                         return LDAP_INVALID_SYNTAX;
2499                 }
2500         }
2501
2502         if ( *p != ':' ) {
2503                 return LDAP_INVALID_SYNTAX;
2504         }
2505
2506         /* path */
2507         for ( p++; p < e; p++ ) {
2508                 if ( !SLAP_PRINTABLE( *p ) ) {
2509                         return LDAP_INVALID_SYNTAX;
2510                 }
2511         }
2512
2513         return LDAP_SUCCESS;
2514 }
2515
2516 static int
2517 firstComponentNormalize(
2518         slap_mask_t usage,
2519         Syntax *syntax,
2520         MatchingRule *mr,
2521         struct berval *val,
2522         struct berval *normalized,
2523         void *ctx )
2524 {
2525         int rc;
2526         struct berval oid;
2527         ber_len_t len;
2528
2529         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2530
2531         if( val->bv_val[0] != '(' /*')'*/ &&
2532                 val->bv_val[0] != '{' /*'}'*/ )
2533         {
2534                 return LDAP_INVALID_SYNTAX;
2535         }
2536
2537         /* trim leading white space */
2538         for( len=1;
2539                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
2540                 len++ )
2541         {
2542                 /* empty */
2543         }
2544
2545         /* grab next word */
2546         oid.bv_val = &val->bv_val[len];
2547         len = val->bv_len - len;
2548         for( oid.bv_len=0;
2549                 !ASCII_SPACE(oid.bv_val[oid.bv_len]) && oid.bv_len < len;
2550                 oid.bv_len++ )
2551         {
2552                 /* empty */
2553         }
2554
2555         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
2556                 rc = numericoidValidate( NULL, &oid );
2557         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
2558                 rc = integerValidate( NULL, &oid );
2559         } else {
2560                 rc = LDAP_INVALID_SYNTAX;
2561         }
2562         
2563
2564         if( rc == LDAP_SUCCESS ) {
2565                 ber_dupbv_x( normalized, &oid, ctx );
2566         }
2567
2568         return rc;
2569 }
2570
2571 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
2572 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
2573
2574 static slap_syntax_defs_rec syntax_defs[] = {
2575         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
2576                 X_BINARY X_NOT_H_R ")",
2577                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
2578         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
2579                 0, NULL, NULL},
2580         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
2581                 0, NULL, NULL},
2582         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
2583                 X_NOT_H_R ")",
2584                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2585         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
2586                 X_NOT_H_R ")",
2587                 SLAP_SYNTAX_BER, berValidate, NULL},
2588         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
2589                 0, bitStringValidate, NULL },
2590         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
2591                 0, booleanValidate, NULL},
2592         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
2593                 X_BINARY X_NOT_H_R ")",
2594                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2595         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
2596                 X_BINARY X_NOT_H_R ")",
2597                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2598         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
2599                 X_BINARY X_NOT_H_R ")",
2600                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2601         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
2602                 0, countryStringValidate, NULL},
2603         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
2604                 0, dnValidate, dnPretty},
2605         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
2606                 0, NULL, NULL},
2607         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
2608                 0, NULL, NULL},
2609         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
2610                 0, UTF8StringValidate, NULL},
2611         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
2612                 0, NULL, NULL},
2613         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
2614                 0, NULL, NULL},
2615         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
2616                 0, NULL, NULL},
2617         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
2618                 0, NULL, NULL},
2619         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
2620                 0, NULL, NULL},
2621         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
2622                 0, printablesStringValidate, NULL},
2623         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
2624                 SLAP_SYNTAX_BLOB, NULL, NULL},
2625         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
2626                 0, generalizedTimeValidate, NULL},
2627         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
2628                 0, NULL, NULL},
2629         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
2630                 0, IA5StringValidate, NULL},
2631         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
2632                 0, integerValidate, NULL},
2633         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
2634                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2635         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
2636                 0, NULL, NULL},
2637         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
2638                 0, NULL, NULL},
2639         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
2640                 0, NULL, NULL},
2641         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
2642                 0, NULL, NULL},
2643         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
2644                 0, NULL, NULL},
2645         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
2646                 0, nameUIDValidate, NULL},
2647         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
2648                 0, NULL, NULL},
2649         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
2650                 0, numericStringValidate, NULL},
2651         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
2652                 0, NULL, NULL},
2653         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
2654                 0, numericoidValidate, NULL},
2655         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
2656                 0, IA5StringValidate, NULL},
2657         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
2658                 0, blobValidate, NULL},
2659         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
2660                 0, UTF8StringValidate, NULL},
2661         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
2662                 0, NULL, NULL},
2663         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
2664                 0, NULL, NULL},
2665         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
2666                 0, printableStringValidate, NULL},
2667         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
2668 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
2669                 0, subtreeSpecificationValidate, NULL},
2670         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
2671                 X_BINARY X_NOT_H_R ")",
2672                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2673         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
2674                 0, printableStringValidate, NULL},
2675         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
2676                 0, NULL, NULL},
2677         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
2678                 0, printablesStringValidate, NULL},
2679 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2680         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
2681                 0, utcTimeValidate, NULL},
2682 #endif
2683         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
2684                 0, NULL, NULL},
2685         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
2686                 0, NULL, NULL},
2687         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
2688                 0, NULL, NULL},
2689         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
2690                 0, NULL, NULL},
2691         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
2692                 0, NULL, NULL},
2693
2694         /* RFC 2307 NIS Syntaxes */
2695         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
2696                 0, nisNetgroupTripleValidate, NULL},
2697         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
2698                 0, bootParameterValidate, NULL},
2699
2700 #ifdef HAVE_TLS
2701         /* From PKIX */
2702         /* These OIDs are not published yet, but will be in the next
2703          * I-D for PKIX LDAPv3 schema as have been advanced by David
2704          * Chadwick in private mail.
2705          */
2706         {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
2707                 0, UTF8StringValidate, NULL},
2708 #endif
2709
2710         /* OpenLDAP Experimental Syntaxes */
2711 #ifdef SLAPD_ACI_ENABLED
2712         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
2713                 SLAP_SYNTAX_HIDE,
2714                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
2715                 NULL},
2716 #endif
2717
2718 #ifdef SLAPD_AUTHPASSWD
2719         /* needs updating */
2720         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
2721                 SLAP_SYNTAX_HIDE, NULL, NULL},
2722 #endif
2723
2724         /* OpenLDAP Void Syntax */
2725         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
2726                 SLAP_SYNTAX_HIDE, inValidate, NULL},
2727         {NULL, 0, NULL, NULL}
2728 };
2729
2730 #ifdef HAVE_TLS
2731 char *certificateExactMatchSyntaxes[] = {
2732         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
2733         NULL
2734 };
2735 #endif
2736 char *directoryStringSyntaxes[] = {
2737         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
2738         NULL
2739 };
2740 char *integerFirstComponentMatchSyntaxes[] = {
2741         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
2742         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
2743         NULL
2744 };
2745 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
2746         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
2747         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
2748         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
2749         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
2750         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
2751         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
2752         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
2753         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
2754         NULL
2755 };
2756
2757 /*
2758  * Other matching rules in X.520 that we do not use (yet):
2759  *
2760  * 2.5.13.9             numericStringOrderingMatch
2761  * 2.5.13.25    uTCTimeMatch
2762  * 2.5.13.26    uTCTimeOrderingMatch
2763  * 2.5.13.31    directoryStringFirstComponentMatch
2764  * 2.5.13.32    wordMatch
2765  * 2.5.13.33    keywordMatch
2766  * 2.5.13.35    certificateMatch
2767  * 2.5.13.36    certificatePairExactMatch
2768  * 2.5.13.37    certificatePairMatch
2769  * 2.5.13.38    certificateListExactMatch
2770  * 2.5.13.39    certificateListMatch
2771  * 2.5.13.40    algorithmIdentifierMatch
2772  * 2.5.13.41    storedPrefixMatch
2773  * 2.5.13.42    attributeCertificateMatch
2774  * 2.5.13.43    readerAndKeyIDMatch
2775  * 2.5.13.44    attributeIntegrityMatch
2776  */
2777 static slap_mrule_defs_rec mrule_defs[] = {
2778         /*
2779          * EQUALITY matching rules must be listed after associated APPROX
2780          * matching rules.  So, we list all APPROX matching rules first.
2781          */
2782 #ifndef SLAP_NVALUES
2783         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
2784                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2785                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2786                 NULL, NULL, directoryStringApproxMatch,
2787                 directoryStringApproxIndexer, directoryStringApproxFilter,
2788                 NULL},
2789
2790         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
2791                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2792                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2793                 NULL, NULL, IA5StringApproxMatch,
2794                 IA5StringApproxIndexer, IA5StringApproxFilter,
2795                 NULL},
2796 #endif
2797
2798         /*
2799          * Other matching rules
2800          */
2801         
2802         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
2803                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2804                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2805                 NULL, NULL, octetStringMatch,
2806                 octetStringIndexer, octetStringFilter,
2807                 NULL },
2808
2809         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
2810                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
2811                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2812                 NULL, dnNormalize, dnMatch,
2813                 octetStringIndexer, octetStringFilter,
2814                 NULL },
2815
2816         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
2817                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2818                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2819                 NULL, UTF8StringNormalize, octetStringMatch,
2820                 octetStringIndexer, octetStringFilter,
2821                 directoryStringApproxMatchOID },
2822
2823         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
2824                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2825                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2826                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2827                 NULL, NULL,
2828                 "caseIgnoreMatch" },
2829
2830         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
2831                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2832                 SLAP_MR_SUBSTR, NULL,
2833                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2834                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2835                 "caseIgnoreMatch" },
2836
2837         {"( 2.5.13.5 NAME 'caseExactMatch' "
2838                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2839                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2840                 NULL, UTF8StringNormalize, octetStringMatch,
2841                 octetStringIndexer, octetStringFilter,
2842                 directoryStringApproxMatchOID },
2843
2844         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
2845                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2846                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2847                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2848                 NULL, NULL,
2849                 "caseExactMatch" },
2850
2851         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
2852                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2853                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
2854                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2855                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2856                 "caseExactMatch" },
2857
2858         {"( 2.5.13.8 NAME 'numericStringMatch' "
2859                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
2860                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2861                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2862                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2863                 NULL },
2864
2865         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
2866                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2867                 SLAP_MR_SUBSTR, NULL,
2868                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2869                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2870                 "numericStringMatch" },
2871
2872         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
2873                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
2874                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2875                 NULL, NULL, NULL, NULL, NULL, NULL },
2876
2877         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
2878                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2879                 SLAP_MR_SUBSTR, NULL,
2880                 NULL, NULL, NULL, NULL, NULL,
2881                 "caseIgnoreListMatch" },
2882
2883         {"( 2.5.13.13 NAME 'booleanMatch' "
2884                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
2885                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2886                 NULL, NULL, booleanMatch,
2887                 octetStringIndexer, octetStringFilter,
2888                 NULL },
2889
2890         {"( 2.5.13.14 NAME 'integerMatch' "
2891                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2892                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2893                 NULL, NULL, integerMatch,
2894                 octetStringIndexer, octetStringFilter,
2895                 NULL },
2896
2897         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
2898                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2899                 SLAP_MR_ORDERING, NULL,
2900                 NULL, NULL, integerMatch,
2901                 NULL, NULL,
2902                 "integerMatch" },
2903
2904         {"( 2.5.13.16 NAME 'bitStringMatch' "
2905                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
2906                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2907                 NULL, NULL, octetStringMatch,
2908                 octetStringIndexer, octetStringFilter,
2909                 NULL },
2910
2911         {"( 2.5.13.17 NAME 'octetStringMatch' "
2912                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2913                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2914                 NULL, NULL, octetStringMatch,
2915                 octetStringIndexer, octetStringFilter,
2916                 NULL },
2917
2918         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
2919                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2920                 SLAP_MR_ORDERING, NULL,
2921                 NULL, NULL, octetStringOrderingMatch,
2922                 NULL, NULL,
2923                 "octetStringMatch" },
2924
2925         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
2926                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2927                 SLAP_MR_SUBSTR, NULL,
2928                 NULL, NULL, octetStringSubstringsMatch,
2929                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2930                 "octetStringMatch" },
2931
2932         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
2933                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
2934                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2935                 NULL,
2936                 telephoneNumberNormalize, octetStringMatch,
2937                 octetStringIndexer, octetStringFilter,
2938                 NULL },
2939
2940         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
2941                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2942                 SLAP_MR_SUBSTR, NULL,
2943                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
2944                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2945                 "telephoneNumberMatch" },
2946
2947         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
2948                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
2949                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2950                 NULL, NULL, NULL, NULL, NULL, NULL },
2951
2952         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
2953                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
2954                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2955                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
2956                 NULL, NULL,
2957                 NULL },
2958
2959         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
2960                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
2961                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2962                 NULL, NULL, NULL, NULL, NULL, NULL },
2963
2964         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
2965                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
2966                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2967                 NULL, generalizedTimeNormalize, octetStringMatch,
2968                 NULL, NULL,
2969                 NULL },
2970
2971         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
2972                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
2973                 SLAP_MR_ORDERING, NULL,
2974                 NULL, generalizedTimeNormalize, octetStringOrderingMatch,
2975                 NULL, NULL,
2976                 "generalizedTimeMatch" },
2977
2978         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
2979                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2980                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
2981                         integerFirstComponentMatchSyntaxes,
2982                 NULL, firstComponentNormalize, integerMatch,
2983                 octetStringIndexer, octetStringFilter,
2984                 NULL },
2985
2986         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
2987                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2988                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
2989                         objectIdentifierFirstComponentMatchSyntaxes,
2990                 NULL, firstComponentNormalize, octetStringMatch,
2991                 octetStringIndexer, octetStringFilter,
2992                 NULL },
2993
2994 #ifndef SLAP_NVALUES
2995 #ifdef HAVE_TLS
2996         {"( 2.5.13.34 NAME 'certificateExactMatch' "
2997                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
2998                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
2999                 certificateExactConvert, NULL, certificateExactMatch,
3000                 certificateExactIndexer, certificateExactFilter,
3001                 NULL },
3002 #endif
3003 #endif
3004
3005         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3006                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3007                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3008                 NULL, IA5StringNormalize, octetStringMatch,
3009                 octetStringIndexer, octetStringFilter,
3010                 IA5StringApproxMatchOID },
3011
3012         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3013                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3014                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3015                 NULL, IA5StringNormalize, octetStringMatch,
3016                 octetStringIndexer, octetStringFilter,
3017                 IA5StringApproxMatchOID },
3018
3019         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3020                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3021                 SLAP_MR_SUBSTR, NULL,
3022                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3023                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3024                 "caseIgnoreIA5Match" },
3025
3026         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3027                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3028                 SLAP_MR_SUBSTR, NULL,
3029                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3030                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3031                 "caseExactIA5Match" },
3032
3033 #ifdef SLAPD_AUTHPASSWD
3034         /* needs updating */
3035         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3036                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3037                 SLAP_MR_EQUALITY, NULL,
3038                 NULL, NULL, authPasswordMatch,
3039                 NULL, NULL,
3040                 NULL},
3041 #endif
3042
3043 #ifdef SLAPD_ACI_ENABLED
3044         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3045                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3046                 SLAP_MR_EQUALITY, NULL,
3047                 NULL, NULL, OpenLDAPaciMatch,
3048                 NULL, NULL,
3049                 NULL},
3050 #endif
3051
3052         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3053                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3054                 SLAP_MR_EXT, NULL,
3055                 NULL, NULL, integerBitAndMatch,
3056                 NULL, NULL,
3057                 "integerMatch" },
3058
3059         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3060                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3061                 SLAP_MR_EXT, NULL,
3062                 NULL, NULL, integerBitOrMatch,
3063                 NULL, NULL,
3064                 "integerMatch" },
3065
3066         {NULL, SLAP_MR_NONE, NULL,
3067                 NULL, NULL, NULL, NULL, NULL,
3068                 NULL }
3069 };
3070
3071 int
3072 slap_schema_init( void )
3073 {
3074         int             res;
3075         int             i;
3076
3077         /* we should only be called once (from main) */
3078         assert( schema_init_done == 0 );
3079
3080         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3081                 res = register_syntax( &syntax_defs[i] );
3082
3083                 if ( res ) {
3084                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3085                                  syntax_defs[i].sd_desc );
3086                         return LDAP_OTHER;
3087                 }
3088         }
3089
3090         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3091                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3092                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3093                 {
3094                         fprintf( stderr,
3095                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3096                                  mrule_defs[i].mrd_desc );
3097                         continue;
3098                 }
3099
3100                 res = register_matching_rule( &mrule_defs[i] );
3101
3102                 if ( res ) {
3103                         fprintf( stderr,
3104                                 "slap_schema_init: Error registering matching rule %s\n",
3105                                  mrule_defs[i].mrd_desc );
3106                         return LDAP_OTHER;
3107                 }
3108         }
3109
3110         res = slap_schema_load();
3111         schema_init_done = 1;
3112         return res;
3113 }
3114
3115 void
3116 schema_destroy( void )
3117 {
3118         oidm_destroy();
3119         oc_destroy();
3120         at_destroy();
3121         mr_destroy();
3122         mru_destroy();
3123         syn_destroy();
3124 }