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