]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
5ff82c99749524f389a799e6a0b9cd6f42a12d79
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
23
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
28
29 #include "slap.h"
30
31 #include "ldap_utf8.h"
32
33 #ifdef HAVE_TLS
34 #include <openssl/x509.h>
35 #include <openssl/err.h>
36 #include <openssl/rsa.h>
37 #include <openssl/crypto.h>
38 #include <openssl/pem.h>
39 #include <openssl/bio.h>
40 #include <openssl/asn1.h>
41 #include <openssl/x509v3.h>
42 #include <openssl/ssl.h>
43 #endif
44
45 #include "lutil.h"
46 #include "lutil_hash.h"
47 #define HASH_BYTES                              LUTIL_HASH_BYTES
48 #define HASH_CONTEXT                    lutil_HASH_CTX
49 #define HASH_Init(c)                    lutil_HASHInit(c)
50 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
51 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
52
53 #define OpenLDAPaciMatch                        octetStringMatch
54
55 /* approx matching rules */
56 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
57 #define directoryStringApproxMatch              approxMatch
58 #define directoryStringApproxIndexer    approxIndexer
59 #define directoryStringApproxFilter             approxFilter
60 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
61 #define IA5StringApproxMatch                    approxMatch
62 #define IA5StringApproxIndexer                  approxIndexer
63 #define IA5StringApproxFilter                   approxFilter
64
65 /* Change Sequence Number (CSN) - much of this will change */
66 #define csnValidate                             blobValidate
67 #define csnMatch                                octetStringMatch
68 #define csnOrderingMatch                octetStringOrderingMatch
69 #define csnIndexer                              generalizedTimeIndexer
70 #define csnFilter                               generalizedTimeFilter
71
72 #ifdef SLAP_AUTHZ_SYNTAX
73 /* FIXME: temporary */
74 #define authzMatch                              octetStringMatch
75 #endif /* SLAP_AUTHZ_SYNTAX */
76
77 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
78 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
79 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
80 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
81
82 ldap_pvt_thread_mutex_t ad_undef_mutex;
83 ldap_pvt_thread_mutex_t oc_undef_mutex;
84
85 static int
86 inValidate(
87         Syntax *syntax,
88         struct berval *in )
89 {
90         /* no value allowed */
91         return LDAP_INVALID_SYNTAX;
92 }
93
94 static int
95 blobValidate(
96         Syntax *syntax,
97         struct berval *in )
98 {
99         /* any value allowed */
100         return LDAP_SUCCESS;
101 }
102
103 #define berValidate blobValidate
104
105 static int
106 sequenceValidate(
107         Syntax *syntax,
108         struct berval *in )
109 {
110         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
111         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
112
113         return LDAP_SUCCESS;
114 }
115
116
117 #ifdef HAVE_TLS
118 static int certificateValidate( Syntax *syntax, struct berval *in )
119 {
120         X509 *xcert=NULL;
121         unsigned char *p = (unsigned char *)in->bv_val;
122  
123         xcert = d2i_X509(NULL, &p, in->bv_len);
124         if ( !xcert ) return LDAP_INVALID_SYNTAX;
125         X509_free(xcert);
126         return LDAP_SUCCESS;
127 }
128 #else
129 #define certificateValidate sequenceValidate
130 #endif
131
132 static int
133 octetStringMatch(
134         int *matchp,
135         slap_mask_t flags,
136         Syntax *syntax,
137         MatchingRule *mr,
138         struct berval *value,
139         void *assertedValue )
140 {
141         struct berval *asserted = (struct berval *) assertedValue;
142         int match = value->bv_len - asserted->bv_len;
143
144         if( match == 0 ) {
145                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
146         }
147
148         *matchp = match;
149         return LDAP_SUCCESS;
150 }
151
152 static int
153 octetStringOrderingMatch(
154         int *matchp,
155         slap_mask_t flags,
156         Syntax *syntax,
157         MatchingRule *mr,
158         struct berval *value,
159         void *assertedValue )
160 {
161         struct berval *asserted = (struct berval *) assertedValue;
162         ber_len_t v_len  = value->bv_len;
163         ber_len_t av_len = asserted->bv_len;
164
165         int match = memcmp( value->bv_val, asserted->bv_val,
166                 (v_len < av_len ? v_len : av_len) );
167
168         if( match == 0 ) match = v_len - av_len;
169
170         *matchp = match;
171         return LDAP_SUCCESS;
172 }
173
174 void
175 hashDigestify(
176         HASH_CONTEXT *HASHcontext,
177         unsigned char *HASHdigest,
178         struct berval *prefix,
179         char pre,
180         Syntax *syntax,
181         MatchingRule *mr,
182         unsigned char *value,
183         int value_len)
184 {
185         HASH_Init(HASHcontext);
186         if(prefix && prefix->bv_len > 0) {
187                 HASH_Update(HASHcontext,
188                         (unsigned char *)prefix->bv_val, prefix->bv_len);
189         }
190         if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
191         HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
192         HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
193         HASH_Update(HASHcontext, value, value_len);
194         HASH_Final(HASHdigest, HASHcontext);
195         return;
196 }
197
198 /* Index generation function */
199 int octetStringIndexer(
200         slap_mask_t use,
201         slap_mask_t flags,
202         Syntax *syntax,
203         MatchingRule *mr,
204         struct berval *prefix,
205         BerVarray values,
206         BerVarray *keysp,
207         void *ctx )
208 {
209         int i;
210         size_t slen, mlen;
211         BerVarray keys;
212         HASH_CONTEXT HASHcontext;
213         unsigned char HASHdigest[HASH_BYTES];
214         struct berval digest;
215         digest.bv_val = (char *)HASHdigest;
216         digest.bv_len = sizeof(HASHdigest);
217
218         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
219                 /* just count them */
220         }
221
222         /* we should have at least one value at this point */
223         assert( i > 0 );
224
225         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
226
227         slen = syntax->ssyn_oidlen;
228         mlen = mr->smr_oidlen;
229
230         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
231                 hashDigestify( &HASHcontext, HASHdigest, prefix, 0,
232                         syntax, mr, (unsigned char *)values[i].bv_val, values[i].bv_len );
233                 ber_dupbv_x( &keys[i], &digest, ctx );
234         }
235
236         BER_BVZERO( &keys[i] );
237
238         *keysp = keys;
239
240         return LDAP_SUCCESS;
241 }
242
243 /* Index generation function */
244 int octetStringFilter(
245         slap_mask_t use,
246         slap_mask_t flags,
247         Syntax *syntax,
248         MatchingRule *mr,
249         struct berval *prefix,
250         void * assertedValue,
251         BerVarray *keysp,
252         void *ctx )
253 {
254         size_t slen, mlen;
255         BerVarray keys;
256         HASH_CONTEXT HASHcontext;
257         unsigned char HASHdigest[HASH_BYTES];
258         struct berval *value = (struct berval *) assertedValue;
259         struct berval digest;
260         digest.bv_val = (char *)HASHdigest;
261         digest.bv_len = sizeof(HASHdigest);
262
263         slen = syntax->ssyn_oidlen;
264         mlen = mr->smr_oidlen;
265
266         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
267
268         hashDigestify( &HASHcontext, HASHdigest, prefix, 0,
269                 syntax, mr, (unsigned char *)value->bv_val, value->bv_len );
270
271         ber_dupbv_x( keys, &digest, ctx );
272         BER_BVZERO( &keys[1] );
273
274         *keysp = keys;
275
276         return LDAP_SUCCESS;
277 }
278
279 static int
280 octetStringSubstringsMatch(
281         int *matchp,
282         slap_mask_t flags,
283         Syntax *syntax,
284         MatchingRule *mr,
285         struct berval *value,
286         void *assertedValue )
287 {
288         int match = 0;
289         SubstringsAssertion *sub = assertedValue;
290         struct berval left = *value;
291         int i;
292         ber_len_t inlen = 0;
293
294         /* Add up asserted input length */
295         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
296                 inlen += sub->sa_initial.bv_len;
297         }
298         if ( sub->sa_any ) {
299                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
300                         inlen += sub->sa_any[i].bv_len;
301                 }
302         }
303         if ( !BER_BVISNULL( &sub->sa_final ) ) {
304                 inlen += sub->sa_final.bv_len;
305         }
306
307         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
308                 if ( inlen > left.bv_len ) {
309                         match = 1;
310                         goto done;
311                 }
312
313                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
314                         sub->sa_initial.bv_len );
315
316                 if ( match != 0 ) {
317                         goto done;
318                 }
319
320                 left.bv_val += sub->sa_initial.bv_len;
321                 left.bv_len -= sub->sa_initial.bv_len;
322                 inlen -= sub->sa_initial.bv_len;
323         }
324
325         if ( !BER_BVISNULL( &sub->sa_final ) ) {
326                 if ( inlen > left.bv_len ) {
327                         match = 1;
328                         goto done;
329                 }
330
331                 match = memcmp( sub->sa_final.bv_val,
332                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
333                         sub->sa_final.bv_len );
334
335                 if ( match != 0 ) {
336                         goto done;
337                 }
338
339                 left.bv_len -= sub->sa_final.bv_len;
340                 inlen -= sub->sa_final.bv_len;
341         }
342
343         if ( sub->sa_any ) {
344                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
345                         ber_len_t idx;
346                         char *p;
347
348 retry:
349                         if ( inlen > left.bv_len ) {
350                                 /* not enough length */
351                                 match = 1;
352                                 goto done;
353                         }
354
355                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
356                                 continue;
357                         }
358
359                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
360
361                         if( p == NULL ) {
362                                 match = 1;
363                                 goto done;
364                         }
365
366                         idx = p - left.bv_val;
367
368                         if ( idx >= left.bv_len ) {
369                                 /* this shouldn't happen */
370                                 return LDAP_OTHER;
371                         }
372
373                         left.bv_val = p;
374                         left.bv_len -= idx;
375
376                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
377                                 /* not enough left */
378                                 match = 1;
379                                 goto done;
380                         }
381
382                         match = memcmp( left.bv_val,
383                                 sub->sa_any[i].bv_val,
384                                 sub->sa_any[i].bv_len );
385
386                         if ( match != 0 ) {
387                                 left.bv_val++;
388                                 left.bv_len--;
389                                 goto retry;
390                         }
391
392                         left.bv_val += sub->sa_any[i].bv_len;
393                         left.bv_len -= sub->sa_any[i].bv_len;
394                         inlen -= sub->sa_any[i].bv_len;
395                 }
396         }
397
398 done:
399         *matchp = match;
400         return LDAP_SUCCESS;
401 }
402
403 /* Substrings Index generation function */
404 static int
405 octetStringSubstringsIndexer(
406         slap_mask_t use,
407         slap_mask_t flags,
408         Syntax *syntax,
409         MatchingRule *mr,
410         struct berval *prefix,
411         BerVarray values,
412         BerVarray *keysp,
413         void *ctx )
414 {
415         ber_len_t i, nkeys;
416         size_t slen, mlen;
417         BerVarray keys;
418
419         HASH_CONTEXT HASHcontext;
420         unsigned char HASHdigest[HASH_BYTES];
421         struct berval digest;
422         digest.bv_val = (char *)HASHdigest;
423         digest.bv_len = sizeof(HASHdigest);
424
425         nkeys = 0;
426
427         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
428                 /* count number of indices to generate */
429                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
430                         if( values[i].bv_len >= index_substr_if_maxlen ) {
431                                 nkeys += index_substr_if_maxlen -
432                                         (index_substr_if_minlen - 1);
433                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
434                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
435                         }
436                 }
437
438                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
439                         if( values[i].bv_len >= index_substr_any_len ) {
440                                 nkeys += values[i].bv_len - (index_substr_any_len - 1);
441                         }
442                 }
443
444                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
445                         if( values[i].bv_len >= index_substr_if_maxlen ) {
446                                 nkeys += index_substr_if_maxlen -
447                                         (index_substr_if_minlen - 1);
448                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
449                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
450                         }
451                 }
452         }
453
454         if( nkeys == 0 ) {
455                 /* no keys to generate */
456                 *keysp = NULL;
457                 return LDAP_SUCCESS;
458         }
459
460         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
461
462         slen = syntax->ssyn_oidlen;
463         mlen = mr->smr_oidlen;
464
465         nkeys = 0;
466         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
467                 ber_len_t j,max;
468
469                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
470                         ( values[i].bv_len >= index_substr_any_len ) )
471                 {
472                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
473                         max = values[i].bv_len - (index_substr_any_len - 1);
474
475                         for( j=0; j<max; j++ ) {
476                                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
477                                         syntax, mr, (unsigned char *)&values[i].bv_val[j], index_substr_any_len);
478                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
479                         }
480                 }
481
482                 /* skip if too short */ 
483                 if( values[i].bv_len < index_substr_if_minlen ) continue;
484
485                 max = index_substr_if_maxlen < values[i].bv_len
486                         ? index_substr_if_maxlen : values[i].bv_len;
487
488                 for( j=index_substr_if_minlen; j<=max; j++ ) {
489                         char pre;
490
491                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
492                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
493                                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
494                                         syntax, mr, (unsigned char *)values[i].bv_val, j );
495                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
496                         }
497
498                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
499                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
500                                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
501                                         syntax, mr, (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
502                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
503                         }
504
505                 }
506         }
507
508         if( nkeys > 0 ) {
509                 BER_BVZERO( &keys[nkeys] );
510                 *keysp = keys;
511         } else {
512                 ch_free( keys );
513                 *keysp = NULL;
514         }
515
516         return LDAP_SUCCESS;
517 }
518
519 static int
520 octetStringSubstringsFilter (
521         slap_mask_t use,
522         slap_mask_t flags,
523         Syntax *syntax,
524         MatchingRule *mr,
525         struct berval *prefix,
526         void * assertedValue,
527         BerVarray *keysp,
528         void *ctx)
529 {
530         SubstringsAssertion *sa;
531         char pre;
532         ber_len_t nkeys = 0;
533         size_t slen, mlen, klen;
534         BerVarray keys;
535         HASH_CONTEXT HASHcontext;
536         unsigned char HASHdigest[HASH_BYTES];
537         struct berval *value;
538         struct berval digest;
539
540         sa = (SubstringsAssertion *) assertedValue;
541
542         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
543                 !BER_BVISNULL( &sa->sa_initial ) &&
544                 sa->sa_initial.bv_len >= index_substr_if_minlen )
545         {
546                 nkeys++;
547                 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
548                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
549                 {
550                         nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
551                 }
552         }
553
554         if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
555                 ber_len_t i;
556                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
557                         if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
558                                 /* don't bother accounting with stepping */
559                                 nkeys += sa->sa_any[i].bv_len -
560                                         ( index_substr_any_len - 1 );
561                         }
562                 }
563         }
564
565         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
566                 !BER_BVISNULL( &sa->sa_final ) &&
567                 sa->sa_final.bv_len >= index_substr_if_minlen )
568         {
569                 nkeys++;
570                 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
571                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
572                 {
573                         nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
574                 }
575         }
576
577         if( nkeys == 0 ) {
578                 *keysp = NULL;
579                 return LDAP_SUCCESS;
580         }
581
582         digest.bv_val = (char *)HASHdigest;
583         digest.bv_len = sizeof(HASHdigest);
584
585         slen = syntax->ssyn_oidlen;
586         mlen = mr->smr_oidlen;
587
588         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
589         nkeys = 0;
590
591         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
592                 !BER_BVISNULL( &sa->sa_initial ) &&
593                 sa->sa_initial.bv_len >= index_substr_if_minlen )
594         {
595                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
596                 value = &sa->sa_initial;
597
598                 klen = index_substr_if_maxlen < value->bv_len
599                         ? index_substr_if_maxlen : value->bv_len;
600
601                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
602                         syntax, mr, (unsigned char *)value->bv_val, klen );
603                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
604
605                 /* If initial is too long and we have subany indexed, use it
606                  * to match the excess...
607                  */
608                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
609                 {
610                         ber_len_t j;
611                         pre = SLAP_INDEX_SUBSTR_PREFIX;
612                         for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
613                         {
614                                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
615                                         syntax, mr, (unsigned char *)&value->bv_val[j], index_substr_any_len );
616                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
617                         }
618                 }
619         }
620
621         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
622                 ber_len_t i, j;
623                 pre = SLAP_INDEX_SUBSTR_PREFIX;
624                 klen = index_substr_any_len;
625
626                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
627                         if( sa->sa_any[i].bv_len < index_substr_any_len ) {
628                                 continue;
629                         }
630
631                         value = &sa->sa_any[i];
632
633                         for(j=0;
634                                 j <= value->bv_len - index_substr_any_len;
635                                 j += index_substr_any_step )
636                         {
637                                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
638                                         syntax, mr, (unsigned char *)&value->bv_val[j], klen ); 
639                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
640                         }
641                 }
642         }
643
644         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
645                 !BER_BVISNULL( &sa->sa_final ) &&
646                 sa->sa_final.bv_len >= index_substr_if_minlen )
647         {
648                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
649                 value = &sa->sa_final;
650
651                 klen = index_substr_if_maxlen < value->bv_len
652                         ? index_substr_if_maxlen : value->bv_len;
653
654                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
655                         syntax, mr, (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
656                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
657
658                 /* If final is too long and we have subany indexed, use it
659                  * to match the excess...
660                  */
661                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
662                 {
663                         ber_len_t j;
664                         pre = SLAP_INDEX_SUBSTR_PREFIX;
665                         for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
666                         {
667                                 hashDigestify( &HASHcontext, HASHdigest, prefix, pre,
668                                         syntax, mr, (unsigned char *)&value->bv_val[j], index_substr_any_len );
669                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
670                         }
671                 }
672         }
673
674         if( nkeys > 0 ) {
675                 BER_BVZERO( &keys[nkeys] );
676                 *keysp = keys;
677         } else {
678                 ch_free( keys );
679                 *keysp = NULL;
680         }
681
682         return LDAP_SUCCESS;
683 }
684
685 static int
686 bitStringValidate(
687         Syntax *syntax,
688         struct berval *in )
689 {
690         ber_len_t i;
691
692         /* very unforgiving validation, requires no normalization
693          * before simplistic matching
694          */
695         if( in->bv_len < 3 ) {
696                 return LDAP_INVALID_SYNTAX;
697         }
698
699         /*
700          * RFC 2252 section 6.3 Bit String
701          *      bitstring = "'" *binary-digit "'B"
702          *      binary-digit = "0" / "1"
703          * example: '0101111101'B
704          */
705         
706         if( in->bv_val[0] != '\'' ||
707                 in->bv_val[in->bv_len - 2] != '\'' ||
708                 in->bv_val[in->bv_len - 1] != 'B' )
709         {
710                 return LDAP_INVALID_SYNTAX;
711         }
712
713         for( i = in->bv_len - 3; i > 0; i-- ) {
714                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
715                         return LDAP_INVALID_SYNTAX;
716                 }
717         }
718
719         return LDAP_SUCCESS;
720 }
721
722 /*
723  * Syntax is [RFC2252]:
724  *
725
726 6.3. Bit String
727
728    ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
729
730    Values in this syntax are encoded according to the following BNF:
731
732       bitstring = "'" *binary-digit "'B"
733
734       binary-digit = "0" / "1"
735
736    ... 
737
738 6.21. Name And Optional UID
739
740    ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
741
742    Values in this syntax are encoded according to the following BNF:
743
744       NameAndOptionalUID = DistinguishedName [ "#" bitstring ]
745
746    Although the '#' character may occur in a string representation of a
747    distinguished name, no additional special quoting is done.  This
748    syntax has been added subsequent to RFC 1778.
749
750    Example:
751
752       1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
753
754  *
755  * draft-ietf-ldapbis-syntaxes-xx.txt says:
756  *
757
758 3.3.2.  Bit String
759
760    A value of the Bit String syntax is a sequence of binary digits.  The
761    LDAP-specific encoding of a value of this syntax is defined by the
762    following ABNF:
763
764       BitString    = SQUOTE *binary-digit SQUOTE "B"
765
766       binary-digit = "0" / "1"
767
768    The <SQUOTE> rule is defined in [MODELS].
769
770       Example:
771          '0101111101'B
772
773    The LDAP definition for the Bit String syntax is:
774
775       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
776
777    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
778
779    ...
780
781 3.3.21.  Name and Optional UID
782
783    A value of the Name and Optional UID syntax is the distinguished name
784    [MODELS] of an entity optionally accompanied by a unique identifier
785    that serves to differentiate the entity from others with an identical
786    distinguished name.
787
788    The LDAP-specific encoding of a value of this syntax is defined by
789    the following ABNF:
790
791        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
792
793    The <BitString> rule is defined in Section 3.3.2.  The
794    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
795    defined in [MODELS].
796
797    Note that although the '#' character may occur in the string
798    representation of a distinguished name, no additional escaping of
799    this character is performed when a <distinguishedName> is encoded in
800    a <NameAndOptionalUID>.
801
802       Example:
803          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
804
805    The LDAP definition for the Name and Optional UID syntax is:
806
807       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
808
809    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
810    [X.520].
811
812  *
813  * draft-ietf-ldapbis-models-xx.txt [MODELS] says:
814  *
815
816 1.4. Common ABNF Productions
817
818   ...
819       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
820   ...
821       SQUOTE  = %x27 ; single quote ("'")
822   ...
823       
824  *
825  * Note: normalization strips any leading "0"s, unless the
826  * bit string is exactly "'0'B", so the normalized example,
827  * in slapd, would result in
828  * 
829  * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
830  * 
831  * Since draft-ietf-ldapbis-dn-xx.txt clarifies that SHARP,
832  * i.e. "#", doesn't have to be escaped except when at the
833  * beginning of a value, the definition of Name and Optional
834  * UID appears to be flawed, because there is no clear means
835  * to determine whether the UID part is present or not.
836  *
837  * Example:
838  *
839  *      cn=Someone,dc=example,dc=com#'1'B
840  *
841  * could be either a NameAndOptionalUID with trailing UID, i.e.
842  *
843  *      DN = "cn=Someone,dc=example,dc=com"
844  *      UID = "'1'B"
845  * 
846  * or a NameAndOptionalUID with no trailing UID, and the AVA
847  * in the last RDN made of
848  *
849  *      attributeType = dc 
850  *      attributeValue = com#'1'B
851  *
852  * in fact "com#'1'B" is a valid IA5 string.
853  *
854  * As a consequence, current slapd code assumes that the
855  * presence of portions of a BitString at the end of the string 
856  * representation of a NameAndOptionalUID means a BitString
857  * is expected, and cause an error otherwise.  This is quite
858  * arbitrary, and might change in the future.
859  */
860
861
862 static int
863 nameUIDValidate(
864         Syntax *syntax,
865         struct berval *in )
866 {
867         int rc;
868         struct berval dn, uid;
869
870         if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
871
872         ber_dupbv( &dn, in );
873         if( !dn.bv_val ) return LDAP_OTHER;
874
875         /* if there's a "#", try bitStringValidate()... */
876         uid.bv_val = strrchr( dn.bv_val, '#' );
877         if ( !BER_BVISNULL( &uid ) ) {
878                 uid.bv_val++;
879                 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
880
881                 rc = bitStringValidate( NULL, &uid );
882                 if ( rc == LDAP_SUCCESS ) {
883                         /* in case of success, trim the UID,
884                          * otherwise treat it as part of the DN */
885                         dn.bv_len -= uid.bv_len + 1;
886                         uid.bv_val[-1] = '\0';
887                 }
888         }
889
890         rc = dnValidate( NULL, &dn );
891
892         ber_memfree( dn.bv_val );
893         return rc;
894 }
895
896 int
897 nameUIDPretty(
898         Syntax *syntax,
899         struct berval *val,
900         struct berval *out,
901         void *ctx )
902 {
903         assert( val != NULL );
904         assert( out != NULL );
905
906
907         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
908
909         if( BER_BVISEMPTY( val ) ) {
910                 ber_dupbv_x( out, val, ctx );
911
912         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
913                 return LDAP_INVALID_SYNTAX;
914
915         } else {
916                 int             rc;
917                 struct berval   dnval = *val;
918                 struct berval   uidval = BER_BVNULL;
919
920                 uidval.bv_val = strrchr( val->bv_val, '#' );
921                 if ( !BER_BVISNULL( &uidval ) ) {
922                         uidval.bv_val++;
923                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
924
925                         rc = bitStringValidate( NULL, &uidval );
926
927                         if ( rc == LDAP_SUCCESS ) {
928                                 ber_dupbv_x( &dnval, val, ctx );
929                                 dnval.bv_len -= uidval.bv_len + 1;
930                                 dnval.bv_val[dnval.bv_len] = '\0';
931
932                         } else {
933                                 BER_BVZERO( &uidval );
934                         }
935                 }
936
937                 rc = dnPretty( syntax, &dnval, out, ctx );
938                 if ( dnval.bv_val != val->bv_val ) {
939                         slap_sl_free( dnval.bv_val, ctx );
940                 }
941                 if( rc != LDAP_SUCCESS ) {
942                         return rc;
943                 }
944
945                 if( !BER_BVISNULL( &uidval ) ) {
946                         int     i, c, got1;
947                         char    *tmp;
948
949                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
950                                 + STRLENOF( "#" ) + uidval.bv_len + 1,
951                                 ctx );
952                         if( tmp == NULL ) {
953                                 ber_memfree_x( out->bv_val, ctx );
954                                 return LDAP_OTHER;
955                         }
956                         out->bv_val = tmp;
957                         out->bv_val[out->bv_len++] = '#';
958                         out->bv_val[out->bv_len++] = '\'';
959
960                         got1 = uidval.bv_len < sizeof("'0'B"); 
961                         for( i = 1; i < uidval.bv_len - 2; i++ ) {
962                                 c = uidval.bv_val[i];
963                                 switch(c) {
964                                         case '0':
965                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
966                                                 break;
967                                         case '1':
968                                                 got1 = 1;
969                                                 out->bv_val[out->bv_len++] = c;
970                                                 break;
971                                 }
972                         }
973
974                         out->bv_val[out->bv_len++] = '\'';
975                         out->bv_val[out->bv_len++] = 'B';
976                         out->bv_val[out->bv_len] = '\0';
977                 }
978         }
979
980         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
981
982         return LDAP_SUCCESS;
983 }
984
985 static int
986 uniqueMemberNormalize(
987         slap_mask_t usage,
988         Syntax *syntax,
989         MatchingRule *mr,
990         struct berval *val,
991         struct berval *normalized,
992         void *ctx )
993 {
994         struct berval out;
995         int rc;
996
997         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
998
999         ber_dupbv_x( &out, val, ctx );
1000         if ( BER_BVISEMPTY( &out ) ) {
1001                 *normalized = out;
1002
1003         } else {
1004                 struct berval uid = BER_BVNULL;
1005
1006                 uid.bv_val = strrchr( out.bv_val, '#' );
1007                 if ( !BER_BVISNULL( &uid ) ) {
1008                         uid.bv_val++;
1009                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1010
1011                         rc = bitStringValidate( NULL, &uid );
1012                         if ( rc == LDAP_SUCCESS ) {
1013                                 uid.bv_val[-1] = '\0';
1014                                 out.bv_len -= uid.bv_len + 1;
1015                         } else {
1016                                 BER_BVZERO( &uid );
1017                         }
1018                 }
1019
1020                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1021
1022                 if( rc != LDAP_SUCCESS ) {
1023                         slap_sl_free( out.bv_val, ctx );
1024                         return LDAP_INVALID_SYNTAX;
1025                 }
1026
1027                 if( !BER_BVISNULL( &uid ) ) {
1028                         char    *tmp;
1029
1030                         tmp = ch_realloc( normalized->bv_val,
1031                                 normalized->bv_len + uid.bv_len
1032                                 + STRLENOF("#") + 1 );
1033                         if ( tmp == NULL ) {
1034                                 ber_memfree_x( normalized->bv_val, ctx );
1035                                 return LDAP_OTHER;
1036                         }
1037
1038                         normalized->bv_val = tmp;
1039
1040                         /* insert the separator */
1041                         normalized->bv_val[normalized->bv_len++] = '#';
1042
1043                         /* append the UID */
1044                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1045                                 uid.bv_val, uid.bv_len );
1046                         normalized->bv_len += uid.bv_len;
1047
1048                         /* terminate */
1049                         normalized->bv_val[normalized->bv_len] = '\0';
1050                 }
1051
1052                 slap_sl_free( out.bv_val, ctx );
1053         }
1054
1055         return LDAP_SUCCESS;
1056 }
1057
1058 static int
1059 uniqueMemberMatch(
1060         int *matchp,
1061         slap_mask_t flags,
1062         Syntax *syntax,
1063         MatchingRule *mr,
1064         struct berval *value,
1065         void *assertedValue )
1066 {
1067         int match;
1068         struct berval *asserted = (struct berval *) assertedValue;
1069         struct berval assertedDN = *asserted;
1070         struct berval assertedUID = BER_BVNULL;
1071         struct berval valueDN = BER_BVNULL;
1072         struct berval valueUID = BER_BVNULL;
1073         int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1074
1075         if ( !BER_BVISEMPTY( asserted ) ) {
1076                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1077                 if ( !BER_BVISNULL( &assertedUID ) ) {
1078                         assertedUID.bv_val++;
1079                         assertedUID.bv_len = assertedDN.bv_len
1080                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1081
1082                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1083                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1084
1085                         } else {
1086                                 BER_BVZERO( &assertedUID );
1087                         }
1088                 }
1089         }
1090
1091         if ( !BER_BVISEMPTY( value ) ) {
1092                 valueDN = *value;
1093
1094                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1095                 if ( !BER_BVISNULL( &valueUID ) ) {
1096                         valueUID.bv_val++;
1097                         valueUID.bv_len = valueDN.bv_len
1098                                 - ( valueUID.bv_val - valueDN.bv_val );
1099
1100                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1101                                 valueDN.bv_len -= valueUID.bv_len + 1;
1102
1103                         } else {
1104                                 BER_BVZERO( &valueUID );
1105                         }
1106                 }
1107         }
1108
1109         if( valueUID.bv_len && assertedUID.bv_len ) {
1110                 match = valueUID.bv_len - assertedUID.bv_len;
1111                 if ( match ) {
1112                         *matchp = match;
1113                         return LDAP_SUCCESS;
1114                 }
1115
1116                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1117                 if( match ) {
1118                         *matchp = match;
1119                         return LDAP_SUCCESS;
1120                 }
1121
1122         } else if ( !approx && valueUID.bv_len ) {
1123                 match = -1;
1124                 *matchp = match;
1125                 return LDAP_SUCCESS;
1126
1127         } else if ( !approx && assertedUID.bv_len ) {
1128                 match = 1;
1129                 *matchp = match;
1130                 return LDAP_SUCCESS;
1131         }
1132
1133         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1134 }
1135
1136 static int 
1137 uniqueMemberIndexer(
1138         slap_mask_t use,
1139         slap_mask_t flags,
1140         Syntax *syntax,
1141         MatchingRule *mr,
1142         struct berval *prefix,
1143         BerVarray values,
1144         BerVarray *keysp,
1145         void *ctx )
1146 {
1147         BerVarray dnvalues;
1148         int rc;
1149         int i;
1150         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1151                 /* just count them */                 
1152         }
1153         assert( i > 0 );
1154
1155         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1156
1157         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1158                 struct berval assertedDN = values[i];
1159                 struct berval assertedUID = BER_BVNULL;
1160
1161                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1162                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1163                         if ( !BER_BVISNULL( &assertedUID ) ) {
1164                                 assertedUID.bv_val++;
1165                                 assertedUID.bv_len = assertedDN.bv_len
1166                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1167         
1168                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1169                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1170
1171                                 } else {
1172                                         BER_BVZERO( &assertedUID );
1173                                 }
1174                         }
1175                 }
1176
1177                 dnvalues[i] = assertedDN;
1178         }
1179         BER_BVZERO( &dnvalues[i] );
1180
1181         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1182                 dnvalues, keysp, ctx );
1183
1184         slap_sl_free( dnvalues, ctx );
1185         return rc;
1186 }
1187
1188 static int 
1189 uniqueMemberFilter(
1190         slap_mask_t use,
1191         slap_mask_t flags,
1192         Syntax *syntax,
1193         MatchingRule *mr,
1194         struct berval *prefix,
1195         void * assertedValue,
1196         BerVarray *keysp,
1197         void *ctx )
1198 {
1199         struct berval *asserted = (struct berval *) assertedValue;
1200         struct berval assertedDN = *asserted;
1201         struct berval assertedUID = BER_BVNULL;
1202
1203         if ( !BER_BVISEMPTY( asserted ) ) {
1204                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1205                 if ( !BER_BVISNULL( &assertedUID ) ) {
1206                         assertedUID.bv_val++;
1207                         assertedUID.bv_len = assertedDN.bv_len
1208                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1209
1210                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1211                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1212
1213                         } else {
1214                                 BER_BVZERO( &assertedUID );
1215                         }
1216                 }
1217         }
1218
1219         return octetStringFilter( use, flags, syntax, mr, prefix,
1220                 &assertedDN, keysp, ctx );
1221 }
1222
1223
1224 /*
1225  * Handling boolean syntax and matching is quite rigid.
1226  * A more flexible approach would be to allow a variety
1227  * of strings to be normalized and prettied into TRUE
1228  * and FALSE.
1229  */
1230 static int
1231 booleanValidate(
1232         Syntax *syntax,
1233         struct berval *in )
1234 {
1235         /* very unforgiving validation, requires no normalization
1236          * before simplistic matching
1237          */
1238
1239         if( in->bv_len == 4 ) {
1240                 if( bvmatch( in, &slap_true_bv ) ) {
1241                         return LDAP_SUCCESS;
1242                 }
1243         } else if( in->bv_len == 5 ) {
1244                 if( bvmatch( in, &slap_false_bv ) ) {
1245                         return LDAP_SUCCESS;
1246                 }
1247         }
1248
1249         return LDAP_INVALID_SYNTAX;
1250 }
1251
1252 static int
1253 booleanMatch(
1254         int *matchp,
1255         slap_mask_t flags,
1256         Syntax *syntax,
1257         MatchingRule *mr,
1258         struct berval *value,
1259         void *assertedValue )
1260 {
1261         /* simplistic matching allowed by rigid validation */
1262         struct berval *asserted = (struct berval *) assertedValue;
1263         *matchp = value->bv_len != asserted->bv_len;
1264         return LDAP_SUCCESS;
1265 }
1266
1267 /*-------------------------------------------------------------------
1268 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1269 comment attempts to detail how slapd(8) treats them.
1270
1271 Summary:
1272   StringSyntax          X.500   LDAP    Matching/Comments
1273   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1274   PrintableString       subset  subset  i/e + ignore insignificant spaces
1275   PrintableString       subset  subset  i/e + ignore insignificant spaces
1276   NumericString         subset  subset  ignore all spaces
1277   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1278   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1279
1280   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1281
1282   See draft-ietf-ldapbis-strpro for details (once published).
1283
1284
1285 Directory String -
1286   In X.500(93), a directory string can be either a PrintableString,
1287   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1288   In later versions, more CHOICEs were added.  In all cases the string
1289   must be non-empty.
1290
1291   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1292   A directory string cannot be zero length.
1293
1294   For matching, there are both case ignore and exact rules.  Both
1295   also require that "insignificant" spaces be ignored.
1296         spaces before the first non-space are ignored;
1297         spaces after the last non-space are ignored;
1298         spaces after a space are ignored.
1299   Note: by these rules (and as clarified in X.520), a string of only
1300   spaces is to be treated as if held one space, not empty (which
1301   would be a syntax error).
1302
1303 NumericString
1304   In ASN.1, numeric string is just a string of digits and spaces
1305   and could be empty.  However, in X.500, all attribute values of
1306   numeric string carry a non-empty constraint.  For example:
1307
1308         internationalISDNNumber ATTRIBUTE ::= {
1309                 WITH SYNTAX InternationalISDNNumber
1310                 EQUALITY MATCHING RULE numericStringMatch
1311                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1312                 ID id-at-internationalISDNNumber }
1313         InternationalISDNNumber ::=
1314             NumericString (SIZE(1..ub-international-isdn-number))
1315
1316   Unforunately, some assertion values are don't carry the same
1317   constraint (but its unclear how such an assertion could ever
1318   be true). In LDAP, there is one syntax (numericString) not two
1319   (numericString with constraint, numericString without constraint).
1320   This should be treated as numericString with non-empty constraint.
1321   Note that while someone may have no ISDN number, there are no ISDN
1322   numbers which are zero length.
1323
1324   In matching, spaces are ignored.
1325
1326 PrintableString
1327   In ASN.1, Printable string is just a string of printable characters
1328   and can be empty.  In X.500, semantics much like NumericString (see
1329   serialNumber for a like example) excepting uses insignificant space
1330   handling instead of ignore all spaces.  
1331
1332 IA5String
1333   Basically same as PrintableString.  There are no examples in X.500,
1334   but same logic applies.  So we require them to be non-empty as
1335   well.
1336
1337 -------------------------------------------------------------------*/
1338
1339 static int
1340 UTF8StringValidate(
1341         Syntax *syntax,
1342         struct berval *in )
1343 {
1344         ber_len_t count;
1345         int len;
1346         unsigned char *u = (unsigned char *)in->bv_val;
1347
1348         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1349                 /* directory strings cannot be empty */
1350                 return LDAP_INVALID_SYNTAX;
1351         }
1352
1353         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1354                 /* get the length indicated by the first byte */
1355                 len = LDAP_UTF8_CHARLEN2( u, len );
1356
1357                 /* very basic checks */
1358                 switch( len ) {
1359                         case 6:
1360                                 if( (u[5] & 0xC0) != 0x80 ) {
1361                                         return LDAP_INVALID_SYNTAX;
1362                                 }
1363                         case 5:
1364                                 if( (u[4] & 0xC0) != 0x80 ) {
1365                                         return LDAP_INVALID_SYNTAX;
1366                                 }
1367                         case 4:
1368                                 if( (u[3] & 0xC0) != 0x80 ) {
1369                                         return LDAP_INVALID_SYNTAX;
1370                                 }
1371                         case 3:
1372                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1373                                         return LDAP_INVALID_SYNTAX;
1374                                 }
1375                         case 2:
1376                                 if( (u[1] & 0xC0) != 0x80 ) {
1377                                         return LDAP_INVALID_SYNTAX;
1378                                 }
1379                         case 1:
1380                                 /* CHARLEN already validated it */
1381                                 break;
1382                         default:
1383                                 return LDAP_INVALID_SYNTAX;
1384                 }
1385
1386                 /* make sure len corresponds with the offset
1387                         to the next character */
1388                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1389         }
1390
1391         if( count != 0 ) {
1392                 return LDAP_INVALID_SYNTAX;
1393         }
1394
1395         return LDAP_SUCCESS;
1396 }
1397
1398 static int
1399 UTF8StringNormalize(
1400         slap_mask_t use,
1401         Syntax *syntax,
1402         MatchingRule *mr,
1403         struct berval *val,
1404         struct berval *normalized,
1405         void *ctx )
1406 {
1407         struct berval tmp, nvalue;
1408         int flags;
1409         int i, wasspace;
1410
1411         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1412
1413         if( BER_BVISNULL( val ) ) {
1414                 /* assume we're dealing with a syntax (e.g., UTF8String)
1415                  * which allows empty strings
1416                  */
1417                 BER_BVZERO( normalized );
1418                 return LDAP_SUCCESS;
1419         }
1420
1421         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1422                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1423         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1424                 ? LDAP_UTF8_APPROX : 0;
1425
1426         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1427         if( val == NULL ) {
1428                 return LDAP_OTHER;
1429         }
1430         
1431         /* collapse spaces (in place) */
1432         nvalue.bv_len = 0;
1433         nvalue.bv_val = tmp.bv_val;
1434
1435         /* trim leading spaces? */
1436         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1437                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1438
1439         for( i = 0; i < tmp.bv_len; i++) {
1440                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1441                         if( wasspace++ == 0 ) {
1442                                 /* trim repeated spaces */
1443                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1444                         }
1445                 } else {
1446                         wasspace = 0;
1447                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1448                 }
1449         }
1450
1451         if( !BER_BVISEMPTY( &nvalue ) ) {
1452                 /* trim trailing space? */
1453                 if( wasspace && (
1454                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1455                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1456                 {
1457                         --nvalue.bv_len;
1458                 }
1459                 nvalue.bv_val[nvalue.bv_len] = '\0';
1460
1461         } else {
1462                 /* string of all spaces is treated as one space */
1463                 nvalue.bv_val[0] = ' ';
1464                 nvalue.bv_val[1] = '\0';
1465                 nvalue.bv_len = 1;
1466         }
1467
1468         *normalized = nvalue;
1469         return LDAP_SUCCESS;
1470 }
1471
1472 static int
1473 directoryStringSubstringsMatch(
1474         int *matchp,
1475         slap_mask_t flags,
1476         Syntax *syntax,
1477         MatchingRule *mr,
1478         struct berval *value,
1479         void *assertedValue )
1480 {
1481         int match = 0;
1482         SubstringsAssertion *sub = assertedValue;
1483         struct berval left = *value;
1484         int i;
1485         int priorspace=0;
1486
1487         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1488                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1489                         /* not enough left */
1490                         match = 1;
1491                         goto done;
1492                 }
1493
1494                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1495                         sub->sa_initial.bv_len );
1496
1497                 if ( match != 0 ) {
1498                         goto done;
1499                 }
1500
1501                 left.bv_val += sub->sa_initial.bv_len;
1502                 left.bv_len -= sub->sa_initial.bv_len;
1503
1504                 priorspace = ASCII_SPACE(
1505                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1506         }
1507
1508         if ( sub->sa_any ) {
1509                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1510                         ber_len_t idx;
1511                         char *p;
1512
1513                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1514                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1515                         { 
1516                                 /* allow next space to match */
1517                                 left.bv_val--;
1518                                 left.bv_len++;
1519                         }
1520                         priorspace=0;
1521
1522 retry:
1523                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1524                                 continue;
1525                         }
1526
1527                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1528                                 /* not enough left */
1529                                 match = 1;
1530                                 goto done;
1531                         }
1532
1533                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1534
1535                         if( p == NULL ) {
1536                                 match = 1;
1537                                 goto done;
1538                         }
1539
1540                         idx = p - left.bv_val;
1541
1542                         if ( idx >= left.bv_len ) {
1543                                 /* this shouldn't happen */
1544                                 return LDAP_OTHER;
1545                         }
1546
1547                         left.bv_val = p;
1548                         left.bv_len -= idx;
1549
1550                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1551                                 /* not enough left */
1552                                 match = 1;
1553                                 goto done;
1554                         }
1555
1556                         match = memcmp( left.bv_val,
1557                                 sub->sa_any[i].bv_val,
1558                                 sub->sa_any[i].bv_len );
1559
1560                         if ( match != 0 ) {
1561                                 left.bv_val++;
1562                                 left.bv_len--;
1563                                 goto retry;
1564                         }
1565
1566                         left.bv_val += sub->sa_any[i].bv_len;
1567                         left.bv_len -= sub->sa_any[i].bv_len;
1568
1569                         priorspace = ASCII_SPACE(
1570                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1571                 }
1572         }
1573
1574         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1575                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1576                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1577                 { 
1578                         /* allow next space to match */
1579                         left.bv_val--;
1580                         left.bv_len++;
1581                 }
1582
1583                 if ( sub->sa_final.bv_len > left.bv_len ) {
1584                         /* not enough left */
1585                         match = 1;
1586                         goto done;
1587                 }
1588
1589                 match = memcmp( sub->sa_final.bv_val,
1590                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1591                         sub->sa_final.bv_len );
1592
1593                 if ( match != 0 ) {
1594                         goto done;
1595                 }
1596         }
1597
1598 done:
1599         *matchp = match;
1600         return LDAP_SUCCESS;
1601 }
1602
1603 #if defined(SLAPD_APPROX_INITIALS)
1604 #       define SLAPD_APPROX_DELIMITER "._ "
1605 #       define SLAPD_APPROX_WORDLEN 2
1606 #else
1607 #       define SLAPD_APPROX_DELIMITER " "
1608 #       define SLAPD_APPROX_WORDLEN 1
1609 #endif
1610
1611 static int
1612 approxMatch(
1613         int *matchp,
1614         slap_mask_t flags,
1615         Syntax *syntax,
1616         MatchingRule *mr,
1617         struct berval *value,
1618         void *assertedValue )
1619 {
1620         struct berval *nval, *assertv;
1621         char *val, **values, **words, *c;
1622         int i, count, len, nextchunk=0, nextavail=0;
1623
1624         /* Yes, this is necessary */
1625         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1626         if( nval == NULL ) {
1627                 *matchp = 1;
1628                 return LDAP_SUCCESS;
1629         }
1630
1631         /* Yes, this is necessary */
1632         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1633                 NULL, LDAP_UTF8_APPROX, NULL );
1634         if( assertv == NULL ) {
1635                 ber_bvfree( nval );
1636                 *matchp = 1;
1637                 return LDAP_SUCCESS;
1638         }
1639
1640         /* Isolate how many words there are */
1641         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1642                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1643                 if ( c == NULL ) break;
1644                 *c = '\0';
1645                 count++;
1646         }
1647
1648         /* Get a phonetic copy of each word */
1649         words = (char **)ch_malloc( count * sizeof(char *) );
1650         values = (char **)ch_malloc( count * sizeof(char *) );
1651         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1652                 words[i] = c;
1653                 values[i] = phonetic(c);
1654         }
1655
1656         /* Work through the asserted value's words, to see if at least some
1657            of the words are there, in the same order. */
1658         len = 0;
1659         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1660                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1661                 if( len == 0 ) {
1662                         nextchunk++;
1663                         continue;
1664                 }
1665 #if defined(SLAPD_APPROX_INITIALS)
1666                 else if( len == 1 ) {
1667                         /* Single letter words need to at least match one word's initial */
1668                         for( i=nextavail; i<count; i++ )
1669                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1670                                         nextavail=i+1;
1671                                         break;
1672                                 }
1673                 }
1674 #endif
1675                 else {
1676                         /* Isolate the next word in the asserted value and phonetic it */
1677                         assertv->bv_val[nextchunk+len] = '\0';
1678                         val = phonetic( assertv->bv_val + nextchunk );
1679
1680                         /* See if this phonetic chunk is in the remaining words of *value */
1681                         for( i=nextavail; i<count; i++ ){
1682                                 if( !strcmp( val, values[i] ) ){
1683                                         nextavail = i+1;
1684                                         break;
1685                                 }
1686                         }
1687                         ch_free( val );
1688                 }
1689
1690                 /* This chunk in the asserted value was NOT within the *value. */
1691                 if( i >= count ) {
1692                         nextavail=-1;
1693                         break;
1694                 }
1695
1696                 /* Go on to the next word in the asserted value */
1697                 nextchunk += len+1;
1698         }
1699
1700         /* If some of the words were seen, call it a match */
1701         if( nextavail > 0 ) {
1702                 *matchp = 0;
1703         }
1704         else {
1705                 *matchp = 1;
1706         }
1707
1708         /* Cleanup allocs */
1709         ber_bvfree( assertv );
1710         for( i=0; i<count; i++ ) {
1711                 ch_free( values[i] );
1712         }
1713         ch_free( values );
1714         ch_free( words );
1715         ber_bvfree( nval );
1716
1717         return LDAP_SUCCESS;
1718 }
1719
1720 static int 
1721 approxIndexer(
1722         slap_mask_t use,
1723         slap_mask_t flags,
1724         Syntax *syntax,
1725         MatchingRule *mr,
1726         struct berval *prefix,
1727         BerVarray values,
1728         BerVarray *keysp,
1729         void *ctx )
1730 {
1731         char *c;
1732         int i,j, len, wordcount, keycount=0;
1733         struct berval *newkeys;
1734         BerVarray keys=NULL;
1735
1736         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1737                 struct berval val = BER_BVNULL;
1738                 /* Yes, this is necessary */
1739                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1740                 assert( !BER_BVISNULL( &val ) );
1741
1742                 /* Isolate how many words there are. There will be a key for each */
1743                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1744                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1745                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1746                         c+= len;
1747                         if (*c == '\0') break;
1748                         *c = '\0';
1749                 }
1750
1751                 /* Allocate/increase storage to account for new keys */
1752                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1753                         * sizeof(struct berval) );
1754                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1755                 if( keys ) ch_free( keys );
1756                 keys = newkeys;
1757
1758                 /* Get a phonetic copy of each word */
1759                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1760                         len = strlen( c );
1761                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1762                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1763                         keycount++;
1764                         i++;
1765                 }
1766
1767                 ber_memfree( val.bv_val );
1768         }
1769         BER_BVZERO( &keys[keycount] );
1770         *keysp = keys;
1771
1772         return LDAP_SUCCESS;
1773 }
1774
1775 static int 
1776 approxFilter(
1777         slap_mask_t use,
1778         slap_mask_t flags,
1779         Syntax *syntax,
1780         MatchingRule *mr,
1781         struct berval *prefix,
1782         void * assertedValue,
1783         BerVarray *keysp,
1784         void *ctx )
1785 {
1786         char *c;
1787         int i, count, len;
1788         struct berval *val;
1789         BerVarray keys;
1790
1791         /* Yes, this is necessary */
1792         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1793                 NULL, LDAP_UTF8_APPROX, NULL );
1794         if( val == NULL || BER_BVISNULL( val ) ) {
1795                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1796                 BER_BVZERO( &keys[0] );
1797                 *keysp = keys;
1798                 ber_bvfree( val );
1799                 return LDAP_SUCCESS;
1800         }
1801
1802         /* Isolate how many words there are. There will be a key for each */
1803         for( count = 0,c = val->bv_val; *c; c++) {
1804                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1805                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1806                 c+= len;
1807                 if (*c == '\0') break;
1808                 *c = '\0';
1809         }
1810
1811         /* Allocate storage for new keys */
1812         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1813
1814         /* Get a phonetic copy of each word */
1815         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1816                 len = strlen(c);
1817                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1818                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1819                 i++;
1820         }
1821
1822         ber_bvfree( val );
1823
1824         BER_BVZERO( &keys[count] );
1825         *keysp = keys;
1826
1827         return LDAP_SUCCESS;
1828 }
1829
1830 /* Remove all spaces and '-' characters */
1831 static int
1832 telephoneNumberNormalize(
1833         slap_mask_t usage,
1834         Syntax *syntax,
1835         MatchingRule *mr,
1836         struct berval *val,
1837         struct berval *normalized,
1838         void *ctx )
1839 {
1840         char *p, *q;
1841
1842         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1843
1844         /* validator should have refused an empty string */
1845         assert( !BER_BVISEMPTY( val ) );
1846
1847         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1848
1849         for( p = val->bv_val; *p; p++ ) {
1850                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1851                         *q++ = *p;
1852                 }
1853         }
1854         *q = '\0';
1855
1856         normalized->bv_len = q - normalized->bv_val;
1857
1858         if( BER_BVISEMPTY( normalized ) ) {
1859                 slap_sl_free( normalized->bv_val, ctx );
1860                 BER_BVZERO( normalized );
1861                 return LDAP_INVALID_SYNTAX;
1862         }
1863
1864         return LDAP_SUCCESS;
1865 }
1866
1867 int
1868 numericoidValidate(
1869         Syntax *syntax,
1870         struct berval *in )
1871 {
1872         struct berval val = *in;
1873
1874         if( BER_BVISEMPTY( &val ) ) {
1875                 /* disallow empty strings */
1876                 return LDAP_INVALID_SYNTAX;
1877         }
1878
1879         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1880                 if ( val.bv_len == 1 ) {
1881                         return LDAP_SUCCESS;
1882                 }
1883
1884                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1885                         break;
1886                 }
1887
1888                 val.bv_val++;
1889                 val.bv_len--;
1890
1891                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1892                         val.bv_val++;
1893                         val.bv_len--;
1894
1895                         if ( val.bv_len == 0 ) {
1896                                 return LDAP_SUCCESS;
1897                         }
1898                 }
1899
1900                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1901                         break;
1902                 }
1903
1904                 val.bv_val++;
1905                 val.bv_len--;
1906         }
1907
1908         return LDAP_INVALID_SYNTAX;
1909 }
1910
1911 static int
1912 integerValidate(
1913         Syntax *syntax,
1914         struct berval *in )
1915 {
1916         ber_len_t i;
1917         struct berval val = *in;
1918
1919         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1920
1921         if ( val.bv_val[0] == '-' ) {
1922                 val.bv_len--;
1923                 val.bv_val++;
1924
1925                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1926                         return LDAP_INVALID_SYNTAX;
1927                 }
1928
1929                 if( val.bv_val[0] == '0' ) { /* "-0" */
1930                         return LDAP_INVALID_SYNTAX;
1931                 }
1932
1933         } else if ( val.bv_val[0] == '0' ) {
1934                 if( val.bv_len > 1 ) { /* "0<more>" */
1935                         return LDAP_INVALID_SYNTAX;
1936                 }
1937
1938                 return LDAP_SUCCESS;
1939         }
1940
1941         for( i=0; i < val.bv_len; i++ ) {
1942                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1943                         return LDAP_INVALID_SYNTAX;
1944                 }
1945         }
1946
1947         return LDAP_SUCCESS;
1948 }
1949
1950 static int
1951 integerMatch(
1952         int *matchp,
1953         slap_mask_t flags,
1954         Syntax *syntax,
1955         MatchingRule *mr,
1956         struct berval *value,
1957         void *assertedValue )
1958 {
1959         struct berval *asserted = (struct berval *) assertedValue;
1960         int vsign = 1, asign = 1;       /* default sign = '+' */
1961         struct berval v, a;
1962         int match;
1963
1964         v = *value;
1965         if( v.bv_val[0] == '-' ) {
1966                 vsign = -1;
1967                 v.bv_val++;
1968                 v.bv_len--;
1969         }
1970
1971         if( BER_BVISEMPTY( &v ) ) vsign = 0;
1972
1973         a = *asserted;
1974         if( a.bv_val[0] == '-' ) {
1975                 asign = -1;
1976                 a.bv_val++;
1977                 a.bv_len--;
1978         }
1979
1980         if( BER_BVISEMPTY( &a ) ) vsign = 0;
1981
1982         match = vsign - asign;
1983         if( match == 0 ) {
1984                 match = ( v.bv_len != a.bv_len
1985                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1986                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1987                 if( vsign < 0 ) match = -match;
1988         }
1989
1990         *matchp = match;
1991         return LDAP_SUCCESS;
1992 }
1993         
1994 static int
1995 countryStringValidate(
1996         Syntax *syntax,
1997         struct berval *val )
1998 {
1999         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2000
2001         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2002                 return LDAP_INVALID_SYNTAX;
2003         }
2004         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2005                 return LDAP_INVALID_SYNTAX;
2006         }
2007
2008         return LDAP_SUCCESS;
2009 }
2010
2011 static int
2012 printableStringValidate(
2013         Syntax *syntax,
2014         struct berval *val )
2015 {
2016         ber_len_t i;
2017
2018         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2019
2020         for(i=0; i < val->bv_len; i++) {
2021                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2022                         return LDAP_INVALID_SYNTAX;
2023                 }
2024         }
2025
2026         return LDAP_SUCCESS;
2027 }
2028
2029 static int
2030 printablesStringValidate(
2031         Syntax *syntax,
2032         struct berval *val )
2033 {
2034         ber_len_t i, len;
2035
2036         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2037
2038         for(i=0,len=0; i < val->bv_len; i++) {
2039                 int c = val->bv_val[i];
2040
2041                 if( c == '$' ) {
2042                         if( len == 0 ) {
2043                                 return LDAP_INVALID_SYNTAX;
2044                         }
2045                         len = 0;
2046
2047                 } else if ( SLAP_PRINTABLE(c) ) {
2048                         len++;
2049                 } else {
2050                         return LDAP_INVALID_SYNTAX;
2051                 }
2052         }
2053
2054         if( len == 0 ) {
2055                 return LDAP_INVALID_SYNTAX;
2056         }
2057
2058         return LDAP_SUCCESS;
2059 }
2060
2061 static int
2062 IA5StringValidate(
2063         Syntax *syntax,
2064         struct berval *val )
2065 {
2066         ber_len_t i;
2067
2068         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2069
2070         for(i=0; i < val->bv_len; i++) {
2071                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2072                         return LDAP_INVALID_SYNTAX;
2073                 }
2074         }
2075
2076         return LDAP_SUCCESS;
2077 }
2078
2079 static int
2080 IA5StringNormalize(
2081         slap_mask_t use,
2082         Syntax *syntax,
2083         MatchingRule *mr,
2084         struct berval *val,
2085         struct berval *normalized,
2086         void *ctx )
2087 {
2088         char *p, *q;
2089         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
2090
2091         assert( !BER_BVISEMPTY( val ) );
2092
2093         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
2094
2095         p = val->bv_val;
2096
2097         /* Ignore initial whitespace */
2098         while ( ASCII_SPACE( *p ) ) p++;
2099
2100         normalized->bv_val = ber_strdup_x( p, ctx );
2101         p = q = normalized->bv_val;
2102
2103         while ( *p ) {
2104                 if ( ASCII_SPACE( *p ) ) {
2105                         *q++ = *p++;
2106
2107                         /* Ignore the extra whitespace */
2108                         while ( ASCII_SPACE( *p ) ) {
2109                                 p++;
2110                         }
2111
2112                 } else if ( casefold ) {
2113                         /* Most IA5 rules require casefolding */
2114                         *q++ = TOLOWER(*p); p++;
2115
2116                 } else {
2117                         *q++ = *p++;
2118                 }
2119         }
2120
2121         assert( normalized->bv_val <= p );
2122         assert( q <= p );
2123
2124         /*
2125          * If the string ended in space, backup the pointer one
2126          * position.  One is enough because the above loop collapsed
2127          * all whitespace to a single space.
2128          */
2129         if ( ASCII_SPACE( q[-1] ) ) --q;
2130
2131         /* null terminate */
2132         *q = '\0';
2133
2134         normalized->bv_len = q - normalized->bv_val;
2135         if( BER_BVISEMPTY( normalized ) ) {
2136                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2137                 normalized->bv_val[0] = ' ';
2138                 normalized->bv_val[1] = '\0';
2139                 normalized->bv_len = 1;
2140         }
2141
2142         return LDAP_SUCCESS;
2143 }
2144
2145 static int
2146 UUIDValidate(
2147         Syntax *syntax,
2148         struct berval *in )
2149 {
2150         int i;
2151         if( in->bv_len != 36 ) {
2152                 return LDAP_INVALID_SYNTAX;
2153         }
2154
2155         for( i=0; i<36; i++ ) {
2156                 switch(i) {
2157                         case 8:
2158                         case 13:
2159                         case 18:
2160                         case 23:
2161                                 if( in->bv_val[i] != '-' ) {
2162                                         return LDAP_INVALID_SYNTAX;
2163                                 }
2164                                 break;
2165                         default:
2166                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2167                                         return LDAP_INVALID_SYNTAX;
2168                                 }
2169                 }
2170         }
2171         
2172         return LDAP_SUCCESS;
2173 }
2174
2175 static int
2176 UUIDNormalize(
2177         slap_mask_t usage,
2178         Syntax *syntax,
2179         MatchingRule *mr,
2180         struct berval *val,
2181         struct berval *normalized,
2182         void *ctx )
2183 {
2184         unsigned char octet = '\0';
2185         int i;
2186         int j;
2187         normalized->bv_len = 16;
2188         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2189
2190         for( i=0, j=0; i<36; i++ ) {
2191                 unsigned char nibble;
2192                 if( val->bv_val[i] == '-' ) {
2193                         continue;
2194
2195                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2196                         nibble = val->bv_val[i] - '0';
2197
2198                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2199                         nibble = val->bv_val[i] - ('a'-10);
2200
2201                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2202                         nibble = val->bv_val[i] - ('A'-10);
2203
2204                 } else {
2205                         slap_sl_free( normalized->bv_val, ctx );
2206                         return LDAP_INVALID_SYNTAX;
2207                 }
2208
2209                 if( j & 1 ) {
2210                         octet |= nibble;
2211                         normalized->bv_val[j>>1] = octet;
2212                 } else {
2213                         octet = nibble << 4;
2214                 }
2215                 j++;
2216         }
2217
2218         normalized->bv_val[normalized->bv_len] = 0;
2219         return LDAP_SUCCESS;
2220 }
2221
2222
2223
2224 static int
2225 numericStringValidate(
2226         Syntax *syntax,
2227         struct berval *in )
2228 {
2229         ber_len_t i;
2230
2231         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2232
2233         for(i=0; i < in->bv_len; i++) {
2234                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2235                         return LDAP_INVALID_SYNTAX;
2236                 }
2237         }
2238
2239         return LDAP_SUCCESS;
2240 }
2241
2242 static int
2243 numericStringNormalize(
2244         slap_mask_t usage,
2245         Syntax *syntax,
2246         MatchingRule *mr,
2247         struct berval *val,
2248         struct berval *normalized,
2249         void *ctx )
2250 {
2251         /* removal all spaces */
2252         char *p, *q;
2253
2254         assert( !BER_BVISEMPTY( val ) );
2255
2256         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2257
2258         p = val->bv_val;
2259         q = normalized->bv_val;
2260
2261         while ( *p ) {
2262                 if ( ASCII_SPACE( *p ) ) {
2263                         /* Ignore whitespace */
2264                         p++;
2265                 } else {
2266                         *q++ = *p++;
2267                 }
2268         }
2269
2270         /* we should have copied no more then is in val */
2271         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2272
2273         /* null terminate */
2274         *q = '\0';
2275
2276         normalized->bv_len = q - normalized->bv_val;
2277
2278         if( BER_BVISEMPTY( normalized ) ) {
2279                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2280                 normalized->bv_val[0] = ' ';
2281                 normalized->bv_val[1] = '\0';
2282                 normalized->bv_len = 1;
2283         }
2284
2285         return LDAP_SUCCESS;
2286 }
2287
2288 /*
2289  * Integer conversion macros that will use the largest available
2290  * type.
2291  */
2292 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) \
2293         && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2294 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2295 # define SLAP_LONG_MAX       LLONG_MAX
2296 # define SLAP_LONG_MIN       LLONG_MIN
2297 # define SLAP_LONG           long long
2298 #else
2299 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2300 # define SLAP_LONG_MAX       LONG_MAX
2301 # define SLAP_LONG_MIN       LONG_MIN
2302 # define SLAP_LONG           long
2303 #endif /* HAVE_STRTOLL ... */
2304
2305 static int
2306 integerBitAndMatch(
2307         int *matchp,
2308         slap_mask_t flags,
2309         Syntax *syntax,
2310         MatchingRule *mr,
2311         struct berval *value,
2312         void *assertedValue )
2313 {
2314         SLAP_LONG lValue, lAssertedValue;
2315
2316         /* safe to assume integers are NUL terminated? */
2317         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2318         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2319                 errno == ERANGE )
2320         {
2321                 return LDAP_CONSTRAINT_VIOLATION;
2322         }
2323
2324         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2325                 NULL, 10);
2326         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2327                 errno == ERANGE )
2328         {
2329                 return LDAP_CONSTRAINT_VIOLATION;
2330         }
2331
2332         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2333         return LDAP_SUCCESS;
2334 }
2335
2336 static int
2337 integerBitOrMatch(
2338         int *matchp,
2339         slap_mask_t flags,
2340         Syntax *syntax,
2341         MatchingRule *mr,
2342         struct berval *value,
2343         void *assertedValue )
2344 {
2345         SLAP_LONG lValue, lAssertedValue;
2346
2347         /* safe to assume integers are NUL terminated? */
2348         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2349         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2350                 errno == ERANGE )
2351         {
2352                 return LDAP_CONSTRAINT_VIOLATION;
2353         }
2354
2355         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2356                 NULL, 10);
2357         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2358                 errno == ERANGE )
2359         {
2360                 return LDAP_CONSTRAINT_VIOLATION;
2361         }
2362
2363         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2364         return LDAP_SUCCESS;
2365 }
2366
2367 static int
2368 serialNumberAndIssuerValidate(
2369         Syntax *syntax,
2370         struct berval *in )
2371 {
2372         int rc;
2373         ber_len_t n;
2374         struct berval sn, i;
2375         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2376
2377         i.bv_val = strchr( in->bv_val, '$' );
2378         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2379
2380         sn.bv_val = in->bv_val;
2381         sn.bv_len = i.bv_val - in->bv_val;
2382
2383         i.bv_val++;
2384         i.bv_len = in->bv_len - (sn.bv_len + 1);
2385
2386         /* validate serial number (strict for now) */
2387         for( n=0; n < sn.bv_len; n++ ) {
2388                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2389         }
2390
2391         /* validate DN */
2392         rc = dnValidate( NULL, &i );
2393         if( rc ) return LDAP_INVALID_SYNTAX;
2394
2395         return LDAP_SUCCESS;
2396 }
2397
2398 int
2399 serialNumberAndIssuerPretty(
2400         Syntax *syntax,
2401         struct berval *val,
2402         struct berval *out,
2403         void *ctx )
2404 {
2405         int rc;
2406         ber_len_t n;
2407         struct berval sn, i, newi;
2408
2409         assert( val != NULL );
2410         assert( out != NULL );
2411
2412         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2413                 val->bv_val, 0, 0 );
2414
2415         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2416
2417         i.bv_val = strchr( val->bv_val, '$' );
2418         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2419
2420         sn.bv_val = val->bv_val;
2421         sn.bv_len = i.bv_val - val->bv_val;
2422
2423         i.bv_val++;
2424         i.bv_len = val->bv_len - (sn.bv_len + 1);
2425
2426         /* eat leading zeros */
2427         for( n=0; n < (sn.bv_len-1); n++ ) {
2428                 if( sn.bv_val[n] != '0' ) break;
2429         }
2430         sn.bv_val += n;
2431         sn.bv_len -= n;
2432
2433         for( n=0; n < sn.bv_len; n++ ) {
2434                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2435         }
2436
2437         /* pretty DN */
2438         rc = dnPretty( syntax, &i, &newi, ctx );
2439         if( rc ) return LDAP_INVALID_SYNTAX;
2440
2441         /* make room from sn + "$" */
2442         out->bv_len = sn.bv_len + newi.bv_len + 1;
2443         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2444
2445         if( out->bv_val == NULL ) {
2446                 out->bv_len = 0;
2447                 slap_sl_free( newi.bv_val, ctx );
2448                 return LDAP_OTHER;
2449         }
2450
2451         /* push issuer over */
2452         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2453         /* insert sn and "$" */
2454         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2455         out->bv_val[sn.bv_len] = '$';
2456         /* terminate */
2457         out->bv_val[out->bv_len] = '\0';
2458
2459         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2460                 out->bv_val, 0, 0 );
2461
2462         return LDAP_SUCCESS;
2463 }
2464
2465 /*
2466  * This routine is called by certificateExactNormalize when
2467  * certificateExactNormalize receives a search string instead of
2468  * a certificate. This routine checks if the search value is valid
2469  * and then returns the normalized value
2470  */
2471 static int
2472 serialNumberAndIssuerNormalize(
2473         slap_mask_t usage,
2474         Syntax *syntax,
2475         MatchingRule *mr,
2476         struct berval *val,
2477         struct berval *out,
2478         void *ctx )
2479 {
2480         int rc;
2481         ber_len_t n;
2482         struct berval sn, i, newi;
2483
2484         assert( val != NULL );
2485         assert( out != NULL );
2486
2487         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2488                 val->bv_val, 0, 0 );
2489
2490         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2491
2492         i.bv_val = strchr( val->bv_val, '$' );
2493         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2494
2495         sn.bv_val = val->bv_val;
2496         sn.bv_len = i.bv_val - val->bv_val;
2497
2498         i.bv_val++;
2499         i.bv_len = val->bv_len - (sn.bv_len + 1);
2500
2501         /* eat leading zeros */
2502         for( n=0; n < (sn.bv_len-1); n++ ) {
2503                 if( sn.bv_val[n] != '0' ) break;
2504         }
2505         sn.bv_val += n;
2506         sn.bv_len -= n;
2507
2508         for( n=0; n < sn.bv_len; n++ ) {
2509                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2510                         return LDAP_INVALID_SYNTAX;
2511                 }
2512         }
2513
2514         /* pretty DN */
2515         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2516         if( rc ) return LDAP_INVALID_SYNTAX;
2517
2518         /* make room from sn + "$" */
2519         out->bv_len = sn.bv_len + newi.bv_len + 1;
2520         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2521
2522         if( out->bv_val == NULL ) {
2523                 out->bv_len = 0;
2524                 slap_sl_free( newi.bv_val, ctx );
2525                 return LDAP_OTHER;
2526         }
2527
2528         /* push issuer over */
2529         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2530         /* insert sn and "$" */
2531         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2532         out->bv_val[sn.bv_len] = '$';
2533         /* terminate */
2534         out->bv_val[out->bv_len] = '\0';
2535
2536         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2537                 out->bv_val, 0, 0 );
2538
2539         return rc;
2540 }
2541
2542 #ifdef HAVE_TLS
2543 static int
2544 certificateExactNormalize(
2545         slap_mask_t usage,
2546         Syntax *syntax,
2547         MatchingRule *mr,
2548         struct berval *val,
2549         struct berval *normalized,
2550         void *ctx )
2551 {
2552         int rc = LDAP_INVALID_SYNTAX;
2553         unsigned char *p;
2554         char *serial = NULL;
2555         ber_len_t seriallen;
2556         struct berval issuer_dn = BER_BVNULL;
2557         X509_NAME *name = NULL;
2558         ASN1_INTEGER *sn = NULL;
2559         X509 *xcert = NULL;
2560
2561         if( BER_BVISEMPTY( val ) ) goto done;
2562
2563         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2564                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2565         }
2566
2567         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2568
2569         p = (unsigned char *)val->bv_val;
2570         xcert = d2i_X509( NULL, &p, val->bv_len);
2571         if( xcert == NULL ) goto done;
2572
2573         sn=X509_get_serialNumber(xcert);
2574         if ( sn == NULL ) goto done;
2575         serial=i2s_ASN1_INTEGER(0, sn );
2576         if( serial == NULL ) goto done;
2577         seriallen=strlen(serial);
2578
2579         name=X509_get_issuer_name(xcert);
2580         if( name == NULL ) goto done;
2581         rc = dnX509normalize( name, &issuer_dn );
2582         if( rc != LDAP_SUCCESS ) goto done;
2583
2584         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2585         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2586         p = (unsigned char *)normalized->bv_val;
2587         AC_MEMCPY(p, serial, seriallen);
2588         p += seriallen;
2589         *p++ = '$';
2590         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2591         p += issuer_dn.bv_len;
2592         *p = '\0';
2593
2594         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2595                 normalized->bv_val, NULL, NULL );
2596
2597 done:
2598         if (xcert) X509_free(xcert);
2599         if (serial) ch_free(serial);
2600         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2601
2602         return rc;
2603 }
2604 #endif /* HAVE_TLS */
2605
2606
2607 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2608 /* slight optimization - does not need the start parameter */
2609 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2610 enum { start = 0 };
2611 #endif
2612
2613 static int
2614 check_time_syntax (struct berval *val,
2615         int start,
2616         int *parts,
2617         struct berval *fraction)
2618 {
2619         /*
2620          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2621          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2622          * GeneralizedTime supports leap seconds, UTCTime does not.
2623          */
2624         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2625         static const int mdays[2][12] = {
2626                 /* non-leap years */
2627                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2628                 /* leap years */
2629                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2630         };
2631         char *p, *e;
2632         int part, c, c1, c2, tzoffset, leapyear = 0;
2633
2634         p = val->bv_val;
2635         e = p + val->bv_len;
2636
2637 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2638         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2639 #endif
2640         for (part = start; part < 7 && p < e; part++) {
2641                 c1 = *p;
2642                 if (!ASCII_DIGIT(c1)) {
2643                         break;
2644                 }
2645                 p++;
2646                 if (p == e) {
2647                         return LDAP_INVALID_SYNTAX;
2648                 }
2649                 c = *p++;
2650                 if (!ASCII_DIGIT(c)) {
2651                         return LDAP_INVALID_SYNTAX;
2652                 }
2653                 c += c1 * 10 - '0' * 11;
2654                 if ((part | 1) == 3) {
2655                         --c;
2656                         if (c < 0) {
2657                                 return LDAP_INVALID_SYNTAX;
2658                         }
2659                 }
2660                 if (c >= ceiling[part]) {
2661                         if (! (c == 60 && part == 6 && start == 0))
2662                                 return LDAP_INVALID_SYNTAX;
2663                 }
2664                 parts[part] = c;
2665         }
2666         if (part < 5 + start) {
2667                 return LDAP_INVALID_SYNTAX;
2668         }
2669         for (; part < 9; part++) {
2670                 parts[part] = 0;
2671         }
2672
2673         /* leapyear check for the Gregorian calendar (year>1581) */
2674         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2675                 leapyear = 1;
2676         }
2677
2678         if (parts[3] >= mdays[leapyear][parts[2]]) {
2679                 return LDAP_INVALID_SYNTAX;
2680         }
2681
2682         if (start == 0) {
2683                 fraction->bv_val = p;
2684                 fraction->bv_len = 0;
2685                 if (p < e && (*p == '.' || *p == ',')) {
2686                         char *end_num;
2687                         while (++p < e && ASCII_DIGIT(*p)) {
2688                                 /* EMTPY */;
2689                         }
2690                         if (p - fraction->bv_val == 1) {
2691                                 return LDAP_INVALID_SYNTAX;
2692                         }
2693                         for (end_num = p; end_num[-1] == '0'; --end_num) {
2694                                 /* EMPTY */;
2695                         }
2696                         c = end_num - fraction->bv_val;
2697                         if (c != 1) fraction->bv_len = c;
2698                 }
2699         }
2700
2701         if (p == e) {
2702                 /* no time zone */
2703                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2704         }
2705
2706         tzoffset = *p++;
2707         switch (tzoffset) {
2708         default:
2709                 return LDAP_INVALID_SYNTAX;
2710         case 'Z':
2711                 /* UTC */
2712                 break;
2713         case '+':
2714         case '-':
2715                 for (part = 7; part < 9 && p < e; part++) {
2716                         c1 = *p;
2717                         if (!ASCII_DIGIT(c1)) {
2718                                 break;
2719                         }
2720                         p++;
2721                         if (p == e) {
2722                                 return LDAP_INVALID_SYNTAX;
2723                         }
2724                         c2 = *p++;
2725                         if (!ASCII_DIGIT(c2)) {
2726                                 return LDAP_INVALID_SYNTAX;
2727                         }
2728                         parts[part] = c1 * 10 + c2 - '0' * 11;
2729                         if (parts[part] >= ceiling[part]) {
2730                                 return LDAP_INVALID_SYNTAX;
2731                         }
2732                 }
2733                 if (part < 8 + start) {
2734                         return LDAP_INVALID_SYNTAX;
2735                 }
2736
2737                 if (tzoffset == '-') {
2738                         /* negative offset to UTC, ie west of Greenwich */
2739                         parts[4] += parts[7];
2740                         parts[5] += parts[8];
2741                         /* offset is just hhmm, no seconds */
2742                         for (part = 6; --part >= 0; ) {
2743                                 if (part != 3) {
2744                                         c = ceiling[part];
2745                                 } else {
2746                                         c = mdays[leapyear][parts[2]];
2747                                 }
2748                                 if (parts[part] >= c) {
2749                                         if (part == 0) {
2750                                                 return LDAP_INVALID_SYNTAX;
2751                                         }
2752                                         parts[part] -= c;
2753                                         parts[part - 1]++;
2754                                         continue;
2755                                 } else if (part != 5) {
2756                                         break;
2757                                 }
2758                         }
2759                 } else {
2760                         /* positive offset to UTC, ie east of Greenwich */
2761                         parts[4] -= parts[7];
2762                         parts[5] -= parts[8];
2763                         for (part = 6; --part >= 0; ) {
2764                                 if (parts[part] < 0) {
2765                                         if (part == 0) {
2766                                                 return LDAP_INVALID_SYNTAX;
2767                                         }
2768                                         if (part != 3) {
2769                                                 c = ceiling[part];
2770                                         } else {
2771                                                 /* make first arg to % non-negative */
2772                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2773                                         }
2774                                         parts[part] += c;
2775                                         parts[part - 1]--;
2776                                         continue;
2777                                 } else if (part != 5) {
2778                                         break;
2779                                 }
2780                         }
2781                 }
2782         }
2783
2784         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2785 }
2786
2787 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2788
2789 #if 0
2790 static int
2791 xutcTimeNormalize(
2792         Syntax *syntax,
2793         struct berval *val,
2794         struct berval *normalized )
2795 {
2796         int parts[9], rc;
2797
2798         rc = check_time_syntax(val, 1, parts, NULL);
2799         if (rc != LDAP_SUCCESS) {
2800                 return rc;
2801         }
2802
2803         normalized->bv_val = ch_malloc( 14 );
2804         if ( normalized->bv_val == NULL ) {
2805                 return LBER_ERROR_MEMORY;
2806         }
2807
2808         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2809                 parts[1], parts[2] + 1, parts[3] + 1,
2810                 parts[4], parts[5], parts[6] );
2811         normalized->bv_len = 13;
2812
2813         return LDAP_SUCCESS;
2814 }
2815 #endif /* 0 */
2816
2817 static int
2818 utcTimeValidate(
2819         Syntax *syntax,
2820         struct berval *in )
2821 {
2822         int parts[9];
2823         return check_time_syntax(in, 1, parts, NULL);
2824 }
2825
2826 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2827
2828 static int
2829 generalizedTimeValidate(
2830         Syntax *syntax,
2831         struct berval *in )
2832 {
2833         int parts[9];
2834         struct berval fraction;
2835         return check_time_syntax(in, 0, parts, &fraction);
2836 }
2837
2838 static int
2839 generalizedTimeNormalize(
2840         slap_mask_t usage,
2841         Syntax *syntax,
2842         MatchingRule *mr,
2843         struct berval *val,
2844         struct berval *normalized,
2845         void *ctx )
2846 {
2847         int parts[9], rc;
2848         unsigned int len;
2849         struct berval fraction;
2850
2851         rc = check_time_syntax(val, 0, parts, &fraction);
2852         if (rc != LDAP_SUCCESS) {
2853                 return rc;
2854         }
2855
2856         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2857         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2858         if ( BER_BVISNULL( normalized ) ) {
2859                 return LBER_ERROR_MEMORY;
2860         }
2861
2862         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2863                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2864                 parts[4], parts[5], parts[6] );
2865         if ( !BER_BVISEMPTY( &fraction ) ) {
2866                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2867                         fraction.bv_val, fraction.bv_len );
2868                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2869         }
2870         strcpy( normalized->bv_val + len-1, "Z" );
2871         normalized->bv_len = len;
2872
2873         return LDAP_SUCCESS;
2874 }
2875
2876 static int
2877 generalizedTimeOrderingMatch(
2878         int *matchp,
2879         slap_mask_t flags,
2880         Syntax *syntax,
2881         MatchingRule *mr,
2882         struct berval *value,
2883         void *assertedValue )
2884 {
2885         struct berval *asserted = (struct berval *) assertedValue;
2886         ber_len_t v_len  = value->bv_len;
2887         ber_len_t av_len = asserted->bv_len;
2888
2889         /* ignore trailing 'Z' when comparing */
2890         int match = memcmp( value->bv_val, asserted->bv_val,
2891                 (v_len < av_len ? v_len : av_len) - 1 );
2892         if ( match == 0 ) match = v_len - av_len;
2893
2894         *matchp = match;
2895         return LDAP_SUCCESS;
2896 }
2897
2898 /* Index generation function */
2899 int generalizedTimeIndexer(
2900         slap_mask_t use,
2901         slap_mask_t flags,
2902         Syntax *syntax,
2903         MatchingRule *mr,
2904         struct berval *prefix,
2905         BerVarray values,
2906         BerVarray *keysp,
2907         void *ctx )
2908 {
2909         int i, j;
2910         BerVarray keys;
2911         char tmp[5];
2912         BerValue bvtmp; /* 40 bit index */
2913         struct lutil_tm tm;
2914         struct lutil_timet tt;
2915
2916         bvtmp.bv_len = sizeof(tmp);
2917         bvtmp.bv_val = tmp;
2918         for( i=0; values[i].bv_val != NULL; i++ ) {
2919                 /* just count them */
2920         }
2921
2922         /* we should have at least one value at this point */
2923         assert( i > 0 );
2924
2925         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2926
2927         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2928         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2929                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2930                 /* Use 40 bits of time for key */
2931                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2932                         lutil_tm2time( &tm, &tt );
2933                         tmp[0] = tt.tt_gsec & 0xff;
2934                         tmp[4] = tt.tt_sec & 0xff;
2935                         tt.tt_sec >>= 8;
2936                         tmp[3] = tt.tt_sec & 0xff;
2937                         tt.tt_sec >>= 8;
2938                         tmp[2] = tt.tt_sec & 0xff;
2939                         tt.tt_sec >>= 8;
2940                         tmp[1] = tt.tt_sec & 0xff;
2941                         
2942                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
2943                 }
2944         }
2945
2946         keys[j].bv_val = NULL;
2947         keys[j].bv_len = 0;
2948
2949         *keysp = keys;
2950
2951         return LDAP_SUCCESS;
2952 }
2953
2954 /* Index generation function */
2955 int generalizedTimeFilter(
2956         slap_mask_t use,
2957         slap_mask_t flags,
2958         Syntax *syntax,
2959         MatchingRule *mr,
2960         struct berval *prefix,
2961         void * assertedValue,
2962         BerVarray *keysp,
2963         void *ctx )
2964 {
2965         BerVarray keys;
2966         char tmp[5];
2967         BerValue bvtmp; /* 40 bit index */
2968         BerValue *value = (BerValue *) assertedValue;
2969         struct lutil_tm tm;
2970         struct lutil_timet tt;
2971         
2972         bvtmp.bv_len = sizeof(tmp);
2973         bvtmp.bv_val = tmp;
2974         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2975         /* Use 40 bits of time for key */
2976         if ( value->bv_val && value->bv_len >= 10 &&
2977                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
2978
2979                 lutil_tm2time( &tm, &tt );
2980                 tmp[0] = tt.tt_gsec & 0xff;
2981                 tmp[4] = tt.tt_sec & 0xff;
2982                 tt.tt_sec >>= 8;
2983                 tmp[3] = tt.tt_sec & 0xff;
2984                 tt.tt_sec >>= 8;
2985                 tmp[2] = tt.tt_sec & 0xff;
2986                 tt.tt_sec >>= 8;
2987                 tmp[1] = tt.tt_sec & 0xff;
2988
2989                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2990                 ber_dupbv_x(keys, &bvtmp, ctx );
2991                 keys[1].bv_val = NULL;
2992                 keys[1].bv_len = 0;
2993         } else {
2994                 keys = NULL;
2995         }
2996
2997         *keysp = keys;
2998
2999         return LDAP_SUCCESS;
3000 }
3001
3002 static int
3003 deliveryMethodValidate(
3004         Syntax *syntax,
3005         struct berval *val )
3006 {
3007 #undef LENOF
3008 #define LENOF(s) (sizeof(s)-1)
3009         struct berval tmp = *val;
3010         /*
3011      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3012          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3013          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3014          */
3015 again:
3016         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3017
3018         switch( tmp.bv_val[0] ) {
3019         case 'a':
3020         case 'A':
3021                 if(( tmp.bv_len >= LENOF("any") ) &&
3022                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3023                 {
3024                         tmp.bv_len -= LENOF("any");
3025                         tmp.bv_val += LENOF("any");
3026                         break;
3027                 }
3028                 return LDAP_INVALID_SYNTAX;
3029
3030         case 'm':
3031         case 'M':
3032                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3033                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3034                 {
3035                         tmp.bv_len -= LENOF("mhs");
3036                         tmp.bv_val += LENOF("mhs");
3037                         break;
3038                 }
3039                 return LDAP_INVALID_SYNTAX;
3040
3041         case 'p':
3042         case 'P':
3043                 if(( tmp.bv_len >= LENOF("physical") ) &&
3044                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3045                 {
3046                         tmp.bv_len -= LENOF("physical");
3047                         tmp.bv_val += LENOF("physical");
3048                         break;
3049                 }
3050                 return LDAP_INVALID_SYNTAX;
3051
3052         case 't':
3053         case 'T': /* telex or teletex or telephone */
3054                 if(( tmp.bv_len >= LENOF("telex") ) &&
3055                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3056                 {
3057                         tmp.bv_len -= LENOF("telex");
3058                         tmp.bv_val += LENOF("telex");
3059                         break;
3060                 }
3061                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3062                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3063                 {
3064                         tmp.bv_len -= LENOF("teletex");
3065                         tmp.bv_val += LENOF("teletex");
3066                         break;
3067                 }
3068                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3069                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3070                 {
3071                         tmp.bv_len -= LENOF("telephone");
3072                         tmp.bv_val += LENOF("telephone");
3073                         break;
3074                 }
3075                 return LDAP_INVALID_SYNTAX;
3076
3077         case 'g':
3078         case 'G': /* g3fax or g4fax */
3079                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3080                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3081                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3082                 {
3083                         tmp.bv_len -= LENOF("g3fax");
3084                         tmp.bv_val += LENOF("g3fax");
3085                         break;
3086                 }
3087                 return LDAP_INVALID_SYNTAX;
3088
3089         case 'i':
3090         case 'I':
3091                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3092                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3093                 {
3094                         tmp.bv_len -= LENOF("ia5");
3095                         tmp.bv_val += LENOF("ia5");
3096                         break;
3097                 }
3098                 return LDAP_INVALID_SYNTAX;
3099
3100         case 'v':
3101         case 'V':
3102                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3103                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3104                 {
3105                         tmp.bv_len -= LENOF("videotex");
3106                         tmp.bv_val += LENOF("videotex");
3107                         break;
3108                 }
3109                 return LDAP_INVALID_SYNTAX;
3110
3111         default:
3112                 return LDAP_INVALID_SYNTAX;
3113         }
3114
3115         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3116
3117         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3118                 tmp.bv_len++;
3119                 tmp.bv_val--;
3120         }
3121         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3122                 tmp.bv_len++;
3123                 tmp.bv_val--;
3124         } else {
3125                 return LDAP_INVALID_SYNTAX;
3126         }
3127         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3128                 tmp.bv_len++;
3129                 tmp.bv_val--;
3130         }
3131
3132         goto again;
3133 }
3134
3135 static int
3136 nisNetgroupTripleValidate(
3137         Syntax *syntax,
3138         struct berval *val )
3139 {
3140         char *p, *e;
3141         int commas = 0;
3142
3143         if ( BER_BVISEMPTY( val ) ) {
3144                 return LDAP_INVALID_SYNTAX;
3145         }
3146
3147         p = (char *)val->bv_val;
3148         e = p + val->bv_len;
3149
3150         if ( *p != '(' /*')'*/ ) {
3151                 return LDAP_INVALID_SYNTAX;
3152         }
3153
3154         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3155                 if ( *p == ',' ) {
3156                         commas++;
3157                         if ( commas > 2 ) {
3158                                 return LDAP_INVALID_SYNTAX;
3159                         }
3160
3161                 } else if ( !AD_CHAR( *p ) ) {
3162                         return LDAP_INVALID_SYNTAX;
3163                 }
3164         }
3165
3166         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3167                 return LDAP_INVALID_SYNTAX;
3168         }
3169
3170         p++;
3171
3172         if (p != e) {
3173                 return LDAP_INVALID_SYNTAX;
3174         }
3175
3176         return LDAP_SUCCESS;
3177 }
3178
3179 static int
3180 bootParameterValidate(
3181         Syntax *syntax,
3182         struct berval *val )
3183 {
3184         char *p, *e;
3185
3186         if ( BER_BVISEMPTY( val ) ) {
3187                 return LDAP_INVALID_SYNTAX;
3188         }
3189
3190         p = (char *)val->bv_val;
3191         e = p + val->bv_len;
3192
3193         /* key */
3194         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3195                 if ( !AD_CHAR( *p ) ) {
3196                         return LDAP_INVALID_SYNTAX;
3197                 }
3198         }
3199
3200         if ( *p != '=' ) {
3201                 return LDAP_INVALID_SYNTAX;
3202         }
3203
3204         /* server */
3205         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3206                 if ( !AD_CHAR( *p ) ) {
3207                         return LDAP_INVALID_SYNTAX;
3208                 }
3209         }
3210
3211         if ( *p != ':' ) {
3212                 return LDAP_INVALID_SYNTAX;
3213         }
3214
3215         /* path */
3216         for ( p++; p < e; p++ ) {
3217                 if ( !SLAP_PRINTABLE( *p ) ) {
3218                         return LDAP_INVALID_SYNTAX;
3219                 }
3220         }
3221
3222         return LDAP_SUCCESS;
3223 }
3224
3225 static int
3226 firstComponentNormalize(
3227         slap_mask_t usage,
3228         Syntax *syntax,
3229         MatchingRule *mr,
3230         struct berval *val,
3231         struct berval *normalized,
3232         void *ctx )
3233 {
3234         int rc;
3235         struct berval comp;
3236         ber_len_t len;
3237
3238         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3239                 ber_dupbv_x( normalized, val, ctx );
3240                 return LDAP_SUCCESS;
3241         }
3242
3243         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3244
3245         if( val->bv_val[0] != '(' /*')'*/ &&
3246                 val->bv_val[0] != '{' /*'}'*/ )
3247         {
3248                 return LDAP_INVALID_SYNTAX;
3249         }
3250
3251         /* trim leading white space */
3252         for( len=1;
3253                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3254                 len++ )
3255         {
3256                 /* empty */
3257         }
3258
3259         /* grab next word */
3260         comp.bv_val = &val->bv_val[len];
3261         len = val->bv_len - len;
3262         for( comp.bv_len = 0;
3263                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3264                 comp.bv_len++ )
3265         {
3266                 /* empty */
3267         }
3268
3269         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3270                 rc = numericoidValidate( NULL, &comp );
3271         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3272                 rc = integerValidate( NULL, &comp );
3273         } else {
3274                 rc = LDAP_INVALID_SYNTAX;
3275         }
3276         
3277
3278         if( rc == LDAP_SUCCESS ) {
3279                 ber_dupbv_x( normalized, &comp, ctx );
3280         }
3281
3282         return rc;
3283 }
3284
3285
3286 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3287 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3288
3289 static slap_syntax_defs_rec syntax_defs[] = {
3290         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3291                 X_BINARY X_NOT_H_R ")",
3292                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3293         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3294                 0, NULL, NULL},
3295         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3296                 0, NULL, NULL},
3297         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3298                 X_NOT_H_R ")",
3299                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3300         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3301                 X_NOT_H_R ")",
3302                 SLAP_SYNTAX_BER, berValidate, NULL},
3303         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3304                 0, bitStringValidate, NULL },
3305         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3306                 0, booleanValidate, NULL},
3307         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3308                 X_BINARY X_NOT_H_R ")",
3309                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3310         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3311                 X_BINARY X_NOT_H_R ")",
3312                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3313         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3314                 X_BINARY X_NOT_H_R ")",
3315                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3316         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3317                 0, countryStringValidate, NULL},
3318         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3319                 0, dnValidate, dnPretty},
3320         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3321                 0, rdnValidate, rdnPretty},
3322 #ifdef LDAP_COMP_MATCH
3323         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3324                 0, allComponentsValidate, NULL},
3325         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3326                 0, componentFilterValidate, NULL},
3327 #endif
3328         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3329                 0, NULL, NULL},
3330         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3331                 0, deliveryMethodValidate, NULL},
3332         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3333                 0, UTF8StringValidate, NULL},
3334         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3335                 0, NULL, NULL},
3336         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3337                 0, NULL, NULL},
3338         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3339                 0, NULL, NULL},
3340         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3341                 0, NULL, NULL},
3342         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3343                 0, NULL, NULL},
3344         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3345                 0, printablesStringValidate, NULL},
3346         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3347                 SLAP_SYNTAX_BLOB, NULL, NULL},
3348         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3349                 0, generalizedTimeValidate, NULL},
3350         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3351                 0, NULL, NULL},
3352         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3353                 0, IA5StringValidate, NULL},
3354         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3355                 0, integerValidate, NULL},
3356         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3357                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3358         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3359                 0, NULL, NULL},
3360         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3361                 0, NULL, NULL},
3362         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3363                 0, NULL, NULL},
3364         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3365                 0, NULL, NULL},
3366         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3367                 0, NULL, NULL},
3368         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3369                 0, nameUIDValidate, nameUIDPretty },
3370         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3371                 0, NULL, NULL},
3372         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3373                 0, numericStringValidate, NULL},
3374         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3375                 0, NULL, NULL},
3376         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3377                 0, numericoidValidate, NULL},
3378         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3379                 0, IA5StringValidate, NULL},
3380         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3381                 0, blobValidate, NULL},
3382         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3383                 0, UTF8StringValidate, NULL},
3384         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3385                 0, NULL, NULL},
3386         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3387                 0, NULL, NULL},
3388         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3389                 0, printableStringValidate, NULL},
3390         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3391 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3392                 0, subtreeSpecificationValidate, NULL},
3393         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3394                 X_BINARY X_NOT_H_R ")",
3395                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3396         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3397                 0, printableStringValidate, NULL},
3398         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3399                 0, NULL, NULL},
3400         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3401                 0, printablesStringValidate, NULL},
3402 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3403         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3404                 0, utcTimeValidate, NULL},
3405 #endif
3406         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3407                 0, NULL, NULL},
3408         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3409                 0, NULL, NULL},
3410         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3411                 0, NULL, NULL},
3412         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3413                 0, NULL, NULL},
3414         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3415                 0, NULL, NULL},
3416
3417         /* RFC 2307 NIS Syntaxes */
3418         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3419                 0, nisNetgroupTripleValidate, NULL},
3420         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3421                 0, bootParameterValidate, NULL},
3422
3423         /* From PKIX *//* This OID is not published yet. */
3424         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3425                 SLAP_SYNTAX_HIDE,
3426                 serialNumberAndIssuerValidate,
3427                 serialNumberAndIssuerPretty},
3428
3429 #ifdef SLAPD_ACI_ENABLED
3430         /* OpenLDAP Experimental Syntaxes */
3431         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
3432                 SLAP_SYNTAX_HIDE,
3433                 OpenLDAPaciValidate,
3434                 OpenLDAPaciPretty},
3435 #endif
3436
3437 #ifdef SLAPD_AUTHPASSWD
3438         /* needs updating */
3439         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3440                 SLAP_SYNTAX_HIDE, NULL, NULL},
3441 #endif
3442
3443         {"( 1.3.6.1.4.1.4203.666.2.6 DESC 'UUID' )",
3444                 SLAP_SYNTAX_HIDE, UUIDValidate, NULL},
3445
3446         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3447                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3448
3449         /* OpenLDAP Void Syntax */
3450         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3451                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3452
3453 #ifdef SLAP_AUTHZ_SYNTAX
3454         /* FIXME: OID is unused, but not registered yet */
3455         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
3456                 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
3457 #endif /* SLAP_AUTHZ_SYNTAX */
3458
3459         {NULL, 0, NULL, NULL}
3460 };
3461
3462 char *certificateExactMatchSyntaxes[] = {
3463         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3464         NULL
3465 };
3466 #ifdef LDAP_COMP_MATCH
3467 char *componentFilterMatchSyntaxes[] = {
3468         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3469         NULL
3470 };
3471 #endif
3472 char *directoryStringSyntaxes[] = {
3473         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3474         NULL
3475 };
3476 char *integerFirstComponentMatchSyntaxes[] = {
3477         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3478         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3479         NULL
3480 };
3481 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3482         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3483         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3484         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3485         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3486         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3487         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3488         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3489         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3490         NULL
3491 };
3492
3493 /*
3494  * Other matching rules in X.520 that we do not use (yet):
3495  *
3496  * 2.5.13.25    uTCTimeMatch
3497  * 2.5.13.26    uTCTimeOrderingMatch
3498  * 2.5.13.31*   directoryStringFirstComponentMatch
3499  * 2.5.13.32*   wordMatch
3500  * 2.5.13.33*   keywordMatch
3501  * 2.5.13.36    certificatePairExactMatch
3502  * 2.5.13.37    certificatePairMatch
3503  * 2.5.13.38    certificateListExactMatch
3504  * 2.5.13.39    certificateListMatch
3505  * 2.5.13.40    algorithmIdentifierMatch
3506  * 2.5.13.41*   storedPrefixMatch
3507  * 2.5.13.42    attributeCertificateMatch
3508  * 2.5.13.43    readerAndKeyIDMatch
3509  * 2.5.13.44    attributeIntegrityMatch
3510  *
3511  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3512  */
3513 static slap_mrule_defs_rec mrule_defs[] = {
3514         /*
3515          * EQUALITY matching rules must be listed after associated APPROX
3516          * matching rules.  So, we list all APPROX matching rules first.
3517          */
3518         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3519                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3520                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3521                 NULL, NULL, directoryStringApproxMatch,
3522                 directoryStringApproxIndexer, directoryStringApproxFilter,
3523                 NULL},
3524
3525         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3526                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3527                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3528                 NULL, NULL, IA5StringApproxMatch,
3529                 IA5StringApproxIndexer, IA5StringApproxFilter,
3530                 NULL},
3531
3532         /*
3533          * Other matching rules
3534          */
3535         
3536         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3537                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3538                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3539                 NULL, NULL, octetStringMatch,
3540                 octetStringIndexer, octetStringFilter,
3541                 NULL },
3542
3543         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3544                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3545                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3546                 NULL, dnNormalize, dnMatch,
3547                 octetStringIndexer, octetStringFilter,
3548                 NULL },
3549
3550         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3551                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3552                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3553                 NULL, dnNormalize, dnRelativeMatch,
3554                 NULL, NULL,
3555                 NULL },
3556
3557         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3558                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3559                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3560                 NULL, dnNormalize, dnRelativeMatch,
3561                 NULL, NULL,
3562                 NULL },
3563
3564         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3565                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3566                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3567                 NULL, dnNormalize, dnRelativeMatch,
3568                 NULL, NULL,
3569                 NULL },
3570
3571         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3572                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3573                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3574                 NULL, dnNormalize, dnRelativeMatch,
3575                 NULL, NULL,
3576                 NULL },
3577
3578         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3579                 "SYNTAX 1.2.36.79672281.1.5.0 )",
3580                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3581                 NULL, rdnNormalize, rdnMatch,
3582                 octetStringIndexer, octetStringFilter,
3583                 NULL },
3584
3585 #ifdef LDAP_COMP_MATCH
3586         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3587                 "SYNTAX 1.2.36.79672281.1.5.2 )",
3588                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3589                 NULL, NULL , componentFilterMatch,
3590                 octetStringIndexer, octetStringFilter,
3591                 NULL },
3592
3593         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3594                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3595                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3596                 NULL, NULL , allComponentsMatch,
3597                 octetStringIndexer, octetStringFilter,
3598                 NULL },
3599
3600         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3601                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3602                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3603                 NULL, NULL , directoryComponentsMatch,
3604                 octetStringIndexer, octetStringFilter,
3605                 NULL },
3606 #endif
3607
3608         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3609                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3610                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3611                 NULL, UTF8StringNormalize, octetStringMatch,
3612                 octetStringIndexer, octetStringFilter,
3613                 directoryStringApproxMatchOID },
3614
3615         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3616                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3617                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3618                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3619                 NULL, NULL,
3620                 "caseIgnoreMatch" },
3621
3622         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3623                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3624                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3625                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3626                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3627                 "caseIgnoreMatch" },
3628
3629         {"( 2.5.13.5 NAME 'caseExactMatch' "
3630                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3631                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3632                 NULL, UTF8StringNormalize, octetStringMatch,
3633                 octetStringIndexer, octetStringFilter,
3634                 directoryStringApproxMatchOID },
3635
3636         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3637                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3638                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3639                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3640                 NULL, NULL,
3641                 "caseExactMatch" },
3642
3643         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3644                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3645                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3646                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3647                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3648                 "caseExactMatch" },
3649
3650         {"( 2.5.13.8 NAME 'numericStringMatch' "
3651                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3652                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3653                 NULL, numericStringNormalize, octetStringMatch,
3654                 octetStringIndexer, octetStringFilter,
3655                 NULL },
3656
3657         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3658                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3659                 SLAP_MR_ORDERING, NULL,
3660                 NULL, numericStringNormalize, octetStringOrderingMatch,
3661                 NULL, NULL,
3662                 "numericStringMatch" },
3663
3664         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3665                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3666                 SLAP_MR_SUBSTR, NULL,
3667                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3668                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3669                 "numericStringMatch" },
3670
3671         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3672                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3673                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3674                 NULL, NULL, NULL, NULL, NULL, NULL },
3675
3676         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3677                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3678                 SLAP_MR_SUBSTR, NULL,
3679                 NULL, NULL, NULL, NULL, NULL,
3680                 "caseIgnoreListMatch" },
3681
3682         {"( 2.5.13.13 NAME 'booleanMatch' "
3683                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3684                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3685                 NULL, NULL, booleanMatch,
3686                 octetStringIndexer, octetStringFilter,
3687                 NULL },
3688
3689         {"( 2.5.13.14 NAME 'integerMatch' "
3690                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3691                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3692                 NULL, NULL, integerMatch,
3693                 octetStringIndexer, octetStringFilter,
3694                 NULL },
3695
3696         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3697                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3698                 SLAP_MR_ORDERING, NULL,
3699                 NULL, NULL, integerMatch,
3700                 NULL, NULL,
3701                 "integerMatch" },
3702
3703         {"( 2.5.13.16 NAME 'bitStringMatch' "
3704                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3705                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3706                 NULL, NULL, octetStringMatch,
3707                 octetStringIndexer, octetStringFilter,
3708                 NULL },
3709
3710         {"( 2.5.13.17 NAME 'octetStringMatch' "
3711                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3712                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3713                 NULL, NULL, octetStringMatch,
3714                 octetStringIndexer, octetStringFilter,
3715                 NULL },
3716
3717         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3718                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3719                 SLAP_MR_ORDERING, NULL,
3720                 NULL, NULL, octetStringOrderingMatch,
3721                 NULL, NULL,
3722                 "octetStringMatch" },
3723
3724         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3725                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3726                 SLAP_MR_SUBSTR, NULL,
3727                 NULL, NULL, octetStringSubstringsMatch,
3728                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3729                 "octetStringMatch" },
3730
3731         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3732                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3733                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3734                 NULL,
3735                 telephoneNumberNormalize, octetStringMatch,
3736                 octetStringIndexer, octetStringFilter,
3737                 NULL },
3738
3739         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3740                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3741                 SLAP_MR_SUBSTR, NULL,
3742                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3743                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3744                 "telephoneNumberMatch" },
3745
3746         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3747                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3748                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3749                 NULL, NULL, NULL, NULL, NULL, NULL },
3750
3751         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3752                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3753                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3754                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3755                 uniqueMemberIndexer, uniqueMemberFilter,
3756                 NULL },
3757
3758         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3759                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3760                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3761                 NULL, NULL, NULL, NULL, NULL, NULL },
3762
3763         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3764                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3765                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3766                 NULL, generalizedTimeNormalize, octetStringMatch,
3767                 generalizedTimeIndexer, generalizedTimeFilter,
3768                 NULL },
3769
3770         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3771                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3772                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3773                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3774                 NULL, NULL,
3775                 "generalizedTimeMatch" },
3776
3777         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3778                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3779                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3780                         integerFirstComponentMatchSyntaxes,
3781                 NULL, firstComponentNormalize, integerMatch,
3782                 octetStringIndexer, octetStringFilter,
3783                 NULL },
3784
3785         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3786                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3787                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3788                         objectIdentifierFirstComponentMatchSyntaxes,
3789                 NULL, firstComponentNormalize, octetStringMatch,
3790                 octetStringIndexer, octetStringFilter,
3791                 NULL },
3792
3793         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3794                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3795                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3796 #ifdef HAVE_TLS
3797                 NULL, certificateExactNormalize, octetStringMatch,
3798                 octetStringIndexer, octetStringFilter,
3799 #else
3800                 NULL, NULL, NULL, NULL, NULL,
3801 #endif
3802                 NULL },
3803
3804         {"( 2.5.13.35 NAME 'certificateMatch' "
3805                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3806                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3807 #ifdef HAVE_TLS
3808                 NULL, NULL, octetStringMatch,
3809                 octetStringIndexer, octetStringFilter,
3810 #else
3811                 NULL, NULL, NULL, NULL, NULL,
3812 #endif
3813                 NULL },
3814
3815         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3816                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3817                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3818                 NULL, IA5StringNormalize, octetStringMatch,
3819                 octetStringIndexer, octetStringFilter,
3820                 IA5StringApproxMatchOID },
3821
3822         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3823                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3824                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3825                 NULL, IA5StringNormalize, octetStringMatch,
3826                 octetStringIndexer, octetStringFilter,
3827                 IA5StringApproxMatchOID },
3828
3829         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3830                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3831                 SLAP_MR_SUBSTR, NULL,
3832                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3833                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3834                 "caseIgnoreIA5Match" },
3835
3836         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3837                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3838                 SLAP_MR_SUBSTR, NULL,
3839                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3840                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3841                 "caseExactIA5Match" },
3842
3843 #ifdef SLAPD_AUTHPASSWD
3844         /* needs updating */
3845         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3846                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3847                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3848                 NULL, NULL, authPasswordMatch,
3849                 NULL, NULL,
3850                 NULL},
3851 #endif
3852
3853 #ifdef SLAPD_ACI_ENABLED
3854         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3855                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3856                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3857                 NULL, OpenLDAPaciNormalize, OpenLDAPaciMatch,
3858                 NULL, NULL,
3859                 NULL},
3860 #endif
3861
3862         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3863                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3864                 SLAP_MR_EXT, NULL,
3865                 NULL, NULL, integerBitAndMatch,
3866                 NULL, NULL,
3867                 "integerMatch" },
3868
3869         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3870                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3871                 SLAP_MR_EXT, NULL,
3872                 NULL, NULL, integerBitOrMatch,
3873                 NULL, NULL,
3874                 "integerMatch" },
3875
3876         {"( 1.3.6.1.4.1.4203.666.4.6 NAME 'UUIDMatch' "
3877                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3878                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3879                 NULL, UUIDNormalize, octetStringMatch,
3880                 octetStringIndexer, octetStringFilter,
3881                 NULL},
3882
3883         {"( 1.3.6.1.4.1.4203.666.4.7 NAME 'UUIDOrderingMatch' "
3884                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3885                 SLAP_MR_HIDE | SLAP_MR_ORDERING, NULL,
3886                 NULL, UUIDNormalize, octetStringOrderingMatch,
3887                 octetStringIndexer, octetStringFilter,
3888                 "UUIDMatch"},
3889
3890         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3891                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3892                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3893                 NULL, NULL, csnMatch,
3894                 csnIndexer, csnFilter,
3895                 NULL},
3896
3897         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3898                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3899                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3900                 NULL, NULL, csnOrderingMatch,
3901                 NULL, NULL,
3902                 "CSNMatch" },
3903
3904 #ifdef SLAP_AUTHZ_SYNTAX
3905         /* FIXME: OID is unused, but not registered yet */
3906         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
3907                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
3908                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3909                 NULL, authzNormalize, authzMatch,
3910                 NULL, NULL,
3911                 NULL},
3912 #endif /* SLAP_AUTHZ_SYNTAX */
3913
3914         {NULL, SLAP_MR_NONE, NULL,
3915                 NULL, NULL, NULL, NULL, NULL,
3916                 NULL }
3917 };
3918
3919 int
3920 slap_schema_init( void )
3921 {
3922         int             res;
3923         int             i;
3924
3925         /* we should only be called once (from main) */
3926         assert( schema_init_done == 0 );
3927
3928         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3929                 res = register_syntax( &syntax_defs[i] );
3930
3931                 if ( res ) {
3932                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3933                                  syntax_defs[i].sd_desc );
3934                         return LDAP_OTHER;
3935                 }
3936         }
3937
3938         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3939                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3940                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3941                 {
3942                         fprintf( stderr,
3943                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3944                                  mrule_defs[i].mrd_desc );
3945                         continue;
3946                 }
3947
3948                 res = register_matching_rule( &mrule_defs[i] );
3949
3950                 if ( res ) {
3951                         fprintf( stderr,
3952                                 "slap_schema_init: Error registering matching rule %s\n",
3953                                  mrule_defs[i].mrd_desc );
3954                         return LDAP_OTHER;
3955                 }
3956         }
3957
3958         res = slap_schema_load();
3959         schema_init_done = 1;
3960         return res;
3961 }
3962
3963 void
3964 schema_destroy( void )
3965 {
3966         oidm_destroy();
3967         oc_destroy();
3968         at_destroy();
3969         mr_destroy();
3970         mru_destroy();
3971         syn_destroy();
3972
3973         ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
3974         ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
3975 }