]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
schema_destroy(): Handle failed slap_schema_init()
[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(LLONG_MAX) \
2357         && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2358 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2359 # define SLAP_LONG_MAX       LLONG_MAX
2360 # define SLAP_LONG_MIN       LLONG_MIN
2361 # define SLAP_LONG           long long
2362 #else
2363 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2364 # define SLAP_LONG_MAX       LONG_MAX
2365 # define SLAP_LONG_MIN       LONG_MIN
2366 # define SLAP_LONG           long
2367 #endif /* HAVE_STRTOLL ... */
2368
2369 static int
2370 integerBitAndMatch(
2371         int *matchp,
2372         slap_mask_t flags,
2373         Syntax *syntax,
2374         MatchingRule *mr,
2375         struct berval *value,
2376         void *assertedValue )
2377 {
2378         SLAP_LONG lValue, lAssertedValue;
2379
2380         /* safe to assume integers are NUL terminated? */
2381         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2382         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2383                 errno == ERANGE )
2384         {
2385                 return LDAP_CONSTRAINT_VIOLATION;
2386         }
2387
2388         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2389                 NULL, 10);
2390         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2391                 errno == ERANGE )
2392         {
2393                 return LDAP_CONSTRAINT_VIOLATION;
2394         }
2395
2396         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2397         return LDAP_SUCCESS;
2398 }
2399
2400 static int
2401 integerBitOrMatch(
2402         int *matchp,
2403         slap_mask_t flags,
2404         Syntax *syntax,
2405         MatchingRule *mr,
2406         struct berval *value,
2407         void *assertedValue )
2408 {
2409         SLAP_LONG lValue, lAssertedValue;
2410
2411         /* safe to assume integers are NUL terminated? */
2412         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2413         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2414                 errno == ERANGE )
2415         {
2416                 return LDAP_CONSTRAINT_VIOLATION;
2417         }
2418
2419         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2420                 NULL, 10);
2421         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2422                 errno == ERANGE )
2423         {
2424                 return LDAP_CONSTRAINT_VIOLATION;
2425         }
2426
2427         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2428         return LDAP_SUCCESS;
2429 }
2430
2431 static int
2432 serialNumberAndIssuerValidate(
2433         Syntax *syntax,
2434         struct berval *in )
2435 {
2436         int rc;
2437         ber_len_t n;
2438         struct berval sn, i;
2439
2440         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2441                 in->bv_val, 0, 0 );
2442
2443         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2444
2445         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2446                 /* Parse old format */
2447                 i.bv_val = ber_bvchr( in, '$' );
2448                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2449
2450                 sn.bv_val = in->bv_val;
2451                 sn.bv_len = i.bv_val - in->bv_val;
2452
2453                 i.bv_val++;
2454                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2455
2456                 /* eat leading zeros */
2457                 for( n=0; n < (sn.bv_len-1); n++ ) {
2458                         if( sn.bv_val[n] != '0' ) break;
2459                 }
2460                 sn.bv_val += n;
2461                 sn.bv_len -= n;
2462
2463                 for( n=0; n < sn.bv_len; n++ ) {
2464                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2465                 }
2466
2467         } else {
2468                 /* Parse GSER format */ 
2469                 int havesn=0,haveissuer=0;
2470                 struct berval x = *in;
2471                 x.bv_val++;
2472                 x.bv_len-=2;
2473
2474                 /* eat leading spaces */
2475                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2476                         /* empty */;
2477                 }
2478
2479                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2480                         return LDAP_INVALID_SYNTAX;
2481                 }
2482
2483                 /* should be at issuer or serialNumber NamedValue */
2484                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2485                         /* parse issuer */
2486                         x.bv_val += STRLENOF("issuer");
2487                         x.bv_len -= STRLENOF("issuer");
2488
2489                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2490                         x.bv_val++; x.bv_len--;
2491
2492                         /* eat leading spaces */
2493                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2494                                 /* empty */;
2495                         }
2496                         
2497                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2498                         x.bv_val++; x.bv_len--;
2499
2500                         i.bv_val = x.bv_val;
2501                         i.bv_len = 0;
2502
2503                         for( ; i.bv_len < x.bv_len; ) {
2504                                 if ( i.bv_val[i.bv_len] != '"' ) {
2505                                         i.bv_len++;
2506                                         continue;
2507                                 }
2508                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2509                                         /* double dquote */
2510                                         i.bv_len+=2;
2511                                         continue;
2512                                 }
2513                                 break;
2514                         }
2515                         x.bv_val += i.bv_len+1;
2516                         x.bv_len -= i.bv_len+1;
2517
2518                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2519                                 return LDAP_INVALID_SYNTAX;
2520                         }
2521
2522                         haveissuer++;
2523
2524                 } else if( strncasecmp( x.bv_val, "serialNumber",
2525                         STRLENOF("serialNumber")) == 0 )
2526                 {
2527                         /* parse serialNumber */
2528                         int neg=0;
2529                         x.bv_val += STRLENOF("serialNumber");
2530                         x.bv_len -= STRLENOF("serialNumber");
2531
2532                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2533                         x.bv_val++; x.bv_len--;
2534
2535                         /* eat leading spaces */
2536                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2537                                 /* empty */;
2538                         }
2539                         
2540                         sn.bv_val = x.bv_val;
2541                         sn.bv_len = 0;
2542
2543                         if( sn.bv_val[0] == '-' ) {
2544                                 neg++;
2545                                 sn.bv_len++;
2546                         }
2547
2548                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2549                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2550                         }
2551
2552                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2553                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2554                                 return LDAP_INVALID_SYNTAX;
2555                         }
2556
2557                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2558
2559                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2560                                 return LDAP_INVALID_SYNTAX;
2561                         }
2562
2563                         havesn++;
2564
2565                 } else return LDAP_INVALID_SYNTAX;
2566
2567                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2568                 x.bv_val++; x.bv_len--;
2569
2570                 /* eat spaces */
2571                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2572                         /* empty */;
2573                 }
2574
2575                 /* should be at remaining NamedValue */
2576                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2577                         STRLENOF("issuer" )) == 0 ))
2578                 {
2579                         /* parse issuer */
2580                         x.bv_val += STRLENOF("issuer");
2581                         x.bv_len -= STRLENOF("issuer");
2582
2583                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2584                         x.bv_val++; x.bv_len--;
2585
2586                         /* eat leading spaces */
2587                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2588                                  /* empty */;
2589                         }
2590                         
2591                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2592                         x.bv_val++; x.bv_len--;
2593
2594                         i.bv_val = x.bv_val;
2595                         i.bv_len = 0;
2596
2597                         for( ; i.bv_len < x.bv_len; ) {
2598                                 if ( i.bv_val[i.bv_len] != '"' ) {
2599                                         i.bv_len++;
2600                                         continue;
2601                                 }
2602                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2603                                         /* double dquote */
2604                                         i.bv_len+=2;
2605                                         continue;
2606                                 }
2607                                 break;
2608                         }
2609                         x.bv_val += i.bv_len+1;
2610                         x.bv_len -= i.bv_len+1;
2611
2612                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2613                         STRLENOF("serialNumber")) == 0 ))
2614                 {
2615                         /* parse serialNumber */
2616                         int neg=0;
2617                         x.bv_val += STRLENOF("serialNumber");
2618                         x.bv_len -= STRLENOF("serialNumber");
2619
2620                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2621                         x.bv_val++; x.bv_len--;
2622
2623                         /* eat leading spaces */
2624                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2625                                 /* empty */;
2626                         }
2627                         
2628                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2629                         x.bv_val++; x.bv_len--;
2630
2631                         sn.bv_val = x.bv_val;
2632                         sn.bv_len = 0;
2633
2634                         if( sn.bv_val[0] == '-' ) {
2635                                 neg++;
2636                                 sn.bv_len++;
2637                         }
2638
2639                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2640                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2641                         }
2642
2643                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2644                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2645                                 return LDAP_INVALID_SYNTAX;
2646                         }
2647
2648                         x.bv_val += sn.bv_len;
2649                         x.bv_len -= sn.bv_len;
2650
2651                 } else return LDAP_INVALID_SYNTAX;
2652
2653                 /* eat trailing spaces */
2654                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2655                         /* empty */;
2656                 }
2657
2658                 /* should have no characters left... */
2659                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2660         }
2661
2662         /* validate DN -- doesn't handle double dquote */ 
2663         rc = dnValidate( NULL, &i );
2664         if( rc ) return LDAP_INVALID_SYNTAX;
2665
2666         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2667                 in->bv_val, 0, 0 );
2668         return LDAP_SUCCESS;
2669 }
2670
2671 int
2672 serialNumberAndIssuerPretty(
2673         Syntax *syntax,
2674         struct berval *in,
2675         struct berval *out,
2676         void *ctx )
2677 {
2678         int rc;
2679         ber_len_t n;
2680         struct berval sn, i, ni;
2681
2682         assert( in != NULL );
2683         assert( out != NULL );
2684
2685         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2686                 in->bv_val, 0, 0 );
2687
2688         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2689
2690         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2691                 /* Parse old format */
2692                 i.bv_val = ber_bvchr( in, '$' );
2693                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2694
2695                 sn.bv_val = in->bv_val;
2696                 sn.bv_len = i.bv_val - in->bv_val;
2697
2698                 i.bv_val++;
2699                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2700
2701                 /* eat leading zeros */
2702                 for( n=0; n < (sn.bv_len-1); n++ ) {
2703                         if( sn.bv_val[n] != '0' ) break;
2704                 }
2705                 sn.bv_val += n;
2706                 sn.bv_len -= n;
2707
2708                 for( n=0; n < sn.bv_len; n++ ) {
2709                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2710                 }
2711
2712         } else {
2713                 /* Parse GSER format */ 
2714                 int havesn=0,haveissuer=0;
2715                 struct berval x = *in;
2716                 x.bv_val++;
2717                 x.bv_len-=2;
2718
2719                 /* eat leading spaces */
2720                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2721                         /* empty */;
2722                 }
2723
2724                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2725                         return LDAP_INVALID_SYNTAX;
2726                 }
2727
2728                 /* should be at issuer or serialNumber NamedValue */
2729                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2730                         /* parse issuer */
2731                         x.bv_val += STRLENOF("issuer");
2732                         x.bv_len -= STRLENOF("issuer");
2733
2734                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2735                         x.bv_val++; x.bv_len--;
2736
2737                         /* eat leading spaces */
2738                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2739                                 /* empty */;
2740                         }
2741                         
2742                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2743                         x.bv_val++; x.bv_len--;
2744
2745                         i.bv_val = x.bv_val;
2746                         i.bv_len = 0;
2747
2748                         for( ; i.bv_len < x.bv_len; ) {
2749                                 if ( i.bv_val[i.bv_len] != '"' ) {
2750                                         i.bv_len++;
2751                                         continue;
2752                                 }
2753                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2754                                         /* double dquote */
2755                                         i.bv_len+=2;
2756                                         continue;
2757                                 }
2758                                 break;
2759                         }
2760                         x.bv_val += i.bv_len+1;
2761                         x.bv_len -= i.bv_len+1;
2762
2763                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2764                                 return LDAP_INVALID_SYNTAX;
2765                         }
2766
2767                         haveissuer++;
2768
2769                 } else if( strncasecmp( x.bv_val, "serialNumber",
2770                         STRLENOF("serialNumber")) == 0 )
2771                 {
2772                         /* parse serialNumber */
2773                         int neg=0;
2774                         x.bv_val += STRLENOF("serialNumber");
2775                         x.bv_len -= STRLENOF("serialNumber");
2776
2777                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2778                         x.bv_val++; x.bv_len--;
2779
2780                         /* eat leading spaces */
2781                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2782                                 /* empty */;
2783                         }
2784                         
2785                         sn.bv_val = x.bv_val;
2786                         sn.bv_len = 0;
2787
2788                         if( sn.bv_val[0] == '-' ) {
2789                                 neg++;
2790                                 sn.bv_len++;
2791                         }
2792
2793                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2794                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2795                         }
2796
2797                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2798                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2799                                 return LDAP_INVALID_SYNTAX;
2800                         }
2801
2802                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2803
2804                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2805                                 return LDAP_INVALID_SYNTAX;
2806                         }
2807
2808                         havesn++;
2809
2810                 } else return LDAP_INVALID_SYNTAX;
2811
2812                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2813                 x.bv_val++; x.bv_len--;
2814
2815                 /* eat spaces */
2816                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2817                         /* empty */;
2818                 }
2819
2820                 /* should be at remaining NamedValue */
2821                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2822                         STRLENOF("issuer" )) == 0 ))
2823                 {
2824                         /* parse issuer */
2825                         x.bv_val += STRLENOF("issuer");
2826                         x.bv_len -= STRLENOF("issuer");
2827
2828                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2829                         x.bv_val++; x.bv_len--;
2830
2831                         /* eat leading spaces */
2832                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2833                                  /* empty */;
2834                         }
2835                         
2836                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2837                         x.bv_val++; x.bv_len--;
2838
2839                         i.bv_val = x.bv_val;
2840                         i.bv_len = 0;
2841
2842                         for( ; i.bv_len < x.bv_len; ) {
2843                                 if ( i.bv_val[i.bv_len] != '"' ) {
2844                                         i.bv_len++;
2845                                         continue;
2846                                 }
2847                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2848                                         /* double dquote */
2849                                         i.bv_len+=2;
2850                                         continue;
2851                                 }
2852                                 break;
2853                         }
2854                         x.bv_val += i.bv_len+1;
2855                         x.bv_len -= i.bv_len+1;
2856
2857                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2858                         STRLENOF("serialNumber")) == 0 ))
2859                 {
2860                         /* parse serialNumber */
2861                         int neg=0;
2862                         x.bv_val += STRLENOF("serialNumber");
2863                         x.bv_len -= STRLENOF("serialNumber");
2864
2865                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2866                         x.bv_val++; x.bv_len--;
2867
2868                         /* eat leading spaces */
2869                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2870                                 /* empty */;
2871                         }
2872                         
2873                         sn.bv_val = x.bv_val;
2874                         sn.bv_len = 0;
2875
2876                         if( sn.bv_val[0] == '-' ) {
2877                                 neg++;
2878                                 sn.bv_len++;
2879                         }
2880
2881                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2882                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2883                         }
2884
2885                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2886                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2887                                 return LDAP_INVALID_SYNTAX;
2888                         }
2889
2890                         x.bv_val += sn.bv_len;
2891                         x.bv_len -= sn.bv_len;
2892
2893                 } else return LDAP_INVALID_SYNTAX;
2894
2895                 /* eat trailing spaces */
2896                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2897                         /* empty */;
2898                 }
2899
2900                 /* should have no characters left... */
2901                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2902
2903                 ber_dupbv_x( &ni, &i, ctx );
2904                 i = ni;
2905
2906                 /* need to handle double dquotes here */
2907         }
2908
2909         rc = dnPretty( syntax, &i, &ni, ctx );
2910
2911         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2912                 slap_sl_free( i.bv_val, ctx );
2913         }
2914
2915         if( rc ) return LDAP_INVALID_SYNTAX;
2916
2917         /* make room from sn + "$" */
2918         out->bv_len = STRLENOF("{ serialNumber , issuer \"\" }")
2919                 + sn.bv_len + ni.bv_len;
2920         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2921
2922         if( out->bv_val == NULL ) {
2923                 out->bv_len = 0;
2924                 slap_sl_free( ni.bv_val, ctx );
2925                 return LDAP_OTHER;
2926         }
2927
2928         n = 0;
2929         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
2930                 STRLENOF("{ serialNumber "));
2931         n = STRLENOF("{ serialNumber ");
2932
2933         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
2934         n += sn.bv_len;
2935
2936         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
2937         n += STRLENOF(", issuer \"");
2938
2939         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
2940         n += ni.bv_len;
2941
2942         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
2943         n += STRLENOF("\" }");
2944
2945         out->bv_val[n] = '\0';
2946
2947         assert( n == out->bv_len );
2948
2949         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2950                 out->bv_val, 0, 0 );
2951
2952         slap_sl_free( ni.bv_val, ctx );
2953
2954         return LDAP_SUCCESS; 
2955 }
2956
2957 /*
2958  * This routine is called by certificateExactNormalize when
2959  * certificateExactNormalize receives a search string instead of
2960  * a certificate. This routine checks if the search value is valid
2961  * and then returns the normalized value
2962  */
2963 static int
2964 serialNumberAndIssuerNormalize(
2965         slap_mask_t usage,
2966         Syntax *syntax,
2967         MatchingRule *mr,
2968         struct berval *in,
2969         struct berval *out,
2970         void *ctx )
2971 {
2972         int rc;
2973         ber_len_t n;
2974         struct berval sn, i, ni;
2975
2976         assert( in != NULL );
2977         assert( out != NULL );
2978
2979         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2980                 in->bv_val, 0, 0 );
2981
2982         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2983
2984         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2985                 /* Parse old format */
2986                 i.bv_val = ber_bvchr( in, '$' );
2987                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2988
2989                 sn.bv_val = in->bv_val;
2990                 sn.bv_len = i.bv_val - in->bv_val;
2991
2992                 i.bv_val++;
2993                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2994
2995                 /* eat leading zeros */
2996                 for( n=0; n < (sn.bv_len-1); n++ ) {
2997                         if( sn.bv_val[n] != '0' ) break;
2998                 }
2999                 sn.bv_val += n;
3000                 sn.bv_len -= n;
3001
3002                 for( n=0; n < sn.bv_len; n++ ) {
3003                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3004                 }
3005
3006         } else {
3007                 /* Parse GSER format */ 
3008                 int havesn=0,haveissuer=0;
3009                 struct berval x = *in;
3010                 x.bv_val++;
3011                 x.bv_len-=2;
3012
3013                 /* eat leading spaces */
3014                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3015                         /* empty */;
3016                 }
3017
3018                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
3019                         return LDAP_INVALID_SYNTAX;
3020                 }
3021
3022                 /* should be at issuer or serialNumber NamedValue */
3023                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
3024                         /* parse issuer */
3025                         x.bv_val += STRLENOF("issuer");
3026                         x.bv_len -= STRLENOF("issuer");
3027
3028                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3029                         x.bv_val++; x.bv_len--;
3030
3031                         /* eat leading spaces */
3032                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3033                                 /* empty */;
3034                         }
3035                         
3036                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3037                         x.bv_val++; x.bv_len--;
3038
3039                         i.bv_val = x.bv_val;
3040                         i.bv_len = 0;
3041
3042                         for( ; i.bv_len < x.bv_len; ) {
3043                                 if ( i.bv_val[i.bv_len] != '"' ) {
3044                                         i.bv_len++;
3045                                         continue;
3046                                 }
3047                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
3048                                         /* double dquote */
3049                                         i.bv_len+=2;
3050                                         continue;
3051                                 }
3052                                 break;
3053                         }
3054                         x.bv_val += i.bv_len+1;
3055                         x.bv_len -= i.bv_len+1;
3056
3057                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
3058                                 return LDAP_INVALID_SYNTAX;
3059                         }
3060
3061                         haveissuer++;
3062
3063                 } else if( strncasecmp( x.bv_val, "serialNumber",
3064                         STRLENOF("serialNumber")) == 0 )
3065                 {
3066                         /* parse serialNumber */
3067                         int neg=0;
3068                         x.bv_val += STRLENOF("serialNumber");
3069                         x.bv_len -= STRLENOF("serialNumber");
3070
3071                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3072                         x.bv_val++; x.bv_len--;
3073
3074                         /* eat leading spaces */
3075                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3076                                 /* empty */;
3077                         }
3078                         
3079                         sn.bv_val = x.bv_val;
3080                         sn.bv_len = 0;
3081
3082                         if( sn.bv_val[0] == '-' ) {
3083                                 neg++;
3084                                 sn.bv_len++;
3085                         }
3086
3087                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3088                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3089                         }
3090
3091                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3092                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3093                                 return LDAP_INVALID_SYNTAX;
3094                         }
3095
3096                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
3097
3098                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
3099                                 return LDAP_INVALID_SYNTAX;
3100                         }
3101
3102                         havesn++;
3103
3104                 } else return LDAP_INVALID_SYNTAX;
3105
3106                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
3107                 x.bv_val++; x.bv_len--;
3108
3109                 /* eat spaces */
3110                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3111                         /* empty */;
3112                 }
3113
3114                 /* should be at remaining NamedValue */
3115                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
3116                         STRLENOF("issuer" )) == 0 ))
3117                 {
3118                         /* parse issuer */
3119                         x.bv_val += STRLENOF("issuer");
3120                         x.bv_len -= STRLENOF("issuer");
3121
3122                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3123                         x.bv_val++; x.bv_len--;
3124
3125                         /* eat leading spaces */
3126                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3127                                  /* empty */;
3128                         }
3129                         
3130                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3131                         x.bv_val++; x.bv_len--;
3132
3133                         i.bv_val = x.bv_val;
3134                         i.bv_len = 0;
3135
3136                         for( ; i.bv_len < x.bv_len; ) {
3137                                 if ( i.bv_val[i.bv_len] != '"' ) {
3138                                         i.bv_len++;
3139                                         continue;
3140                                 }
3141                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
3142                                         /* double dquote */
3143                                         i.bv_len+=2;
3144                                         continue;
3145                                 }
3146                                 break;
3147                         }
3148                         x.bv_val += i.bv_len+1;
3149                         x.bv_len -= i.bv_len+1;
3150
3151                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
3152                         STRLENOF("serialNumber")) == 0 ))
3153                 {
3154                         /* parse serialNumber */
3155                         int neg=0;
3156                         x.bv_val += STRLENOF("serialNumber");
3157                         x.bv_len -= STRLENOF("serialNumber");
3158
3159                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3160                         x.bv_val++; x.bv_len--;
3161
3162                         /* eat leading spaces */
3163                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
3164                                 /* empty */;
3165                         }
3166                         
3167                         sn.bv_val = x.bv_val;
3168                         sn.bv_len = 0;
3169
3170                         if( sn.bv_val[0] == '-' ) {
3171                                 neg++;
3172                                 sn.bv_len++;
3173                         }
3174
3175                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3176                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3177                         }
3178
3179                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3180                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3181                                 return LDAP_INVALID_SYNTAX;
3182                         }
3183
3184                         x.bv_val += sn.bv_len;
3185                         x.bv_len -= sn.bv_len;
3186
3187                 } else return LDAP_INVALID_SYNTAX;
3188
3189                 /* eat trailing spaces */
3190                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3191                         /* empty */;
3192                 }
3193
3194                 /* should have no characters left... */
3195                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3196
3197                 ber_dupbv_x( &ni, &i, ctx );
3198                 i = ni;
3199
3200                 /* need to handle double dquotes here */
3201         }
3202
3203         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3204
3205         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3206                 slap_sl_free( i.bv_val, ctx );
3207         }
3208
3209         if( rc ) return LDAP_INVALID_SYNTAX;
3210
3211         /* make room from sn + "$" */
3212         out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3213                 + sn.bv_len + ni.bv_len;
3214         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3215
3216         if( out->bv_val == NULL ) {
3217                 out->bv_len = 0;
3218                 slap_sl_free( ni.bv_val, ctx );
3219                 return LDAP_OTHER;
3220         }
3221
3222         n = 0;
3223         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3224                 STRLENOF( "{ serialNumber " ));
3225         n = STRLENOF( "{ serialNumber " );
3226
3227         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3228         n += sn.bv_len;
3229
3230         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
3231         n += STRLENOF( ", issuer \"" );
3232
3233         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3234         n += ni.bv_len;
3235
3236         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3237         n += STRLENOF( "\" }" );
3238
3239         out->bv_val[n] = '\0';
3240
3241         assert( n == out->bv_len );
3242
3243         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3244                 out->bv_val, 0, 0 );
3245
3246         slap_sl_free( ni.bv_val, ctx );
3247
3248         return LDAP_SUCCESS;
3249 }
3250
3251 #ifdef HAVE_TLS
3252 static int
3253 certificateExactNormalize(
3254         slap_mask_t usage,
3255         Syntax *syntax,
3256         MatchingRule *mr,
3257         struct berval *val,
3258         struct berval *normalized,
3259         void *ctx )
3260 {
3261         int rc = LDAP_INVALID_SYNTAX;
3262         unsigned char *p;
3263         char *serial = NULL;
3264         ber_len_t seriallen;
3265         struct berval issuer_dn = BER_BVNULL;
3266         X509_NAME *name = NULL;
3267         ASN1_INTEGER *sn = NULL;
3268         X509 *xcert = NULL;
3269
3270         if( BER_BVISEMPTY( val ) ) goto done;
3271
3272         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3273                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3274         }
3275
3276         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3277
3278         p = (unsigned char *)val->bv_val;
3279         xcert = d2i_X509( NULL, &p, val->bv_len);
3280         if( xcert == NULL ) goto done;
3281
3282         sn=X509_get_serialNumber(xcert);
3283         if ( sn == NULL ) goto done;
3284         serial=i2s_ASN1_INTEGER(0, sn );
3285         if( serial == NULL ) goto done;
3286         seriallen=strlen(serial);
3287
3288         name=X509_get_issuer_name(xcert);
3289         if( name == NULL ) goto done;
3290         rc = dnX509normalize( name, &issuer_dn );
3291         if( rc != LDAP_SUCCESS ) goto done;
3292
3293         normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3294                 + seriallen + issuer_dn.bv_len;
3295         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3296
3297         p = (unsigned char *)normalized->bv_val;
3298
3299         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3300         p += STRLENOF( "{ serialNumber " );
3301
3302         AC_MEMCPY(p, serial, seriallen);
3303         p += seriallen;
3304
3305         AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3306         p += STRLENOF( ", issuer \"" );
3307
3308         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3309         p += issuer_dn.bv_len;
3310
3311         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3312         p += STRLENOF( "\" }" );
3313
3314         *p = '\0';
3315
3316         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3317                 normalized->bv_val, NULL, NULL );
3318
3319         rc = LDAP_SUCCESS;
3320
3321 done:
3322         if (xcert) X509_free(xcert);
3323         if (serial) ch_free(serial);
3324         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
3325
3326         return rc;
3327 }
3328 #endif /* HAVE_TLS */
3329
3330
3331 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3332 /* slight optimization - does not need the start parameter */
3333 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3334 enum { start = 0 };
3335 #endif
3336
3337 static int
3338 check_time_syntax (struct berval *val,
3339         int start,
3340         int *parts,
3341         struct berval *fraction)
3342 {
3343         /*
3344          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3345          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3346          * GeneralizedTime supports leap seconds, UTCTime does not.
3347          */
3348         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3349         static const int mdays[2][12] = {
3350                 /* non-leap years */
3351                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3352                 /* leap years */
3353                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3354         };
3355         char *p, *e;
3356         int part, c, c1, c2, tzoffset, leapyear = 0;
3357
3358         p = val->bv_val;
3359         e = p + val->bv_len;
3360
3361 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3362         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3363 #endif
3364         for (part = start; part < 7 && p < e; part++) {
3365                 c1 = *p;
3366                 if (!ASCII_DIGIT(c1)) {
3367                         break;
3368                 }
3369                 p++;
3370                 if (p == e) {
3371                         return LDAP_INVALID_SYNTAX;
3372                 }
3373                 c = *p++;
3374                 if (!ASCII_DIGIT(c)) {
3375                         return LDAP_INVALID_SYNTAX;
3376                 }
3377                 c += c1 * 10 - '0' * 11;
3378                 if ((part | 1) == 3) {
3379                         --c;
3380                         if (c < 0) {
3381                                 return LDAP_INVALID_SYNTAX;
3382                         }
3383                 }
3384                 if (c >= ceiling[part]) {
3385                         if (! (c == 60 && part == 6 && start == 0))
3386                                 return LDAP_INVALID_SYNTAX;
3387                 }
3388                 parts[part] = c;
3389         }
3390         if (part < 5 + start) {
3391                 return LDAP_INVALID_SYNTAX;
3392         }
3393         for (; part < 9; part++) {
3394                 parts[part] = 0;
3395         }
3396
3397         /* leapyear check for the Gregorian calendar (year>1581) */
3398         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3399                 leapyear = 1;
3400         }
3401
3402         if (parts[3] >= mdays[leapyear][parts[2]]) {
3403                 return LDAP_INVALID_SYNTAX;
3404         }
3405
3406         if (start == 0) {
3407                 fraction->bv_val = p;
3408                 fraction->bv_len = 0;
3409                 if (p < e && (*p == '.' || *p == ',')) {
3410                         char *end_num;
3411                         while (++p < e && ASCII_DIGIT(*p)) {
3412                                 /* EMTPY */;
3413                         }
3414                         if (p - fraction->bv_val == 1) {
3415                                 return LDAP_INVALID_SYNTAX;
3416                         }
3417                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3418                                 /* EMPTY */;
3419                         }
3420                         c = end_num - fraction->bv_val;
3421                         if (c != 1) fraction->bv_len = c;
3422                 }
3423         }
3424
3425         if (p == e) {
3426                 /* no time zone */
3427                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3428         }
3429
3430         tzoffset = *p++;
3431         switch (tzoffset) {
3432         default:
3433                 return LDAP_INVALID_SYNTAX;
3434         case 'Z':
3435                 /* UTC */
3436                 break;
3437         case '+':
3438         case '-':
3439                 for (part = 7; part < 9 && p < e; part++) {
3440                         c1 = *p;
3441                         if (!ASCII_DIGIT(c1)) {
3442                                 break;
3443                         }
3444                         p++;
3445                         if (p == e) {
3446                                 return LDAP_INVALID_SYNTAX;
3447                         }
3448                         c2 = *p++;
3449                         if (!ASCII_DIGIT(c2)) {
3450                                 return LDAP_INVALID_SYNTAX;
3451                         }
3452                         parts[part] = c1 * 10 + c2 - '0' * 11;
3453                         if (parts[part] >= ceiling[part]) {
3454                                 return LDAP_INVALID_SYNTAX;
3455                         }
3456                 }
3457                 if (part < 8 + start) {
3458                         return LDAP_INVALID_SYNTAX;
3459                 }
3460
3461                 if (tzoffset == '-') {
3462                         /* negative offset to UTC, ie west of Greenwich */
3463                         parts[4] += parts[7];
3464                         parts[5] += parts[8];
3465                         /* offset is just hhmm, no seconds */
3466                         for (part = 6; --part >= 0; ) {
3467                                 if (part != 3) {
3468                                         c = ceiling[part];
3469                                 } else {
3470                                         c = mdays[leapyear][parts[2]];
3471                                 }
3472                                 if (parts[part] >= c) {
3473                                         if (part == 0) {
3474                                                 return LDAP_INVALID_SYNTAX;
3475                                         }
3476                                         parts[part] -= c;
3477                                         parts[part - 1]++;
3478                                         continue;
3479                                 } else if (part != 5) {
3480                                         break;
3481                                 }
3482                         }
3483                 } else {
3484                         /* positive offset to UTC, ie east of Greenwich */
3485                         parts[4] -= parts[7];
3486                         parts[5] -= parts[8];
3487                         for (part = 6; --part >= 0; ) {
3488                                 if (parts[part] < 0) {
3489                                         if (part == 0) {
3490                                                 return LDAP_INVALID_SYNTAX;
3491                                         }
3492                                         if (part != 3) {
3493                                                 c = ceiling[part];
3494                                         } else {
3495                                                 /* make first arg to % non-negative */
3496                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3497                                         }
3498                                         parts[part] += c;
3499                                         parts[part - 1]--;
3500                                         continue;
3501                                 } else if (part != 5) {
3502                                         break;
3503                                 }
3504                         }
3505                 }
3506         }
3507
3508         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3509 }
3510
3511 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3512
3513 #if 0
3514 static int
3515 xutcTimeNormalize(
3516         Syntax *syntax,
3517         struct berval *val,
3518         struct berval *normalized )
3519 {
3520         int parts[9], rc;
3521
3522         rc = check_time_syntax(val, 1, parts, NULL);
3523         if (rc != LDAP_SUCCESS) {
3524                 return rc;
3525         }
3526
3527         normalized->bv_val = ch_malloc( 14 );
3528         if ( normalized->bv_val == NULL ) {
3529                 return LBER_ERROR_MEMORY;
3530         }
3531
3532         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3533                 parts[1], parts[2] + 1, parts[3] + 1,
3534                 parts[4], parts[5], parts[6] );
3535         normalized->bv_len = 13;
3536
3537         return LDAP_SUCCESS;
3538 }
3539 #endif /* 0 */
3540
3541 static int
3542 utcTimeValidate(
3543         Syntax *syntax,
3544         struct berval *in )
3545 {
3546         int parts[9];
3547         return check_time_syntax(in, 1, parts, NULL);
3548 }
3549
3550 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3551
3552 static int
3553 generalizedTimeValidate(
3554         Syntax *syntax,
3555         struct berval *in )
3556 {
3557         int parts[9];
3558         struct berval fraction;
3559         return check_time_syntax(in, 0, parts, &fraction);
3560 }
3561
3562 static int
3563 generalizedTimeNormalize(
3564         slap_mask_t usage,
3565         Syntax *syntax,
3566         MatchingRule *mr,
3567         struct berval *val,
3568         struct berval *normalized,
3569         void *ctx )
3570 {
3571         int parts[9], rc;
3572         unsigned int len;
3573         struct berval fraction;
3574
3575         rc = check_time_syntax(val, 0, parts, &fraction);
3576         if (rc != LDAP_SUCCESS) {
3577                 return rc;
3578         }
3579
3580         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3581         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3582         if ( BER_BVISNULL( normalized ) ) {
3583                 return LBER_ERROR_MEMORY;
3584         }
3585
3586         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3587                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3588                 parts[4], parts[5], parts[6] );
3589         if ( !BER_BVISEMPTY( &fraction ) ) {
3590                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3591                         fraction.bv_val, fraction.bv_len );
3592                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3593         }
3594         strcpy( normalized->bv_val + len-1, "Z" );
3595         normalized->bv_len = len;
3596
3597         return LDAP_SUCCESS;
3598 }
3599
3600 static int
3601 generalizedTimeOrderingMatch(
3602         int *matchp,
3603         slap_mask_t flags,
3604         Syntax *syntax,
3605         MatchingRule *mr,
3606         struct berval *value,
3607         void *assertedValue )
3608 {
3609         struct berval *asserted = (struct berval *) assertedValue;
3610         ber_len_t v_len  = value->bv_len;
3611         ber_len_t av_len = asserted->bv_len;
3612
3613         /* ignore trailing 'Z' when comparing */
3614         int match = memcmp( value->bv_val, asserted->bv_val,
3615                 (v_len < av_len ? v_len : av_len) - 1 );
3616         if ( match == 0 ) match = v_len - av_len;
3617
3618         *matchp = match;
3619         return LDAP_SUCCESS;
3620 }
3621
3622 /* Index generation function */
3623 int generalizedTimeIndexer(
3624         slap_mask_t use,
3625         slap_mask_t flags,
3626         Syntax *syntax,
3627         MatchingRule *mr,
3628         struct berval *prefix,
3629         BerVarray values,
3630         BerVarray *keysp,
3631         void *ctx )
3632 {
3633         int i, j;
3634         BerVarray keys;
3635         char tmp[5];
3636         BerValue bvtmp; /* 40 bit index */
3637         struct lutil_tm tm;
3638         struct lutil_timet tt;
3639
3640         bvtmp.bv_len = sizeof(tmp);
3641         bvtmp.bv_val = tmp;
3642         for( i=0; values[i].bv_val != NULL; i++ ) {
3643                 /* just count them */
3644         }
3645
3646         /* we should have at least one value at this point */
3647         assert( i > 0 );
3648
3649         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
3650
3651         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3652         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
3653                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
3654                 /* Use 40 bits of time for key */
3655                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
3656                         lutil_tm2time( &tm, &tt );
3657                         tmp[0] = tt.tt_gsec & 0xff;
3658                         tmp[4] = tt.tt_sec & 0xff;
3659                         tt.tt_sec >>= 8;
3660                         tmp[3] = tt.tt_sec & 0xff;
3661                         tt.tt_sec >>= 8;
3662                         tmp[2] = tt.tt_sec & 0xff;
3663                         tt.tt_sec >>= 8;
3664                         tmp[1] = tt.tt_sec & 0xff;
3665                         
3666                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
3667                 }
3668         }
3669
3670         keys[j].bv_val = NULL;
3671         keys[j].bv_len = 0;
3672
3673         *keysp = keys;
3674
3675         return LDAP_SUCCESS;
3676 }
3677
3678 /* Index generation function */
3679 int generalizedTimeFilter(
3680         slap_mask_t use,
3681         slap_mask_t flags,
3682         Syntax *syntax,
3683         MatchingRule *mr,
3684         struct berval *prefix,
3685         void * assertedValue,
3686         BerVarray *keysp,
3687         void *ctx )
3688 {
3689         BerVarray keys;
3690         char tmp[5];
3691         BerValue bvtmp; /* 40 bit index */
3692         BerValue *value = (BerValue *) assertedValue;
3693         struct lutil_tm tm;
3694         struct lutil_timet tt;
3695         
3696         bvtmp.bv_len = sizeof(tmp);
3697         bvtmp.bv_val = tmp;
3698         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3699         /* Use 40 bits of time for key */
3700         if ( value->bv_val && value->bv_len >= 10 &&
3701                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3702
3703                 lutil_tm2time( &tm, &tt );
3704                 tmp[0] = tt.tt_gsec & 0xff;
3705                 tmp[4] = tt.tt_sec & 0xff;
3706                 tt.tt_sec >>= 8;
3707                 tmp[3] = tt.tt_sec & 0xff;
3708                 tt.tt_sec >>= 8;
3709                 tmp[2] = tt.tt_sec & 0xff;
3710                 tt.tt_sec >>= 8;
3711                 tmp[1] = tt.tt_sec & 0xff;
3712
3713                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3714                 ber_dupbv_x(keys, &bvtmp, ctx );
3715                 keys[1].bv_val = NULL;
3716                 keys[1].bv_len = 0;
3717         } else {
3718                 keys = NULL;
3719         }
3720
3721         *keysp = keys;
3722
3723         return LDAP_SUCCESS;
3724 }
3725
3726 static int
3727 deliveryMethodValidate(
3728         Syntax *syntax,
3729         struct berval *val )
3730 {
3731 #undef LENOF
3732 #define LENOF(s) (sizeof(s)-1)
3733         struct berval tmp = *val;
3734         /*
3735      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3736          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3737          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3738          */
3739 again:
3740         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3741
3742         switch( tmp.bv_val[0] ) {
3743         case 'a':
3744         case 'A':
3745                 if(( tmp.bv_len >= LENOF("any") ) &&
3746                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3747                 {
3748                         tmp.bv_len -= LENOF("any");
3749                         tmp.bv_val += LENOF("any");
3750                         break;
3751                 }
3752                 return LDAP_INVALID_SYNTAX;
3753
3754         case 'm':
3755         case 'M':
3756                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3757                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3758                 {
3759                         tmp.bv_len -= LENOF("mhs");
3760                         tmp.bv_val += LENOF("mhs");
3761                         break;
3762                 }
3763                 return LDAP_INVALID_SYNTAX;
3764
3765         case 'p':
3766         case 'P':
3767                 if(( tmp.bv_len >= LENOF("physical") ) &&
3768                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3769                 {
3770                         tmp.bv_len -= LENOF("physical");
3771                         tmp.bv_val += LENOF("physical");
3772                         break;
3773                 }
3774                 return LDAP_INVALID_SYNTAX;
3775
3776         case 't':
3777         case 'T': /* telex or teletex or telephone */
3778                 if(( tmp.bv_len >= LENOF("telex") ) &&
3779                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3780                 {
3781                         tmp.bv_len -= LENOF("telex");
3782                         tmp.bv_val += LENOF("telex");
3783                         break;
3784                 }
3785                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3786                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3787                 {
3788                         tmp.bv_len -= LENOF("teletex");
3789                         tmp.bv_val += LENOF("teletex");
3790                         break;
3791                 }
3792                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3793                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3794                 {
3795                         tmp.bv_len -= LENOF("telephone");
3796                         tmp.bv_val += LENOF("telephone");
3797                         break;
3798                 }
3799                 return LDAP_INVALID_SYNTAX;
3800
3801         case 'g':
3802         case 'G': /* g3fax or g4fax */
3803                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3804                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3805                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3806                 {
3807                         tmp.bv_len -= LENOF("g3fax");
3808                         tmp.bv_val += LENOF("g3fax");
3809                         break;
3810                 }
3811                 return LDAP_INVALID_SYNTAX;
3812
3813         case 'i':
3814         case 'I':
3815                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3816                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3817                 {
3818                         tmp.bv_len -= LENOF("ia5");
3819                         tmp.bv_val += LENOF("ia5");
3820                         break;
3821                 }
3822                 return LDAP_INVALID_SYNTAX;
3823
3824         case 'v':
3825         case 'V':
3826                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3827                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3828                 {
3829                         tmp.bv_len -= LENOF("videotex");
3830                         tmp.bv_val += LENOF("videotex");
3831                         break;
3832                 }
3833                 return LDAP_INVALID_SYNTAX;
3834
3835         default:
3836                 return LDAP_INVALID_SYNTAX;
3837         }
3838
3839         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3840
3841         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3842                 tmp.bv_len++;
3843                 tmp.bv_val--;
3844         }
3845         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3846                 tmp.bv_len++;
3847                 tmp.bv_val--;
3848         } else {
3849                 return LDAP_INVALID_SYNTAX;
3850         }
3851         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3852                 tmp.bv_len++;
3853                 tmp.bv_val--;
3854         }
3855
3856         goto again;
3857 }
3858
3859 static int
3860 nisNetgroupTripleValidate(
3861         Syntax *syntax,
3862         struct berval *val )
3863 {
3864         char *p, *e;
3865         int commas = 0;
3866
3867         if ( BER_BVISEMPTY( val ) ) {
3868                 return LDAP_INVALID_SYNTAX;
3869         }
3870
3871         p = (char *)val->bv_val;
3872         e = p + val->bv_len;
3873
3874         if ( *p != '(' /*')'*/ ) {
3875                 return LDAP_INVALID_SYNTAX;
3876         }
3877
3878         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3879                 if ( *p == ',' ) {
3880                         commas++;
3881                         if ( commas > 2 ) {
3882                                 return LDAP_INVALID_SYNTAX;
3883                         }
3884
3885                 } else if ( !AD_CHAR( *p ) ) {
3886                         return LDAP_INVALID_SYNTAX;
3887                 }
3888         }
3889
3890         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3891                 return LDAP_INVALID_SYNTAX;
3892         }
3893
3894         p++;
3895
3896         if (p != e) {
3897                 return LDAP_INVALID_SYNTAX;
3898         }
3899
3900         return LDAP_SUCCESS;
3901 }
3902
3903 static int
3904 bootParameterValidate(
3905         Syntax *syntax,
3906         struct berval *val )
3907 {
3908         char *p, *e;
3909
3910         if ( BER_BVISEMPTY( val ) ) {
3911                 return LDAP_INVALID_SYNTAX;
3912         }
3913
3914         p = (char *)val->bv_val;
3915         e = p + val->bv_len;
3916
3917         /* key */
3918         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3919                 if ( !AD_CHAR( *p ) ) {
3920                         return LDAP_INVALID_SYNTAX;
3921                 }
3922         }
3923
3924         if ( *p != '=' ) {
3925                 return LDAP_INVALID_SYNTAX;
3926         }
3927
3928         /* server */
3929         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3930                 if ( !AD_CHAR( *p ) ) {
3931                         return LDAP_INVALID_SYNTAX;
3932                 }
3933         }
3934
3935         if ( *p != ':' ) {
3936                 return LDAP_INVALID_SYNTAX;
3937         }
3938
3939         /* path */
3940         for ( p++; p < e; p++ ) {
3941                 if ( !SLAP_PRINTABLE( *p ) ) {
3942                         return LDAP_INVALID_SYNTAX;
3943                 }
3944         }
3945
3946         return LDAP_SUCCESS;
3947 }
3948
3949 static int
3950 firstComponentNormalize(
3951         slap_mask_t usage,
3952         Syntax *syntax,
3953         MatchingRule *mr,
3954         struct berval *val,
3955         struct berval *normalized,
3956         void *ctx )
3957 {
3958         int rc;
3959         struct berval comp;
3960         ber_len_t len;
3961
3962         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3963                 ber_dupbv_x( normalized, val, ctx );
3964                 return LDAP_SUCCESS;
3965         }
3966
3967         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3968
3969         if( val->bv_val[0] != '(' /*')'*/ &&
3970                 val->bv_val[0] != '{' /*'}'*/ )
3971         {
3972                 return LDAP_INVALID_SYNTAX;
3973         }
3974
3975         /* trim leading white space */
3976         for( len=1;
3977                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3978                 len++ )
3979         {
3980                 /* empty */
3981         }
3982
3983         /* grab next word */
3984         comp.bv_val = &val->bv_val[len];
3985         len = val->bv_len - len;
3986         for( comp.bv_len = 0;
3987                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3988                 comp.bv_len++ )
3989         {
3990                 /* empty */
3991         }
3992
3993         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3994                 rc = numericoidValidate( NULL, &comp );
3995         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3996                 rc = integerValidate( NULL, &comp );
3997         } else {
3998                 rc = LDAP_INVALID_SYNTAX;
3999         }
4000         
4001
4002         if( rc == LDAP_SUCCESS ) {
4003                 ber_dupbv_x( normalized, &comp, ctx );
4004         }
4005
4006         return rc;
4007 }
4008
4009
4010 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4011 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4012
4013 static slap_syntax_defs_rec syntax_defs[] = {
4014         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4015                 X_BINARY X_NOT_H_R ")",
4016                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
4017         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4018                 0, NULL, NULL},
4019         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4020                 0, NULL, NULL},
4021         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4022                 X_NOT_H_R ")",
4023                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
4024         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4025                 X_NOT_H_R ")",
4026                 SLAP_SYNTAX_BER, berValidate, NULL},
4027         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4028                 0, bitStringValidate, NULL },
4029         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4030                 0, booleanValidate, NULL},
4031         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4032                 X_BINARY X_NOT_H_R ")",
4033                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
4034         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4035                 X_BINARY X_NOT_H_R ")",
4036                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
4037         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4038                 X_BINARY X_NOT_H_R ")",
4039                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
4040         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4041                 0, countryStringValidate, NULL},
4042         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4043                 0, dnValidate, dnPretty},
4044         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4045                 0, rdnValidate, rdnPretty},
4046 #ifdef LDAP_COMP_MATCH
4047         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4048                 0, allComponentsValidate, NULL},
4049         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4050                 0, componentFilterValidate, NULL},
4051 #endif
4052         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4053                 0, NULL, NULL},
4054         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4055                 0, deliveryMethodValidate, NULL},
4056         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4057                 0, UTF8StringValidate, NULL},
4058         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4059                 0, NULL, NULL},
4060         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4061                 0, NULL, NULL},
4062         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4063                 0, NULL, NULL},
4064         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4065                 0, NULL, NULL},
4066         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4067                 0, NULL, NULL},
4068         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4069                 0, printablesStringValidate, NULL},
4070         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4071                 SLAP_SYNTAX_BLOB, NULL, NULL},
4072         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4073                 0, generalizedTimeValidate, NULL},
4074         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4075                 0, NULL, NULL},
4076         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4077                 0, IA5StringValidate, NULL},
4078         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4079                 0, integerValidate, NULL},
4080         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4081                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
4082         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4083                 0, NULL, NULL},
4084         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4085                 0, NULL, NULL},
4086         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4087                 0, NULL, NULL},
4088         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4089                 0, NULL, NULL},
4090         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4091                 0, NULL, NULL},
4092         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4093                 0, nameUIDValidate, nameUIDPretty },
4094         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4095                 0, NULL, NULL},
4096         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4097                 0, numericStringValidate, NULL},
4098         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4099                 0, NULL, NULL},
4100         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4101                 0, numericoidValidate, NULL},
4102         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4103                 0, IA5StringValidate, NULL},
4104         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4105                 0, blobValidate, NULL},
4106         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4107                 0, UTF8StringValidate, NULL},
4108         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4109                 0, NULL, NULL},
4110         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4111                 0, NULL, NULL},
4112         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4113                 0, printableStringValidate, NULL},
4114         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4115 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4116                 0, subtreeSpecificationValidate, NULL},
4117         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4118                 X_BINARY X_NOT_H_R ")",
4119                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
4120         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4121                 0, printableStringValidate, NULL},
4122         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4123                 0, NULL, NULL},
4124         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4125                 0, printablesStringValidate, NULL},
4126 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4127         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4128                 0, utcTimeValidate, NULL},
4129 #endif
4130         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4131                 0, NULL, NULL},
4132         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4133                 0, NULL, NULL},
4134         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4135                 0, NULL, NULL},
4136         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4137                 0, NULL, NULL},
4138         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4139                 0, NULL, NULL},
4140
4141         /* RFC 2307 NIS Syntaxes */
4142         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4143                 0, nisNetgroupTripleValidate, NULL},
4144         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4145                 0, bootParameterValidate, NULL},
4146
4147         /* draft-zeilenga-ldap-x509 */
4148         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4149                 SLAP_SYNTAX_HIDE,
4150                 serialNumberAndIssuerValidate,
4151                 serialNumberAndIssuerPretty},
4152         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4153                 SLAP_SYNTAX_HIDE, NULL, NULL},
4154         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4155                 SLAP_SYNTAX_HIDE, NULL, NULL},
4156         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4157                 SLAP_SYNTAX_HIDE, NULL, NULL},
4158         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4159                 SLAP_SYNTAX_HIDE, NULL, NULL},
4160         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4161                 SLAP_SYNTAX_HIDE, NULL, NULL},
4162         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4163                 SLAP_SYNTAX_HIDE, NULL, NULL},
4164
4165 #ifdef SLAPD_AUTHPASSWD
4166         /* needs updating */
4167         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4168                 SLAP_SYNTAX_HIDE, NULL, NULL},
4169 #endif
4170
4171         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4172                 0, UUIDValidate, UUIDPretty},
4173
4174         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4175                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
4176
4177         /* OpenLDAP Void Syntax */
4178         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4179                 SLAP_SYNTAX_HIDE, inValidate, NULL},
4180
4181         /* FIXME: OID is unused, but not registered yet */
4182         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4183                 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
4184
4185         {NULL, 0, NULL, NULL}
4186 };
4187
4188 char *certificateExactMatchSyntaxes[] = {
4189         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4190         NULL
4191 };
4192 #ifdef LDAP_COMP_MATCH
4193 char *componentFilterMatchSyntaxes[] = {
4194         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4195         NULL
4196 };
4197 #endif
4198 char *directoryStringSyntaxes[] = {
4199         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4200         NULL
4201 };
4202 char *integerFirstComponentMatchSyntaxes[] = {
4203         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4204         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
4205         NULL
4206 };
4207 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4208         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4209         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4210         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
4211         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4212         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4213         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4214         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4215         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4216         NULL
4217 };
4218
4219 /*
4220  * Other matching rules in X.520 that we do not use (yet):
4221  *
4222  * 2.5.13.25    uTCTimeMatch
4223  * 2.5.13.26    uTCTimeOrderingMatch
4224  * 2.5.13.31*   directoryStringFirstComponentMatch
4225  * 2.5.13.32*   wordMatch
4226  * 2.5.13.33*   keywordMatch
4227  * 2.5.13.36+   certificatePairExactMatch
4228  * 2.5.13.37+   certificatePairMatch
4229  * 2.5.13.38+   certificateListExactMatch
4230  * 2.5.13.39+   certificateListMatch
4231  * 2.5.13.40+   algorithmIdentifierMatch
4232  * 2.5.13.41*   storedPrefixMatch
4233  * 2.5.13.42    attributeCertificateMatch
4234  * 2.5.13.43    readerAndKeyIDMatch
4235  * 2.5.13.44    attributeIntegrityMatch
4236  *
4237  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4238  * (+) described in draft-zeilenga-ldap-x509
4239  */
4240 static slap_mrule_defs_rec mrule_defs[] = {
4241         /*
4242          * EQUALITY matching rules must be listed after associated APPROX
4243          * matching rules.  So, we list all APPROX matching rules first.
4244          */
4245         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4246                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4247                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4248                 NULL, NULL, directoryStringApproxMatch,
4249                 directoryStringApproxIndexer, directoryStringApproxFilter,
4250                 NULL},
4251
4252         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4253                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4254                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4255                 NULL, NULL, IA5StringApproxMatch,
4256                 IA5StringApproxIndexer, IA5StringApproxFilter,
4257                 NULL},
4258
4259         /*
4260          * Other matching rules
4261          */
4262         
4263         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4264                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4265                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4266                 NULL, NULL, octetStringMatch,
4267                 octetStringIndexer, octetStringFilter,
4268                 NULL },
4269
4270         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4271                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4272                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4273                 NULL, dnNormalize, dnMatch,
4274                 octetStringIndexer, octetStringFilter,
4275                 NULL },
4276
4277         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
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.8 NAME 'dnOneLevelMatch' "
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.10 NAME 'dnSubordinateMatch' "
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.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4299                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4300                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4301                 NULL, dnNormalize, dnRelativeMatch,
4302                 NULL, NULL,
4303                 NULL },
4304
4305         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4306                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4307                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4308                 NULL, rdnNormalize, rdnMatch,
4309                 octetStringIndexer, octetStringFilter,
4310                 NULL },
4311
4312 #ifdef LDAP_COMP_MATCH
4313         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4314                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4315                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4316                 NULL, NULL , componentFilterMatch,
4317                 octetStringIndexer, octetStringFilter,
4318                 NULL },
4319
4320         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4321                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4322                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4323                 NULL, NULL , allComponentsMatch,
4324                 octetStringIndexer, octetStringFilter,
4325                 NULL },
4326
4327         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4328                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4329                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4330                 NULL, NULL , directoryComponentsMatch,
4331                 octetStringIndexer, octetStringFilter,
4332                 NULL },
4333 #endif
4334
4335         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4336                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4337                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4338                 NULL, UTF8StringNormalize, octetStringMatch,
4339                 octetStringIndexer, octetStringFilter,
4340                 directoryStringApproxMatchOID },
4341
4342         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4343                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4344                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4345                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4346                 NULL, NULL,
4347                 "caseIgnoreMatch" },
4348
4349         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4350                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4351                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4352                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4353                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4354                 "caseIgnoreMatch" },
4355
4356         {"( 2.5.13.5 NAME 'caseExactMatch' "
4357                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4358                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4359                 NULL, UTF8StringNormalize, octetStringMatch,
4360                 octetStringIndexer, octetStringFilter,
4361                 directoryStringApproxMatchOID },
4362
4363         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4364                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4365                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4366                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4367                 NULL, NULL,
4368                 "caseExactMatch" },
4369
4370         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4371                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4372                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4373                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4374                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4375                 "caseExactMatch" },
4376
4377         {"( 2.5.13.8 NAME 'numericStringMatch' "
4378                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4379                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4380                 NULL, numericStringNormalize, octetStringMatch,
4381                 octetStringIndexer, octetStringFilter,
4382                 NULL },
4383
4384         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4385                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4386                 SLAP_MR_ORDERING, NULL,
4387                 NULL, numericStringNormalize, octetStringOrderingMatch,
4388                 NULL, NULL,
4389                 "numericStringMatch" },
4390
4391         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4392                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4393                 SLAP_MR_SUBSTR, NULL,
4394                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4395                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4396                 "numericStringMatch" },
4397
4398         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4399                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4400                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4401                 NULL, NULL, NULL, NULL, NULL, NULL },
4402
4403         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4404                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4405                 SLAP_MR_SUBSTR, NULL,
4406                 NULL, NULL, NULL, NULL, NULL,
4407                 "caseIgnoreListMatch" },
4408
4409         {"( 2.5.13.13 NAME 'booleanMatch' "
4410                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4411                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4412                 NULL, NULL, booleanMatch,
4413                 octetStringIndexer, octetStringFilter,
4414                 NULL },
4415
4416         {"( 2.5.13.14 NAME 'integerMatch' "
4417                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4418                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4419                 NULL, NULL, integerMatch,
4420                 octetStringIndexer, octetStringFilter,
4421                 NULL },
4422
4423         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4424                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4425                 SLAP_MR_ORDERING, NULL,
4426                 NULL, NULL, integerMatch,
4427                 NULL, NULL,
4428                 "integerMatch" },
4429
4430         {"( 2.5.13.16 NAME 'bitStringMatch' "
4431                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4432                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4433                 NULL, NULL, octetStringMatch,
4434                 octetStringIndexer, octetStringFilter,
4435                 NULL },
4436
4437         {"( 2.5.13.17 NAME 'octetStringMatch' "
4438                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4439                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4440                 NULL, NULL, octetStringMatch,
4441                 octetStringIndexer, octetStringFilter,
4442                 NULL },
4443
4444         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4445                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4446                 SLAP_MR_ORDERING, NULL,
4447                 NULL, NULL, octetStringOrderingMatch,
4448                 NULL, NULL,
4449                 "octetStringMatch" },
4450
4451         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4452                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4453                 SLAP_MR_SUBSTR, NULL,
4454                 NULL, NULL, octetStringSubstringsMatch,
4455                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4456                 "octetStringMatch" },
4457
4458         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4459                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4460                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4461                 NULL,
4462                 telephoneNumberNormalize, octetStringMatch,
4463                 octetStringIndexer, octetStringFilter,
4464                 NULL },
4465
4466         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4467                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4468                 SLAP_MR_SUBSTR, NULL,
4469                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4470                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4471                 "telephoneNumberMatch" },
4472
4473         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4474                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4475                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4476                 NULL, NULL, NULL, NULL, NULL, NULL },
4477
4478         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4479                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4480                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4481                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4482                 uniqueMemberIndexer, uniqueMemberFilter,
4483                 NULL },
4484
4485         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4486                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4487                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4488                 NULL, NULL, NULL, NULL, NULL, NULL },
4489
4490         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4491                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4492                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4493                 NULL, generalizedTimeNormalize, octetStringMatch,
4494                 generalizedTimeIndexer, generalizedTimeFilter,
4495                 NULL },
4496
4497         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4498                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4499                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4500                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4501                 NULL, NULL,
4502                 "generalizedTimeMatch" },
4503
4504         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4505                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4506                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4507                         integerFirstComponentMatchSyntaxes,
4508                 NULL, firstComponentNormalize, integerMatch,
4509                 octetStringIndexer, octetStringFilter,
4510                 NULL },
4511
4512         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4513                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4514                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4515                         objectIdentifierFirstComponentMatchSyntaxes,
4516                 NULL, firstComponentNormalize, octetStringMatch,
4517                 octetStringIndexer, octetStringFilter,
4518                 NULL },
4519
4520         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4521                 "SYNTAX 1.3.6.1.1.15.1 )",
4522                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4523 #ifdef HAVE_TLS
4524                 NULL, certificateExactNormalize, octetStringMatch,
4525                 octetStringIndexer, octetStringFilter,
4526 #else
4527                 NULL, NULL, NULL, NULL, NULL,
4528 #endif
4529                 NULL },
4530
4531         {"( 2.5.13.35 NAME 'certificateMatch' "
4532                 "SYNTAX 1.3.6.1.1.15.2 )",
4533                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4534                 NULL, NULL, NULL, NULL, NULL,
4535                 NULL },
4536
4537         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
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.2 NAME 'caseIgnoreIA5Match' "
4545                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4546                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4547                 NULL, IA5StringNormalize, octetStringMatch,
4548                 octetStringIndexer, octetStringFilter,
4549                 IA5StringApproxMatchOID },
4550
4551         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
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                 "caseIgnoreIA5Match" },
4557
4558         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4559                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4560                 SLAP_MR_SUBSTR, NULL,
4561                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4562                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4563                 "caseExactIA5Match" },
4564
4565 #ifdef SLAPD_AUTHPASSWD
4566         /* needs updating */
4567         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4568                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4569                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4570                 NULL, NULL, authPasswordMatch,
4571                 NULL, NULL,
4572                 NULL},
4573 #endif
4574
4575         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4576                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4577                 SLAP_MR_EXT, NULL,
4578                 NULL, NULL, integerBitAndMatch,
4579                 NULL, NULL,
4580                 "integerMatch" },
4581
4582         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4583                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4584                 SLAP_MR_EXT, NULL,
4585                 NULL, NULL, integerBitOrMatch,
4586                 NULL, NULL,
4587                 "integerMatch" },
4588
4589         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
4590                 "SYNTAX 1.3.6.1.1.16.1 )",
4591                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
4592                 NULL, UUIDNormalize, octetStringMatch,
4593                 octetStringIndexer, octetStringFilter,
4594                 NULL},
4595
4596         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
4597                 "SYNTAX 1.3.6.1.1.16.1 )",
4598                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
4599                 NULL, UUIDNormalize, octetStringOrderingMatch,
4600                 octetStringIndexer, octetStringFilter,
4601                 "UUIDMatch"},
4602
4603         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
4604                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4605                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
4606                 NULL, NULL, csnMatch,
4607                 csnIndexer, csnFilter,
4608                 NULL},
4609
4610         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
4611                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4612                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4613                 NULL, NULL, csnOrderingMatch,
4614                 NULL, NULL,
4615                 "CSNMatch" },
4616
4617         /* FIXME: OID is unused, but not registered yet */
4618         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
4619                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
4620                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4621                 NULL, authzNormalize, authzMatch,
4622                 NULL, NULL,
4623                 NULL},
4624
4625         {NULL, SLAP_MR_NONE, NULL,
4626                 NULL, NULL, NULL, NULL, NULL,
4627                 NULL }
4628 };
4629
4630 int
4631 slap_schema_init( void )
4632 {
4633         int             res;
4634         int             i;
4635
4636         /* we should only be called once (from main) */
4637         assert( schema_init_done == 0 );
4638
4639         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4640                 res = register_syntax( &syntax_defs[i] );
4641
4642                 if ( res ) {
4643                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4644                                  syntax_defs[i].sd_desc );
4645                         return LDAP_OTHER;
4646                 }
4647         }
4648
4649         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4650                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
4651                         mrule_defs[i].mrd_compat_syntaxes == NULL )
4652                 {
4653                         fprintf( stderr,
4654                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
4655                                  mrule_defs[i].mrd_desc );
4656                         continue;
4657                 }
4658
4659                 res = register_matching_rule( &mrule_defs[i] );
4660
4661                 if ( res ) {
4662                         fprintf( stderr,
4663                                 "slap_schema_init: Error registering matching rule %s\n",
4664                                  mrule_defs[i].mrd_desc );
4665                         return LDAP_OTHER;
4666                 }
4667         }
4668
4669         res = slap_schema_load();
4670         schema_init_done = 1;
4671         return res;
4672 }
4673
4674 void
4675 schema_destroy( void )
4676 {
4677         oidm_destroy();
4678         oc_destroy();
4679         at_destroy();
4680         mr_destroy();
4681         mru_destroy();
4682         syn_destroy();
4683
4684         if( schema_init_done ) {
4685                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4686                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
4687         }
4688 }