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