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