]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
df955ade6eb0465cd8b3b41fd7edd51d78eb8d31
[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 /* 10**INDEX_INTLEN_CHOP < 256**INDEX_INTLEN_CHOPBYTES */
2118 #define INDEX_INTLEN_CHOP 7
2119 #define INDEX_INTLEN_CHOPBYTES 3
2120
2121 static int
2122 integerVal2Key(
2123         struct berval *in,
2124         struct berval *key,
2125         struct berval *tmp,
2126         void *ctx
2127 )
2128 {
2129         /* index format:
2130          * only if too large: one's complement <sign*length of chopped bytes>,
2131          * two's complement value (sign-extended or chopped as needed),
2132          * with 1st byte of the above adjusted as follows:
2133          *   inverse sign in the top <number of length-bytes + 1> bits,
2134          *   then the sign bit as delimiter.
2135          */
2136         ber_slen_t k = index_intlen_strlen, chop = 0;
2137         unsigned char neg = 0xff, signmask = 0x80;
2138         unsigned char lenbuf[sizeof(k) + 2], *lenp;
2139         struct berval val = *in, itmp = *tmp;
2140
2141         if ( val.bv_val[0] != '-' ) {
2142                 neg = 0;
2143                 --k;
2144         }
2145
2146         /* Chop least significant digits, increase length instead */
2147         if ( val.bv_len > k ) {
2148                 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2149                 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2150                 chop *= INDEX_INTLEN_CHOPBYTES;         /* #bytes added */
2151                 if ( chop > 0x7fffffff ) {
2152                         memset( key->bv_val, neg ^ 0xff, index_intlen );
2153                         return 0;
2154                 }
2155         }
2156
2157         if ( lutil_str2bin( &val, &itmp, ctx )) {
2158                 return LDAP_INVALID_SYNTAX;
2159         }
2160
2161         /* Omit leading sign byte */
2162         if ( itmp.bv_val[0] == neg ) {
2163                 itmp.bv_val++;
2164                 itmp.bv_len--;
2165         }
2166
2167         k = (ber_slen_t) index_intlen - ((ber_slen_t) itmp.bv_len + chop);
2168         if ( k > 0 ) {
2169                 assert( chop == 0 );
2170                 memset( key->bv_val, neg, k );  /* sign-extend */
2171         } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2172                 lenp = lenbuf + sizeof(lenbuf);
2173                 k = -k;
2174                 do {
2175                         *--lenp = k ^ neg;
2176                         signmask >>= 1;
2177                 } while ( (k >>= 8) != 0 || (signmask >> 1) <= (*lenp ^ neg) );
2178                 /* With n bytes used in lenbuf, the top n+1 bits of signmask
2179                  * are 1, and the top n+2 bits of *lenp are the sign bit. */
2180                 k = (lenbuf + sizeof(lenbuf)) - lenp;
2181                 if ( k > index_intlen )
2182                         k = index_intlen;
2183                 memcpy( key->bv_val, lenp, k );
2184                 itmp.bv_len = index_intlen - k;
2185         }
2186         memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2187         key->bv_val[0] ^= (unsigned char) -signmask & 0xff; /* invert sign */
2188         return 0;
2189 }
2190
2191 /* Index generation function */
2192 static int
2193 integerIndexer(
2194         slap_mask_t use,
2195         slap_mask_t flags,
2196         Syntax *syntax,
2197         MatchingRule *mr,
2198         struct berval *prefix,
2199         BerVarray values,
2200         BerVarray *keysp,
2201         void *ctx )
2202 {
2203         char ibuf[64];
2204         struct berval itmp;
2205         BerVarray keys;
2206         ber_len_t vlen;
2207         int i, rc;
2208         unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2209
2210         /* count the values and find max needed length */
2211         vlen = 0;
2212         for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2213                 if ( vlen < values[i].bv_len )
2214                         vlen = values[i].bv_len;
2215         }
2216         if ( vlen > maxstrlen )
2217                 vlen = maxstrlen;
2218
2219         /* we should have at least one value at this point */
2220         assert( i > 0 );
2221
2222         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2223         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2224                 keys[i].bv_len = index_intlen;
2225                 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2226         }
2227         keys[i].bv_len = 0;
2228         keys[i].bv_val = NULL;
2229
2230         if ( vlen > sizeof(ibuf) ) {
2231                 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2232         } else {
2233                 itmp.bv_val = ibuf;
2234         }
2235         itmp.bv_len = sizeof(ibuf);
2236
2237         for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2238                 if ( itmp.bv_val != ibuf ) {
2239                         itmp.bv_len = values[i].bv_len;
2240                         if ( itmp.bv_len <= sizeof(ibuf) )
2241                                 itmp.bv_len = sizeof(ibuf);
2242                         else if ( itmp.bv_len > maxstrlen )
2243                                 itmp.bv_len = maxstrlen;
2244                 }
2245                 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2246                 if ( rc )
2247                         goto leave;
2248         }
2249         *keysp = keys;
2250 leave:
2251         if ( itmp.bv_val != ibuf ) {
2252                 slap_sl_free( itmp.bv_val, ctx );
2253         }
2254         return rc;
2255 }
2256
2257 /* Index generation function */
2258 static int
2259 integerFilter(
2260         slap_mask_t use,
2261         slap_mask_t flags,
2262         Syntax *syntax,
2263         MatchingRule *mr,
2264         struct berval *prefix,
2265         void * assertedValue,
2266         BerVarray *keysp,
2267         void *ctx )
2268 {
2269         char ibuf[64];
2270         struct berval iv;
2271         BerVarray keys;
2272         struct berval *value;
2273         int rc;
2274
2275         value = (struct berval *) assertedValue;
2276
2277         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2278
2279         keys[0].bv_len = index_intlen;
2280         keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2281
2282         iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2283                 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2284         if ( iv.bv_len > (int) sizeof(ibuf) ) {
2285                 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2286         } else {
2287                 iv.bv_val = ibuf;
2288                 iv.bv_len = sizeof(ibuf);
2289         }
2290
2291         rc = integerVal2Key( value, keys, &iv, ctx );
2292         if ( rc == 0 )
2293                 *keysp = keys;
2294
2295         if ( iv.bv_val != ibuf ) {
2296                 slap_sl_free( iv.bv_val, ctx );
2297         }
2298         return rc;
2299 }
2300
2301 static int
2302 countryStringValidate(
2303         Syntax *syntax,
2304         struct berval *val )
2305 {
2306         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2307
2308         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2309                 return LDAP_INVALID_SYNTAX;
2310         }
2311         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2312                 return LDAP_INVALID_SYNTAX;
2313         }
2314
2315         return LDAP_SUCCESS;
2316 }
2317
2318 static int
2319 printableStringValidate(
2320         Syntax *syntax,
2321         struct berval *val )
2322 {
2323         ber_len_t i;
2324
2325         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2326
2327         for(i=0; i < val->bv_len; i++) {
2328                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2329                         return LDAP_INVALID_SYNTAX;
2330                 }
2331         }
2332
2333         return LDAP_SUCCESS;
2334 }
2335
2336 static int
2337 printablesStringValidate(
2338         Syntax *syntax,
2339         struct berval *val )
2340 {
2341         ber_len_t i, len;
2342
2343         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2344
2345         for(i=0,len=0; i < val->bv_len; i++) {
2346                 int c = val->bv_val[i];
2347
2348                 if( c == '$' ) {
2349                         if( len == 0 ) {
2350                                 return LDAP_INVALID_SYNTAX;
2351                         }
2352                         len = 0;
2353
2354                 } else if ( SLAP_PRINTABLE(c) ) {
2355                         len++;
2356                 } else {
2357                         return LDAP_INVALID_SYNTAX;
2358                 }
2359         }
2360
2361         if( len == 0 ) {
2362                 return LDAP_INVALID_SYNTAX;
2363         }
2364
2365         return LDAP_SUCCESS;
2366 }
2367
2368 static int
2369 IA5StringValidate(
2370         Syntax *syntax,
2371         struct berval *val )
2372 {
2373         ber_len_t i;
2374
2375         for(i=0; i < val->bv_len; i++) {
2376                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2377                         return LDAP_INVALID_SYNTAX;
2378                 }
2379         }
2380
2381         return LDAP_SUCCESS;
2382 }
2383
2384 static int
2385 IA5StringNormalize(
2386         slap_mask_t use,
2387         Syntax *syntax,
2388         MatchingRule *mr,
2389         struct berval *val,
2390         struct berval *normalized,
2391         void *ctx )
2392 {
2393         char *p, *q;
2394         int casefold = !SLAP_MR_ASSOCIATED( mr,
2395                 slap_schema.si_mr_caseExactIA5Match );
2396
2397         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2398
2399         p = val->bv_val;
2400
2401         /* Ignore initial whitespace */
2402         while ( ASCII_SPACE( *p ) ) p++;
2403
2404         normalized->bv_len = val->bv_len - ( p - val->bv_val );
2405         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2406         AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2407         normalized->bv_val[normalized->bv_len] = '\0';
2408
2409         p = q = normalized->bv_val;
2410
2411         while ( *p ) {
2412                 if ( ASCII_SPACE( *p ) ) {
2413                         *q++ = *p++;
2414
2415                         /* Ignore the extra whitespace */
2416                         while ( ASCII_SPACE( *p ) ) {
2417                                 p++;
2418                         }
2419
2420                 } else if ( casefold ) {
2421                         /* Most IA5 rules require casefolding */
2422                         *q++ = TOLOWER(*p); p++;
2423
2424                 } else {
2425                         *q++ = *p++;
2426                 }
2427         }
2428
2429         assert( normalized->bv_val <= p );
2430         assert( q <= p );
2431
2432         /*
2433          * If the string ended in space, backup the pointer one
2434          * position.  One is enough because the above loop collapsed
2435          * all whitespace to a single space.
2436          */
2437         if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2438
2439         /* null terminate */
2440         *q = '\0';
2441
2442         normalized->bv_len = q - normalized->bv_val;
2443
2444         return LDAP_SUCCESS;
2445 }
2446
2447 static int
2448 UUIDValidate(
2449         Syntax *syntax,
2450         struct berval *in )
2451 {
2452         int i;
2453         if( in->bv_len != 36 ) {
2454                 return LDAP_INVALID_SYNTAX;
2455         }
2456
2457         for( i=0; i<36; i++ ) {
2458                 switch(i) {
2459                         case 8:
2460                         case 13:
2461                         case 18:
2462                         case 23:
2463                                 if( in->bv_val[i] != '-' ) {
2464                                         return LDAP_INVALID_SYNTAX;
2465                                 }
2466                                 break;
2467                         default:
2468                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2469                                         return LDAP_INVALID_SYNTAX;
2470                                 }
2471                 }
2472         }
2473         
2474         return LDAP_SUCCESS;
2475 }
2476
2477 static int
2478 UUIDPretty(
2479         Syntax *syntax,
2480         struct berval *in,
2481         struct berval *out,
2482         void *ctx )
2483 {
2484         int i;
2485         int rc=LDAP_INVALID_SYNTAX;
2486
2487         assert( in != NULL );
2488         assert( out != NULL );
2489
2490         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2491
2492         out->bv_len = 36;
2493         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2494
2495         for( i=0; i<36; i++ ) {
2496                 switch(i) {
2497                         case 8:
2498                         case 13:
2499                         case 18:
2500                         case 23:
2501                                 if( in->bv_val[i] != '-' ) {
2502                                         goto handle_error;
2503                                 }
2504                                 out->bv_val[i] = '-';
2505                                 break;
2506
2507                         default:
2508                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2509                                         goto handle_error;
2510                                 }
2511                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2512                 }
2513         }
2514
2515         rc = LDAP_SUCCESS;
2516         out->bv_val[ out->bv_len ] = '\0';
2517
2518         if( 0 ) {
2519 handle_error:
2520                 slap_sl_free( out->bv_val, ctx );
2521                 out->bv_val = NULL;
2522         }
2523
2524         return rc;
2525 }
2526
2527 int
2528 UUIDNormalize(
2529         slap_mask_t usage,
2530         Syntax *syntax,
2531         MatchingRule *mr,
2532         struct berval *val,
2533         struct berval *normalized,
2534         void *ctx )
2535 {
2536         unsigned char octet = '\0';
2537         int i;
2538         int j;
2539
2540         if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2541                 /* NOTE: must be a normalized UUID */
2542                 assert( val->bv_len == 16 );
2543
2544                 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2545                 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2546                         val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2547                 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2548
2549                 return LDAP_SUCCESS;
2550         }
2551
2552         normalized->bv_len = 16;
2553         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2554
2555         for( i=0, j=0; i<36; i++ ) {
2556                 unsigned char nibble;
2557                 if( val->bv_val[i] == '-' ) {
2558                         continue;
2559
2560                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2561                         nibble = val->bv_val[i] - '0';
2562
2563                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2564                         nibble = val->bv_val[i] - ('a'-10);
2565
2566                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2567                         nibble = val->bv_val[i] - ('A'-10);
2568
2569                 } else {
2570                         slap_sl_free( normalized->bv_val, ctx );
2571                         return LDAP_INVALID_SYNTAX;
2572                 }
2573
2574                 if( j & 1 ) {
2575                         octet |= nibble;
2576                         normalized->bv_val[j>>1] = octet;
2577                 } else {
2578                         octet = nibble << 4;
2579                 }
2580                 j++;
2581         }
2582
2583         normalized->bv_val[normalized->bv_len] = 0;
2584         return LDAP_SUCCESS;
2585 }
2586
2587
2588
2589 int
2590 numericStringValidate(
2591         Syntax *syntax,
2592         struct berval *in )
2593 {
2594         ber_len_t i;
2595
2596         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2597
2598         for(i=0; i < in->bv_len; i++) {
2599                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2600                         return LDAP_INVALID_SYNTAX;
2601                 }
2602         }
2603
2604         return LDAP_SUCCESS;
2605 }
2606
2607 static int
2608 numericStringNormalize(
2609         slap_mask_t usage,
2610         Syntax *syntax,
2611         MatchingRule *mr,
2612         struct berval *val,
2613         struct berval *normalized,
2614         void *ctx )
2615 {
2616         /* removal all spaces */
2617         char *p, *q;
2618
2619         assert( !BER_BVISEMPTY( val ) );
2620
2621         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2622
2623         p = val->bv_val;
2624         q = normalized->bv_val;
2625
2626         while ( *p ) {
2627                 if ( ASCII_SPACE( *p ) ) {
2628                         /* Ignore whitespace */
2629                         p++;
2630                 } else {
2631                         *q++ = *p++;
2632                 }
2633         }
2634
2635         /* we should have copied no more than is in val */
2636         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2637
2638         /* null terminate */
2639         *q = '\0';
2640
2641         normalized->bv_len = q - normalized->bv_val;
2642
2643         if( BER_BVISEMPTY( normalized ) ) {
2644                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2645                 normalized->bv_val[0] = ' ';
2646                 normalized->bv_val[1] = '\0';
2647                 normalized->bv_len = 1;
2648         }
2649
2650         return LDAP_SUCCESS;
2651 }
2652
2653 /*
2654  * Integer conversion macros that will use the largest available
2655  * type.
2656  */
2657 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2658 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2659 # define SLAP_LONG           long long
2660 #else
2661 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2662 # define SLAP_LONG           long
2663 #endif /* HAVE_STRTOLL ... */
2664
2665 static int
2666 integerBitAndMatch(
2667         int *matchp,
2668         slap_mask_t flags,
2669         Syntax *syntax,
2670         MatchingRule *mr,
2671         struct berval *value,
2672         void *assertedValue )
2673 {
2674         SLAP_LONG lValue, lAssertedValue;
2675
2676         errno = 0;
2677         /* safe to assume integers are NUL terminated? */
2678         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2679         if( errno == ERANGE )
2680         {
2681                 return LDAP_CONSTRAINT_VIOLATION;
2682         }
2683
2684         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2685                 NULL, 10);
2686         if( errno == ERANGE )
2687         {
2688                 return LDAP_CONSTRAINT_VIOLATION;
2689         }
2690
2691         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2692         return LDAP_SUCCESS;
2693 }
2694
2695 static int
2696 integerBitOrMatch(
2697         int *matchp,
2698         slap_mask_t flags,
2699         Syntax *syntax,
2700         MatchingRule *mr,
2701         struct berval *value,
2702         void *assertedValue )
2703 {
2704         SLAP_LONG lValue, lAssertedValue;
2705
2706         errno = 0;
2707         /* safe to assume integers are NUL terminated? */
2708         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2709         if( errno == ERANGE )
2710         {
2711                 return LDAP_CONSTRAINT_VIOLATION;
2712         }
2713
2714         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2715                 NULL, 10);
2716         if( errno == ERANGE )
2717         {
2718                 return LDAP_CONSTRAINT_VIOLATION;
2719         }
2720
2721         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2722         return LDAP_SUCCESS;
2723 }
2724
2725 static int
2726 serialNumberAndIssuerCheck(
2727         struct berval *in,
2728         struct berval *sn,
2729         struct berval *is,
2730         void *ctx
2731 )
2732 {
2733         int is_hex = 0, n;
2734
2735         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2736
2737         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2738                 /* Parse old format */
2739                 is->bv_val = ber_bvchr( in, '$' );
2740                 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
2741
2742                 sn->bv_val = in->bv_val;
2743                 sn->bv_len = is->bv_val - in->bv_val;
2744
2745                 is->bv_val++;
2746                 is->bv_len = in->bv_len - (sn->bv_len + 1);
2747
2748                 /* eat leading zeros */
2749                 for( n=0; n < (sn->bv_len-1); n++ ) {
2750                         if( sn->bv_val[n] != '0' ) break;
2751                 }
2752                 sn->bv_val += n;
2753                 sn->bv_len -= n;
2754
2755                 for( n=0; n < sn->bv_len; n++ ) {
2756                         if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2757                 }
2758
2759         } else {
2760                 /* Parse GSER format */ 
2761                 int havesn=0,haveissuer=0;
2762                 struct berval x = *in;
2763                 struct berval ni;
2764                 x.bv_val++;
2765                 x.bv_len-=2;
2766
2767                 /* eat leading spaces */
2768                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2769                         /* empty */;
2770                 }
2771
2772                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2773                         return LDAP_INVALID_SYNTAX;
2774                 }
2775
2776                 /* should be at issuer or serialNumber NamedValue */
2777                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2778                         /* parse issuer */
2779                         x.bv_val += STRLENOF("issuer");
2780                         x.bv_len -= STRLENOF("issuer");
2781
2782                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2783                         x.bv_val++; x.bv_len--;
2784
2785                         /* eat leading spaces */
2786                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2787                                 /* empty */;
2788                         }
2789
2790                         /* For backward compatibility, this part is optional */
2791                         if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2792                                 x.bv_val += STRLENOF("rdnSequence:");
2793                                 x.bv_len -= STRLENOF("rdnSequence:");
2794                         }
2795
2796                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2797                         x.bv_val++; x.bv_len--;
2798
2799                         is->bv_val = x.bv_val;
2800                         is->bv_len = 0;
2801
2802                         for( ; is->bv_len < x.bv_len; ) {
2803                                 if ( is->bv_val[is->bv_len] != '"' ) {
2804                                         is->bv_len++;
2805                                         continue;
2806                                 }
2807                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
2808                                         /* double dquote */
2809                                         is->bv_len+=2;
2810                                         continue;
2811                                 }
2812                                 break;
2813                         }
2814                         x.bv_val += is->bv_len+1;
2815                         x.bv_len -= is->bv_len+1;
2816
2817                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2818                                 return LDAP_INVALID_SYNTAX;
2819                         }
2820
2821                         haveissuer++;
2822
2823                 } else if( strncasecmp( x.bv_val, "serialNumber",
2824                         STRLENOF("serialNumber")) == 0 )
2825                 {
2826                         /* parse serialNumber */
2827                         int neg=0;
2828                         x.bv_val += STRLENOF("serialNumber");
2829                         x.bv_len -= STRLENOF("serialNumber");
2830
2831                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2832                         x.bv_val++; x.bv_len--;
2833
2834                         /* eat leading spaces */
2835                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2836                                 /* empty */;
2837                         }
2838                         
2839                         sn->bv_val = x.bv_val;
2840                         sn->bv_len = 0;
2841
2842                         if( sn->bv_val[0] == '-' ) {
2843                                 neg++;
2844                                 sn->bv_len++;
2845                         }
2846
2847                         if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2848                                 sn->bv_val[1] == 'X' )) {
2849                                 is_hex = 1;
2850                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2851                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2852                                 }
2853                         } else if ( sn->bv_val[0] == '\'' ) {
2854                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2855                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2856                                 }
2857                                 if ( sn->bv_val[sn->bv_len] == '\'' &&
2858                                         sn->bv_val[sn->bv_len+1] == 'H' )
2859                                         is_hex = 1;
2860                                 else
2861                                         return LDAP_INVALID_SYNTAX;
2862                                 sn->bv_len += 2;
2863                         } else {
2864                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2865                                         if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2866                                 }
2867                         }
2868
2869                         if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2870                         if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2871                                 return LDAP_INVALID_SYNTAX;
2872                         }
2873
2874                         x.bv_val += sn->bv_len; x.bv_len -= sn->bv_len;
2875
2876                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2877                                 return LDAP_INVALID_SYNTAX;
2878                         }
2879
2880                         havesn++;
2881
2882                 } else return LDAP_INVALID_SYNTAX;
2883
2884                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2885                 x.bv_val++; x.bv_len--;
2886
2887                 /* eat spaces */
2888                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2889                         /* empty */;
2890                 }
2891
2892                 /* should be at remaining NamedValue */
2893                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2894                         STRLENOF("issuer" )) == 0 ))
2895                 {
2896                         /* parse issuer */
2897                         x.bv_val += STRLENOF("issuer");
2898                         x.bv_len -= STRLENOF("issuer");
2899
2900                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2901                         x.bv_val++; x.bv_len--;
2902
2903                         /* eat leading spaces */
2904                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2905                                  /* empty */;
2906                         }
2907
2908                         /* For backward compatibility, this part is optional */
2909                         if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2910                                 x.bv_val += STRLENOF("rdnSequence:");
2911                                 x.bv_len -= STRLENOF("rdnSequence:");
2912                         }
2913
2914                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2915                         x.bv_val++; x.bv_len--;
2916
2917                         is->bv_val = x.bv_val;
2918                         is->bv_len = 0;
2919
2920                         for( ; is->bv_len < x.bv_len; ) {
2921                                 if ( is->bv_val[is->bv_len] != '"' ) {
2922                                         is->bv_len++;
2923                                         continue;
2924                                 }
2925                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
2926                                         /* double dquote */
2927                                         is->bv_len+=2;
2928                                         continue;
2929                                 }
2930                                 break;
2931                         }
2932                         x.bv_val += is->bv_len+1;
2933                         x.bv_len -= is->bv_len+1;
2934
2935                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2936                         STRLENOF("serialNumber")) == 0 ))
2937                 {
2938                         /* parse serialNumber */
2939                         int neg=0;
2940                         x.bv_val += STRLENOF("serialNumber");
2941                         x.bv_len -= STRLENOF("serialNumber");
2942
2943                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2944                         x.bv_val++; x.bv_len--;
2945
2946                         /* eat leading spaces */
2947                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2948                                 /* empty */;
2949                         }
2950                         
2951                         sn->bv_val = x.bv_val;
2952                         sn->bv_len = 0;
2953
2954                         if( sn->bv_val[0] == '-' ) {
2955                                 neg++;
2956                                 sn->bv_len++;
2957                         }
2958
2959                         if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2960                                 sn->bv_val[1] == 'X' )) {
2961                                 is_hex = 1;
2962                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2963                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2964                                 }
2965                         } else if ( sn->bv_val[0] == '\'' ) {
2966                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2967                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2968                                 }
2969                                 if ( sn->bv_val[sn->bv_len] == '\'' &&
2970                                         sn->bv_val[sn->bv_len+1] == 'H' )
2971                                         is_hex = 1;
2972                                 else
2973                                         return LDAP_INVALID_SYNTAX;
2974                                 sn->bv_len += 2;
2975                         } else {
2976                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2977                                         if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2978                                 }
2979                         }
2980
2981                         if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2982                         if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2983                                 return LDAP_INVALID_SYNTAX;
2984                         }
2985
2986                         x.bv_val += sn->bv_len;
2987                         x.bv_len -= sn->bv_len;
2988
2989                 } else return LDAP_INVALID_SYNTAX;
2990
2991                 /* eat trailing spaces */
2992                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2993                         /* empty */;
2994                 }
2995
2996                 /* should have no characters left... */
2997                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2998
2999                 ber_dupbv_x( &ni, is, ctx );
3000                 *is = ni;
3001
3002                 /* need to handle double dquotes here */
3003         }
3004         return 0;
3005 }
3006         
3007 static int
3008 serialNumberAndIssuerValidate(
3009         Syntax *syntax,
3010         struct berval *in )
3011 {
3012         int rc;
3013         struct berval sn, i;
3014
3015         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3016                 in->bv_val, 0, 0 );
3017
3018         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3019         if ( rc )
3020                 return rc;
3021
3022         /* validate DN -- doesn't handle double dquote */ 
3023         rc = dnValidate( NULL, &i );
3024         if( rc )
3025                 rc = LDAP_INVALID_SYNTAX;
3026
3027         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3028                 slap_sl_free( i.bv_val, NULL );
3029         }
3030
3031         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
3032                 0, 0, 0 );
3033         return rc;
3034 }
3035
3036 int
3037 serialNumberAndIssuerPretty(
3038         Syntax *syntax,
3039         struct berval *in,
3040         struct berval *out,
3041         void *ctx )
3042 {
3043         int n, rc;
3044         struct berval sn, i, ni;
3045
3046         assert( in != NULL );
3047         assert( out != NULL );
3048
3049         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3050                 in->bv_val, 0, 0 );
3051
3052         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3053         if ( rc )
3054                 return rc;
3055
3056         rc = dnPretty( syntax, &i, &ni, ctx );
3057
3058         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3059                 slap_sl_free( i.bv_val, ctx );
3060         }
3061
3062         if( rc ) return LDAP_INVALID_SYNTAX;
3063
3064         /* make room from sn + "$" */
3065         out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3066                 + sn.bv_len + ni.bv_len;
3067         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3068
3069         if( out->bv_val == NULL ) {
3070                 out->bv_len = 0;
3071                 slap_sl_free( ni.bv_val, ctx );
3072                 return LDAP_OTHER;
3073         }
3074
3075         n = 0;
3076         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3077                 STRLENOF("{ serialNumber "));
3078         n = STRLENOF("{ serialNumber ");
3079
3080         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3081         n += sn.bv_len;
3082
3083         AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF(", issuer rdnSequence:\""));
3084         n += STRLENOF(", issuer rdnSequence:\"");
3085
3086         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3087         n += ni.bv_len;
3088
3089         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3090         n += STRLENOF("\" }");
3091
3092         out->bv_val[n] = '\0';
3093
3094         assert( n == out->bv_len );
3095
3096         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3097                 out->bv_val, 0, 0 );
3098
3099         slap_sl_free( ni.bv_val, ctx );
3100
3101         return LDAP_SUCCESS; 
3102 }
3103
3104 /*
3105  * This routine is called by certificateExactNormalize when
3106  * certificateExactNormalize receives a search string instead of
3107  * a certificate. This routine checks if the search value is valid
3108  * and then returns the normalized value
3109  */
3110 static int
3111 serialNumberAndIssuerNormalize(
3112         slap_mask_t usage,
3113         Syntax *syntax,
3114         MatchingRule *mr,
3115         struct berval *in,
3116         struct berval *out,
3117         void *ctx )
3118 {
3119         struct berval sn, sn2, i, ni;
3120         char sbuf[64], *stmp = sbuf;
3121         int rc;
3122         ber_len_t n;
3123
3124         assert( in != NULL );
3125         assert( out != NULL );
3126
3127         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3128                 in->bv_val, 0, 0 );
3129
3130         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3131         if ( rc )
3132                 return rc;
3133
3134         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3135
3136         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3137                 slap_sl_free( i.bv_val, ctx );
3138         }
3139
3140         if( rc ) return LDAP_INVALID_SYNTAX;
3141
3142         /* Convert sn to canonical hex */
3143         if ( sn.bv_len > sizeof( sbuf )) {
3144                 stmp = slap_sl_malloc( sn.bv_len, ctx );
3145         }
3146         sn2.bv_val = stmp;
3147         sn2.bv_len = sn.bv_len;
3148         if ( lutil_str2bin( &sn, &sn2, ctx )) {
3149                 rc = LDAP_INVALID_SYNTAX;
3150                 goto leave;
3151         }
3152
3153         /* make room for sn + "$" */
3154         out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3155                 + ( sn2.bv_len * 2 + 3 ) + ni.bv_len;
3156         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3157
3158         if( out->bv_val == NULL ) {
3159                 out->bv_len = 0;
3160                 slap_sl_free( ni.bv_val, ctx );
3161                 rc = LDAP_OTHER;
3162                 goto leave;
3163         }
3164
3165         n = 0;
3166         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3167                 STRLENOF( "{ serialNumber " ));
3168         n = STRLENOF( "{ serialNumber " );
3169
3170         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3171         {
3172                 int j;
3173                 unsigned char *v = (unsigned char *)sn2.bv_val;
3174                 out->bv_val[n++] = '\'';
3175                 for ( j = 0; j < sn2.bv_len; j++ ) {
3176                         snprintf( &out->bv_val[n], out->bv_len - n + 1,
3177                                 "%02X", v[j] );
3178                         n += 2;
3179                 }
3180                 out->bv_val[n++] = '\'';
3181                 out->bv_val[n++] = 'H';
3182         }
3183
3184         AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3185         n += STRLENOF( ", issuer rdnSequence:\"" );
3186
3187         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3188         n += ni.bv_len;
3189
3190         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3191         n += STRLENOF( "\" }" );
3192
3193         out->bv_val[n] = '\0';
3194
3195         assert( n == out->bv_len );
3196
3197         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3198                 out->bv_val, 0, 0 );
3199
3200 leave:
3201         if ( stmp != sbuf )
3202                 slap_sl_free( stmp, ctx );
3203         slap_sl_free( ni.bv_val, ctx );
3204
3205         return rc;
3206 }
3207
3208 static int
3209 certificateExactNormalize(
3210         slap_mask_t usage,
3211         Syntax *syntax,
3212         MatchingRule *mr,
3213         struct berval *val,
3214         struct berval *normalized,
3215         void *ctx )
3216 {
3217         BerElementBuffer berbuf;
3218         BerElement *ber = (BerElement *)&berbuf;
3219         ber_tag_t tag;
3220         ber_len_t len;
3221         ber_int_t i;
3222         char serialbuf[64], *serial = serialbuf;
3223         ber_len_t seriallen;
3224         struct berval issuer_dn = BER_BVNULL, bvdn;
3225         unsigned char *p;
3226         int rc = LDAP_INVALID_SYNTAX;
3227
3228         if( BER_BVISEMPTY( val ) ) goto done;
3229
3230         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3231                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3232         }
3233
3234         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3235
3236         ber_init2( ber, val, LBER_USE_DER );
3237         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3238         tag = ber_skip_tag( ber, &len );        /* Sequence */
3239         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3240         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3241                 tag = ber_skip_tag( ber, &len );
3242                 tag = ber_get_int( ber, &i );   /* version */
3243         }
3244
3245         /* NOTE: move the test here from certificateValidate,
3246          * so that we can validate certs with serial longer
3247          * than sizeof(ber_int_t) */
3248         tag = ber_peek_tag( ber, &len );        /* serial */
3249
3250         /* Use hex format. '123456789abcdef'H
3251          */
3252         {
3253                 unsigned char *ptr;
3254                 char *sptr;
3255                 
3256                 tag = ber_skip_tag( ber, &len );
3257                 ptr = (unsigned char *)ber->ber_ptr;
3258                 ber_skip_data( ber, len );
3259
3260                 /* Check for minimal encodings */
3261                 if ( len > 1 ) {
3262                         if ( ptr[0] & 0x80 ) {
3263                                 if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3264                                         return LDAP_INVALID_SYNTAX;
3265                         } else if ( ptr[0] == 0 ) {
3266                                 if (!( ptr[1] & 0x80 ))
3267                                         return LDAP_INVALID_SYNTAX;
3268                         }
3269                 }
3270
3271                 seriallen = len * 2 + 4;        /* quotes, H, NUL */
3272                 if ( seriallen > sizeof( serialbuf ))
3273                         serial = slap_sl_malloc( seriallen, ctx );
3274                 sptr = serial;
3275                 *sptr++ = '\'';
3276                 for ( i = 0; i<len; i++ ) {
3277                         sprintf( sptr, "%02X", ptr[i] );
3278                         sptr += 2;
3279                 }
3280                 *sptr++ = '\'';
3281                 *sptr++ = 'H';
3282                 seriallen--;
3283         }
3284         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3285         ber_skip_data( ber, len );
3286         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3287         len = ber_ptrlen( ber );
3288         bvdn.bv_val = val->bv_val + len;
3289         bvdn.bv_len = val->bv_len - len;
3290
3291         rc = dnX509normalize( &bvdn, &issuer_dn );
3292         if( rc != LDAP_SUCCESS ) goto done;
3293
3294         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3295                 + seriallen + issuer_dn.bv_len;
3296         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3297
3298         p = (unsigned char *)normalized->bv_val;
3299
3300         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3301         p += STRLENOF( "{ serialNumber " );
3302
3303         AC_MEMCPY(p, serial, seriallen);
3304         p += seriallen;
3305
3306         AC_MEMCPY(p, ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3307         p += STRLENOF( ", issuer rdnSequence:\"" );
3308
3309         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3310         p += issuer_dn.bv_len;
3311
3312         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3313         p += STRLENOF( "\" }" );
3314
3315         *p = '\0';
3316
3317         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3318                 normalized->bv_val, NULL, NULL );
3319
3320         rc = LDAP_SUCCESS;
3321
3322 done:
3323         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3324         if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3325
3326         return rc;
3327 }
3328
3329 static int
3330 hexValidate(
3331         Syntax *syntax,
3332         struct berval *in )
3333 {
3334         int     i;
3335
3336         assert( in != NULL );
3337         assert( !BER_BVISNULL( in ) );
3338
3339         for ( i = 0; i < in->bv_len; i++ ) {
3340                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3341                         return LDAP_INVALID_SYNTAX;
3342                 }
3343         }
3344
3345         return LDAP_SUCCESS;
3346 }
3347
3348 /* Normalize a SID as used inside a CSN:
3349  * three-digit numeric string */
3350 static int
3351 hexNormalize(
3352         slap_mask_t usage,
3353         Syntax *syntax,
3354         MatchingRule *mr,
3355         struct berval *val,
3356         struct berval *normalized,
3357         void *ctx )
3358 {
3359         int     i;
3360
3361         assert( val != NULL );
3362         assert( normalized != NULL );
3363
3364         ber_dupbv_x( normalized, val, ctx );
3365
3366         for ( i = 0; i < normalized->bv_len; i++ ) {
3367                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3368                         ber_memfree_x( normalized->bv_val, ctx );
3369                         BER_BVZERO( normalized );
3370                         return LDAP_INVALID_SYNTAX;
3371                 }
3372
3373                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3374         }
3375
3376         return LDAP_SUCCESS;
3377 }
3378
3379 static int
3380 sidValidate (
3381         Syntax *syntax,
3382         struct berval *in )
3383 {
3384         assert( in != NULL );
3385         assert( !BER_BVISNULL( in ) );
3386
3387         if ( in->bv_len != 3 ) {
3388                 return LDAP_INVALID_SYNTAX;
3389         }
3390
3391         return hexValidate( NULL, in );
3392 }
3393
3394 /* Normalize a SID as used inside a CSN:
3395  * three-digit numeric string */
3396 static int
3397 sidNormalize(
3398         slap_mask_t usage,
3399         Syntax *syntax,
3400         MatchingRule *mr,
3401         struct berval *val,
3402         struct berval *normalized,
3403         void *ctx )
3404 {
3405         if ( val->bv_len != 3 ) {
3406                 return LDAP_INVALID_SYNTAX;
3407         }
3408
3409         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3410 }
3411
3412 static int
3413 sidPretty(
3414         Syntax *syntax,
3415         struct berval *val,
3416         struct berval *out,
3417         void *ctx )
3418 {
3419         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3420 }
3421
3422 /* Normalize a SID as used inside a CSN, either as-is
3423  * (assertion value) or extracted from the CSN
3424  * (attribute value) */
3425 static int
3426 csnSidNormalize(
3427         slap_mask_t usage,
3428         Syntax *syntax,
3429         MatchingRule *mr,
3430         struct berval *val,
3431         struct berval *normalized,
3432         void *ctx )
3433 {
3434         struct berval   bv;
3435         char            *ptr,
3436                         buf[ 4 ];
3437
3438
3439         if ( BER_BVISEMPTY( val ) ) {
3440                 return LDAP_INVALID_SYNTAX;
3441         }
3442
3443         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3444                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3445         }
3446
3447         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3448
3449         ptr = ber_bvchr( val, '#' );
3450         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3451                 return LDAP_INVALID_SYNTAX;
3452         }
3453
3454         bv.bv_val = ptr + 1;
3455         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3456
3457         ptr = ber_bvchr( &bv, '#' );
3458         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3459                 return LDAP_INVALID_SYNTAX;
3460         }
3461
3462         bv.bv_val = ptr + 1;
3463         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3464                 
3465         ptr = ber_bvchr( &bv, '#' );
3466         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3467                 return LDAP_INVALID_SYNTAX;
3468         }
3469
3470         bv.bv_len = ptr - bv.bv_val;
3471
3472         if ( bv.bv_len == 2 ) {
3473                 /* OpenLDAP 2.3 SID */
3474                 buf[ 0 ] = '0';
3475                 buf[ 1 ] = bv.bv_val[ 0 ];
3476                 buf[ 2 ] = bv.bv_val[ 1 ];
3477                 buf[ 3 ] = '\0';
3478
3479                 bv.bv_val = buf;
3480                 bv.bv_len = 3;
3481         }
3482
3483         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3484 }
3485
3486 static int
3487 csnValidate(
3488         Syntax *syntax,
3489         struct berval *in )
3490 {
3491         struct berval   bv;
3492         char            *ptr;
3493         int             rc;
3494
3495         assert( in != NULL );
3496         assert( !BER_BVISNULL( in ) );
3497
3498         if ( BER_BVISEMPTY( in ) ) {
3499                 return LDAP_INVALID_SYNTAX;
3500         }
3501
3502         bv = *in;
3503
3504         ptr = ber_bvchr( &bv, '#' );
3505         if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3506                 return LDAP_INVALID_SYNTAX;
3507         }
3508
3509         bv.bv_len = ptr - bv.bv_val;
3510         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3511                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3512         {
3513                 return LDAP_INVALID_SYNTAX;
3514         }
3515
3516         rc = generalizedTimeValidate( NULL, &bv );
3517         if ( rc != LDAP_SUCCESS ) {
3518                 return rc;
3519         }
3520
3521         bv.bv_val = ptr + 1;
3522         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3523
3524         ptr = ber_bvchr( &bv, '#' );
3525         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3526                 return LDAP_INVALID_SYNTAX;
3527         }
3528
3529         bv.bv_len = ptr - bv.bv_val;
3530         if ( bv.bv_len != 6 ) {
3531                 return LDAP_INVALID_SYNTAX;
3532         }
3533
3534         rc = hexValidate( NULL, &bv );
3535         if ( rc != LDAP_SUCCESS ) {
3536                 return rc;
3537         }
3538
3539         bv.bv_val = ptr + 1;
3540         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3541
3542         ptr = ber_bvchr( &bv, '#' );
3543         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3544                 return LDAP_INVALID_SYNTAX;
3545         }
3546
3547         bv.bv_len = ptr - bv.bv_val;
3548         if ( bv.bv_len == 2 ) {
3549                 /* tolerate old 2-digit replica-id */
3550                 rc = hexValidate( NULL, &bv );
3551
3552         } else {
3553                 rc = sidValidate( NULL, &bv );
3554         }
3555         if ( rc != LDAP_SUCCESS ) {
3556                 return rc;
3557         }
3558
3559         bv.bv_val = ptr + 1;
3560         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3561
3562         if ( bv.bv_len != 6 ) {
3563                 return LDAP_INVALID_SYNTAX;
3564         }
3565
3566         return hexValidate( NULL, &bv );
3567 }
3568
3569 /* Normalize a CSN in OpenLDAP 2.3 format */
3570 static int
3571 csnNormalize23(
3572         slap_mask_t usage,
3573         Syntax *syntax,
3574         MatchingRule *mr,
3575         struct berval *val,
3576         struct berval *normalized,
3577         void *ctx )
3578 {
3579         struct berval   gt, cnt, sid, mod;
3580         char            *ptr;
3581         int             i;
3582
3583         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3584         assert( !BER_BVISEMPTY( val ) );
3585
3586         gt = *val;
3587
3588         ptr = ber_bvchr( &gt, '#' );
3589         if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3590                 return LDAP_INVALID_SYNTAX;
3591         }
3592
3593         gt.bv_len = ptr - gt.bv_val;
3594         assert( gt.bv_len == STRLENOF( "YYYYmmddHHMMSSZ" ) );
3595
3596         cnt.bv_val = ptr + 1;
3597         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3598
3599         ptr = ber_bvchr( &cnt, '#' );
3600         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3601                 return LDAP_INVALID_SYNTAX;
3602         }
3603
3604         cnt.bv_len = ptr - cnt.bv_val;
3605         assert( cnt.bv_len == STRLENOF( "000000" ) );
3606
3607         sid.bv_val = ptr + 1;
3608         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3609                 
3610         ptr = ber_bvchr( &sid, '#' );
3611         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3612                 return LDAP_INVALID_SYNTAX;
3613         }
3614
3615         sid.bv_len = ptr - sid.bv_val;
3616         assert( sid.bv_len == STRLENOF( "00" ) );
3617
3618         mod.bv_val = ptr + 1;
3619         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3620         assert( mod.bv_len == STRLENOF( "000000" ) );
3621
3622         normalized->bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3623         normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
3624
3625         ptr = normalized->bv_val;
3626         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3627         ptr = lutil_strcopy( ptr, ".000000Z#" );
3628         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3629         *ptr++ = '#';
3630         *ptr++ = '0';
3631         for ( i = 0; i < sid.bv_len; i++ ) {
3632                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3633         }
3634         *ptr++ = '#';
3635         for ( i = 0; i < mod.bv_len; i++ ) {
3636                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3637         }
3638         *ptr = '\0';
3639
3640         assert( ptr - normalized->bv_val == normalized->bv_len );
3641
3642         return LDAP_SUCCESS;
3643 }
3644
3645 /* Normalize a CSN */
3646 static int
3647 csnNormalize(
3648         slap_mask_t usage,
3649         Syntax *syntax,
3650         MatchingRule *mr,
3651         struct berval *val,
3652         struct berval *normalized,
3653         void *ctx )
3654 {
3655         struct berval   cnt, sid, mod;
3656         char            *ptr;
3657         int             i;
3658
3659         assert( val != NULL );
3660         assert( normalized != NULL );
3661
3662         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3663
3664         if ( BER_BVISEMPTY( val ) ) {
3665                 return LDAP_INVALID_SYNTAX;
3666         }
3667
3668         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3669                 /* Openldap <= 2.3 */
3670
3671                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3672         }
3673
3674         assert( val->bv_len == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) );
3675
3676         ptr = ber_bvchr( val, '#' );
3677         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3678                 return LDAP_INVALID_SYNTAX;
3679         }
3680
3681         assert( ptr - val->bv_val == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) );
3682
3683         cnt.bv_val = ptr + 1;
3684         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3685
3686         ptr = ber_bvchr( &cnt, '#' );
3687         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3688                 return LDAP_INVALID_SYNTAX;
3689         }
3690
3691         assert( ptr - cnt.bv_val == STRLENOF( "000000" ) );
3692
3693         sid.bv_val = ptr + 1;
3694         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3695                 
3696         ptr = ber_bvchr( &sid, '#' );
3697         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3698                 return LDAP_INVALID_SYNTAX;
3699         }
3700
3701         sid.bv_len = ptr - sid.bv_val;
3702         assert( sid.bv_len == STRLENOF( "000" ) );
3703
3704         mod.bv_val = ptr + 1;
3705         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3706
3707         assert( mod.bv_len == STRLENOF( "000000" ) );
3708
3709         ber_dupbv_x( normalized, val, ctx );
3710
3711         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3712                 i < normalized->bv_len; i++ )
3713         {
3714                 /* assume it's already validated that's all hex digits */
3715                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3716         }
3717
3718         return LDAP_SUCCESS;
3719 }
3720
3721 static int
3722 csnPretty(
3723         Syntax *syntax,
3724         struct berval *val,
3725         struct berval *out,
3726         void *ctx )
3727 {
3728         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3729 }
3730
3731 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3732 /* slight optimization - does not need the start parameter */
3733 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3734 enum { start = 0 };
3735 #endif
3736
3737 static int
3738 check_time_syntax (struct berval *val,
3739         int start,
3740         int *parts,
3741         struct berval *fraction)
3742 {
3743         /*
3744          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3745          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3746          * GeneralizedTime supports leap seconds, UTCTime does not.
3747          */
3748         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3749         static const int mdays[2][12] = {
3750                 /* non-leap years */
3751                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3752                 /* leap years */
3753                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3754         };
3755         char *p, *e;
3756         int part, c, c1, c2, tzoffset, leapyear = 0;
3757
3758         p = val->bv_val;
3759         e = p + val->bv_len;
3760
3761 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3762         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3763 #endif
3764         for (part = start; part < 7 && p < e; part++) {
3765                 c1 = *p;
3766                 if (!ASCII_DIGIT(c1)) {
3767                         break;
3768                 }
3769                 p++;
3770                 if (p == e) {
3771                         return LDAP_INVALID_SYNTAX;
3772                 }
3773                 c = *p++;
3774                 if (!ASCII_DIGIT(c)) {
3775                         return LDAP_INVALID_SYNTAX;
3776                 }
3777                 c += c1 * 10 - '0' * 11;
3778                 if ((part | 1) == 3) {
3779                         --c;
3780                         if (c < 0) {
3781                                 return LDAP_INVALID_SYNTAX;
3782                         }
3783                 }
3784                 if (c >= ceiling[part]) {
3785                         if (! (c == 60 && part == 6 && start == 0))
3786                                 return LDAP_INVALID_SYNTAX;
3787                 }
3788                 parts[part] = c;
3789         }
3790         if (part < 5 + start) {
3791                 return LDAP_INVALID_SYNTAX;
3792         }
3793         for (; part < 9; part++) {
3794                 parts[part] = 0;
3795         }
3796
3797         /* leapyear check for the Gregorian calendar (year>1581) */
3798         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3799                 leapyear = 1;
3800         }
3801
3802         if (parts[3] >= mdays[leapyear][parts[2]]) {
3803                 return LDAP_INVALID_SYNTAX;
3804         }
3805
3806         if (start == 0) {
3807                 fraction->bv_val = p;
3808                 fraction->bv_len = 0;
3809                 if (p < e && (*p == '.' || *p == ',')) {
3810                         char *end_num;
3811                         while (++p < e && ASCII_DIGIT(*p)) {
3812                                 /* EMTPY */;
3813                         }
3814                         if (p - fraction->bv_val == 1) {
3815                                 return LDAP_INVALID_SYNTAX;
3816                         }
3817                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3818                                 /* EMPTY */;
3819                         }
3820                         c = end_num - fraction->bv_val;
3821                         if (c != 1) fraction->bv_len = c;
3822                 }
3823         }
3824
3825         if (p == e) {
3826                 /* no time zone */
3827                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3828         }
3829
3830         tzoffset = *p++;
3831         switch (tzoffset) {
3832         default:
3833                 return LDAP_INVALID_SYNTAX;
3834         case 'Z':
3835                 /* UTC */
3836                 break;
3837         case '+':
3838         case '-':
3839                 for (part = 7; part < 9 && p < e; part++) {
3840                         c1 = *p;
3841                         if (!ASCII_DIGIT(c1)) {
3842                                 break;
3843                         }
3844                         p++;
3845                         if (p == e) {
3846                                 return LDAP_INVALID_SYNTAX;
3847                         }
3848                         c2 = *p++;
3849                         if (!ASCII_DIGIT(c2)) {
3850                                 return LDAP_INVALID_SYNTAX;
3851                         }
3852                         parts[part] = c1 * 10 + c2 - '0' * 11;
3853                         if (parts[part] >= ceiling[part]) {
3854                                 return LDAP_INVALID_SYNTAX;
3855                         }
3856                 }
3857                 if (part < 8 + start) {
3858                         return LDAP_INVALID_SYNTAX;
3859                 }
3860
3861                 if (tzoffset == '-') {
3862                         /* negative offset to UTC, ie west of Greenwich */
3863                         parts[4] += parts[7];
3864                         parts[5] += parts[8];
3865                         /* offset is just hhmm, no seconds */
3866                         for (part = 6; --part >= 0; ) {
3867                                 if (part != 3) {
3868                                         c = ceiling[part];
3869                                 } else {
3870                                         c = mdays[leapyear][parts[2]];
3871                                 }
3872                                 if (parts[part] >= c) {
3873                                         if (part == 0) {
3874                                                 return LDAP_INVALID_SYNTAX;
3875                                         }
3876                                         parts[part] -= c;
3877                                         parts[part - 1]++;
3878                                         continue;
3879                                 } else if (part != 5) {
3880                                         break;
3881                                 }
3882                         }
3883                 } else {
3884                         /* positive offset to UTC, ie east of Greenwich */
3885                         parts[4] -= parts[7];
3886                         parts[5] -= parts[8];
3887                         for (part = 6; --part >= 0; ) {
3888                                 if (parts[part] < 0) {
3889                                         if (part == 0) {
3890                                                 return LDAP_INVALID_SYNTAX;
3891                                         }
3892                                         if (part != 3) {
3893                                                 c = ceiling[part];
3894                                         } else {
3895                                                 /* make first arg to % non-negative */
3896                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3897                                         }
3898                                         parts[part] += c;
3899                                         parts[part - 1]--;
3900                                         continue;
3901                                 } else if (part != 5) {
3902                                         break;
3903                                 }
3904                         }
3905                 }
3906         }
3907
3908         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3909 }
3910
3911 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3912
3913 #if 0
3914 static int
3915 xutcTimeNormalize(
3916         Syntax *syntax,
3917         struct berval *val,
3918         struct berval *normalized )
3919 {
3920         int parts[9], rc;
3921
3922         rc = check_time_syntax(val, 1, parts, NULL);
3923         if (rc != LDAP_SUCCESS) {
3924                 return rc;
3925         }
3926
3927         normalized->bv_val = ch_malloc( 14 );
3928         if ( normalized->bv_val == NULL ) {
3929                 return LBER_ERROR_MEMORY;
3930         }
3931
3932         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3933                 parts[1], parts[2] + 1, parts[3] + 1,
3934                 parts[4], parts[5], parts[6] );
3935         normalized->bv_len = 13;
3936
3937         return LDAP_SUCCESS;
3938 }
3939 #endif /* 0 */
3940
3941 static int
3942 utcTimeValidate(
3943         Syntax *syntax,
3944         struct berval *in )
3945 {
3946         int parts[9];
3947         return check_time_syntax(in, 1, parts, NULL);
3948 }
3949
3950 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3951
3952 static int
3953 generalizedTimeValidate(
3954         Syntax *syntax,
3955         struct berval *in )
3956 {
3957         int parts[9];
3958         struct berval fraction;
3959         return check_time_syntax(in, 0, parts, &fraction);
3960 }
3961
3962 static int
3963 generalizedTimeNormalize(
3964         slap_mask_t usage,
3965         Syntax *syntax,
3966         MatchingRule *mr,
3967         struct berval *val,
3968         struct berval *normalized,
3969         void *ctx )
3970 {
3971         int parts[9], rc;
3972         unsigned int len;
3973         struct berval fraction;
3974
3975         rc = check_time_syntax(val, 0, parts, &fraction);
3976         if (rc != LDAP_SUCCESS) {
3977                 return rc;
3978         }
3979
3980         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3981         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3982         if ( BER_BVISNULL( normalized ) ) {
3983                 return LBER_ERROR_MEMORY;
3984         }
3985
3986         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3987                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3988                 parts[4], parts[5], parts[6] );
3989         if ( !BER_BVISEMPTY( &fraction ) ) {
3990                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3991                         fraction.bv_val, fraction.bv_len );
3992                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3993         }
3994         strcpy( normalized->bv_val + len-1, "Z" );
3995         normalized->bv_len = len;
3996
3997         return LDAP_SUCCESS;
3998 }
3999
4000 static int
4001 generalizedTimeOrderingMatch(
4002         int *matchp,
4003         slap_mask_t flags,
4004         Syntax *syntax,
4005         MatchingRule *mr,
4006         struct berval *value,
4007         void *assertedValue )
4008 {
4009         struct berval *asserted = (struct berval *) assertedValue;
4010         ber_len_t v_len  = value->bv_len;
4011         ber_len_t av_len = asserted->bv_len;
4012
4013         /* ignore trailing 'Z' when comparing */
4014         int match = memcmp( value->bv_val, asserted->bv_val,
4015                 (v_len < av_len ? v_len : av_len) - 1 );
4016         if ( match == 0 ) match = v_len - av_len;
4017
4018         *matchp = match;
4019         return LDAP_SUCCESS;
4020 }
4021
4022 /* Index generation function */
4023 int generalizedTimeIndexer(
4024         slap_mask_t use,
4025         slap_mask_t flags,
4026         Syntax *syntax,
4027         MatchingRule *mr,
4028         struct berval *prefix,
4029         BerVarray values,
4030         BerVarray *keysp,
4031         void *ctx )
4032 {
4033         int i, j;
4034         BerVarray keys;
4035         char tmp[5];
4036         BerValue bvtmp; /* 40 bit index */
4037         struct lutil_tm tm;
4038         struct lutil_timet tt;
4039
4040         bvtmp.bv_len = sizeof(tmp);
4041         bvtmp.bv_val = tmp;
4042         for( i=0; values[i].bv_val != NULL; i++ ) {
4043                 /* just count them */
4044         }
4045
4046         /* we should have at least one value at this point */
4047         assert( i > 0 );
4048
4049         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4050
4051         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4052         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4053                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4054                 /* Use 40 bits of time for key */
4055                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4056                         lutil_tm2time( &tm, &tt );
4057                         tmp[0] = tt.tt_gsec & 0xff;
4058                         tmp[4] = tt.tt_sec & 0xff;
4059                         tt.tt_sec >>= 8;
4060                         tmp[3] = tt.tt_sec & 0xff;
4061                         tt.tt_sec >>= 8;
4062                         tmp[2] = tt.tt_sec & 0xff;
4063                         tt.tt_sec >>= 8;
4064                         tmp[1] = tt.tt_sec & 0xff;
4065                         
4066                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4067                 }
4068         }
4069
4070         keys[j].bv_val = NULL;
4071         keys[j].bv_len = 0;
4072
4073         *keysp = keys;
4074
4075         return LDAP_SUCCESS;
4076 }
4077
4078 /* Index generation function */
4079 int generalizedTimeFilter(
4080         slap_mask_t use,
4081         slap_mask_t flags,
4082         Syntax *syntax,
4083         MatchingRule *mr,
4084         struct berval *prefix,
4085         void * assertedValue,
4086         BerVarray *keysp,
4087         void *ctx )
4088 {
4089         BerVarray keys;
4090         char tmp[5];
4091         BerValue bvtmp; /* 40 bit index */
4092         BerValue *value = (BerValue *) assertedValue;
4093         struct lutil_tm tm;
4094         struct lutil_timet tt;
4095         
4096         bvtmp.bv_len = sizeof(tmp);
4097         bvtmp.bv_val = tmp;
4098         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4099         /* Use 40 bits of time for key */
4100         if ( value->bv_val && value->bv_len >= 10 &&
4101                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4102
4103                 lutil_tm2time( &tm, &tt );
4104                 tmp[0] = tt.tt_gsec & 0xff;
4105                 tmp[4] = tt.tt_sec & 0xff;
4106                 tt.tt_sec >>= 8;
4107                 tmp[3] = tt.tt_sec & 0xff;
4108                 tt.tt_sec >>= 8;
4109                 tmp[2] = tt.tt_sec & 0xff;
4110                 tt.tt_sec >>= 8;
4111                 tmp[1] = tt.tt_sec & 0xff;
4112
4113                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4114                 ber_dupbv_x(keys, &bvtmp, ctx );
4115                 keys[1].bv_val = NULL;
4116                 keys[1].bv_len = 0;
4117         } else {
4118                 keys = NULL;
4119         }
4120
4121         *keysp = keys;
4122
4123         return LDAP_SUCCESS;
4124 }
4125
4126 static int
4127 deliveryMethodValidate(
4128         Syntax *syntax,
4129         struct berval *val )
4130 {
4131 #undef LENOF
4132 #define LENOF(s) (sizeof(s)-1)
4133         struct berval tmp = *val;
4134         /*
4135      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4136          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4137          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4138          */
4139 again:
4140         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4141
4142         switch( tmp.bv_val[0] ) {
4143         case 'a':
4144         case 'A':
4145                 if(( tmp.bv_len >= LENOF("any") ) &&
4146                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4147                 {
4148                         tmp.bv_len -= LENOF("any");
4149                         tmp.bv_val += LENOF("any");
4150                         break;
4151                 }
4152                 return LDAP_INVALID_SYNTAX;
4153
4154         case 'm':
4155         case 'M':
4156                 if(( tmp.bv_len >= LENOF("mhs") ) &&
4157                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4158                 {
4159                         tmp.bv_len -= LENOF("mhs");
4160                         tmp.bv_val += LENOF("mhs");
4161                         break;
4162                 }
4163                 return LDAP_INVALID_SYNTAX;
4164
4165         case 'p':
4166         case 'P':
4167                 if(( tmp.bv_len >= LENOF("physical") ) &&
4168                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4169                 {
4170                         tmp.bv_len -= LENOF("physical");
4171                         tmp.bv_val += LENOF("physical");
4172                         break;
4173                 }
4174                 return LDAP_INVALID_SYNTAX;
4175
4176         case 't':
4177         case 'T': /* telex or teletex or telephone */
4178                 if(( tmp.bv_len >= LENOF("telex") ) &&
4179                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4180                 {
4181                         tmp.bv_len -= LENOF("telex");
4182                         tmp.bv_val += LENOF("telex");
4183                         break;
4184                 }
4185                 if(( tmp.bv_len >= LENOF("teletex") ) &&
4186                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4187                 {
4188                         tmp.bv_len -= LENOF("teletex");
4189                         tmp.bv_val += LENOF("teletex");
4190                         break;
4191                 }
4192                 if(( tmp.bv_len >= LENOF("telephone") ) &&
4193                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4194                 {
4195                         tmp.bv_len -= LENOF("telephone");
4196                         tmp.bv_val += LENOF("telephone");
4197                         break;
4198                 }
4199                 return LDAP_INVALID_SYNTAX;
4200
4201         case 'g':
4202         case 'G': /* g3fax or g4fax */
4203                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4204                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4205                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4206                 {
4207                         tmp.bv_len -= LENOF("g3fax");
4208                         tmp.bv_val += LENOF("g3fax");
4209                         break;
4210                 }
4211                 return LDAP_INVALID_SYNTAX;
4212
4213         case 'i':
4214         case 'I':
4215                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4216                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4217                 {
4218                         tmp.bv_len -= LENOF("ia5");
4219                         tmp.bv_val += LENOF("ia5");
4220                         break;
4221                 }
4222                 return LDAP_INVALID_SYNTAX;
4223
4224         case 'v':
4225         case 'V':
4226                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4227                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4228                 {
4229                         tmp.bv_len -= LENOF("videotex");
4230                         tmp.bv_val += LENOF("videotex");
4231                         break;
4232                 }
4233                 return LDAP_INVALID_SYNTAX;
4234
4235         default:
4236                 return LDAP_INVALID_SYNTAX;
4237         }
4238
4239         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4240
4241         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4242                 tmp.bv_len++;
4243                 tmp.bv_val--;
4244         }
4245         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4246                 tmp.bv_len++;
4247                 tmp.bv_val--;
4248         } else {
4249                 return LDAP_INVALID_SYNTAX;
4250         }
4251         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4252                 tmp.bv_len++;
4253                 tmp.bv_val--;
4254         }
4255
4256         goto again;
4257 }
4258
4259 static int
4260 nisNetgroupTripleValidate(
4261         Syntax *syntax,
4262         struct berval *val )
4263 {
4264         char *p, *e;
4265         int commas = 0;
4266
4267         if ( BER_BVISEMPTY( val ) ) {
4268                 return LDAP_INVALID_SYNTAX;
4269         }
4270
4271         p = (char *)val->bv_val;
4272         e = p + val->bv_len;
4273
4274         if ( *p != '(' /*')'*/ ) {
4275                 return LDAP_INVALID_SYNTAX;
4276         }
4277
4278         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4279                 if ( *p == ',' ) {
4280                         commas++;
4281                         if ( commas > 2 ) {
4282                                 return LDAP_INVALID_SYNTAX;
4283                         }
4284
4285                 } else if ( !AD_CHAR( *p ) ) {
4286                         return LDAP_INVALID_SYNTAX;
4287                 }
4288         }
4289
4290         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4291                 return LDAP_INVALID_SYNTAX;
4292         }
4293
4294         p++;
4295
4296         if (p != e) {
4297                 return LDAP_INVALID_SYNTAX;
4298         }
4299
4300         return LDAP_SUCCESS;
4301 }
4302
4303 static int
4304 bootParameterValidate(
4305         Syntax *syntax,
4306         struct berval *val )
4307 {
4308         char *p, *e;
4309
4310         if ( BER_BVISEMPTY( val ) ) {
4311                 return LDAP_INVALID_SYNTAX;
4312         }
4313
4314         p = (char *)val->bv_val;
4315         e = p + val->bv_len;
4316
4317         /* key */
4318         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4319                 if ( !AD_CHAR( *p ) ) {
4320                         return LDAP_INVALID_SYNTAX;
4321                 }
4322         }
4323
4324         if ( *p != '=' ) {
4325                 return LDAP_INVALID_SYNTAX;
4326         }
4327
4328         /* server */
4329         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4330                 if ( !AD_CHAR( *p ) ) {
4331                         return LDAP_INVALID_SYNTAX;
4332                 }
4333         }
4334
4335         if ( *p != ':' ) {
4336                 return LDAP_INVALID_SYNTAX;
4337         }
4338
4339         /* path */
4340         for ( p++; p < e; p++ ) {
4341                 if ( !SLAP_PRINTABLE( *p ) ) {
4342                         return LDAP_INVALID_SYNTAX;
4343                 }
4344         }
4345
4346         return LDAP_SUCCESS;
4347 }
4348
4349 static int
4350 firstComponentNormalize(
4351         slap_mask_t usage,
4352         Syntax *syntax,
4353         MatchingRule *mr,
4354         struct berval *val,
4355         struct berval *normalized,
4356         void *ctx )
4357 {
4358         int rc;
4359         struct berval comp;
4360         ber_len_t len;
4361
4362         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4363                 ber_dupbv_x( normalized, val, ctx );
4364                 return LDAP_SUCCESS;
4365         }
4366
4367         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4368
4369         if( val->bv_val[0] != '(' /*')'*/ &&
4370                 val->bv_val[0] != '{' /*'}'*/ )
4371         {
4372                 return LDAP_INVALID_SYNTAX;
4373         }
4374
4375         /* trim leading white space */
4376         for( len=1;
4377                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4378                 len++ )
4379         {
4380                 /* empty */
4381         }
4382
4383         /* grab next word */
4384         comp.bv_val = &val->bv_val[len];
4385         len = val->bv_len - len;
4386         for( comp.bv_len = 0;
4387                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4388                 comp.bv_len++ )
4389         {
4390                 /* empty */
4391         }
4392
4393         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4394                 rc = numericoidValidate( NULL, &comp );
4395         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4396                 rc = integerValidate( NULL, &comp );
4397         } else {
4398                 rc = LDAP_INVALID_SYNTAX;
4399         }
4400         
4401
4402         if( rc == LDAP_SUCCESS ) {
4403                 ber_dupbv_x( normalized, &comp, ctx );
4404         }
4405
4406         return rc;
4407 }
4408
4409 static char *country_gen_syn[] = {
4410         "1.3.6.1.4.1.1466.115.121.1.15",
4411         "1.3.6.1.4.1.1466.115.121.1.26",
4412         "1.3.6.1.4.1.1466.115.121.1.44",
4413         NULL
4414 };
4415
4416 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4417 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4418
4419 static slap_syntax_defs_rec syntax_defs[] = {
4420         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4421                 X_BINARY X_NOT_H_R ")",
4422                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4423         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4424                 0, NULL, NULL, NULL},
4425         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4426                 0, NULL, NULL, NULL},
4427         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4428                 X_NOT_H_R ")",
4429                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4430         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4431                 X_NOT_H_R ")",
4432                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4433         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4434                 0, NULL, bitStringValidate, NULL },
4435         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4436                 0, NULL, booleanValidate, NULL},
4437         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4438                 X_BINARY X_NOT_H_R ")",
4439                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4440                 NULL, certificateValidate, NULL},
4441         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4442                 X_BINARY X_NOT_H_R ")",
4443                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4444                 NULL, certificateListValidate, NULL},
4445         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4446                 X_BINARY X_NOT_H_R ")",
4447                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4448                 NULL, sequenceValidate, NULL},
4449 #if 0   /* need to go __after__ printableString */
4450         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4451                 0, "1.3.6.1.4.1.1466.115.121.1.44",
4452                 countryStringValidate, NULL},
4453 #endif
4454         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4455                 0, NULL, dnValidate, dnPretty},
4456         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4457                 0, NULL, rdnValidate, rdnPretty},
4458 #ifdef LDAP_COMP_MATCH
4459         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4460                 0, NULL, allComponentsValidate, NULL},
4461         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4462                 0, NULL, componentFilterValidate, NULL},
4463 #endif
4464         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4465                 0, NULL, NULL, NULL},
4466         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4467                 0, NULL, deliveryMethodValidate, NULL},
4468         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4469                 0, NULL, UTF8StringValidate, NULL},
4470         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4471                 0, NULL, NULL, NULL},
4472         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4473                 0, NULL, NULL, NULL},
4474         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4475                 0, NULL, NULL, NULL},
4476         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4477                 0, NULL, NULL, NULL},
4478         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4479                 0, NULL, NULL, NULL},
4480         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4481                 0, NULL, printablesStringValidate, NULL},
4482         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4483                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4484         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4485                 0, NULL, generalizedTimeValidate, NULL},
4486         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4487                 0, NULL, NULL, NULL},
4488         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4489                 0, NULL, IA5StringValidate, NULL},
4490         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4491                 0, NULL, integerValidate, NULL},
4492         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4493                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4494         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4495                 0, NULL, NULL, NULL},
4496         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4497                 0, NULL, NULL, NULL},
4498         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4499                 0, NULL, NULL, NULL},
4500         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4501                 0, NULL, NULL, NULL},
4502         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4503                 0, NULL, NULL, NULL},
4504         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4505                 0, NULL, nameUIDValidate, nameUIDPretty },
4506         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4507                 0, NULL, NULL, NULL},
4508         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4509                 0, NULL, numericStringValidate, NULL},
4510         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4511                 0, NULL, NULL, NULL},
4512         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4513                 0, NULL, numericoidValidate, NULL},
4514         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4515                 0, NULL, IA5StringValidate, NULL},
4516         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4517                 0, NULL, blobValidate, NULL},
4518         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4519                 0, NULL, UTF8StringValidate, NULL},
4520         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4521                 0, NULL, NULL, NULL},
4522         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4523                 0, NULL, NULL, NULL},
4524         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4525                 0, NULL, printableStringValidate, NULL},
4526         /* moved here because now depends on Directory String, IA5 String 
4527          * and Printable String */
4528         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4529                 0, country_gen_syn, countryStringValidate, NULL},
4530         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4531 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4532                 0, NULL, subtreeSpecificationValidate, NULL},
4533         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4534                 X_BINARY X_NOT_H_R ")",
4535                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4536         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4537                 0, NULL, printableStringValidate, NULL},
4538         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4539                 0, NULL, NULL, NULL},
4540         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4541                 0, NULL, printablesStringValidate, NULL},
4542 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4543         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4544                 0, NULL, utcTimeValidate, NULL},
4545 #endif
4546         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4547                 0, NULL, NULL, NULL},
4548         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4549                 0, NULL, NULL, NULL},
4550         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4551                 0, NULL, NULL, NULL},
4552         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4553                 0, NULL, NULL, NULL},
4554         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4555                 0, NULL, NULL, NULL},
4556
4557         /* RFC 2307 NIS Syntaxes */
4558         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4559                 0, NULL, nisNetgroupTripleValidate, NULL},
4560         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4561                 0, NULL, bootParameterValidate, NULL},
4562
4563         /* draft-zeilenga-ldap-x509 */
4564         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4565                 SLAP_SYNTAX_HIDE, NULL,
4566                 serialNumberAndIssuerValidate,
4567                 serialNumberAndIssuerPretty},
4568         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4569                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4570         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4571                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4572         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4573                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4574         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4575                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4576         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4577                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4578         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4579                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4580
4581 #ifdef SLAPD_AUTHPASSWD
4582         /* needs updating */
4583         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4584                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4585 #endif
4586
4587         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4588                 0, NULL, UUIDValidate, UUIDPretty},
4589
4590         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4591                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4592
4593         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4594                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4595
4596         /* OpenLDAP Void Syntax */
4597         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4598                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4599
4600         /* FIXME: OID is unused, but not registered yet */
4601         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4602                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4603
4604         {NULL, 0, NULL, NULL, NULL}
4605 };
4606
4607 char *csnSIDMatchSyntaxes[] = {
4608         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4609         NULL
4610 };
4611 char *certificateExactMatchSyntaxes[] = {
4612         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4613         NULL
4614 };
4615 #ifdef LDAP_COMP_MATCH
4616 char *componentFilterMatchSyntaxes[] = {
4617         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4618         NULL
4619 };
4620 #endif
4621 char *directoryStringSyntaxes[] = {
4622         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4623         NULL
4624 };
4625 char *integerFirstComponentMatchSyntaxes[] = {
4626         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4627         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4628         NULL
4629 };
4630 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4631         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4632         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4633         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4634         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4635         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4636         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4637         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4638         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4639         NULL
4640 };
4641
4642 /*
4643  * Other matching rules in X.520 that we do not use (yet):
4644  *
4645  * 2.5.13.25    uTCTimeMatch
4646  * 2.5.13.26    uTCTimeOrderingMatch
4647  * 2.5.13.31*   directoryStringFirstComponentMatch
4648  * 2.5.13.32*   wordMatch
4649  * 2.5.13.33*   keywordMatch
4650  * 2.5.13.36+   certificatePairExactMatch
4651  * 2.5.13.37+   certificatePairMatch
4652  * 2.5.13.38+   certificateListExactMatch
4653  * 2.5.13.39+   certificateListMatch
4654  * 2.5.13.40+   algorithmIdentifierMatch
4655  * 2.5.13.41*   storedPrefixMatch
4656  * 2.5.13.42    attributeCertificateMatch
4657  * 2.5.13.43    readerAndKeyIDMatch
4658  * 2.5.13.44    attributeIntegrityMatch
4659  *
4660  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4661  * (+) described in draft-zeilenga-ldap-x509
4662  */
4663 static slap_mrule_defs_rec mrule_defs[] = {
4664         /*
4665          * EQUALITY matching rules must be listed after associated APPROX
4666          * matching rules.  So, we list all APPROX matching rules first.
4667          */
4668         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4669                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4670                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4671                 NULL, NULL, directoryStringApproxMatch,
4672                 directoryStringApproxIndexer, directoryStringApproxFilter,
4673                 NULL},
4674
4675         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4676                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4677                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4678                 NULL, NULL, IA5StringApproxMatch,
4679                 IA5StringApproxIndexer, IA5StringApproxFilter,
4680                 NULL},
4681
4682         /*
4683          * Other matching rules
4684          */
4685         
4686         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4687                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4688                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4689                 NULL, NULL, octetStringMatch,
4690                 octetStringIndexer, octetStringFilter,
4691                 NULL },
4692
4693         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4694                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4695                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4696                 NULL, dnNormalize, dnMatch,
4697                 octetStringIndexer, octetStringFilter,
4698                 NULL },
4699
4700         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4701                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4702                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4703                 NULL, dnNormalize, dnRelativeMatch,
4704                 NULL, NULL,
4705                 NULL },
4706
4707         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4708                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4709                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4710                 NULL, dnNormalize, dnRelativeMatch,
4711                 NULL, NULL,
4712                 NULL },
4713
4714         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4715                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4716                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4717                 NULL, dnNormalize, dnRelativeMatch,
4718                 NULL, NULL,
4719                 NULL },
4720
4721         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4722                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4723                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4724                 NULL, dnNormalize, dnRelativeMatch,
4725                 NULL, NULL,
4726                 NULL },
4727
4728         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4729                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4730                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4731                 NULL, rdnNormalize, rdnMatch,
4732                 octetStringIndexer, octetStringFilter,
4733                 NULL },
4734
4735 #ifdef LDAP_COMP_MATCH
4736         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4737                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4738                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4739                 NULL, NULL , componentFilterMatch,
4740                 octetStringIndexer, octetStringFilter,
4741                 NULL },
4742
4743         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4744                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4745                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4746                 NULL, NULL , allComponentsMatch,
4747                 octetStringIndexer, octetStringFilter,
4748                 NULL },
4749
4750         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4751                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4752                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4753                 NULL, NULL , directoryComponentsMatch,
4754                 octetStringIndexer, octetStringFilter,
4755                 NULL },
4756 #endif
4757
4758         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4759                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4760                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4761                 NULL, UTF8StringNormalize, octetStringMatch,
4762                 octetStringIndexer, octetStringFilter,
4763                 directoryStringApproxMatchOID },
4764
4765         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4766                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4767                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4768                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4769                 NULL, NULL,
4770                 "caseIgnoreMatch" },
4771
4772         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4773                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4774                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4775                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4776                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4777                 "caseIgnoreMatch" },
4778
4779         {"( 2.5.13.5 NAME 'caseExactMatch' "
4780                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4781                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4782                 NULL, UTF8StringNormalize, octetStringMatch,
4783                 octetStringIndexer, octetStringFilter,
4784                 directoryStringApproxMatchOID },
4785
4786         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4787                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4788                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4789                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4790                 NULL, NULL,
4791                 "caseExactMatch" },
4792
4793         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4794                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4795                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4796                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4797                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4798                 "caseExactMatch" },
4799
4800         {"( 2.5.13.8 NAME 'numericStringMatch' "
4801                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4802                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4803                 NULL, numericStringNormalize, octetStringMatch,
4804                 octetStringIndexer, octetStringFilter,
4805                 NULL },
4806
4807         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4808                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4809                 SLAP_MR_ORDERING, NULL,
4810                 NULL, numericStringNormalize, octetStringOrderingMatch,
4811                 NULL, NULL,
4812                 "numericStringMatch" },
4813
4814         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4815                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4816                 SLAP_MR_SUBSTR, NULL,
4817                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4818                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4819                 "numericStringMatch" },
4820
4821         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4822                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4823                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4824                 NULL, NULL, NULL, NULL, NULL, NULL },
4825
4826         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4827                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4828                 SLAP_MR_SUBSTR, NULL,
4829                 NULL, NULL, NULL, NULL, NULL,
4830                 "caseIgnoreListMatch" },
4831
4832         {"( 2.5.13.13 NAME 'booleanMatch' "
4833                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4834                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4835                 NULL, NULL, booleanMatch,
4836                 octetStringIndexer, octetStringFilter,
4837                 NULL },
4838
4839         {"( 2.5.13.14 NAME 'integerMatch' "
4840                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4841                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4842                 NULL, NULL, integerMatch,
4843                 integerIndexer, integerFilter,
4844                 NULL },
4845
4846         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4847                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4848                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4849                 NULL, NULL, integerMatch,
4850                 NULL, NULL,
4851                 "integerMatch" },
4852
4853         {"( 2.5.13.16 NAME 'bitStringMatch' "
4854                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4855                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4856                 NULL, NULL, octetStringMatch,
4857                 octetStringIndexer, octetStringFilter,
4858                 NULL },
4859
4860         {"( 2.5.13.17 NAME 'octetStringMatch' "
4861                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4862                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4863                 NULL, NULL, octetStringMatch,
4864                 octetStringIndexer, octetStringFilter,
4865                 NULL },
4866
4867         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4868                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4869                 SLAP_MR_ORDERING, NULL,
4870                 NULL, NULL, octetStringOrderingMatch,
4871                 NULL, NULL,
4872                 "octetStringMatch" },
4873
4874         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4875                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4876                 SLAP_MR_SUBSTR, NULL,
4877                 NULL, NULL, octetStringSubstringsMatch,
4878                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4879                 "octetStringMatch" },
4880
4881         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4882                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4883                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4884                 NULL,
4885                 telephoneNumberNormalize, octetStringMatch,
4886                 octetStringIndexer, octetStringFilter,
4887                 NULL },
4888
4889         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4890                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4891                 SLAP_MR_SUBSTR, NULL,
4892                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4893                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4894                 "telephoneNumberMatch" },
4895
4896         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4897                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4898                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4899                 NULL, NULL, NULL, NULL, NULL, NULL },
4900
4901         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4902                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4903                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4904                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4905                 uniqueMemberIndexer, uniqueMemberFilter,
4906                 NULL },
4907
4908         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4909                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4910                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4911                 NULL, NULL, NULL, NULL, NULL, NULL },
4912
4913         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4914                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4915                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4916                 NULL, generalizedTimeNormalize, octetStringMatch,
4917                 generalizedTimeIndexer, generalizedTimeFilter,
4918                 NULL },
4919
4920         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4921                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4922                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4923                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4924                 NULL, NULL,
4925                 "generalizedTimeMatch" },
4926
4927         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4928                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4929                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4930                         integerFirstComponentMatchSyntaxes,
4931                 NULL, firstComponentNormalize, integerMatch,
4932                 octetStringIndexer, octetStringFilter,
4933                 NULL },
4934
4935         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4936                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4937                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4938                         objectIdentifierFirstComponentMatchSyntaxes,
4939                 NULL, firstComponentNormalize, octetStringMatch,
4940                 octetStringIndexer, octetStringFilter,
4941                 NULL },
4942
4943         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4944                 "SYNTAX 1.3.6.1.1.15.1 )",
4945                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4946                 NULL, certificateExactNormalize, octetStringMatch,
4947                 octetStringIndexer, octetStringFilter,
4948                 NULL },
4949
4950         {"( 2.5.13.35 NAME 'certificateMatch' "
4951                 "SYNTAX 1.3.6.1.1.15.2 )",
4952                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4953                 NULL, NULL, NULL, NULL, NULL,
4954                 NULL },
4955
4956         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4957                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4958                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4959                 NULL, IA5StringNormalize, octetStringMatch,
4960                 octetStringIndexer, octetStringFilter,
4961                 IA5StringApproxMatchOID },
4962
4963         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4964                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4965                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4966                 NULL, IA5StringNormalize, octetStringMatch,
4967                 octetStringIndexer, octetStringFilter,
4968                 IA5StringApproxMatchOID },
4969
4970         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4971                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4972                 SLAP_MR_SUBSTR, NULL,
4973                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4974                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4975                 "caseIgnoreIA5Match" },
4976
4977         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4978                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4979                 SLAP_MR_SUBSTR, NULL,
4980                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4981                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4982                 "caseExactIA5Match" },
4983
4984 #ifdef SLAPD_AUTHPASSWD
4985         /* needs updating */
4986         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4987                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4988                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4989                 NULL, NULL, authPasswordMatch,
4990                 NULL, NULL,
4991                 NULL},
4992 #endif
4993
4994         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4995                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4996                 SLAP_MR_EXT, NULL,
4997                 NULL, NULL, integerBitAndMatch,
4998                 NULL, NULL,
4999                 "integerMatch" },
5000
5001         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5002                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5003                 SLAP_MR_EXT, NULL,
5004                 NULL, NULL, integerBitOrMatch,
5005                 NULL, NULL,
5006                 "integerMatch" },
5007
5008         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5009                 "SYNTAX 1.3.6.1.1.16.1 )",
5010                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5011                 NULL, UUIDNormalize, octetStringMatch,
5012                 octetStringIndexer, octetStringFilter,
5013                 NULL},
5014
5015         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5016                 "SYNTAX 1.3.6.1.1.16.1 )",
5017                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5018                 NULL, UUIDNormalize, octetStringOrderingMatch,
5019                 octetStringIndexer, octetStringFilter,
5020                 "UUIDMatch"},
5021
5022         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5023                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5024                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5025                 NULL, csnNormalize, csnMatch,
5026                 csnIndexer, csnFilter,
5027                 NULL},
5028
5029         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5030                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5031                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5032                 NULL, NULL, csnOrderingMatch,
5033                 NULL, NULL,
5034                 "CSNMatch" },
5035
5036         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5037                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5038                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5039                 NULL, csnSidNormalize, octetStringMatch,
5040                 octetStringIndexer, octetStringFilter,
5041                 NULL },
5042
5043         /* FIXME: OID is unused, but not registered yet */
5044         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5045                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5046                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5047                 NULL, authzNormalize, authzMatch,
5048                 NULL, NULL,
5049                 NULL},
5050
5051         {NULL, SLAP_MR_NONE, NULL,
5052                 NULL, NULL, NULL, NULL, NULL,
5053                 NULL }
5054 };
5055
5056 int
5057 slap_schema_init( void )
5058 {
5059         int             res;
5060         int             i;
5061
5062         /* we should only be called once (from main) */
5063         assert( schema_init_done == 0 );
5064
5065         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5066                 res = register_syntax( &syntax_defs[i] );
5067
5068                 if ( res ) {
5069                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5070                                  syntax_defs[i].sd_desc );
5071                         return LDAP_OTHER;
5072                 }
5073         }
5074
5075         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5076                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5077                         mrule_defs[i].mrd_compat_syntaxes == NULL )
5078                 {
5079                         fprintf( stderr,
5080                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
5081                                  mrule_defs[i].mrd_desc );
5082                         continue;
5083                 }
5084
5085                 res = register_matching_rule( &mrule_defs[i] );
5086
5087                 if ( res ) {
5088                         fprintf( stderr,
5089                                 "slap_schema_init: Error registering matching rule %s\n",
5090                                  mrule_defs[i].mrd_desc );
5091                         return LDAP_OTHER;
5092                 }
5093         }
5094
5095         res = slap_schema_load();
5096         schema_init_done = 1;
5097         return res;
5098 }
5099
5100 void
5101 schema_destroy( void )
5102 {
5103         oidm_destroy();
5104         oc_destroy();
5105         at_destroy();
5106         mr_destroy();
5107         mru_destroy();
5108         syn_destroy();
5109
5110         if( schema_init_done ) {
5111                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5112                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5113         }
5114 }