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