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